返回 CodeWhale
index.ts
根目录 / web / lib / i18n / dictionaries / index.ts
1 /**
2 * Dictionary loader for the website localization layer (#3091, #4934).
3 *
4 * Lookup is deterministic: a routed locale with a dictionary gets its own
5 * copy; every other locale gets the English reference dictionary. There is
6 * no per-key fallback chain — each shipped/partial dictionary is held to
7 * exact key parity with English by `web/scripts/check-locales.mjs` and
8 * `dictionaries.test.ts`, so a missing key is a build-time failure, never
9 * a runtime "missing marker".
10 *
11 * English resolves through the `?? enChrome` / `?? enHome` fallback rather
12 * than a map entry, which keeps `DICTIONARY_LOCALES` equal to the set of
13 * non-reference locale directories that `check-locales.mjs` walks.
14 */
15 import type { ChromeDict, HomeDict } from "./types";
16 import { chrome as enChrome } from "./en/chrome";
17 import { home as enHome } from "./en/home";
18 import { chrome as zhChrome } from "./zh/chrome";
19 import { home as zhHome } from "./zh/home";
20 import { chrome as jaChrome } from "./ja/chrome";
21 import { home as jaHome } from "./ja/home";
22 import { chrome as viChrome } from "./vi/chrome";
23 import { home as viHome } from "./vi/home";
24 import { chrome as koChrome } from "./ko/chrome";
25 import { home as koHome } from "./ko/home";
26 import { chrome as ruChrome } from "./ru/chrome";
27 import { home as ruHome } from "./ru/home";
28 import { chrome as ukChrome } from "./uk/chrome";
29 import { home as ukHome } from "./uk/home";
30 import { chrome as esChrome } from "./es/chrome";
31 import { home as esHome } from "./es/home";
32 import { chrome as ptBrChrome } from "./pt-BR/chrome";
33 import { home as ptBrHome } from "./pt-BR/home";
34 import { chrome as idChrome } from "./id/chrome";
35 import { home as idHome } from "./id/home";
36
37 const CHROME: Record<string, ChromeDict> = {
38 zh: zhChrome,
39 ja: jaChrome,
40 vi: viChrome,
41 ko: koChrome,
42 ru: ruChrome,
43 uk: ukChrome,
44 es: esChrome,
45 "pt-BR": ptBrChrome,
46 id: idChrome,
47 };
48
49 const HOME: Record<string, HomeDict> = {
50 zh: zhHome,
51 ja: jaHome,
52 vi: viHome,
53 ko: koHome,
54 ru: ruHome,
55 uk: ukHome,
56 es: esHome,
57 "pt-BR": ptBrHome,
58 id: idHome,
59 };
60
61 /** Locales with their own dictionary directory (English is the reference). */
62 export const DICTIONARY_LOCALES = Object.keys(CHROME) as readonly string[];
63
64 export function getChrome(locale: string): ChromeDict {
65 return CHROME[locale] ?? enChrome;
66 }
67
68 export function getHome(locale: string): HomeDict {
69 return HOME[locale] ?? enHome;
70 }
71
72 /** Reference dictionaries (parity baseline for the locale checks). */
73 export const EN_CHROME = enChrome;
74 export const EN_HOME = enHome;
75
76 /** Interpolate `{name}` tokens in a dictionary template. Unknown tokens are
77 * left intact so a template/variable drift is visible in review, not silent. */
78 export function fill(template: string, vars: Record<string, string | number>): string {
79 return template.replace(/\{(\w+)\}/g, (match, name: string) =>
80 name in vars ? String(vars[name]) : match,
81 );
82 }
83
84 /**
85 * Split a template on a single `{token}` so a call site can typeset the
86 * substituted value as its own element without concatenating translated
87 * fragments around it. Returns the literal parts in template order — the
88 * caller interleaves its node between them, so a locale that puts the token
89 * in a different position still renders correctly.
90 */
91 export function splitToken(template: string, token: string): string[] {
92 return template.split(`{${token}}`);
93 }
94
94 lines TYPESCRIPT