mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-20 22:01:45 +00:00
e63a7799fb
Every non-en locale now exposes the exact same flat key set as en. Keys that had drifted out of sync are backfilled with the English source value (tagged en-fallback) so t() resolves a real string instead of relying on the silent runtime fallback; no existing translation was touched and no key was removed. Add a parity test that imports each aggregated locale bundle and asserts its key set matches en, with a diagnostic listing of any missing/extra keys. This complements the file-level check in shared/scripts by guarding the merged export the app actually serves. Finish internationalising OAuthAuthorizePage: the ~15 remaining hardcoded English chrome strings now go through oauth.authorize.* keys (English source in en, en-fallback placeholders elsewhere). Markup and behaviour are unchanged.
65 lines
2.7 KiB
TypeScript
65 lines
2.7 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import type { TranslationStrings } from '@trek/shared/i18n'
|
|
import en from '@trek/shared/i18n/en'
|
|
import de from '@trek/shared/i18n/de'
|
|
import es from '@trek/shared/i18n/es'
|
|
import fr from '@trek/shared/i18n/fr'
|
|
import hu from '@trek/shared/i18n/hu'
|
|
import itIT from '@trek/shared/i18n/it'
|
|
import tr from '@trek/shared/i18n/tr'
|
|
import ru from '@trek/shared/i18n/ru'
|
|
import zh from '@trek/shared/i18n/zh'
|
|
import zhTW from '@trek/shared/i18n/zh-TW'
|
|
import nl from '@trek/shared/i18n/nl'
|
|
import idID from '@trek/shared/i18n/id'
|
|
import ar from '@trek/shared/i18n/ar'
|
|
import br from '@trek/shared/i18n/br'
|
|
import cs from '@trek/shared/i18n/cs'
|
|
import pl from '@trek/shared/i18n/pl'
|
|
import ja from '@trek/shared/i18n/ja'
|
|
import ko from '@trek/shared/i18n/ko'
|
|
import uk from '@trek/shared/i18n/uk'
|
|
import gr from '@trek/shared/i18n/gr'
|
|
|
|
// Runtime guard for the aggregated i18n bundles. `t()` resolves keys against the
|
|
// active locale's flat dot-key map (see TranslationContext), so a key that is
|
|
// present in en but missing in another locale silently falls back to English at
|
|
// runtime — easy to ship, hard to notice. This test fails loudly when any locale
|
|
// drifts away from the en key set so translators get an explicit, diagnostic list.
|
|
//
|
|
// The shared package also runs a file-level parity check (shared/scripts), but
|
|
// that one only inspects per-domain source files; this one asserts the *merged*
|
|
// export each locale actually serves to the app.
|
|
|
|
const NON_EN_LOCALES: Record<string, TranslationStrings> = {
|
|
de, es, fr, hu, it: itIT, tr, ru, zh, 'zh-TW': zhTW, nl, id: idID,
|
|
ar, br, cs, pl, ja, ko, uk, gr,
|
|
}
|
|
|
|
const enKeys = new Set(Object.keys(en))
|
|
|
|
describe('i18n locale key parity', () => {
|
|
it('covers every non-en locale', () => {
|
|
// Keep the assertion set in lockstep with the supported language list minus en.
|
|
expect(Object.keys(NON_EN_LOCALES)).toHaveLength(19)
|
|
})
|
|
|
|
for (const [locale, strings] of Object.entries(NON_EN_LOCALES)) {
|
|
it(`${locale} has the exact same key set as en`, () => {
|
|
const localeKeys = new Set(Object.keys(strings))
|
|
const missing = [...enKeys].filter((k) => !localeKeys.has(k))
|
|
const extra = [...localeKeys].filter((k) => !enKeys.has(k))
|
|
|
|
const diagnostic =
|
|
`Locale "${locale}" key drift vs en — ` +
|
|
`missing ${missing.length}` +
|
|
(missing.length ? ` (${missing.slice(0, 10).join(', ')}${missing.length > 10 ? ', …' : ''})` : '') +
|
|
`; extra ${extra.length}` +
|
|
(extra.length ? ` (${extra.slice(0, 10).join(', ')}${extra.length > 10 ? ', …' : ''})` : '')
|
|
|
|
expect(missing, diagnostic).toEqual([])
|
|
expect(extra, diagnostic).toEqual([])
|
|
})
|
|
}
|
|
})
|