Skip to content

Commit ca6dca3

Browse files
committed
feat: refine i18n loading guardrails
1 parent 8a93ed7 commit ca6dca3

18 files changed

Lines changed: 601 additions & 50 deletions

File tree

AGENTS-CN.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ pnpm run fmt:rs # 只格式化已改动 / 已暂存的 Rust
5454
pnpm run lint:web
5555
pnpm run type-check:web
5656
pnpm --dir src/mobile-web run type-check
57+
pnpm run i18n:contract:test
58+
pnpm run i18n:audit
5759
pnpm run check:repo-hygiene
5860
pnpm run check:github-config
5961
cargo check --workspace
@@ -78,6 +80,18 @@ pnpm run installer:build:fast # 安装器应用,快速模式
7880

7981
## 全局规则
8082

83+
### 国际化
84+
85+
- Locale id、alias、fallback 和各形态默认语言统一由
86+
`src/shared/i18n/contract/locales.json` 管理;修改后运行
87+
`pnpm run i18n:generate`
88+
- 跨形态稳定标签放在
89+
`src/shared/i18n/resources/shared/<locale>/terms.json`;流程文案留在所属
90+
产品形态资源中。
91+
- 不要把 Web UI locale 资源导入 `src/mobile-web``BitFun-Installer` 等较小形态。
92+
- Web UI 只急切加载 bootstrap namespace;路由或功能文案使用
93+
`useI18n(namespace)`,直接 `i18nService.t(...)` 只用于 bootstrap namespace。
94+
8195
### 日志
8296

8397
日志必须只用英文,且不能使用 emoji。
@@ -171,14 +185,15 @@ SessionManager → Session → DialogTurn → ModelRound
171185

172186
| 改动类型 | 最低验证要求 |
173187
|---|---|
174-
| 前端 UI、状态、适配层或多语言文案 | `pnpm run lint:web && pnpm run type-check:web && pnpm --dir src/web-ui run test:run` |
188+
| 前端 UI、状态、适配层或多语言文案 | `pnpm run i18n:contract:test && pnpm run i18n:audit && pnpm run lint:web && pnpm run type-check:web && pnpm --dir src/web-ui run test:run` |
175189
| Mobile web UI、状态、配对、断开或重连行为 | `pnpm --dir src/mobile-web run type-check && pnpm run build:mobile-web`;行为变化还需要在 PR 中说明手动配对 / 重连验证 |
176190
| Deep Review / 代码审核团队行为 | 运行上面的前端验证,再运行 `cargo test -p bitfun-core deep_review -- --nocapture`;如果触及后端或 Tauri API,还需要运行下方 Rust / 桌面端验证 |
177191
| `core``transport``api-layer` 或共享服务中的 Rust 逻辑 | `cargo check --workspace && cargo test --workspace` |
178192
| 桌面端集成、Tauri API、browser/computer-use 或桌面专属行为 | `cargo check -p bitfun-desktop && cargo test -p bitfun-desktop` |
179193
| 被桌面端 smoke/functional 流覆盖的行为 | `cargo build -p bitfun-desktop` 后运行最接近的 E2E spec,或 `pnpm run e2e:test:l0` |
180194
| `src/crates/ai-adapters` | 运行上面相关 Rust 检查,**并且**运行 `cargo test -p bitfun-agent-stream` 验证 stream contract |
181-
| 安装器应用 | `pnpm run installer:build` |
195+
| 安装器前端、多语言或 locale contract | `pnpm --dir BitFun-Installer run type-check && cargo check --manifest-path BitFun-Installer/src-tauri/Cargo.toml && pnpm --dir BitFun-Installer run build` |
196+
| 安装器打包、payload、安装/卸载流程或 native bundling | `pnpm run installer:build` |
182197

183198
## 先看哪里
184199

AGENTS.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ pnpm run fmt:rs # format only changed / staged Rust files
5454
pnpm run lint:web
5555
pnpm run type-check:web
5656
pnpm --dir src/mobile-web run type-check
57+
pnpm run i18n:contract:test
58+
pnpm run i18n:audit
5759
pnpm run check:repo-hygiene
5860
pnpm run check:github-config
5961
cargo check --workspace
@@ -88,6 +90,9 @@ For the full script list, see [`package.json`](package.json).
8890
in the owning product surface.
8991
- Do not import Web UI locale resources into smaller product surfaces such as
9092
`src/mobile-web` or `BitFun-Installer`. See `docs/architecture/i18n.md`.
93+
- Web UI loads only bootstrap namespaces eagerly; use `useI18n(namespace)` for
94+
route or feature copy and keep direct `i18nService.t(...)` calls in bootstrap
95+
namespaces.
9196

9297
### Logging
9398

@@ -186,7 +191,7 @@ Session data is stored under `.bitfun/sessions/{session_id}/`.
186191

187192
| Change type | Minimum verification |
188193
|---|---|
189-
| Frontend UI, state, adapters, or locales | `pnpm run lint:web && pnpm run type-check:web && pnpm --dir src/web-ui run test:run` |
194+
| Frontend UI, state, adapters, or locales | `pnpm run i18n:contract:test && pnpm run i18n:audit && pnpm run lint:web && pnpm run type-check:web && pnpm --dir src/web-ui run test:run` |
190195
| Mobile web UI, state, pairing, disconnect, or reconnect behavior | `pnpm --dir src/mobile-web run type-check && pnpm run build:mobile-web`; include manual pairing / reconnect verification when behavior changes |
191196
| Deep Review / Code Review Team behavior | Web UI verification above, plus `cargo test -p bitfun-core deep_review -- --nocapture`; also run the Rust / desktop rows below when backend or Tauri APIs are touched |
192197
| Shared Rust logic in `core`, `transport`, `api-layer`, or services | `cargo check --workspace && cargo test --workspace` |

BitFun-Installer/AGENTS-CN.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
- `src-tauri/src/installer/shortcut.rs`:快捷方式创建
1818
- `src-tauri/src/installer/extract.rs`:压缩包解压
1919
- `src/hooks/useInstaller.ts`:前端安装流程状态
20+
- `src/i18n/`:安装器专属文案;locale 元数据由
21+
`src/shared/i18n/contract/locales.json` 生成
2022

2123
安装流程:
2224

@@ -36,6 +38,16 @@ pnpm --dir BitFun-Installer run installer:build
3638

3739
## 验证
3840

41+
前端、国际化、语言契约或非打包安装器改动,优先运行轻量检查:
42+
43+
```bash
44+
pnpm --dir BitFun-Installer run type-check
45+
cargo check --manifest-path BitFun-Installer/src-tauri/Cargo.toml
46+
pnpm --dir BitFun-Installer run build
47+
```
48+
49+
只有修改打包、payload、native bundling、安装/卸载流程、注册表、快捷方式或解压逻辑时,才运行完整安装器构建:
50+
3951
```bash
4052
pnpm --dir BitFun-Installer run type-check && pnpm --dir BitFun-Installer run installer:build
4153
```

CONTRIBUTING.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ Captured data is logged as structured JSON under the `bitfun::devtools` target.
7878
- Frontend: `createLogger('ModuleName')`
7979
- Backend: `log::{info, debug, warn, error}` macros
8080

81+
### Internationalization
82+
83+
- Locale metadata lives in `src/shared/i18n/contract/locales.json`; run
84+
`pnpm run i18n:generate` after editing it.
85+
- Put stable cross-surface labels in `src/shared/i18n/resources/shared`; keep
86+
workflow copy in the owning surface.
87+
- Web UI route or feature copy should use `useI18n(namespace)`. Do not import
88+
Web UI locale catalogs into mobile-web, installer, backend, or static pages.
89+
8190
### Platform-agnostic core
8291

8392
Do not use platform-specific dependencies in `core`:
@@ -175,6 +184,7 @@ For `/usage` UI copy changes, keep `en-US`, `zh-CN`, and `zh-TW` locale strings
175184
| Change type | Recommended verification |
176185
| --- | --- |
177186
| Repository metadata, PR/issue templates, or GitHub workflows | `pnpm run check:repo-hygiene && pnpm run check:github-config && git diff --check` |
187+
| Locale contract, shared terms, or i18n resources | `pnpm run i18n:contract:test && pnpm run i18n:audit`, plus the touched surface checks |
178188
| Web UI, state, adapters, or locale changes | `pnpm run lint:web && pnpm run type-check:web && pnpm --dir src/web-ui run test:run` |
179189
| Mobile web UI, pairing, reconnect, disconnect, or chat-flow changes | `pnpm --dir src/mobile-web run type-check && pnpm run build:mobile-web` |
180190
| Rust core, transport, API layer, services, or shared runtime logic | `cargo check --workspace && cargo test --workspace` |

CONTRIBUTING_CN.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ pnpm run e2e:test
7878
- 前端:`createLogger('ModuleName')`
7979
- 后端:`log::{info, debug, warn, error}`
8080

81+
### 国际化
82+
83+
- Locale 元数据统一维护在 `src/shared/i18n/contract/locales.json`;修改后运行
84+
`pnpm run i18n:generate`
85+
- 跨形态稳定标签放在 `src/shared/i18n/resources/shared`;流程文案留在所属形态资源中。
86+
- Web UI 路由或功能文案使用 `useI18n(namespace)`。不要把 Web UI locale 资源导入 mobile-web、installer、backend 或静态页面。
87+
8188
### 平台无关核心
8289

8390
`core` 中禁止引入平台相关依赖:
@@ -169,6 +176,7 @@ UI 改动请附前后对比截图或短录屏,方便快速评审。
169176
| 改动类型 | 推荐验证 |
170177
| --- | --- |
171178
| 仓库元信息、PR/Issue 模板或 GitHub workflow | `pnpm run check:repo-hygiene && pnpm run check:github-config && git diff --check` |
179+
| Locale contract、shared terms 或国际化资源 | `pnpm run i18n:contract:test && pnpm run i18n:audit`,再加上被触及形态的检查 |
172180
| Web UI、状态、适配层或多语言文案 | `pnpm run lint:web && pnpm run type-check:web && pnpm --dir src/web-ui run test:run` |
173181
| Mobile web UI、配对、重连、断开或聊天流程 | `pnpm --dir src/mobile-web run type-check && pnpm run build:mobile-web` |
174182
| Rust core、transport、API layer、services 或共享运行时逻辑 | `cargo check --workspace && cargo test --workspace` |

docs/architecture/i18n.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Surface resources stay in their existing owners:
5454
- Mobile Web: `src/mobile-web/src/i18n/messages.ts`
5555
- Installer: `BitFun-Installer/src/i18n/locales/*.json`
5656
- Backend: `src/crates/core/locales/*.ftl`
57+
- Relay static homepage: `src/apps/relay-server/static/homepage`
5758

5859
Shared contract does not mean shared bundle. Importing Web UI locales from
5960
`mobile-web`, installer, backend, or another app is not allowed.
@@ -62,18 +63,25 @@ Shared contract does not mean shared bundle. Importing Web UI locales from
6263

6364
The locale contract is shared; translation resources are not. Each surface must
6465
load only its own resource owner. Smaller surfaces should keep runtime loading
65-
to their current locale data, while Web UI keeps its current eager behavior
66-
until the later namespace-splitting work lands.
66+
to their current locale data.
6767

68-
- Web UI owns Web UI namespaces. The current PR preserves the existing eager
69-
namespace loading; later runtime work should split route or feature namespaces
70-
into independently loadable chunks.
68+
- Web UI owns Web UI namespaces. It eagerly bootstraps only
69+
`WEB_UI_BOOTSTRAP_NAMESPACES`, the small namespace set needed by synchronous
70+
`i18nService.t(...)` call sites during module initialization. Other Web UI
71+
namespaces load lazily through the i18next backend when a component requests
72+
them with `useI18n(namespace)` or `i18nService.loadNamespace(namespace)`.
7173
- Mobile Web owns mobile-only resources and must not import Web UI locale
7274
catalogs.
7375
- Installer owns installer-only resources and must not depend on app runtime
7476
locale catalogs.
7577
- Backend owns backend Fluent resources and uses generated contract helpers for
7678
locale parsing, canonicalization, fallback order, and shared terms.
79+
- Relay static homepage is a self-contained static surface. It is tracked in the
80+
contract and audit baseline, but it does not import runtime locale catalogs.
81+
82+
Direct Web UI `i18nService.t('namespace:key')` calls are allowed only for
83+
bootstrap namespaces. Route, scene, and feature UI should use `useI18n(namespace)`
84+
so the namespace can be loaded on demand.
7785

7886
## Backend And Frontend Language Contract
7987

@@ -95,3 +103,5 @@ store canonical ids.
95103
4. Run `pnpm run i18n:generate`.
96104
5. Run `pnpm run i18n:audit`.
97105
6. Run the focused type checks/builds for the touched surfaces.
106+
7. If a surface intentionally stays self-contained or does not support the new
107+
locale, document that surface decision in the contract and PR.

docs/development/i18n.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
- Do not import `src/web-ui/src/locales` from `src/mobile-web`,
1515
`BitFun-Installer`, Rust crates, or server apps.
1616
- Persist and send canonical app locale ids, not aliases.
17+
- In Web UI, request route or feature namespaces through `useI18n(namespace)`.
18+
Add a namespace to `WEB_UI_BOOTSTRAP_NAMESPACES` only when a synchronous
19+
`i18nService.t('namespace:key')` call must run during module initialization.
1720

1821
## Commands
1922

@@ -97,12 +100,20 @@ Do not rely on literal fallback strings in component code. Add the missing key
97100
to the relevant locale file instead. Literal fallback strings make audits and
98101
translation completeness harder to enforce.
99102

103+
`pnpm run i18n:audit` fails on missing or extra keys in Web UI, mobile-web, and
104+
installer locale resources. It also fails if the checked-in CJK source candidate
105+
budgets grow. Existing budget warnings are grandfathered; new user-facing copy
106+
should be extracted instead of increasing the baseline.
107+
100108
## Loading Size
101109

102110
Unifying the language contract must not unify all translation bundles. Each
103111
surface should ship only the resource set needed for that surface and the current
104-
locale path. Web UI still uses its existing eager namespace loading in PR1; do
105-
not use that as a precedent for smaller surfaces.
112+
locale path.
113+
114+
Web UI eagerly loads only bootstrap namespaces and lazy-loads all other
115+
namespaces. Mobile Web, Installer, Backend, and static relay pages must not
116+
import Web UI locale catalogs to reuse copy.
106117

107118
For bundle-sensitive changes, compare generated asset sizes before and after the
108119
change and include the result in the PR.
@@ -127,3 +138,4 @@ Every i18n PR should state:
127138
- Whether generated files were updated.
128139
- Which i18n verification commands passed.
129140
- Whether any surface intentionally does not support a new locale.
141+
- Whether a hardcoded-copy budget changed, and why that increase is acceptable.

0 commit comments

Comments
 (0)