deveco_hmigbot 0.21.5
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/LICENSE +26 -0
- package/README.md +50 -0
- package/agents/hmigbot-worker.md +61 -0
- package/agents/hmigbot.md +22 -0
- package/agents/workflow-subagent.md +55 -0
- package/commands/hmigbot.md +17 -0
- package/dist/index.js +1 -0
- package/manifest.json +19 -0
- package/package.json +29 -0
- package/skills/migrate-core/FILES.md +26 -0
- package/skills/migrate-core/SKILL.md +484 -0
- package/skills/migrate-core/references/README.md +64 -0
- package/skills/migrate-core/references/flow/arkts-vector-gate.md +55 -0
- package/skills/migrate-core/references/flow/build-error-patterns.md +52 -0
- package/skills/migrate-core/references/flow/conventions-template.md +244 -0
- package/skills/migrate-core/references/flow/navigation-migration.md +42 -0
- package/skills/migrate-core/references/flow/platform-api-guards.md +59 -0
- package/skills/migrate-core/references/flow/platform-model-gaps.md +43 -0
- package/skills/migrate-core/references/flow/resource-conversion.md +46 -0
- package/skills/migrate-core/references/flow/ui-layout-semantics.md +124 -0
- package/skills/migrate-core/references/flow/unit-breakdown.md +42 -0
- package/skills/migrate-core/references/host-capabilities.md +24 -0
- package/skills/migrate-core/references/topics/app-identity.md +214 -0
- package/skills/migrate-core/references/topics/env-doctor.md +245 -0
- package/skills/migrate-core/references/topics/i18n/README.md +458 -0
- package/skills/migrate-core/references/topics/i18n/references/code-examples.md +304 -0
- package/skills/migrate-core/references/topics/i18n/references/common-pitfalls.md +354 -0
- package/skills/migrate-core/references/topics/i18n/references/dynamic-language-switch.md +464 -0
- package/skills/migrate-core/references/topics/i18n/references/language-codes.md +104 -0
- package/skills/migrate-core/references/topics/icon-sizing.md +98 -0
- package/skills/migrate-core/references/topics/library-migration/README.md +234 -0
- package/skills/migrate-core/references/topics/library-migration/closed-source-sdk.md +128 -0
- package/skills/migrate-core/references/topics/library-migration/download-api-decision.md +84 -0
- package/skills/migrate-core/references/topics/library-migration/library-mapping-table.md +100 -0
- package/skills/migrate-core/references/topics/library-migration/napi-compile-guide.md +84 -0
- package/skills/migrate-core/references/topics/library-migration/ohpm-search-guide.md +73 -0
- package/skills/migrate-core/references/topics/library-migration/stdlib-mapping-table.md +34 -0
- package/skills/migrate-core/references/topics/resources/aar-decompile.md +25 -0
- package/skills/migrate-core/references/topics/resources/conversion-rules.md +625 -0
- package/skills/migrate-core/references/topics/resources/dependency-analysis-rules.md +328 -0
- package/skills/migrate-core/references/topics/resources/material-design-icons.md +173 -0
- package/skills/migrate-core/references/topics/resources/svg-fix-patterns.md +175 -0
- package/skills/migrate-core/references/topics/resources/xml-drawable-to-svg-rules.md +513 -0
- package/skills/migrate-core/references/topics/system-capabilities/README.md +331 -0
- package/skills/migrate-core/references/topics/system-capabilities/avplayer-guide.md +161 -0
- package/skills/migrate-core/references/topics/system-capabilities/background-tasks.md +403 -0
- package/skills/migrate-core/references/topics/system-capabilities/browser-intent.md +121 -0
- package/skills/migrate-core/references/topics/system-capabilities/camera-picker.md +118 -0
- package/skills/migrate-core/references/topics/system-capabilities/document-picker.md +246 -0
- package/skills/migrate-core/references/topics/system-capabilities/file-utils.md +131 -0
- package/skills/migrate-core/references/topics/system-capabilities/permission-helper.md +112 -0
- package/skills/migrate-core/references/topics/system-capabilities/photo-access-helper.md +208 -0
- package/skills/migrate-core/references/topics/system-capabilities/print-management.md +213 -0
- package/skills/migrate-core/references/topics/system-capabilities/share-panel.md +177 -0
- package/skills/migrate-core/references/topics/system-capabilities/system-settings.md +322 -0
- package/skills/migrate-core/references/topics/system-capabilities/telephony-dial.md +49 -0
- package/skills/migrate-core/references/topics/system-capabilities/video-playback.md +42 -0
- package/skills/migrate-core/references/topics/system-capabilities/webview-patterns.md +38 -0
- package/skills/migrate-core/references/topics/ui-alignment/README.md +344 -0
- package/skills/migrate-core/references/topics/ui-alignment/references/dark-mode.md +47 -0
- package/skills/migrate-core/references/topics/ui-alignment/references/layout-mapping.md +301 -0
- package/skills/migrate-core/references/topics/ui-alignment/references/visual-patterns.md +411 -0
- package/skills/migrate-core/scripts/closure/check-anchors.mjs +186 -0
- package/skills/migrate-core/scripts/closure/check-api-guards.mjs +175 -0
- package/skills/migrate-core/scripts/closure/check-consumers.mjs +301 -0
- package/skills/migrate-core/scripts/closure/check-permissions.mjs +165 -0
- package/skills/migrate-core/scripts/closure/check-resources.mjs +130 -0
- package/skills/migrate-core/scripts/closure/check-routes.mjs +527 -0
- package/skills/migrate-core/scripts/closure/check-safearea.mjs +122 -0
- package/skills/migrate-core/scripts/closure/check-stubs.mjs +69 -0
- package/skills/migrate-core/scripts/closure/closure-suite.mjs +256 -0
- package/skills/migrate-core/scripts/closure/idioms.json +105 -0
- package/skills/migrate-core/scripts/convert/convert-resources.mjs +437 -0
- package/skills/migrate-core/scripts/feasibility/feasibility.mjs +235 -0
- package/skills/migrate-core/scripts/feasibility/tables/cross-platform.json +11 -0
- package/skills/migrate-core/scripts/feasibility/tables/deprecated-api.json +10 -0
- package/skills/migrate-core/scripts/feasibility/tables/imported-arkts-core.json +425 -0
- package/skills/migrate-core/scripts/feasibility/tables/lib-equivalence.json +206 -0
- package/skills/migrate-core/scripts/feasibility/tables/system-capabilities.json +22 -0
- package/skills/migrate-core/scripts/front.mjs +107 -0
- package/skills/migrate-core/scripts/interface/ark-extract.mjs +172 -0
- package/skills/migrate-core/scripts/interface/interface.mjs +152 -0
- package/skills/migrate-core/scripts/ledger/ledger.mjs +383 -0
- package/skills/migrate-core/scripts/ledger/parse-cards.mjs +98 -0
- package/skills/migrate-core/scripts/lib/literals.mjs +37 -0
- package/skills/migrate-core/scripts/lib/scan.mjs +315 -0
- package/skills/migrate-core/scripts/smoke/align-sdk.mjs +118 -0
- package/skills/migrate-core/scripts/smoke/ensure-sign.mjs +53 -0
- package/skills/migrate-core/scripts/smoke/smoke.mjs +238 -0
- package/skills/migrate-core/scripts/smoke/verdict.mjs +31 -0
- package/skills/migrate-core/scripts/smoke/walk.mjs +480 -0
- package/skills/migrate-core/scripts/transpile/mapping.json +76 -0
- package/skills/migrate-core/scripts/transpile/transpile-layout.mjs +404 -0
- package/skills/migrate-core/scripts/vectors/run-arkts-vectors.mjs +107 -0
- package/skills/migrate-core/scripts/vectors/setup-arkts-test.mjs +90 -0
- package/skills/migrate-core/scripts/wire/extractors.mjs +258 -0
- package/skills/migrate-core/scripts/wire/wire-routes.mjs +507 -0
- package/skills/migrate-core/templates/acceptance.js +365 -0
- package/skills/migrate-core/templates/explore.js +86 -0
- package/skills/migrate-core/templates/implement.js +211 -0
- package/skills/migrate-core/templates/mig_slices.js +491 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<!-- 原技能 hmos-env-doctor,已吸收为 migrate-core 语料专题,不再单独注册 -->
|
|
2
|
+
> HarmonyOS 开发环境检测与修复。在迁移、编译、运行 HarmonyOS 项目前自动诊断环境问题。当用户说"编译失败"、"环境有问题"、"hvigorw 找不到"、"签名错误"、"真机运行白屏"、"网络请求失败"、"检查一下环境"、"为什么编译不过"时触发。也适用于项目初始化后的环境健康检查、DevEco Studio CLI 编译配置、以及迁移前的环境预检。即使用户只说"帮我看看哪里有问题"或者"跑不起来",也应触发。
|
|
3
|
+
|
|
4
|
+
# HarmonyOS 环境医生
|
|
5
|
+
|
|
6
|
+
## 1. 定位
|
|
7
|
+
|
|
8
|
+
开发环境诊断工具。在 HarmonyOS 项目迁移或开发过程中,自动检测 DevEco Studio、SDK、编译工具链、签名配置、权限声明、网络环境等问题,输出诊断报告并提供一键修复方案。
|
|
9
|
+
|
|
10
|
+
**解决的核心痛点**:HarmonyOS 开发涉及多个工具链(hvigorw、ohpm、Java、Node.js、SDK),任何一个缺失或配置错误都会导致编译失败或运行异常,而错误信息往往不直观。本 skill 将散落的环境知识整合为系统化的检查清单。
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 2. 触发时机
|
|
15
|
+
|
|
16
|
+
- 项目初始化后,首次尝试编译前
|
|
17
|
+
- 编译失败且错误信息指向环境问题
|
|
18
|
+
- 真机/模拟器运行出现白屏、闪退、网络失败
|
|
19
|
+
- Android→HarmonyOS 迁移开始前的环境预检
|
|
20
|
+
- 用户主动请求环境检查
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 3. 诊断清单(按优先级排序)
|
|
25
|
+
|
|
26
|
+
### 3.1 DevEco Studio 定位
|
|
27
|
+
|
|
28
|
+
DevEco Studio 是 HarmonyOS 开发的核心 IDE,内置了编译、打包、签名所需的全部工具。
|
|
29
|
+
|
|
30
|
+
**检测步骤**:
|
|
31
|
+
```bash
|
|
32
|
+
# 常见安装路径(按优先级搜索)
|
|
33
|
+
for drive in C D E F; do
|
|
34
|
+
find "/$drive/" -maxdepth 4 -name "DevEco*" -type d 2>/dev/null
|
|
35
|
+
done
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**需要从 DevEco Studio 中提取的工具**:
|
|
39
|
+
| 工具 | 相对路径 | 用途 |
|
|
40
|
+
|------|---------|------|
|
|
41
|
+
| hvigorw | tools/hvigor/bin/hvigorw | 项目编译 |
|
|
42
|
+
| ohpm | tools/ohpm/bin/ohpm | 包管理 |
|
|
43
|
+
| java | jbr/bin/java | Java 运行时(打包需要) |
|
|
44
|
+
| node | tools/node/bin/node | Node.js 运行时 |
|
|
45
|
+
| SDK | sdk/default/openharmony/ | HarmonyOS SDK |
|
|
46
|
+
|
|
47
|
+
**环境变量设置模板**:
|
|
48
|
+
```bash
|
|
49
|
+
export DEVECO_HOME="/path/to/DevEco Studio"
|
|
50
|
+
export PATH="$DEVECO_HOME/tools/hvigor/bin:$DEVECO_HOME/tools/ohpm/bin:$DEVECO_HOME/jbr/bin:$PATH"
|
|
51
|
+
export DEVECO_SDK_HOME="$DEVECO_HOME/sdk"
|
|
52
|
+
export JAVA_HOME="$DEVECO_HOME/jbr"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**诊断结果**:
|
|
56
|
+
- PASS: DevEco Studio 找到,工具链完整
|
|
57
|
+
- FAIL: 未找到 → 提示安装 DevEco Studio
|
|
58
|
+
- WARN: 找到但版本过旧 → 提示升级
|
|
59
|
+
|
|
60
|
+
### 3.2 编译工具链验证
|
|
61
|
+
|
|
62
|
+
定位到 DevEco Studio 后,验证各工具是否可用:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
hvigorw --version # 期望: 6.x.x
|
|
66
|
+
ohpm --version # 期望: 有输出
|
|
67
|
+
java --version # 期望: JDK 17+
|
|
68
|
+
node --version # 期望: v18+
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**常见故障**:
|
|
72
|
+
| 错误信息 | 原因 | 修复 |
|
|
73
|
+
|---------|------|------|
|
|
74
|
+
| `hvigorw: command not found` | PATH 未设置 | 添加 DevEco tools/hvigor/bin 到 PATH |
|
|
75
|
+
| `spawn java ENOENT` | Java 不在 PATH | 添加 DevEco jbr/bin 到 PATH |
|
|
76
|
+
| `Cannot find module 'xxx'` | node_modules 缺失 | 运行 `ohpm install` |
|
|
77
|
+
| `The SDK license agreement is not accepted` | 新机/流水线 SDK 组件从未接受许可(实测一批 20 应用里 3 个整轮报废于此) | 迁移前先空跑一次 `hvigorw assembleHap --no-daemon`;报此错即按错误文本指引:DevEco Studio SDK Manager 重下对应版本 Toolchains/ArkTS/JS/Native/Previewer 并接受许可,或命令行 SDK 工具重下时接受许可;接受后再开工,不在迁移中途处理 |
|
|
78
|
+
|
|
79
|
+
### 3.3 签名配置检查
|
|
80
|
+
|
|
81
|
+
签名问题是 HarmonyOS 编译中最常见的环境卡点。
|
|
82
|
+
|
|
83
|
+
**检测步骤**:
|
|
84
|
+
1. 读取 `build-profile.json5` 中的 `signingConfigs`
|
|
85
|
+
2. 检查 `storeFile`、`certpath`、`profile` 路径是否在本机存在
|
|
86
|
+
3. 如果路径指向其他用户目录(如 `/Users/xxx/`)→ 签名配置来自其他机器
|
|
87
|
+
|
|
88
|
+
**修复策略(按优先级)**:
|
|
89
|
+
1. **方案 A**: 在 DevEco Studio 中重新配置自动签名(File → Project Structure → Signing Configs)
|
|
90
|
+
2. **方案 B**: 移除 `signingConfig` 引用,生成 unsigned HAP(开发调试用)
|
|
91
|
+
```json5
|
|
92
|
+
// build-profile.json5 中移除这一行:
|
|
93
|
+
// "signingConfig": "default",
|
|
94
|
+
```
|
|
95
|
+
3. **方案 C**: 手动创建签名文件(生产发布用)
|
|
96
|
+
|
|
97
|
+
**判断逻辑**:
|
|
98
|
+
- 路径存在 + 文件有效 → PASS
|
|
99
|
+
- 路径不存在但为本机路径 → FAIL: 签名文件缺失
|
|
100
|
+
- 路径指向其他用户/机器 → FAIL: 签名配置来自其他环境
|
|
101
|
+
- 无 signingConfigs 字段 → WARN: 将生成 unsigned HAP
|
|
102
|
+
|
|
103
|
+
### 3.4 Python 环境(可选工具)
|
|
104
|
+
|
|
105
|
+
部分迁移脚本(synthesize_view_xml.py 等)需要 Python。
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
python3 --version || python --version
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**缺失时的影响和降级策略**:
|
|
112
|
+
- 影响: 无法运行确定性脚本合成 view.xml,页面 confidence 降为 medium
|
|
113
|
+
- 降级: LLM 直接分析源码生成 meta.json(精度略低但可用)
|
|
114
|
+
- 建议: 安装 Python 3.8+ 可提升 UI 还原精度
|
|
115
|
+
|
|
116
|
+
### 3.5 项目配置检查
|
|
117
|
+
|
|
118
|
+
**module.json5 权限声明**:
|
|
119
|
+
```bash
|
|
120
|
+
grep -q "ohos.permission.INTERNET" entry/src/main/module.json5
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
缺少 INTERNET 权限是真机上网络请求静默失败的最常见原因。
|
|
124
|
+
|
|
125
|
+
**必须声明的权限**(网络类应用):
|
|
126
|
+
```json5
|
|
127
|
+
"requestPermissions": [
|
|
128
|
+
{ "name": "ohos.permission.INTERNET" },
|
|
129
|
+
{ "name": "ohos.permission.GET_NETWORK_INFO" }
|
|
130
|
+
]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**app.json5 身份检查**:
|
|
134
|
+
- `bundleName` 不应为 `com.example.*`(模板默认值)
|
|
135
|
+
- `vendor` 不应为 `example`
|
|
136
|
+
- 检查 `versionName` 是否已从 Android 同步
|
|
137
|
+
|
|
138
|
+
**main_pages.json 入口检查**:
|
|
139
|
+
- 检查 `src` 数组第一项是否指向实际的启动页(不是默认的 `pages/Index`)
|
|
140
|
+
- 检查 EntryAbility.ets 中 `loadContent` 路径与 main_pages.json 首项一致
|
|
141
|
+
|
|
142
|
+
### 3.6 真机/模拟器运行时问题
|
|
143
|
+
|
|
144
|
+
当应用编译通过但运行异常时,检查以下项:
|
|
145
|
+
|
|
146
|
+
**白屏/内容为空**:
|
|
147
|
+
- 原因 1: `aboutToAppear` 中 async 调用失败,状态变量(`@Local` V2 / `@State` V1)保持初始空值
|
|
148
|
+
- 检查: grep "aboutToAppear" 中的 async 调用,是否有同步 fallback
|
|
149
|
+
- 修复: 关键展示数据同步初始化,async 作为增强
|
|
150
|
+
- 原因 2: ForEach 未提供 key generator,class 实例 key 冲突
|
|
151
|
+
- 检查: grep "ForEach" 是否有第三个参数(key generator)
|
|
152
|
+
- 修复: 添加 `(item) => item.uniqueId` 作为 key generator
|
|
153
|
+
- 原因 3: 网络权限缺失,API 请求静默失败
|
|
154
|
+
- 检查: module.json5 是否有 INTERNET 权限
|
|
155
|
+
|
|
156
|
+
**闪退**:
|
|
157
|
+
- 原因 1: crypto API 在某些设备上不可用
|
|
158
|
+
- 检查: 是否使用了 cryptoFramework 且未 try-catch
|
|
159
|
+
- 修复: crypto 调用必须有 try-catch + fallback
|
|
160
|
+
- 原因 2: 未注册的页面路由
|
|
161
|
+
- 检查: main_pages.json 是否包含所有页面
|
|
162
|
+
- 修复: 确保每个 @Entry 页面都在 src 数组中
|
|
163
|
+
|
|
164
|
+
**网络请求失败**:
|
|
165
|
+
- 原因 1: 缺少 INTERNET 权限
|
|
166
|
+
- 原因 2: HTTP 明文传输被阻止(需配置 network_security_config)
|
|
167
|
+
- 原因 3: API 域名不可达(检查 DNS/代理)
|
|
168
|
+
|
|
169
|
+
### 3.7 子代理权限(宿主相关)
|
|
170
|
+
|
|
171
|
+
并行子代理可能无法访问 Android 源码目录(多数宿主默认只授权工作目录)。
|
|
172
|
+
|
|
173
|
+
**检测**:子代理是否能读取 `$ANDROID_SRC` 路径下的文件。
|
|
174
|
+
|
|
175
|
+
**修复**:
|
|
176
|
+
- 方案 A: 按宿主权限机制放行该目录(DevEco Code:推荐工作目录同时包含 Android 源码与鸿蒙工程,权限询问时允许)
|
|
177
|
+
- 方案 B: 将 Android 源码复制到工作目录下
|
|
178
|
+
- 方案 C: 主会话 fallback(效率低但可用)
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 4. 诊断报告格式
|
|
183
|
+
|
|
184
|
+
```markdown
|
|
185
|
+
# 环境诊断报告
|
|
186
|
+
|
|
187
|
+
| 检查项 | 状态 | 详情 |
|
|
188
|
+
|--------|------|------|
|
|
189
|
+
| DevEco Studio | PASS/FAIL | 路径: xxx, 版本: xxx |
|
|
190
|
+
| hvigorw | PASS/FAIL | 版本: xxx |
|
|
191
|
+
| Java | PASS/FAIL | 版本: xxx |
|
|
192
|
+
| Node.js | PASS/FAIL | 版本: xxx |
|
|
193
|
+
| Python | PASS/WARN | 版本: xxx (可选) |
|
|
194
|
+
| 签名配置 | PASS/FAIL/WARN | 状态描述 |
|
|
195
|
+
| 网络权限 | PASS/FAIL | module.json5 |
|
|
196
|
+
| App 身份 | PASS/WARN | bundleName/vendor |
|
|
197
|
+
| 入口页面 | PASS/FAIL | main_pages.json + EntryAbility |
|
|
198
|
+
|
|
199
|
+
## 需要修复的项
|
|
200
|
+
1. ...
|
|
201
|
+
2. ...
|
|
202
|
+
|
|
203
|
+
## 修复命令
|
|
204
|
+
(自动生成的修复脚本)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 5. 自动修复能力
|
|
210
|
+
|
|
211
|
+
对于可安全自动修复的问题,skill 直接执行修复:
|
|
212
|
+
|
|
213
|
+
| 问题 | 自动修复 | 操作 |
|
|
214
|
+
|------|---------|------|
|
|
215
|
+
| PATH 未设置 | YES | 输出 export 命令 |
|
|
216
|
+
| 缺少 INTERNET 权限 | YES | 追加到 module.json5 |
|
|
217
|
+
| 签名指向其他机器 | YES | 移除 signingConfig 引用 |
|
|
218
|
+
| main_pages.json 入口错误 | YES | 更新 src 数组 |
|
|
219
|
+
| bundleName 为模板默认值 | ASK | 提示用户输入正确的包名 |
|
|
220
|
+
| Python 缺失 | NO | 提示安装命令 |
|
|
221
|
+
| DevEco Studio 缺失 | NO | 提示下载链接 |
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 6. 使用示例
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
检查一下环境
|
|
229
|
+
```
|
|
230
|
+
→ 运行完整诊断清单,输出报告
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
编译失败了,spawn java ENOENT
|
|
234
|
+
```
|
|
235
|
+
→ 定位 Java 问题,输出 PATH 修复命令
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
真机上模版列表是空的
|
|
239
|
+
```
|
|
240
|
+
→ 检查网络权限 + async fallback + ForEach key
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
开始迁移前先检查一下
|
|
244
|
+
```
|
|
245
|
+
→ 运行预检清单(DevEco + 签名 + Python + 权限)
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
> ⚠ 本文样例中 `getContext(this)` 为已废弃写法:组件内一律改 `this.getUIContext().getHostContext()`;Ability 内用 `this.context`。
|
|
2
|
+
|
|
3
|
+
<!-- 原技能 arkts-i18n,已吸收为 migrate-core 语料专题,不再单独注册 -->
|
|
4
|
+
> ArkTS/HarmonyOS 国际化(i18n)技能(V2 优先,API 12+)。当用户需要添加多语言支持、实现动态语言切换、配置资源文件、处理国际化资源目录结构、扫描硬编码字符串,或任何与"国际化"、"多语言"、"切换语言"相关的问题时,务必触发此 skill。 即使用户只是说"怎么添加英文"或"怎么做中英文切换",也应触发。
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# ArkTS I18N — 国际化指南(V2 优先)
|
|
8
|
+
|
|
9
|
+
## API 版本与项目策略
|
|
10
|
+
|
|
11
|
+
本 skill 的代码示例基于 **API 12+(HarmonyOS 5.0.0+)和 ArkTS V2 装饰器体系**。
|
|
12
|
+
|
|
13
|
+
> **项目锁 V2**:所有新生成的"语言切换 / locale 状态 / refreshKey"代码使用 V2 装饰器(`@ComponentV2 / @Local / @Param / @Once / @ObservedV2 / @Trace / AppStorageV2.connect / PersistenceV2.globalConnect`)。i18n 相关 API(`resourceManager` / `intl` / `$r('app.string.xxx')` / `i18n.System.setAppPreferredLanguage` / `getAppPreferredLanguage` / `onConfigurationUpdate`)在 V1/V2 之间**完全不变**。
|
|
14
|
+
>
|
|
15
|
+
|
|
16
|
+
V1 → V2 关键差异(仅与本 skill 相关的 state 部分):
|
|
17
|
+
|
|
18
|
+
| V1 | V2 |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `@Component` | `@ComponentV2` |
|
|
21
|
+
| `@State refreshKey: number = 0` | `@Local refreshKey: number = 0` |
|
|
22
|
+
| `@StorageLink('currentLanguage') lang: string = 'zh'` | `@Local locale: LocaleModel = AppStorageV2.connect(LocaleModel, 'locale', () => new LocaleModel())!`(需先定义 `@ObservedV2 LocaleModel`) |
|
|
23
|
+
| `@Prop currentColumns: number = 3` | `@Param @Once currentColumns: number = 3`(只读) |
|
|
24
|
+
| `@Watch('lang') onLangChange()` | `@Monitor('lang') onLangChange(m: IMonitor)` |
|
|
25
|
+
| `AppStorage.setOrCreate('refreshKey', n)` | `localeModel.refreshKey = n`(直接改 @Trace 字段,自动同步) |
|
|
26
|
+
| `PersistentStorage.persistProp('currentLanguage', 'zh')` | `PersistenceV2.globalConnect({ type: LocaleModel, key: 'locale', defaultCreator: () => new LocaleModel() })` |
|
|
27
|
+
|
|
28
|
+
> **重要**:i18n 业务 API(`i18n.System.setAppPreferredLanguage()` / `$r()` / `onConfigurationUpdate()` 等)**与装饰器版本无关**。本次升级仅替换状态装饰器,API 调用方式不变。
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 触发场景
|
|
33
|
+
|
|
34
|
+
- "怎么做国际化"、"添加多语言支持"
|
|
35
|
+
- "实现中英文切换"
|
|
36
|
+
- "资源文件怎么组织"
|
|
37
|
+
- "动态切换语言不生效"
|
|
38
|
+
- "怎么添加日语/韩语/其他语言"
|
|
39
|
+
- "扫描硬编码字符串"、"找出没有国际化的文本"
|
|
40
|
+
- 迁移流程内批量翻译待办时按下方"自动翻译模式"手动触发(历史自动集成已随旧管线移除)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 自动翻译模式(批量翻译待办的标准流程)
|
|
45
|
+
|
|
46
|
+
当 `spec/placeholder-registry.md` 含 `kind=resource-pending-translation` 条目时,按以下步骤执行:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
skill({
|
|
50
|
+
skill: "arkts-i18n",
|
|
51
|
+
args: "task=translate-pending-todos source_locale=base target_locales=<auto-detect> registry=spec/placeholder-registry.md"
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
收到 `task=translate-pending-todos` 时,按以下流程执行(不需要用户介入):
|
|
56
|
+
|
|
57
|
+
### 自动流程
|
|
58
|
+
|
|
59
|
+
1. **读 registry** — 解析 `spec/placeholder-registry.md`,过滤 `kind=resource-pending-translation` 且 `status ∈ {registered, pending}` 的所有条目;每条 `location` 字段形如 `entry/src/main/resources/<locale>/element/<file>.json:<key>`
|
|
60
|
+
2. **按 locale 分组** — 每个目标 locale 单独处理
|
|
61
|
+
3. **逐 key 翻译** — 对每个 P-ID,读出 `[TODO: translate]` 前缀的英文原值,按目标 locale 生成真实翻译(LLM 按本 skill 既有"步骤 4:添加到 string.json"风格产出)。术语一致性参考 `references/code-examples.md` / `references/language-codes.md`
|
|
62
|
+
4. **落盘** — 用 Edit/Write 把真实翻译写回对应 `resources/<locale>/element/<file>.json` 的 `value` 字段,**移除 `[TODO: translate]` 前缀**
|
|
63
|
+
5. **跨 locale 一致性验证** — 跑 `scripts/audit_i18n_completeness.sh --project-root <abs> --output-json docs/i18n-audit.json`;若 FAIL 则报告 missing keys 并停止
|
|
64
|
+
6. **更新 registry** — 把已处理的 P-ID 的 `status` 字段从 `registered` / `pending` 改为 `resolved`
|
|
65
|
+
7. **返回报告** — 输出 `{translated_count, locales, audit_pass, updated_registry_path}` 结构化结果
|
|
66
|
+
|
|
67
|
+
### 异常处理
|
|
68
|
+
|
|
69
|
+
- 任一 locale 的翻译产出无法通过审阅(含未翻译英文、术语不一致等)→ 保留 `[TODO: translate]` 前缀 + registry status 不更新 + `failed_translations[]` 写进迁移报告
|
|
70
|
+
- `audit_i18n_completeness.sh` 退出码 1(key_missing)→ 同上
|
|
71
|
+
|
|
72
|
+
> 此模式下 LLM 充当翻译引擎,但**仍可被独立审阅**——产出的翻译会留在 git working tree,用户跑完整 pipeline 后随时可 review / amend。
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 核心概念
|
|
77
|
+
|
|
78
|
+
HarmonyOS 国际化基于「**资源文件目录分级**」和「**系统语言检测**」:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
resources/
|
|
82
|
+
├── base/ // Fallback 资源(无匹配时使用)
|
|
83
|
+
├── zh_CN/ // 简体中文
|
|
84
|
+
├── en_US/ // 美国英文
|
|
85
|
+
└── ja/ // 日文
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- **静态引用**:`$r('app.string.xxx')` 由系统根据当前语言自动加载
|
|
89
|
+
- **动态切换**:通过 `i18n.System.setAppPreferredLanguage()` 手动指定语言
|
|
90
|
+
|
|
91
|
+
### ⚠️ base/ 目录的作用
|
|
92
|
+
|
|
93
|
+
**base/ 不是"中文目录",而是 Fallback 目录!**
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
资源匹配规则:
|
|
97
|
+
1. 系统根据当前语言查找匹配目录(zh-CN → zh_CN、zh-Hans、zh)
|
|
98
|
+
2. 找到匹配目录?→ ✅ 使用该目录的资源
|
|
99
|
+
3. 未找到?→ 使用 base/ 目录的资源(Fallback)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 资源文件结构
|
|
105
|
+
|
|
106
|
+
### 标准目录结构
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
src/main/resources/
|
|
110
|
+
├── base/ # Fallback 资源
|
|
111
|
+
│ ├── element/
|
|
112
|
+
│ │ └── string.json # 字符串资源
|
|
113
|
+
│ └── media/ # 图片资源
|
|
114
|
+
├── zh_CN/ # 简体中文
|
|
115
|
+
│ └── element/
|
|
116
|
+
│ └── string.json
|
|
117
|
+
├── en_US/ # 美国英文
|
|
118
|
+
│ ├── element/
|
|
119
|
+
│ │ └── string.json
|
|
120
|
+
│ └── media/
|
|
121
|
+
│ └── logo.png # 英文版 logo(可选)
|
|
122
|
+
└── ja/ # 日文
|
|
123
|
+
└── element/
|
|
124
|
+
└── string.json
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 目录命名规范
|
|
128
|
+
|
|
129
|
+
| 类型 | 格式 | 示例 |
|
|
130
|
+
|------|------|------|
|
|
131
|
+
| 语言 | ISO 639-1 | `en`, `ja`, `ko`, `zh` |
|
|
132
|
+
| 语言+区域 | ISO 639-1 + ISO 3166-1 | `zh_CN`, `en_US`, `zh_TW` |
|
|
133
|
+
|
|
134
|
+
> ⚠️ 目录名必须完全匹配,否则系统无法识别
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 字符串资源文件
|
|
139
|
+
|
|
140
|
+
### JSON 格式
|
|
141
|
+
|
|
142
|
+
**base/element/string.json**:
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"string": [
|
|
146
|
+
{ "name": "app_name", "value": "App Name" },
|
|
147
|
+
{ "name": "confirm", "value": "Confirm" }
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**zh_CN/element/string.json**:
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"string": [
|
|
156
|
+
{ "name": "app_name", "value": "应用名称" },
|
|
157
|
+
{ "name": "confirm", "value": "确认" }
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 引用方式
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// 静态引用
|
|
166
|
+
Text($r('app.string.app_name'))
|
|
167
|
+
Button($r('app.string.confirm'))
|
|
168
|
+
Image($r('app.media.logo'))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 插值参数(占位符)
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
// string.json
|
|
175
|
+
{ "name": "file_count", "value": "共 %d 个文件" }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// 代码中替换
|
|
180
|
+
const str = resourceManager.getStringByNameSync('file_count')
|
|
181
|
+
const message = str.replace('%d', count.toString())
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 语言范围由资源目录决定
|
|
187
|
+
|
|
188
|
+
module.json5 **没有** `supportedLanguages` 字段(hvigor 模块 schema 无此项,写了校验报错)。应用支持哪些语言 = `resources/` 下有哪些 locale 目录(`base/` 必有;`zh_CN/`、`en_US/`、`zh_HK/`、`ja_JP/` … 按平台限定符命名);`i18n.System.setAppPreferredLanguage(lang)` 设到没有资源目录的语言时,`$r` 回退 `base/`。
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 动态语言切换(V2)
|
|
193
|
+
|
|
194
|
+
### 基本实现
|
|
195
|
+
|
|
196
|
+
V2 项目用 `@Local` 持有 refreshKey;i18n API 不变:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { i18n } from '@kit.LocalizationKit'
|
|
200
|
+
import { common } from '@kit.AbilityKit'
|
|
201
|
+
|
|
202
|
+
@Entry
|
|
203
|
+
@ComponentV2
|
|
204
|
+
struct LanguageSettings {
|
|
205
|
+
private context = getContext(this) as common.UIAbilityContext
|
|
206
|
+
@Local private refreshKey: number = 0
|
|
207
|
+
|
|
208
|
+
async switchLanguage(lang: string): Promise<void> {
|
|
209
|
+
i18n.System.setAppPreferredLanguage(lang) // 同步;之后加载的资源按此语言取,已渲染页面靠 refreshKey 重建
|
|
210
|
+
this.refreshKey++ // 触发 UI 重建
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
build() {
|
|
214
|
+
Column() {
|
|
215
|
+
Text($r('app.string.welcome'))
|
|
216
|
+
.fontSize(20)
|
|
217
|
+
}
|
|
218
|
+
.id('lang_' + this.refreshKey)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 全局共享 locale 状态(V2 推荐)
|
|
224
|
+
|
|
225
|
+
把 `currentLanguage` / `refreshKey` 封装到一个 `@ObservedV2 LocaleModel`,用 `AppStorageV2.connect` 在所有页面共享单例:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// common/LocaleModel.ets
|
|
229
|
+
@ObservedV2
|
|
230
|
+
export class LocaleModel {
|
|
231
|
+
@Trace currentLanguage: string = 'zh'
|
|
232
|
+
@Trace refreshKey: number = 0
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 任意 V2 组件
|
|
236
|
+
@ComponentV2
|
|
237
|
+
struct AnyPage {
|
|
238
|
+
@Local locale: LocaleModel = AppStorageV2.connect(
|
|
239
|
+
LocaleModel,
|
|
240
|
+
'locale',
|
|
241
|
+
() => new LocaleModel()
|
|
242
|
+
)!
|
|
243
|
+
|
|
244
|
+
build() {
|
|
245
|
+
Column() {
|
|
246
|
+
Text($r('app.string.hello'))
|
|
247
|
+
.id('page_' + this.locale.refreshKey) // refreshKey 改 → 自动重建
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
> 修改 `this.locale.refreshKey++` 即可同步刷新所有 `connect` 同一 key 的组件,无需 V1 `@StorageLink` 散字段。
|
|
254
|
+
|
|
255
|
+
### 获取当前系统语言
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { i18n } from '@kit.LocalizationKit'
|
|
259
|
+
|
|
260
|
+
getCurrentLanguage(): string {
|
|
261
|
+
return i18n.System.getAppPreferredLanguage() || 'zh' // 同步返回应用当前生效语言(如 'zh-Hans');resourceManager 没有 getPreferredLanguage
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 监听语言变化
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// 在 EntryAbility 中(UIAbility 只有 onConfigurationUpdate 一个配置变化回调,没有单独的语言回调)
|
|
269
|
+
onConfigurationUpdate(config: Configuration): void {
|
|
270
|
+
if (config.language !== undefined) hilog.info(0x0000, 'I18N', `Language changed: ${config.language}`)
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## 图片国际化
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
resources/
|
|
280
|
+
├── base/media/logo.png # 默认 logo
|
|
281
|
+
├── en/media/logo.png # 英文版 logo(同名)
|
|
282
|
+
└── zh_CN/media/logo.png # 中文版 logo(同名)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// 同一引用路径,不同语言加载不同文件
|
|
287
|
+
Image($r('app.media.logo'))
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
> ⚠️ 不同语言目录下的图片**文件名必须一致**
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## 常见错误
|
|
295
|
+
|
|
296
|
+
### 错误 1:硬编码字符串
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// ❌ 错误
|
|
300
|
+
Text('确认')
|
|
301
|
+
Button('登录')
|
|
302
|
+
|
|
303
|
+
// ✅ 正确
|
|
304
|
+
Text($r('app.string.confirm'))
|
|
305
|
+
Button($r('app.string.login'))
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 错误 2:目录命名错误
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
// ❌ 错误
|
|
312
|
+
resources/chinese/element/string.json
|
|
313
|
+
|
|
314
|
+
// ✅ 正确
|
|
315
|
+
resources/zh_CN/element/string.json
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### 错误 3:语言没有对应资源目录
|
|
319
|
+
|
|
320
|
+
`setAppPreferredLanguage` 设到没有 `resources/<locale>/` 的语言,`$r` 回退 `base/`,表现像"不生效"——补对应 locale 目录(module.json5 没有 supportedLanguages 字段)。
|
|
321
|
+
|
|
322
|
+
### 错误 4:动态切换后 UI 不更新
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import { i18n } from '@kit.LocalizationKit'
|
|
326
|
+
// ❌ 错误 — 直接返回
|
|
327
|
+
i18n.System.setAppPreferredLanguage(lang)
|
|
328
|
+
|
|
329
|
+
// ✅ 正确 — 触发重建
|
|
330
|
+
i18n.System.setAppPreferredLanguage(lang)
|
|
331
|
+
this.refreshKey++
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### 错误 5:string.json 格式错误
|
|
335
|
+
|
|
336
|
+
```json
|
|
337
|
+
// ❌ 错误 — value 被双引号包裹
|
|
338
|
+
{ "name": "app_name", "value": "\"图库\"" }
|
|
339
|
+
|
|
340
|
+
// ✅ 正确
|
|
341
|
+
{ "name": "app_name", "value": "图库" }
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 硬编码字符串扫描与迁移
|
|
347
|
+
|
|
348
|
+
当用户需要**扫描项目中的硬编码字符串并迁移到 resources**时,执行以下流程:
|
|
349
|
+
|
|
350
|
+
### 步骤 1:扫描硬编码
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
rg "Text\(['\"]" --type ets -n
|
|
354
|
+
rg "Button\(['\"]" --type ets -n
|
|
355
|
+
rg "showToast\(['\"]" --type ets -n
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### 步骤 2:识别需要迁移的字符串
|
|
359
|
+
|
|
360
|
+
**排除**:已使用 `$r()` 引用、URL、代码变量、正则、单字符
|
|
361
|
+
|
|
362
|
+
**需要迁移**:
|
|
363
|
+
```typescript
|
|
364
|
+
Text('确认')
|
|
365
|
+
Button('取消')
|
|
366
|
+
.title('设置页面')
|
|
367
|
+
promptAction.showToast('操作成功')
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### 步骤 3:生成资源 key
|
|
371
|
+
|
|
372
|
+
| 场景 | key 格式 | 示例 |
|
|
373
|
+
|------|---------|------|
|
|
374
|
+
| 按钮 | `btn_xxx` | `btn_confirm`, `btn_cancel` |
|
|
375
|
+
| 标题 | `title_xxx` | `title_settings` |
|
|
376
|
+
| 消息 | `msg_xxx` | `msg_delete_confirm` |
|
|
377
|
+
| Toast | `toast_xxx` | `toast_save_success` |
|
|
378
|
+
|
|
379
|
+
### 步骤 4:添加到 string.json
|
|
380
|
+
|
|
381
|
+
**base/element/string.json**:
|
|
382
|
+
```json
|
|
383
|
+
{ "name": "confirm", "value": "确认" }
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**en_US/element/string.json**:
|
|
387
|
+
```json
|
|
388
|
+
{ "name": "confirm", "value": "Confirm" }
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### 步骤 5:替换代码
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
// 替换前
|
|
395
|
+
Text('确认')
|
|
396
|
+
|
|
397
|
+
// 替换后
|
|
398
|
+
Text($r('app.string.confirm'))
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### 步骤 6:验证
|
|
402
|
+
|
|
403
|
+
**1) 跨 locale key 一致性** — 规则:`string.json` / `plural.json` / `strarray.json` 里 base 的全部 `name` 必须在每个
|
|
404
|
+
**language locale**(zh_CN / en_US / ...)出现;**mode locale**(dark / horizontal / vertical 等)按差异覆盖即可,豁免。
|
|
405
|
+
对比办法:取 base 与各语言目录同名文件的 `name` 集合求差集(`node -e` 或 `jq` 一行即可,无需专用脚本),差集非空 = 缺翻译,
|
|
406
|
+
补齐后再编译。
|
|
407
|
+
|
|
408
|
+
> 资源 value 内未注册的 `[TODO: translate]` / 裸 TODO 占位由集成闭合 check-stubs 统一扫描,两者职责正交。
|
|
409
|
+
|
|
410
|
+
**2) 手工 / 编译检查**:
|
|
411
|
+
|
|
412
|
+
- [ ] 所有用户可见字符串都已替换为 `$r()` 引用
|
|
413
|
+
- [ ] 替换后能正常编译
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## 生成检查清单
|
|
418
|
+
|
|
419
|
+
- [ ] 资源目录使用标准语言代码
|
|
420
|
+
- [ ] string.json 格式正确
|
|
421
|
+
- [ ] 所有用户可见字符串使用 `$r()` 引用
|
|
422
|
+
- [ ] 需要的语言都有 `resources/<locale>/` 目录(module.json5 没有 supportedLanguages 字段)
|
|
423
|
+
- [ ] 不同语言目录下的图片文件名一致
|
|
424
|
+
- [ ] 已扫描硬编码字符串并迁移到 resources
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## API 验证状态
|
|
429
|
+
|
|
430
|
+
| API | 状态 |
|
|
431
|
+
|-----|------|
|
|
432
|
+
| `resourceManager.getStringByNameSync()` | ✅ 已验证 |
|
|
433
|
+
| `resourceManager.getStringByName()` | ✅ SDK 有声明(异步,返回 Promise<string>) |
|
|
434
|
+
| `i18n.System.setAppPreferredLanguage()` | ✅ SDK 有声明(应用级语言设置) |
|
|
435
|
+
| `i18n.System.getAppPreferredLanguage()` | ✅ SDK 有声明(同步返回 string);`resourceManager.getPreferredLanguage` 不存在 |
|
|
436
|
+
| `$r('app.string.xxx')` | ✅ 已验证 |
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## References
|
|
441
|
+
|
|
442
|
+
详细文档和完整代码示例请参阅(**全部代码示例已升级 V2**):
|
|
443
|
+
|
|
444
|
+
| 文件 | 内容 |
|
|
445
|
+
|------|------|
|
|
446
|
+
| `references/dynamic-language-switch.md` | 动态语言切换完整代码(V2,含 LocaleModel) |
|
|
447
|
+
| `references/common-pitfalls.md` | 避坑指南与错误对照表(V2) |
|
|
448
|
+
| `references/language-codes.md` | 语言代码对照表(ISO 标准) |
|
|
449
|
+
| `references/code-examples.md` | ColumnsDialog 等代码示例(V2) |
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## 相关专题
|
|
454
|
+
|
|
455
|
+
| 需要什么 | 读取哪里 |
|
|
456
|
+
|---------|---------|
|
|
457
|
+
| V2 状态管理(@Local / @Param / @Event / AppStorageV2)与跨页传 locale | 工单 conventions §A2 状态条目为准;不确定的装饰器语义 grep 本机 SDK `.d.ts` |
|
|
458
|
+
|