From 9ddb8dab5318e34ad334c9dc407ab4ba4f11ad0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E9=BA=92?= Date: Fri, 14 Aug 2026 15:56:29 +0800 Subject: [PATCH] refactor(runtime): remove unused i18next dependency --- packages/runtime/package.json | 1 - packages/runtime/src/create-cli.ts | 6 ++-- packages/runtime/src/i18n.ts | 48 +++-------------------------- packages/runtime/tests/i18n.test.ts | 30 +++++++----------- pnpm-lock.yaml | 18 ----------- pnpm-workspace.yaml | 1 - 6 files changed, 17 insertions(+), 87 deletions(-) diff --git a/packages/runtime/package.json b/packages/runtime/package.json index abceb73..79cc59d 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -43,7 +43,6 @@ "bailian-cli-core": "workspace:*", "boxen": "catalog:", "chalk": "catalog:", - "i18next": "catalog:", "undici": "catalog:" }, "devDependencies": { diff --git a/packages/runtime/src/create-cli.ts b/packages/runtime/src/create-cli.ts index 98432e7..be75345 100644 --- a/packages/runtime/src/create-cli.ts +++ b/packages/runtime/src/create-cli.ts @@ -124,10 +124,8 @@ export function createCli(commands: Record, opts: CliOptions async function getRegistry(argv: string[]): Promise { const localeSources = buildSources(pickConfigFlag(argv)); - const [translator, loaded] = await Promise.all([ - createTranslator(localeSources.file.language ?? DEFAULT_LANGUAGE), - getLoadedCommandPacks(), - ]); + const translator = createTranslator(localeSources.file.language ?? DEFAULT_LANGUAGE); + const loaded = await getLoadedCommandPacks(); return new CommandRegistry(loaded.commands, binName, translator); } diff --git a/packages/runtime/src/i18n.ts b/packages/runtime/src/i18n.ts index 8326333..1434c5c 100644 --- a/packages/runtime/src/i18n.ts +++ b/packages/runtime/src/i18n.ts @@ -1,56 +1,16 @@ -import { createInstance, type ResourceLanguage, type TOptions } from "i18next"; -import { - DEFAULT_LANGUAGE, - SUPPORTED_LANGUAGES, - type Language, - type LocalizedText, -} from "bailian-cli-core"; +import { DEFAULT_LANGUAGE, type Language, type LocalizedText } from "bailian-cli-core"; -export type Translate = (key: string, options?: Record) => string; - -/** A colocated namespace that a product or feature can register with the CLI runtime. */ -export interface CliMessageBundle { - namespace: string; - resources: Partial>; -} - -/** Per-CLI translation surface. The mutable i18next instance stays private to runtime. */ +/** Per-CLI localized text selector. */ export interface Translator { language: Language; - translate: Translate; localize(text: LocalizedText): string; } -export async function createTranslator( - language: Language, - bundles: readonly CliMessageBundle[] = [], -): Promise { - const instance = createInstance(); - - await instance.init({ - lng: language, - fallbackLng: DEFAULT_LANGUAGE, - supportedLngs: [...SUPPORTED_LANGUAGES], - initAsync: false, - interpolation: { escapeValue: false }, - }); - - for (const bundle of bundles) { - for (const supportedLanguage of SUPPORTED_LANGUAGES) { - const resource = bundle.resources[supportedLanguage]; - if (resource) { - instance.addResourceBundle(supportedLanguage, bundle.namespace, resource, true, false); - } - } - } - +export function createTranslator(language: Language): Translator { return { language, localize(text) { - return typeof text === "string" ? text : text[language]; - }, - translate(key, options = {}) { - return String(instance.t(key, options as TOptions)); + return typeof text === "string" ? text : (text[language] ?? text[DEFAULT_LANGUAGE]); }, }; } diff --git a/packages/runtime/tests/i18n.test.ts b/packages/runtime/tests/i18n.test.ts index 11fb434..381c94b 100644 --- a/packages/runtime/tests/i18n.test.ts +++ b/packages/runtime/tests/i18n.test.ts @@ -1,27 +1,12 @@ import { expect, test } from "vite-plus/test"; import { defineCommand } from "bailian-cli-core"; -import { createTranslator, type CliMessageBundle } from "../src/i18n.ts"; +import { createTranslator } from "../src/i18n.ts"; import { CommandRegistry } from "../src/registry.ts"; -const messages = { - namespace: "test", - resources: { - "en-US": { greeting: "Hello, {{name}}!", englishOnly: "English fallback" }, - "zh-CN": { greeting: "你好,{{name}}!" }, - }, -} satisfies CliMessageBundle; - -test("translator uses the selected language, interpolation and English fallback", async () => { - const translator = await createTranslator("zh-CN", [messages]); +test("translator resolves colocated text while preserving plain strings", () => { + const translator = createTranslator("zh-CN"); expect(translator.language).toBe("zh-CN"); - expect(translator.translate("test:greeting", { name: "百炼" })).toBe("你好,百炼!"); - expect(translator.translate("test:englishOnly")).toBe("English fallback"); -}); - -test("translator resolves colocated text while preserving plain strings", async () => { - const translator = await createTranslator("zh-CN"); - expect(translator.localize("Already localized")).toBe("Already localized"); expect( translator.localize({ @@ -29,10 +14,17 @@ test("translator resolves colocated text while preserving plain strings", async "zh-CN": "显示帮助信息", }), ).toBe("显示帮助信息"); + + expect( + createTranslator("en-US").localize({ + "en-US": "Show help", + "zh-CN": "显示帮助信息", + }), + ).toBe("Show help"); }); test("registry renders runtime help copy with the selected language", async () => { - const translator = await createTranslator("zh-CN"); + const translator = createTranslator("zh-CN"); const command = defineCommand({ description: { "en-US": "Test command", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 815a16f..d3dd398 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,9 +24,6 @@ catalogs: chalk: specifier: ^5.6.2 version: 5.6.2 - i18next: - specifier: ^26.3.6 - version: 26.3.6 smol-toml: specifier: ^1.4.2 version: 1.7.0 @@ -257,9 +254,6 @@ importers: chalk: specifier: 'catalog:' version: 5.6.2 - i18next: - specifier: 'catalog:' - version: 26.3.6(typescript@6.0.3) undici: specifier: 'catalog:' version: 6.27.0 @@ -1206,14 +1200,6 @@ packages: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} - i18next@26.3.6: - resolution: {integrity: sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==} - peerDependencies: - typescript: ^5 || ^6 || ^7 - peerDependenciesMeta: - typescript: - optional: true - immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} @@ -2264,10 +2250,6 @@ snapshots: get-east-asian-width@1.6.0: {} - i18next@26.3.6(typescript@6.0.3): - optionalDependencies: - typescript: 6.0.3 - immediate@3.0.6: {} inherits@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3ce8416..611df31 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,7 +9,6 @@ catalog: ajv: ^8.20.0 boxen: ^8.0.1 chalk: ^5.6.2 - i18next: ^26.3.6 tar-stream: ^3.2.0 smol-toml: ^1.4.2 tsx: ^4.23.0