refactor(runtime): remove unused i18next dependency

This commit is contained in:
若麒
2026-08-14 15:56:29 +08:00
parent 23f1ab7fd4
commit 9ddb8dab53
6 changed files with 17 additions and 87 deletions
-1
View File
@@ -43,7 +43,6 @@
"bailian-cli-core": "workspace:*",
"boxen": "catalog:",
"chalk": "catalog:",
"i18next": "catalog:",
"undici": "catalog:"
},
"devDependencies": {
+2 -4
View File
@@ -124,10 +124,8 @@ export function createCli(commands: Record<string, AnyCommand>, opts: CliOptions
async function getRegistry(argv: string[]): Promise<CommandRegistry> {
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);
}
+4 -44
View File
@@ -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, unknown>) => string;
/** A colocated namespace that a product or feature can register with the CLI runtime. */
export interface CliMessageBundle {
namespace: string;
resources: Partial<Record<Language, ResourceLanguage>>;
}
/** 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<Translator> {
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]);
},
};
}
+11 -19
View File
@@ -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",
-18
View File
@@ -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: {}
-1
View File
@@ -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