

















@@ -0,0 +1,97 @@
1+import { en } from "./locales/en.js";
2+import { zh_CN } from "./locales/zh-CN.js";
3+import { zh_TW } from "./locales/zh-TW.js";
4+import type {
5+WizardI18nParams,
6+WizardLocale,
7+WizardTranslationMap,
8+WizardTranslationTree,
9+} from "./types.js";
10+11+export type { WizardI18nParams, WizardLocale, WizardTranslationMap };
12+13+const LOCALES: Record<WizardLocale, WizardTranslationMap> = {
14+ en,
15+"zh-CN": zh_CN,
16+"zh-TW": zh_TW,
17+};
18+19+export const WIZARD_DEFAULT_LOCALE: WizardLocale = "en";
20+export const WIZARD_SUPPORTED_LOCALES: readonly WizardLocale[] = ["en", "zh-CN", "zh-TW"];
21+22+function normalizeLocaleToken(raw: string | undefined): string {
23+return (raw ?? "").trim().split(".")[0]?.split("@")[0]?.replaceAll("_", "-") ?? "";
24+}
25+26+export function resolveWizardLocale(value: string | undefined): WizardLocale {
27+const normalized = normalizeLocaleToken(value);
28+if (!normalized) {
29+return WIZARD_DEFAULT_LOCALE;
30+}
31+32+const lower = normalized.toLowerCase();
33+if (lower === "en" || lower.startsWith("en-")) {
34+return "en";
35+}
36+if (lower === "zh-tw" || lower === "zh-hk" || lower === "zh-mo" || lower.includes("hant")) {
37+return "zh-TW";
38+}
39+if (lower === "zh" || lower === "zh-cn" || lower === "zh-sg" || lower.includes("hans")) {
40+return "zh-CN";
41+}
42+return WIZARD_DEFAULT_LOCALE;
43+}
44+45+export function resolveWizardLocaleFromEnv(env: NodeJS.ProcessEnv = process.env): WizardLocale {
46+return resolveWizardLocale(env.OPENCLAW_LOCALE ?? env.LC_ALL ?? env.LC_MESSAGES ?? env.LANG);
47+}
48+49+function readKey(map: WizardTranslationMap, key: string): string | undefined {
50+let value: string | WizardTranslationTree | undefined = map;
51+for (const segment of key.split(".")) {
52+if (!value || typeof value === "string") {
53+return undefined;
54+}
55+value = value[segment];
56+}
57+return typeof value === "string" ? value : undefined;
58+}
59+60+function interpolate(value: string, params?: WizardI18nParams): string {
61+if (!params) {
62+return value;
63+}
64+return value.replace(/\{([A-Za-z0-9_]+)\}/g, (match, key) => {
65+const param = params[key];
66+return param === undefined || param === null ? match : String(param);
67+});
68+}
69+70+export function wizardT(
71+key: string,
72+params?: WizardI18nParams,
73+options?: { locale?: WizardLocale },
74+): string {
75+const locale = options?.locale ?? resolveWizardLocaleFromEnv();
76+const localized = readKey(LOCALES[locale], key);
77+const fallback = localized ?? readKey(LOCALES[WIZARD_DEFAULT_LOCALE], key) ?? key;
78+return interpolate(fallback, params);
79+}
80+81+export const t = wizardT;
82+83+function collectLeafKeys(tree: WizardTranslationTree, prefix = "", out: string[] = []): string[] {
84+for (const [key, value] of Object.entries(tree)) {
85+const next = prefix ? `${prefix}.${key}` : key;
86+if (typeof value === "string") {
87+out.push(next);
88+} else {
89+collectLeafKeys(value, next, out);
90+}
91+}
92+return out;
93+}
94+95+export function listWizardI18nKeys(locale: WizardLocale = WIZARD_DEFAULT_LOCALE): string[] {
96+return collectLeafKeys(LOCALES[locale]).toSorted();
97+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。