feat(i18n): add Lingui runtime and development tooling
- add SSR-safe I18nProvider, Translate, locale hooks, catalog activation, and typed runtime APIs - add consumer-owned Lingui configuration helpers and a CLI for locale creation, extraction, compilation, and project discovery - add catalog read/write services plus a Vite development API plugin scoped to each consuming application - add the portal-based I18nDevtool, message editor, dark-theme tracking, and standalone Message Studio - document the consumer workflow and cover runtime, configuration, catalog, CLI, and Devtool behavior with tests
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import * as React from "react"
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react"
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { MessagePanel } from "./message-panel"
|
||||
import type { DevtoolMessage, MessageRepository } from "./types"
|
||||
|
||||
const message: DevtoolMessage = {
|
||||
catalog: "messages",
|
||||
comments: ["Navigation title"],
|
||||
id: "navigation.home",
|
||||
missing: true,
|
||||
obsolete: false,
|
||||
origins: [{ file: "src/navigation.tsx", line: 12 }],
|
||||
source: "Home",
|
||||
translation: "",
|
||||
}
|
||||
|
||||
describe("MessagePanel", () => {
|
||||
it("loads, filters, and saves messages through the repository", async () => {
|
||||
const updateMessage = vi.fn(async (input) => ({
|
||||
...message,
|
||||
missing: false,
|
||||
translation: input.translation,
|
||||
}))
|
||||
const repository: MessageRepository = {
|
||||
getMessages: vi.fn(async () => [message]),
|
||||
updateMessage,
|
||||
}
|
||||
|
||||
render(<MessagePanel locale="zh-Hans" repository={repository} />)
|
||||
|
||||
expect(await screen.findByText("navigation.home")).toBeTruthy()
|
||||
|
||||
const textarea = screen.getByLabelText(
|
||||
"navigation.home translation for zh-Hans"
|
||||
)
|
||||
fireEvent.change(textarea, { target: { value: "首页" } })
|
||||
fireEvent.click(screen.getByRole("button", { name: "Save" }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(updateMessage).toHaveBeenCalledWith({
|
||||
catalog: "messages",
|
||||
id: "navigation.home",
|
||||
locale: "zh-Hans",
|
||||
translation: "首页",
|
||||
})
|
||||
})
|
||||
expect(await screen.findByText("Saved")).toBeTruthy()
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText("Search messages"), {
|
||||
target: { value: "does not exist" },
|
||||
})
|
||||
expect(
|
||||
screen.getByText("No messages match the current filters.")
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user