Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions frontend/src/i18n/__tests__/translationKeys.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from 'path';
type TranslationTree = { [key: string]: string | TranslationTree };

const eslintConfig = require('../../../.eslintrc.js');
const PLURAL_SUFFIX = /_(zero|one|two|few|many|other)$/;

const flattenKeys = (tree: TranslationTree, prefix = ''): string[] => (
Object.entries(tree).flatMap(([key, value]) => {
Expand Down Expand Up @@ -40,11 +41,23 @@ describe('i18n migration manifest', () => {
const enKeys = new Set(flattenKeys(readJson('en.json')));
const zhKeys = new Set(flattenKeys(readJson('zh-CN.json')));
const hasKey = (keys: Set<string>, key: string): boolean => (
keys.has(key) || keys.has(`${key}_one`) || keys.has(`${key}_other`)
keys.has(key) || [...keys].some((candidate) => candidate.replace(PLURAL_SUFFIX, '') === key)
);

it('keeps English and Simplified Chinese key paths identical', () => {
expect([...zhKeys].sort()).toEqual([...enKeys].sort());
it('keeps English and Simplified Chinese base key paths identical', () => {
const normalize = (keys: Set<string>) => [...new Set([...keys].map((key) => key.replace(PLURAL_SUFFIX, '')))];
expect(normalize(zhKeys).sort()).toEqual(normalize(enKeys).sort());
});

it('provides every CLDR plural form required by each language', () => {
const pluralBases = new Set([...enKeys, ...zhKeys].filter((key) => PLURAL_SUFFIX.test(key)).map((key) => key.replace(PLURAL_SUFFIX, '')));
const missing = (language: string, keys: Set<string>) => [...pluralBases].flatMap((base) => (
new Intl.PluralRules(language).resolvedOptions().pluralCategories
.filter((category) => !keys.has(`${base}_${category}`))
.map((category) => `${language}:${base}_${category}`)
));

expect([...missing('en', enKeys), ...missing('zh-CN', zhKeys)]).toEqual([]);
});

it('resolves every literal translation key used by a migrated component', () => {
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -736,8 +736,10 @@
"hidePodTeam": "Hide pod team",
"createdByMeta": "Created by {{name}} · {{date}}",
"agentCount": "{{count}} agent",
"agentCount_one": "{{count}} agent",
"agentCount_other": "{{count}} agents",
"humanCount": "{{count}} human",
"humanCount_one": "{{count}} human",
"humanCount_other": "{{count}} humans",
"untitledAnnouncement": "Untitled announcement",
"externalLink": "External link",
Expand Down Expand Up @@ -768,6 +770,7 @@
"progress": {
"title": "Progress",
"stat": "{{complete}} of {{total}} task complete",
"stat_one": "{{complete}} of {{total}} task complete",
"stat_other": "{{complete}} of {{total}} tasks complete"
},
"goal": {
Expand Down Expand Up @@ -854,6 +857,7 @@
"emptyDeck": "Empty deck",
"truncated": "Preview truncated at 200 KB. Click Open for the full file.",
"moreRows": "{{count}} more row not shown. Click Open for the full file.",
"moreRows_one": "{{count}} more row not shown. Click Open for the full file.",
"moreRows_other": "{{count}} more rows not shown. Click Open for the full file."
}
},
Expand Down
Loading