pi-extensions-i18n 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -16
- package/README.zh-CN.md +90 -0
- package/package.json +2 -1
- package/src/index.ts +14 -8
package/README.md
CHANGED
|
@@ -1,42 +1,89 @@
|
|
|
1
1
|
# pi-extensions-i18n
|
|
2
2
|
|
|
3
|
-
Shared
|
|
3
|
+
Shared localization runtime for Pi extensions. It provides a small, catalog-backed API for `zh-CN`, `en-US`, and automatic locale selection.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Why a shared package
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- 统一读取 `~/.pi/agent/extensions/pi-extensions-i18n/config.json`;
|
|
9
|
-
- `/pi-language` 终端交互式语言配置命令;
|
|
10
|
-
- `PI_EXTENSIONS_LOCALE` 环境变量覆盖配置;
|
|
11
|
-
- 面向 UI、命令描述和 agent prompt 的翻译器,以及外部 JSON catalog 加载和校验。
|
|
7
|
+
Independent Pi extensions still need the same operational pieces: a portable configuration path, locale precedence, fallback behavior, catalog validation, and parameter interpolation. Keeping those pieces here lets feature packages concentrate on their own behavior while keeping user-facing messages consistent.
|
|
12
8
|
|
|
13
|
-
##
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- `zh-CN`, `en-US`, and `auto` locale preferences.
|
|
12
|
+
- Persistent setting at `~/.pi/agent/extensions/pi-extensions-i18n/config.json`.
|
|
13
|
+
- `PI_EXTENSIONS_LOCALE` environment-variable override.
|
|
14
|
+
- `/config:language` interactive command, plus `/config:language en-US` direct selection.
|
|
15
|
+
- Catalog loading and validation requiring both language entries for every message key.
|
|
16
|
+
- Translator interpolation for user-facing UI, command descriptions, and agent prompts.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
14
19
|
|
|
15
20
|
```bash
|
|
16
21
|
pi install npm:pi-extensions-i18n
|
|
17
22
|
```
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
Feature packages use it as a shared dependency and load its extension entry automatically, so installing a feature package is enough to provide the locale command. Install this package directly only when you want the locale command without another feature package.
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
Reload Pi after installation:
|
|
22
27
|
|
|
23
28
|
```text
|
|
24
|
-
|
|
29
|
+
/reload
|
|
25
30
|
```
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
## Locale precedence
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
PI_EXTENSIONS_LOCALE environment variable
|
|
36
|
+
> persisted config
|
|
37
|
+
> default zh-CN
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The `auto` preference checks `LC_ALL`, `LC_MESSAGES`, and `LANG`; Chinese system locales resolve to `zh-CN`, and other locales resolve to `en-US`. `zh` and `en` are accepted as short aliases.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
28
43
|
|
|
29
44
|
```bash
|
|
30
45
|
PI_EXTENSIONS_LOCALE=en-US pi
|
|
31
46
|
```
|
|
32
47
|
|
|
33
|
-
|
|
48
|
+
```text
|
|
49
|
+
/config:language en-US
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Extension author API
|
|
53
|
+
|
|
54
|
+
The package exports the locale and catalog primitives used by the feature packages:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
createTranslator,
|
|
59
|
+
getLocale,
|
|
60
|
+
loadCatalog,
|
|
61
|
+
} from "pi-extensions-i18n";
|
|
62
|
+
|
|
63
|
+
const messages = loadCatalog(new URL("../locales/messages.json", import.meta.url));
|
|
64
|
+
const i18n = createTranslator(messages);
|
|
65
|
+
|
|
66
|
+
i18n.t("description");
|
|
67
|
+
getLocale();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Catalog entries must contain both locale keys:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"description": {
|
|
75
|
+
"zh-CN": "扩展描述",
|
|
76
|
+
"en-US": "Extension description"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
34
80
|
|
|
35
|
-
|
|
81
|
+
Invalid catalogs fail during loading, which makes missing translations visible in tests and CI instead of silently leaking a single-language message to users.
|
|
36
82
|
|
|
37
|
-
|
|
83
|
+
## Requirements
|
|
38
84
|
|
|
39
|
-
|
|
85
|
+
- Node.js 22 or newer.
|
|
86
|
+
- Pi's extension runtime when using the `/config:language` command. `/pi-language` remains available as a compatibility alias.
|
|
40
87
|
|
|
41
88
|
## License
|
|
42
89
|
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# pi-extensions-i18n
|
|
2
|
+
|
|
3
|
+
Pi 扩展公共国际化运行时。它提供基于 catalog 的小型 API,支持 `zh-CN`、`en-US` 和自动语言选择。
|
|
4
|
+
|
|
5
|
+
## 为什么需要公共包
|
|
6
|
+
|
|
7
|
+
独立的 Pi 扩展仍然需要相同的基础能力:可移植的配置路径、语言优先级、fallback、catalog 校验和参数插值。把这些能力集中在这里,功能包就可以专注于自身逻辑,同时保持用户可见文案的一致性。
|
|
8
|
+
|
|
9
|
+
## 能力
|
|
10
|
+
|
|
11
|
+
- 支持 `zh-CN`、`en-US` 和 `auto` 语言偏好。
|
|
12
|
+
- 将设置持久化到 `~/.pi/agent/extensions/pi-extensions-i18n/config.json`。
|
|
13
|
+
- 支持 `PI_EXTENSIONS_LOCALE` 环境变量覆盖。
|
|
14
|
+
- 提供 `/config:language` 交互式命令,也支持 `/config:language en-US` 直接设置。
|
|
15
|
+
- 加载并校验 catalog,要求每个消息 key 同时提供两种语言。
|
|
16
|
+
- 为 UI、命令描述和 Agent prompt 提供用户文案插值。
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pi install npm:pi-extensions-i18n
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
各功能包会自动安装并加载这个公共依赖,因此安装任意使用它的功能包即可使用语言命令。只有不安装其他功能包、想单独使用语言命令时,才需要直接安装本包。
|
|
25
|
+
|
|
26
|
+
安装后重新加载 Pi:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
/reload
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 语言优先级
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
PI_EXTENSIONS_LOCALE 环境变量
|
|
36
|
+
> 持久化配置
|
|
37
|
+
> 默认 zh-CN
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
选择 `auto` 时会检查 `LC_ALL`、`LC_MESSAGES` 和 `LANG`:中文系统语言解析为 `zh-CN`,其他语言解析为 `en-US`。同时接受 `zh` 和 `en` 简写。
|
|
41
|
+
|
|
42
|
+
示例:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
PI_EXTENSIONS_LOCALE=en-US pi
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
/config:language en-US
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 扩展作者 API
|
|
53
|
+
|
|
54
|
+
本包导出功能扩展使用的语言和 catalog 原语:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
createTranslator,
|
|
59
|
+
getLocale,
|
|
60
|
+
loadCatalog,
|
|
61
|
+
} from "pi-extensions-i18n";
|
|
62
|
+
|
|
63
|
+
const messages = loadCatalog(new URL("../locales/messages.json", import.meta.url));
|
|
64
|
+
const i18n = createTranslator(messages);
|
|
65
|
+
|
|
66
|
+
i18n.t("description");
|
|
67
|
+
getLocale();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
catalog 条目必须同时包含两种语言:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"description": {
|
|
75
|
+
"zh-CN": "扩展描述",
|
|
76
|
+
"en-US": "Extension description"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
无效 catalog 会在加载阶段失败,让缺失翻译在测试和 CI 中暴露,而不是静默向用户泄露单一语言文案。
|
|
82
|
+
|
|
83
|
+
## 要求
|
|
84
|
+
|
|
85
|
+
- Node.js 22 或更高版本。
|
|
86
|
+
- 使用 `/config:language` 命令时需要 Pi 扩展运行时;`/pi-language` 仍作为兼容别名保留。
|
|
87
|
+
|
|
88
|
+
## 许可证
|
|
89
|
+
|
|
90
|
+
[MIT](../../LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extensions-i18n",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Shared i18n catalog loader & translator for pi extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"src",
|
|
13
13
|
"locales",
|
|
14
14
|
"README.md",
|
|
15
|
+
"README.zh-CN.md",
|
|
15
16
|
"tsconfig.json"
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
package/src/index.ts
CHANGED
|
@@ -92,10 +92,12 @@ export function getLocalePreference(): LocalePreference {
|
|
|
92
92
|
return DEFAULT_LOCALE_PREFERENCE;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
const persisted = readPersistedPreference(resolveAgentDir());
|
|
96
|
+
if (persisted) {
|
|
97
|
+
runtimePreference = persisted;
|
|
98
|
+
return persisted;
|
|
99
|
+
}
|
|
100
|
+
return runtimePreference ?? DEFAULT_LOCALE_PREFERENCE;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
function detectSystemLocale(): Locale {
|
|
@@ -174,9 +176,10 @@ export function createTranslator<Catalog extends MessageCatalog>(
|
|
|
174
176
|
if (!entry) {
|
|
175
177
|
throw new Error(`Unknown i18n message key: ${String(key)}`);
|
|
176
178
|
}
|
|
177
|
-
const
|
|
179
|
+
const locale = getLocale();
|
|
180
|
+
const message = entry[locale];
|
|
178
181
|
if (message === undefined) {
|
|
179
|
-
throw new Error(`Missing ${
|
|
182
|
+
throw new Error(`Missing ${locale} translation for message key: ${String(key)}`);
|
|
180
183
|
}
|
|
181
184
|
return interpolate(message, params);
|
|
182
185
|
},
|
|
@@ -189,7 +192,7 @@ const commandMessages = loadCatalog(
|
|
|
189
192
|
|
|
190
193
|
function registerLocaleCommand(pi: ExtensionAPI): void {
|
|
191
194
|
const i18n = createTranslator(commandMessages);
|
|
192
|
-
|
|
195
|
+
const command = {
|
|
193
196
|
description: i18n.t("description"),
|
|
194
197
|
handler: async (args: string, ctx: ExtensionCommandContext) => {
|
|
195
198
|
if (!ctx.hasUI) {
|
|
@@ -243,7 +246,10 @@ function registerLocaleCommand(pi: ExtensionAPI): void {
|
|
|
243
246
|
ctx.ui.notify(i18n.t("failed", { error: String(error) }), "error");
|
|
244
247
|
}
|
|
245
248
|
},
|
|
246
|
-
}
|
|
249
|
+
};
|
|
250
|
+
for (const name of ["config:language", "pi-language"] as const) {
|
|
251
|
+
pi.registerCommand(name, command);
|
|
252
|
+
}
|
|
247
253
|
}
|
|
248
254
|
|
|
249
255
|
export default function piI18n(pi: ExtensionAPI): void {
|