import { render, screen } from "@testing-library/react"; import { test, expect, describe, vi } from "vitest"; import { useTranslation } from "react-i18next"; import translations from "../../src/i18n/translation.json"; import { UserAvatar } from "../../src/components/features/sidebar/user-avatar"; vi.mock("@nextui-org/react", () => ({ Tooltip: ({ content, children }: { content: string; children: React.ReactNode }) => (
{children}
{content}
), })); const supportedLanguages = ['en', 'ja', 'zh-CN', 'zh-TW', 'ko-KR', 'de', 'no', 'it', 'pt', 'es', 'ar', 'fr', 'tr']; // Helper function to check if a translation exists for all supported languages function checkTranslationExists(key: string) { const missingTranslations: string[] = []; const translationEntry = (translations as Record>)[key]; if (!translationEntry) { throw new Error(`Translation key "${key}" does not exist in translation.json`); } for (const lang of supportedLanguages) { if (!translationEntry[lang]) { missingTranslations.push(lang); } } return missingTranslations; } // Helper function to find duplicate translation keys function findDuplicateKeys(obj: Record) { const seen = new Set(); const duplicates = new Set(); // Only check top-level keys as these are our translation keys for (const key in obj) { if (seen.has(key)) { duplicates.add(key); } else { seen.add(key); } } return Array.from(duplicates); } vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string) => { const translationEntry = (translations as Record>)[key]; return translationEntry?.ja || key; }, }), })); describe("Landing page translations", () => { test("should render Japanese translations correctly", () => { // Mock a simple component that uses the translations const TestComponent = () => { const { t } = useTranslation(); return (
{}} />

{t("LANDING$TITLE")}

{t("WORKSPACE$TERMINAL_TAB_LABEL")} {t("WORKSPACE$BROWSER_TAB_LABEL")} {t("WORKSPACE$JUPYTER_TAB_LABEL")} {t("WORKSPACE$CODE_EDITOR_TAB_LABEL")}
{t("WORKSPACE$TITLE")}
{t("TERMINAL$WAITING_FOR_CLIENT")} {t("STATUS$CONNECTED")} {t("STATUS$CONNECTED_TO_SERVER")}
{`5 ${t("TIME$MINUTES_AGO")}`} {`2 ${t("TIME$HOURS_AGO")}`} {`3 ${t("TIME$DAYS_AGO")}`}
); }; render(); // Check main content translations expect(screen.getByText("開発を始めましょう!")).toBeInTheDocument(); expect(screen.getByText("VS Codeで開く")).toBeInTheDocument(); expect(screen.getByText("テストカバレッジを向上させる")).toBeInTheDocument(); expect(screen.getByText("Dependabot PRを自動マージ")).toBeInTheDocument(); expect(screen.getByText("READMEを改善")).toBeInTheDocument(); expect(screen.getByText("依存関係を整理")).toBeInTheDocument(); // Check user avatar tooltip const userAvatar = screen.getByTestId("user-avatar"); userAvatar.focus(); expect(screen.getByText("アカウント設定")).toBeInTheDocument(); // Check tab labels const tabs = screen.getByTestId("tabs"); expect(tabs).toHaveTextContent("ターミナル"); expect(tabs).toHaveTextContent("ブラウザ"); expect(tabs).toHaveTextContent("Jupyter"); expect(tabs).toHaveTextContent("コードエディタ"); // Check workspace label and new project button expect(screen.getByTestId("workspace-label")).toHaveTextContent("ワークスペース"); expect(screen.getByTestId("new-project")).toHaveTextContent("新規プロジェクト"); // Check status messages const status = screen.getByTestId("status"); expect(status).toHaveTextContent("クライアントの準備を待機中"); expect(status).toHaveTextContent("接続済み"); expect(status).toHaveTextContent("サーバーに接続済み"); // Check account settings menu expect(screen.getByText("アカウント設定")).toBeInTheDocument(); // Check time-related translations const time = screen.getByTestId("time"); expect(time).toHaveTextContent("5 分前"); expect(time).toHaveTextContent("2 時間前"); expect(time).toHaveTextContent("3 日前"); }); test("all translation keys should have translations for all supported languages", () => { // Test all translation keys used in the component const translationKeys = [ "LANDING$TITLE", "VSCODE$OPEN", "SUGGESTIONS$INCREASE_TEST_COVERAGE", "SUGGESTIONS$AUTO_MERGE_PRS", "SUGGESTIONS$FIX_README", "SUGGESTIONS$CLEAN_DEPENDENCIES", "WORKSPACE$TERMINAL_TAB_LABEL", "WORKSPACE$BROWSER_TAB_LABEL", "WORKSPACE$JUPYTER_TAB_LABEL", "WORKSPACE$CODE_EDITOR_TAB_LABEL", "WORKSPACE$TITLE", "PROJECT$NEW_PROJECT", "TERMINAL$WAITING_FOR_CLIENT", "STATUS$CONNECTED", "STATUS$CONNECTED_TO_SERVER", "TIME$MINUTES_AGO", "TIME$HOURS_AGO", "TIME$DAYS_AGO" ]; // Check all keys and collect missing translations const missingTranslationsMap = new Map(); translationKeys.forEach(key => { const missing = checkTranslationExists(key); if (missing.length > 0) { missingTranslationsMap.set(key, missing); } }); // If any translations are missing, throw an error with all missing translations if (missingTranslationsMap.size > 0) { const errorMessage = Array.from(missingTranslationsMap.entries()) .map(([key, langs]) => `\n- "${key}" is missing translations for: ${langs.join(', ')}`) .join(''); throw new Error(`Missing translations:${errorMessage}`); } }); test("translation file should not have duplicate keys", () => { const duplicates = findDuplicateKeys(translations); if (duplicates.length > 0) { throw new Error(`Found duplicate translation keys: ${duplicates.join(', ')}`); } }); });