feat(i18n): add Japanese (ja) locale (#1694)
* feat(i18n): add Japanese (ja) locale - Add packages/app/src/i18n/resources/ja.ts with 1287 keys matching en.ts - Register ja in i18next.ts, locales.ts (SupportedLocale, LANGUAGE_OPTIONS, SUPPORTED_LANGUAGES, LANGUAGE_NATIVE_NAMES, LANGUAGE_NAMES_BY_LOCALE, resolveSupportedLocale) - Add ja label key to all six existing locale files (ar, en, es, fr, ru, zh-CN) - Update locales.test.ts to cover ja in all relevant assertions Translation reviewed by Codex across four passes; terminology, placeholder parity, and naturalness confirmed clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(i18n): add ja to resources.test.ts and fix test descriptions - Import ja and add to key-parity, fallback-ratio, interpolation, and model-count assertions in resources.test.ts - Update test descriptions to say "all supported language(s)" instead of "UN official language(s)" (ja is not a UN official language) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add Japanese README (README.ja.md) Add README.ja.md translated from the English source, reviewed by Codex across two passes. Link it in the language navigation of README.md and README.zh-CN.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: apply oxfmt formatting to locales.ts and ja.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
70ea960153
commit
507345dbee
@@ -5,6 +5,7 @@ import { ar } from "./resources/ar";
|
||||
import { en } from "./resources/en";
|
||||
import { es } from "./resources/es";
|
||||
import { fr } from "./resources/fr";
|
||||
import { ja } from "./resources/ja";
|
||||
import { ru } from "./resources/ru";
|
||||
import { zhCN } from "./resources/zh-CN";
|
||||
|
||||
@@ -101,21 +102,23 @@ function findUntranslatedConnectionErrors(): string[] {
|
||||
}
|
||||
|
||||
describe("translation resources", () => {
|
||||
it("keeps UN official language keys in sync with English", () => {
|
||||
it("keeps all supported language keys in sync with English", () => {
|
||||
const englishKeys = flattenKeys(en).sort();
|
||||
expect(flattenKeys(ar).sort()).toEqual(englishKeys);
|
||||
expect(flattenKeys(es).sort()).toEqual(englishKeys);
|
||||
expect(flattenKeys(fr).sort()).toEqual(englishKeys);
|
||||
expect(flattenKeys(ja).sort()).toEqual(englishKeys);
|
||||
expect(flattenKeys(ru).sort()).toEqual(englishKeys);
|
||||
expect(flattenKeys(zhCN).sort()).toEqual(englishKeys);
|
||||
});
|
||||
|
||||
it("keeps non-English UN official languages translated beyond fallback labels", () => {
|
||||
it("keeps non-English supported languages translated beyond fallback labels", () => {
|
||||
const totalStrings = Object.keys(flattenStrings(en)).length;
|
||||
const maxFallbackStrings = Math.floor(totalStrings * 0.25);
|
||||
expect(countMatchingEnglishStrings(ar)).toBeLessThan(maxFallbackStrings);
|
||||
expect(countMatchingEnglishStrings(es)).toBeLessThan(maxFallbackStrings);
|
||||
expect(countMatchingEnglishStrings(fr)).toBeLessThan(maxFallbackStrings);
|
||||
expect(countMatchingEnglishStrings(ja)).toBeLessThan(maxFallbackStrings);
|
||||
expect(countMatchingEnglishStrings(ru)).toBeLessThan(maxFallbackStrings);
|
||||
});
|
||||
|
||||
@@ -123,6 +126,7 @@ describe("translation resources", () => {
|
||||
expect(findInterpolationMismatches(ar)).toEqual([]);
|
||||
expect(findInterpolationMismatches(es)).toEqual([]);
|
||||
expect(findInterpolationMismatches(fr)).toEqual([]);
|
||||
expect(findInterpolationMismatches(ja)).toEqual([]);
|
||||
expect(findInterpolationMismatches(ru)).toEqual([]);
|
||||
expect(findInterpolationMismatches(zhCN)).toEqual([]);
|
||||
});
|
||||
@@ -137,11 +141,13 @@ describe("translation resources", () => {
|
||||
expect(ar.modelSelector.modelCountPlural).toBe("{{count}} نماذج");
|
||||
expect(es.modelSelector.modelCountPlural).toBe("{{count}} modelos");
|
||||
expect(fr.modelSelector.modelCountPlural).toBe("{{count}} modèles");
|
||||
expect(ja.modelSelector.modelCountPlural).toBe("{{count}}つのモデル");
|
||||
expect(ru.modelSelector.modelCountPlural).toBe("{{count}} моделей");
|
||||
expect(zhCN.modelSelector.modelCountPlural).toBe("{{count}} 个模型");
|
||||
expect(ar.settings.providers.models.many).toBe("{{count}} نماذج");
|
||||
expect(es.settings.providers.models.many).toBe("{{count}} modelos");
|
||||
expect(fr.settings.providers.models.many).toBe("{{count}} modèles");
|
||||
expect(ja.settings.providers.models.many).toBe("{{count}}つのモデル");
|
||||
expect(ru.settings.providers.models.many).toBe("{{count}} моделей");
|
||||
expect(zhCN.settings.providers.models.many).toBe("{{count}} 个 Model");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user