Files
spaceflow/docs/advanced/i18n.md
2026-02-15 22:02:21 +08:00

157 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# i18n 国际化
Spaceflow 基于 [i18next](https://www.i18next.com/) 实现国际化,采用纯函数式设计,不依赖 NestJS DI。
## 语言检测优先级
1. 环境变量 `SPACEFLOW_LANG`
2. `spaceflow.json` 中的 `lang` 字段
3. 系统 locale`process.env.LANG` / `process.env.LC_ALL`
4. 回退到 `zh-CN`
## 核心 API
### `initI18n(lang?: string)`
同步初始化 i18next。必须在 NestJS 模块加载前调用。
```typescript
import { initI18n } from "@spaceflow/core";
initI18n(); // 自动检测语言
initI18n("en"); // 手动指定
```
### `t(key: string, options?: Record<string, unknown>)`
全局翻译函数,装饰器和运行时均可使用。
```typescript
import { t } from "@spaceflow/core";
// 公共 key默认命名空间
t("common.executionFailed", { error: msg });
// Extension 命名空间(用 : 分隔)
t("build:description");
t("review:options.dryRun");
```
### `addLocaleResources(ns: string, resources: Record<string, Record<string, string>>)`
注册 Extension 的语言资源到指定命名空间。
```typescript
import { addLocaleResources } from "@spaceflow/core";
addLocaleResources("hello", {
"zh-CN": { description: "打招呼命令" },
en: { description: "Say hello" },
});
```
## 命名空间规则
| 类型 | 命名空间 | 示例 |
|------|----------|------|
| 公共 key | 默认(`translation` | `common.*`, `config.*`, `extensionLoader.*` |
| 内部 Extension | Extension 名称 | `build:`, `dev:`, `commit:`, `install:` 等 |
| 外部 Extension | Extension 名称 | `review:`, `publish:`, `ci-scripts:` 等 |
## 语言包结构
### core 公共语言包
```text
core/src/locales/
├── zh-cn/
│ └── translation.json # 公共 key
└── en/
└── translation.json
```
### Extension 语言包
```text
cli/src/commands/<name>/locales/
├── zh-cn/
│ └── <name>.json
├── en/
│ └── <name>.json
└── index.ts # 导入并注册资源
```
## Extension 中使用 i18n
### 1. 创建语言包文件
```json
// locales/zh-cn/hello.json
{
"description": "打招呼命令",
"options.name": "名字",
"greeting": "你好,{{name}}"
}
```
### 2. 注册语言资源
```typescript
// locales/index.ts
import zhCN from "./zh-cn/hello.json";
import en from "./en/hello.json";
import { addLocaleResources } from "@spaceflow/core";
export const helloLocales = { "zh-CN": zhCN, en };
// Side-effect: 立即注册
addLocaleResources("hello", helloLocales);
```
### 3. 在命令中使用
```typescript
import { t } from "@spaceflow/core";
// 必须在命令模块 import 之前导入 localesside-effect
import "./locales";
@Command({
name: "hello",
description: t("hello:description"),
})
export class HelloCommand extends CommandRunner {
// ...
}
```
### 4. 在 Extension 入口声明
```typescript
export class HelloExtension implements SpaceflowExtension {
getMetadata(): SpaceflowExtensionMetadata {
return {
name: "hello",
commands: ["hello"],
locales: helloLocales, // 加载时自动注册
};
}
}
```
## 插值语法
使用 i18next 默认的 `{{variable}}` 语法:
```typescript
t("hello:greeting", { name: "World" });
// → "你好World"
```
## 注意事项
- **同步初始化** — `initI18n()` 使用 `initSync`,确保装饰器执行时语言包已加载
- **装饰器时机** — `@Command` / `@Option` 在 import 时执行,`initI18n()` 必须在所有命令模块 import 之前调用
- **Side-effect import** — 每个 Extension 的 `locales/index.ts` 在导入时立即调用 `addLocaleResources`
- **key 不存在时** — i18next 默认返回 key 本身,不会报错