116 lines
7.4 KiB
Markdown
116 lines
7.4 KiB
Markdown
# Pebrel internationalization / 多语言架构
|
|
|
|
## Scope / 范围
|
|
|
|
Pebrel 1.6 uses Pebrel names for the application, commands, installed files, and
|
|
new configuration. Legacy names remain accepted where the
|
|
[identity migration](architecture-decisions.md#adr-0003---pebrel-16-identity-migration)
|
|
requires compatibility. Translate product text using Pebrel; do not rewrite old
|
|
configuration keys, wire protocols, historical release notes, or Rust crate names.
|
|
|
|
Pebrel 1.6 的应用、命令、安装文件与新配置统一使用 Pebrel 名称。旧名称按
|
|
[身份迁移决策](architecture-decisions.md#adr-0003---pebrel-16-identity-migration) 保留兼容读取。
|
|
翻译产品文案时使用 Pebrel,不机械修改旧配置键、通信协议、历史发布说明或 Rust crate 名。
|
|
|
|
The first language set is English, Simplified Chinese, Traditional Chinese,
|
|
French, German, Spanish, Brazilian Portuguese, Italian, Russian, Japanese, and
|
|
Korean. The picker displays each language's native name. POSIX locale suffixes,
|
|
regional variants, and Chinese Hans/Hant scripts are negotiated at language resolution.
|
|
Terminal subprocess output and environment variables are not translated or overridden.
|
|
|
|
首批语言为英语、简体中文、繁体中文、法语、德语、西班牙语、巴西葡萄牙语、意大利语、
|
|
俄语、日语及韩语。选择器使用语言自称,并在解析语言时处理 POSIX 后缀、地区变体及
|
|
中文 Hans/Hant。不会翻译终端子进程的输出,也不会覆盖它们的语言环境变量。
|
|
|
|
The initial catalogs cover navigation, common actions, appearance labels, and
|
|
network controls in all eleven languages. French also covers all existing
|
|
catalog-based diagnostics. Many older inline bilingual descriptions are not yet
|
|
migrated; they intentionally fall back to English. This is not a claim of complete
|
|
translation of every screen, configuration template, or installer language.
|
|
|
|
初版词典覆盖全部十一种语言的导航、常用操作、外观标签与网络控件;法语同时覆盖原有
|
|
词典中的诊断文案。大量旧的内联双语长说明尚未迁移,明确回退英文,不宣称所有页面、
|
|
配置模板和安装向导已经完成全量翻译。后续翻译应经过母语审校。
|
|
|
|
## Runtime contract / 运行时合同
|
|
|
|
- `nebula_settings/src/language.rs` owns the supported-language registry,
|
|
native names, saved values, and locale negotiation. Both shells use it.
|
|
- `nebula_app/build/i18n.rs` validates JSON and generates static Rust data at
|
|
compile time. Runtime lookup never parses a JSON file, constructs a map,
|
|
reads a file, takes a lock, or allocates a string.
|
|
- `UiLanguage::text(Message::...)` uses a typed identifier and direct table
|
|
indexing. Use this for new UI code; missing identifiers fail compilation.
|
|
- `tr("stable.id")` is a compatibility interface using a generated string
|
|
match. Its fallback is target language → English → original key.
|
|
- Existing `pick(Chinese, English)` remains a migration bridge: Chinese and
|
|
English retain their immediate branches; other languages use an unambiguous
|
|
catalog match or English. Ambiguous English phrases do not borrow a translation
|
|
from the wrong context. New context-sensitive messages must use typed ids.
|
|
- Formatting is a separate path that builds a `String` only when arguments
|
|
are needed. Values are inserted literally, not recursively interpreted as
|
|
placeholders. Missing arguments stay visible; `{{` and `}}` escape braces.
|
|
- GPUI keeps the resolved language in application state. System locale
|
|
detection is outside text rendering. The pinned component library has a
|
|
smaller locale set; unsupported widget locales explicitly use English.
|
|
|
|
核心原则:运行时只读编译好的静态表;新代码使用类型化 ID 直接索引;只有带参数的文案
|
|
才创建字符串。旧 `tr` 和 `pick` 是渐进迁移入口,不应作为继续堆积双语硬编码的理由。
|
|
组件库的语言覆盖与自有文案分开记录,不支持的组件语言明确使用英文,避免假装全量覆盖。
|
|
|
|
## Add a language / 新增语言
|
|
|
|
1. Add one row to the `languages!` registry in `nebula_settings/src/language.rs`.
|
|
Saved values are canonical locale tags; do not change existing tags or order.
|
|
2. Add `nebula_app/i18n/<locale>.json`. Keep the same message ids and named
|
|
placeholders as English. A partial catalog is allowed and falls back to English.
|
|
Do not copy English entries just to inflate the translation coverage count.
|
|
3. Set the component locale to one actually supplied by the pinned component
|
|
library, or use `en`. Do not claim right-to-left layout support without testing it.
|
|
4. Run the catalog, preference, UI-switching, and allocation tests. Review
|
|
long labels, font coverage, keyboard access, and the real UI with a native speaker.
|
|
|
|
新增语言只需注册表一行及对应 JSON;选择器、语言枚举和运行时表由同一注册表生成,
|
|
无需在所有页面添加分支。构建会拒绝重复 ID、空字符串、未知 ID、非法叶子类型和占位符
|
|
不一致;简中与英文基础词典必须完整对齐,其他语言可渐进补齐。
|
|
|
|
## Module boundaries / 解耦边界
|
|
|
|
- `src/i18n/`: renderer-independent lookup, locale resolution, formatting, and tests.
|
|
- `src/i18n/outcomes.rs`: presentation adapters for provider/proxy results; it is
|
|
compiled separately from the pure lookup core and does not move I/O into translation.
|
|
- `settings_pane/navigation.rs`: route, navigation, and display metadata.
|
|
- `settings_pane/localization.rs`: select values and translated labels.
|
|
- `settings_pane/status.rs`: semantic operation results rendered in the active language.
|
|
- `settings_pane/shell_picker.rs`: shell selector items and import boundary.
|
|
- `settings_pane/initialization.rs`: entity construction and event subscriptions.
|
|
- `settings_pane.rs`: pane state, orchestration, and rendering.
|
|
|
|
这轮优先拆分语言与设置链路,不改变持久化格式、事件含义和设置生效时机。其他存量超大
|
|
文件仍由行数预算约束,应在对应功能改动时按职责拆分,而不是为了行数任意切片。
|
|
|
|
## Checks / 验证
|
|
|
|
```text
|
|
cargo test -p nebula-settings
|
|
cargo test --manifest-path tools/i18n-contract/Cargo.toml --locked
|
|
cargo test -p nebula --test i18n_contract
|
|
cargo test -p nebula --bin pebrel --features gpui-shell i18n::
|
|
cargo test -p nebula --bin pebrel --features gpui-shell gpui_shell::settings_pane::tests::
|
|
cargo test -p nebula --test file_line_budget
|
|
cargo test -p nebula --test i18n_contract --release -- --ignored --nocapture
|
|
```
|
|
|
|
The allocation contract checks both the first and repeated lookup across every
|
|
language. The timing benchmark is informational, not a machine-dependent CI speed
|
|
threshold. The initial translated UTF-8 payload has a 256 KiB budget; string table
|
|
pointers and generated code are additional binary overhead, not included in that count.
|
|
|
|
零分配测试覆盖首次与重复查词;微基准只报告实测值,不把某台机器的耗时写死成 CI 阈值。
|
|
初版 UTF-8 翻译文本预算为 256 KiB;指针表与生成代码是额外开销,不冒充完整二进制体积。
|
|
|
|
The independent contract workspace compiles the production generator and lookup
|
|
files without renderer dependencies. The `architecture-contracts` PR job executes
|
|
it, while real GPUI/platform checks and native-language layout review remain separate.
|
|
Language or ownership changes also follow the [engineering contracts](project-constraints.md).
|