@harmonyos-arkts/d2h 0.1.11 → 0.1.13
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/.claude-plugin/marketplace.json +15 -13
- package/.claude-plugin/plugin.json +13 -7
- package/AGENTS.md +5 -5
- package/README.md +212 -212
- package/agents/android-to-hmos-00-orchestrator.md +318 -318
- package/agents/d2h.md +157 -157
- package/dist/bin/install-opencode.js +30 -30
- package/docs/environment-check.md +86 -86
- package/install-opencode.sh +160 -160
- package/opencode/agents.json +16 -16
- package/opencode/vscode-d2h-package.json +7 -7
- package/opencode/vscode-d2h-plugin.mjs +29 -29
- package/package.json +54 -54
- package/schemas/android-source-manifest.schema.json +25 -25
- package/schemas/checkpoint-provenance.schema.json +67 -67
- package/schemas/final-acceptance.schema.json +29 -29
- package/schemas/managed-evidence-index.schema.json +15 -15
- package/schemas/managed-evidence.schema.json +114 -114
- package/schemas/migration-config.schema.json +51 -51
- package/schemas/migration-report-index.schema.json +39 -39
- package/schemas/migration-report-item.schema.json +51 -51
- package/schemas/migration-report-summary.schema.json +25 -25
- package/schemas/migration-status.schema.json +202 -202
- package/schemas/preflight.schema.json +60 -60
- package/schemas/source-order-audit.schema.json +16 -16
- package/schemas/source-provenance-event.schema.json +19 -19
- package/schemas/spec-app-shard.schema.json +45 -45
- package/schemas/spec-fact-corrections-shard.schema.json +13 -13
- package/schemas/spec-features-shard.schema.json +43 -43
- package/schemas/spec-index.schema.json +26 -26
- package/schemas/spec-interactions-shard.schema.json +40 -40
- package/schemas/spec-page.schema.json +98 -98
- package/schemas/spec-pages-index.schema.json +1 -1
- package/schemas/spec-unresolved-shard.schema.json +1 -1
- package/schemas/task-envelope.schema.json +109 -109
- package/schemas/task-plan.schema.json +341 -341
- package/scripts/check-environment.mjs +320 -320
- package/skills/android2hmos_resources_convert/SKILL.md +180 -180
- package/skills/android2hmos_resources_convert/references/image-conversion-rules.md +230 -230
- package/skills/android2hmos_resources_convert/references/svg-fix-patterns.md +175 -175
- package/skills/android2hmos_resources_convert/references/xml-drawable-to-svg-rules.md +513 -513
- package/skills/arkts-app-identity/SKILL.md +238 -238
- package/skills/arkts-i18n/SKILL.md +496 -496
- package/skills/arkts-i18n/evals/evals.json +84 -84
- package/skills/arkts-i18n/references/code-examples.md +302 -302
- package/skills/arkts-i18n/references/common-pitfalls.md +391 -391
- package/skills/arkts-i18n/references/dynamic-language-switch.md +604 -604
- package/skills/arkts-i18n/references/hardcoded-string-scanner.md +348 -348
- package/skills/arkts-i18n/references/language-codes.md +104 -104
- package/skills/arkts-i18n/references/resource-file-structure.md +775 -775
- package/skills/arkts-i18n/references/static-vs-dynamic.md +242 -242
- package/skills/arkts-i18n/references/v1-compat.md +244 -244
- package/skills/arkts-i18n/scripts/audit_i18n_completeness.sh +174 -174
- package/skills/arkts-icon-sizing/SKILL.md +211 -211
- package/skills/arkts-icon-sizing/scripts/icon_audit.py +131 -131
- package/skills/arkts-icon-sizing/scripts/icon_autofix.py +88 -88
- package/skills/arkts-icon-sizing/scripts/icon_dims.py +179 -179
- package/skills/arkts-icon-sizing/scripts/icon_fix.py +119 -119
- package/skills/arkts-mvvm-architecture/SKILL.md +613 -613
- package/skills/d2h-hypium-forge/SKILL.md +309 -309
- package/skills/d2h-hypium-forge/references/functional-spec-template.md +140 -140
- package/skills/d2h-hypium-forge/references/official-api.md +135 -135
- package/skills/d2h-hypium-forge/references/pitfalls.md +98 -98
- package/skills/d2h-hypium-forge/references/testability-template.md +71 -71
- package/skills/d2h-hypium-forge/scripts/_common_template.py +659 -659
- package/skills/d2h-hypium-forge/scripts/analyze_results.py +165 -165
- package/skills/d2h-hypium-forge/scripts/assert_audit.py +107 -107
- package/skills/d2h-hypium-forge/scripts/collect_runtime_pages.py +169 -169
- package/skills/d2h-hypium-forge/scripts/forge_report.py +325 -325
- package/skills/d2h-hypium-forge/scripts/inject_resource_ids.py +114 -114
- package/skills/d2h-hypium-forge/scripts/lint_asserts.py +80 -80
- package/skills/d2h-hypium-forge/scripts/lint_locate.py +60 -60
- package/skills/d2h-hypium-forge/scripts/merge_appgraph.py +249 -249
- package/skills/d2h-hypium-forge/scripts/precondition.py +140 -140
- package/skills/d2h-hypium-forge/scripts/preinject_ids.py +232 -232
- package/skills/d2h-hypium-forge/scripts/probe.py +197 -197
- package/skills/d2h-hypium-forge/scripts/run_direct.py +823 -823
- package/skills/d2h-hypium-forge/scripts/run_parallel.py +121 -121
- package/skills/d2h-hypium-forge/scripts/scan_features.py +255 -255
- package/skills/d2h-hypium-forge/scripts/upgrade_asserts.py +66 -66
- package/skills/d2h-hypium-forge/scripts/validate_scenarios.py +84 -84
- package/skills/d2h-page-develop/SKILL.md +112 -112
- package/skills/d2h-page-develop/agents/openai.yaml +7 -7
- package/skills/d2h-page-spec-generate/SKILL.md +206 -206
- package/skills/d2h-page-spec-generate/scripts/build_batch_report.py +227 -227
- package/skills/d2h-utg-ai-generate/SKILL.md +128 -128
- package/skills/d2h-utg-ai-generate/references/click-paths-schema.json +76 -76
- package/skills/d2h-utg-ai-generate/references/extraction-guide.md +34 -34
- package/skills/d2h-utg-ai-generate/references/facts-contract.md +96 -96
- package/skills/d2h-utg-ai-generate/references/page-schema.json +61 -61
- package/skills/d2h-utg-ai-generate/references/utg-schema.json +89 -89
- package/skills/d2h-utg-ai-generate/scripts/build_page_json.py +314 -314
- package/skills/d2h-utg-ai-generate/scripts/build_utg.py +123 -123
- package/skills/d2h-utg-ai-generate/scripts/capture_from_page_json.ts +280 -280
- package/skills/d2h-utg-ai-generate/scripts/utg_common.py +524 -524
- package/skills/d2h-utg-ai-generate/scripts/utg_html.py +489 -489
- package/skills/d2h-utg-ai-generate/scripts/validate_utg.py +69 -69
- package/skills/d2h-utg-ai-generate/scripts/vendor/D3-LICENSE +13 -13
- package/skills/d2h-utg-ai-generate/scripts/vendor/d3-7.9.0.min.js +2 -2
- package/skills/d2h-utg-ai-generate/tests/test_pipeline.py +369 -369
- package/skills/d2h-utg-static-generate/SKILL.md +73 -73
- package/skills/d2h-utg-static-generate/references/discoveries.md +38 -38
- package/skills/d2h-utg-static-generate/scripts/generate.py +499 -499
- package/skills/d2h-utg-static-generate/tests/test_static.py +335 -335
- package/skills/d2h-utg-static-generate/tests/verify-offline-html.py +60 -60
- package/skills/d2h-utg-static-generate/tests/verify-produced-fixture.py +131 -131
- package/skills/harmonyos-migration-playbook/SKILL.md +83 -83
- package/skills/harmonyos-migration-playbook/agents/openai.yaml +7 -7
- package/skills/harmonyos-migration-playbook/references/arkts-compile.md +24 -24
- package/skills/harmonyos-migration-playbook/references/harmony-runtime.md +53 -53
- package/skills/harmonyos-migration-playbook/references/lesson-lifecycle.md +45 -45
- package/skills/harmonyos-migration-playbook/references/protocol-e2e.md +23 -23
- package/skills/harmonyos-migration-playbook/references/ui-automation.md +53 -53
- package/skills/harmonyos-migration-playbook/references/windows-environment.md +38 -38
- package/skills/maintaining-migration-report/SKILL.md +144 -144
- package/skills/maintaining-migration-report/references/final-acceptance.md +48 -48
- package/skills/maintaining-migration-report/references/source-provenance.md +66 -66
- package/skills/managing-d2h-toolchain/SKILL.md +24 -24
- package/skills/managing-d2h-toolchain/environment-requirements.json +16 -16
- package/skills/managing-d2h-toolchain/scripts/manage-toolchain.mjs +98 -98
- package/skills/managing-d2h-toolchain/toolchain.json +16 -16
- package/skills/native-library-substitution/SKILL.md +384 -384
- package/skills/native-library-substitution/references/native-library-substitution.json +56905 -56905
- package/skills/native-library-substitution/references/native-library-substitution.md +163 -163
- package/skills/preparing-migration-workspace/SKILL.md +131 -131
- package/skills/reviewing-migration-process/SKILL.md +62 -62
|
@@ -1,244 +1,244 @@
|
|
|
1
|
-
# V1 兼容写法参考(仅老项目查阅)
|
|
2
|
-
|
|
3
|
-
> ⚠️ **本项目锁 ArkTS V2**。本文档为 **V1 历史参考**(`@Component / @State / @StorageLink / @Prop / @Watch` 等),仅用于阅读老代码或迁移老项目时查阅。
|
|
4
|
-
>
|
|
5
|
-
> **新代码请使用 V2 装饰器**:参阅 [`SKILL.md`](../SKILL.md)、[`dynamic-language-switch.md`](./dynamic-language-switch.md)、[`code-examples.md`](./code-examples.md)(已升级 V2)。
|
|
6
|
-
>
|
|
7
|
-
> i18n 相关 API(`resourceManager` / `intl` / `$r('app.string.xxx')` / `setPreferredLanguage` / `getPreferredLanguage` / `onLanguageConfigurationUpdate`)在 V1/V2 之间**完全不变**,本文仅记录"持有 locale / refreshKey 状态"的 V1 装饰器写法。
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## V1 / V2 速查(仅 i18n 相关)
|
|
12
|
-
|
|
13
|
-
| V1 | V2 |
|
|
14
|
-
|---|---|
|
|
15
|
-
| `@Component` | `@ComponentV2` |
|
|
16
|
-
| `@State refreshKey: number = 0` | `@Local refreshKey: number = 0` |
|
|
17
|
-
| `@StorageLink('currentLanguage') lang: string = 'zh'` | 先定义 `@ObservedV2 LocaleModel`,然后 `@Local locale = AppStorageV2.connect(LocaleModel, 'locale', () => new LocaleModel())!`,访问 `this.locale.currentLanguage` |
|
|
18
|
-
| `@StorageLink('languageRefreshKey') key: number = 0` | 同上,访问 `this.locale.refreshKey` |
|
|
19
|
-
| `@Prop currentColumns: number = 3` | `@Param @Once currentColumns: number = 3`(只读) |
|
|
20
|
-
| `@Prop currentColumns: number = 3`(子可改本地副本) | `@Param currentColumns: number = 3`(不带 @Once) |
|
|
21
|
-
| `@Watch('lang') onLangChange()` | `@Monitor('lang') onLangChange(m: IMonitor)` |
|
|
22
|
-
| `AppStorage.setOrCreate('refreshKey', n)` | `localeStore.refreshKey = n`(直接改 @Trace 字段) |
|
|
23
|
-
| `PersistentStorage.persistProp('currentLanguage', 'zh')` | `PersistenceV2.globalConnect({ type: LocaleModel, key: 'locale', defaultCreator: () => new LocaleModel() })` |
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## V1 简单实现(单页面语言切换)
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
import { resourceManager } from '@kit.LocalizationKit'
|
|
31
|
-
import { common } from '@kit.AbilityKit'
|
|
32
|
-
|
|
33
|
-
@Entry
|
|
34
|
-
@Component
|
|
35
|
-
struct LanguageSwitchDemoV1 {
|
|
36
|
-
private context = getContext(this) as common.UIAbilityContext
|
|
37
|
-
@State private currentLanguage: string = 'zh'
|
|
38
|
-
@State private refreshKey: number = 0
|
|
39
|
-
|
|
40
|
-
async switchLanguage(lang: string): Promise<void> {
|
|
41
|
-
const resMgr = this.context.resourceManager
|
|
42
|
-
await resMgr.setPreferredLanguage([lang])
|
|
43
|
-
this.currentLanguage = lang
|
|
44
|
-
this.refreshKey++
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
build() {
|
|
48
|
-
Column() {
|
|
49
|
-
Text($r('app.string.welcome'))
|
|
50
|
-
Button('English').onClick(() => this.switchLanguage('en'))
|
|
51
|
-
}
|
|
52
|
-
.id('lang_' + this.refreshKey)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**升级到 V2**(参考 [`dynamic-language-switch.md`](./dynamic-language-switch.md) 的"基本实现"):
|
|
58
|
-
- `@Component` → `@ComponentV2`
|
|
59
|
-
- `@State` → `@Local`
|
|
60
|
-
- 其他 API 调用不变
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## V1 全局状态共享(@StorageLink 多 key 写法)
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
// V1:散落的 key(拼写易错、无类型保护)
|
|
68
|
-
class LanguageStateV1 {
|
|
69
|
-
@StorageLink('currentLanguage') currentLanguage: string = 'zh'
|
|
70
|
-
@StorageLink('languageRefreshKey') refreshKey: number = 0
|
|
71
|
-
|
|
72
|
-
async setLanguage(context: common.UIAbilityContext, lang: string): Promise<void> {
|
|
73
|
-
const resMgr = context.resourceManager
|
|
74
|
-
await resMgr.setPreferredLanguage([lang])
|
|
75
|
-
this.currentLanguage = lang
|
|
76
|
-
this.refreshKey++
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// V1 设置页面
|
|
81
|
-
@Entry
|
|
82
|
-
@Component
|
|
83
|
-
struct SettingsPageV1 {
|
|
84
|
-
@StorageLink('currentLanguage') currentLanguage: string = 'zh'
|
|
85
|
-
@StorageLink('languageRefreshKey') refreshKey: number = 0
|
|
86
|
-
|
|
87
|
-
build() {
|
|
88
|
-
Column() {
|
|
89
|
-
Text(`Current: ${this.currentLanguage}`)
|
|
90
|
-
}
|
|
91
|
-
.id('settings_' + this.refreshKey)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// V1 任意页面
|
|
96
|
-
@Entry
|
|
97
|
-
@Component
|
|
98
|
-
struct AnyPageV1 {
|
|
99
|
-
@StorageLink('languageRefreshKey') refreshKey: number = 0
|
|
100
|
-
|
|
101
|
-
build() {
|
|
102
|
-
Column() {
|
|
103
|
-
Text($r('app.string.any_string'))
|
|
104
|
-
}
|
|
105
|
-
.id('page_' + this.refreshKey)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
**问题**:
|
|
111
|
-
- key 拼写错误(如 `'lanugageRefreshKey'`)静默失效
|
|
112
|
-
- 无类型保护(值是 Object)
|
|
113
|
-
- 字段加减需改多处
|
|
114
|
-
|
|
115
|
-
**V2 重构**(推荐,见 [`dynamic-language-switch.md`](./dynamic-language-switch.md) 的"全局 LocaleModel"段):
|
|
116
|
-
- 单一 `@ObservedV2 LocaleModel` 封装所有 locale 状态
|
|
117
|
-
- 任意组件 `@Local locale = AppStorageV2.connect(LocaleModel, 'locale', () => new LocaleModel())!`
|
|
118
|
-
- 访问 `this.locale.currentLanguage` / `this.locale.refreshKey`
|
|
119
|
-
- 编译期类型检查 + IDE 重命名安全
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## V1 子组件接收只读 Prop
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
@Component
|
|
127
|
-
export struct ColumnsDialogV1 {
|
|
128
|
-
@Prop currentColumns: number = 3 // V1:单向只读(API 12+ 必须初始化)
|
|
129
|
-
|
|
130
|
-
build() {
|
|
131
|
-
Text(`Columns: ${this.currentColumns}`)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
**V2 等价写法**(见 [`code-examples.md`](./code-examples.md) 的 V2 ColumnsDialog):
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
@ComponentV2
|
|
140
|
-
export struct ColumnsDialog {
|
|
141
|
-
@Param @Once currentColumns: number = 3 // V2:单向只读(编译期检查)
|
|
142
|
-
|
|
143
|
-
build() {
|
|
144
|
-
Text(`Columns: ${this.currentColumns}`)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## V1 监听语言变化(@Watch)
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
@Component
|
|
155
|
-
struct PageV1 {
|
|
156
|
-
@StorageLink('currentLanguage') @Watch('onLangChange') currentLanguage: string = 'zh'
|
|
157
|
-
|
|
158
|
-
onLangChange(propName: string): void {
|
|
159
|
-
console.info(`Language changed: ${this.currentLanguage}`)
|
|
160
|
-
// 副作用:埋点、清缓存等
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
build() { Column() { Text($r('app.string.hello')) } }
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
**V2 等价**:
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
@ComponentV2
|
|
171
|
-
struct Page {
|
|
172
|
-
@Local locale: LocaleModel = AppStorageV2.connect(
|
|
173
|
-
LocaleModel, 'locale', () => new LocaleModel()
|
|
174
|
-
)!
|
|
175
|
-
|
|
176
|
-
@Monitor('locale.currentLanguage')
|
|
177
|
-
onLangChange(monitor: IMonitor): void {
|
|
178
|
-
console.info(`Language changed: ${this.locale.currentLanguage}`)
|
|
179
|
-
// 副作用
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
build() { Column() { Text($r('app.string.hello')) } }
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## V1 持久化语言偏好(PersistentStorage.persistProp)
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
// V1:双层模式(AppStorage + Preferences)
|
|
192
|
-
PersistentStorage.persistProp('currentLanguage', 'zh')
|
|
193
|
-
|
|
194
|
-
@Component
|
|
195
|
-
struct PageV1 {
|
|
196
|
-
@StorageLink('currentLanguage') currentLanguage: string = 'zh'
|
|
197
|
-
// 修改 currentLanguage 自动落盘 + UI 刷新
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**V2 等价**(一站式):
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
@ObservedV2
|
|
205
|
-
class LocaleModel {
|
|
206
|
-
@Trace currentLanguage: string = 'zh'
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
@ComponentV2
|
|
210
|
-
struct Page {
|
|
211
|
-
@Local locale: LocaleModel = PersistenceV2.globalConnect({
|
|
212
|
-
type: LocaleModel,
|
|
213
|
-
key: 'app_locale',
|
|
214
|
-
defaultCreator: () => new LocaleModel()
|
|
215
|
-
})!
|
|
216
|
-
// 修改 this.locale.currentLanguage 自动落盘 + UI 刷新(无需双层)
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## V1 → V2 迁移建议
|
|
223
|
-
|
|
224
|
-
1. **先升级 SKILL.md / 主参考的代码模板**(已完成 — 见本目录其他文件)
|
|
225
|
-
2. **逐文件迁移老代码**:从最常用的 LanguageSettings / Settings 页面开始
|
|
226
|
-
3. **抽取 LocaleModel**:把所有 `@StorageLink('currentLanguage' | 'languageRefreshKey' | ...)` 整合到一个 `@ObservedV2 LocaleModel` 类
|
|
227
|
-
4. **替换装饰器**:
|
|
228
|
-
- `@Component` → `@ComponentV2`
|
|
229
|
-
- `@State` → `@Local`
|
|
230
|
-
- `@StorageLink('xxx') xxx: T = default` → `@Local locale: LocaleModel = AppStorageV2.connect(LocaleModel, 'locale', () => new LocaleModel())!`,访问 `this.locale.xxx`
|
|
231
|
-
- `@Prop` → `@Param @Once`(只读)/ `@Param`(可改本地副本)
|
|
232
|
-
- `@Watch` → `@Monitor`
|
|
233
|
-
- `PersistentStorage.persistProp` → `PersistenceV2.globalConnect`
|
|
234
|
-
5. **同 struct 内不混用 V1/V2 装饰器**(编译报错)
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## 跨文档参考
|
|
239
|
-
|
|
240
|
-
- [`SKILL.md`](../SKILL.md) — V2 优先决策树与陷阱
|
|
241
|
-
- [`dynamic-language-switch.md`](./dynamic-language-switch.md) — V2 完整动态切换模板
|
|
242
|
-
- [`code-examples.md`](./code-examples.md) — V2 ColumnsDialog 实战示例
|
|
243
|
-
- [`common-pitfalls.md`](./common-pitfalls.md) — V2 i18n 避坑
|
|
244
|
-
- 跨 Skill:[`arkts-mvvm-architecture/SKILL.md`](../../arkts-mvvm-architecture/SKILL.md) — 当前工程的 V2 状态管理、组件和架构规范
|
|
1
|
+
# V1 兼容写法参考(仅老项目查阅)
|
|
2
|
+
|
|
3
|
+
> ⚠️ **本项目锁 ArkTS V2**。本文档为 **V1 历史参考**(`@Component / @State / @StorageLink / @Prop / @Watch` 等),仅用于阅读老代码或迁移老项目时查阅。
|
|
4
|
+
>
|
|
5
|
+
> **新代码请使用 V2 装饰器**:参阅 [`SKILL.md`](../SKILL.md)、[`dynamic-language-switch.md`](./dynamic-language-switch.md)、[`code-examples.md`](./code-examples.md)(已升级 V2)。
|
|
6
|
+
>
|
|
7
|
+
> i18n 相关 API(`resourceManager` / `intl` / `$r('app.string.xxx')` / `setPreferredLanguage` / `getPreferredLanguage` / `onLanguageConfigurationUpdate`)在 V1/V2 之间**完全不变**,本文仅记录"持有 locale / refreshKey 状态"的 V1 装饰器写法。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## V1 / V2 速查(仅 i18n 相关)
|
|
12
|
+
|
|
13
|
+
| V1 | V2 |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `@Component` | `@ComponentV2` |
|
|
16
|
+
| `@State refreshKey: number = 0` | `@Local refreshKey: number = 0` |
|
|
17
|
+
| `@StorageLink('currentLanguage') lang: string = 'zh'` | 先定义 `@ObservedV2 LocaleModel`,然后 `@Local locale = AppStorageV2.connect(LocaleModel, 'locale', () => new LocaleModel())!`,访问 `this.locale.currentLanguage` |
|
|
18
|
+
| `@StorageLink('languageRefreshKey') key: number = 0` | 同上,访问 `this.locale.refreshKey` |
|
|
19
|
+
| `@Prop currentColumns: number = 3` | `@Param @Once currentColumns: number = 3`(只读) |
|
|
20
|
+
| `@Prop currentColumns: number = 3`(子可改本地副本) | `@Param currentColumns: number = 3`(不带 @Once) |
|
|
21
|
+
| `@Watch('lang') onLangChange()` | `@Monitor('lang') onLangChange(m: IMonitor)` |
|
|
22
|
+
| `AppStorage.setOrCreate('refreshKey', n)` | `localeStore.refreshKey = n`(直接改 @Trace 字段) |
|
|
23
|
+
| `PersistentStorage.persistProp('currentLanguage', 'zh')` | `PersistenceV2.globalConnect({ type: LocaleModel, key: 'locale', defaultCreator: () => new LocaleModel() })` |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## V1 简单实现(单页面语言切换)
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { resourceManager } from '@kit.LocalizationKit'
|
|
31
|
+
import { common } from '@kit.AbilityKit'
|
|
32
|
+
|
|
33
|
+
@Entry
|
|
34
|
+
@Component
|
|
35
|
+
struct LanguageSwitchDemoV1 {
|
|
36
|
+
private context = getContext(this) as common.UIAbilityContext
|
|
37
|
+
@State private currentLanguage: string = 'zh'
|
|
38
|
+
@State private refreshKey: number = 0
|
|
39
|
+
|
|
40
|
+
async switchLanguage(lang: string): Promise<void> {
|
|
41
|
+
const resMgr = this.context.resourceManager
|
|
42
|
+
await resMgr.setPreferredLanguage([lang])
|
|
43
|
+
this.currentLanguage = lang
|
|
44
|
+
this.refreshKey++
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
build() {
|
|
48
|
+
Column() {
|
|
49
|
+
Text($r('app.string.welcome'))
|
|
50
|
+
Button('English').onClick(() => this.switchLanguage('en'))
|
|
51
|
+
}
|
|
52
|
+
.id('lang_' + this.refreshKey)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**升级到 V2**(参考 [`dynamic-language-switch.md`](./dynamic-language-switch.md) 的"基本实现"):
|
|
58
|
+
- `@Component` → `@ComponentV2`
|
|
59
|
+
- `@State` → `@Local`
|
|
60
|
+
- 其他 API 调用不变
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## V1 全局状态共享(@StorageLink 多 key 写法)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// V1:散落的 key(拼写易错、无类型保护)
|
|
68
|
+
class LanguageStateV1 {
|
|
69
|
+
@StorageLink('currentLanguage') currentLanguage: string = 'zh'
|
|
70
|
+
@StorageLink('languageRefreshKey') refreshKey: number = 0
|
|
71
|
+
|
|
72
|
+
async setLanguage(context: common.UIAbilityContext, lang: string): Promise<void> {
|
|
73
|
+
const resMgr = context.resourceManager
|
|
74
|
+
await resMgr.setPreferredLanguage([lang])
|
|
75
|
+
this.currentLanguage = lang
|
|
76
|
+
this.refreshKey++
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// V1 设置页面
|
|
81
|
+
@Entry
|
|
82
|
+
@Component
|
|
83
|
+
struct SettingsPageV1 {
|
|
84
|
+
@StorageLink('currentLanguage') currentLanguage: string = 'zh'
|
|
85
|
+
@StorageLink('languageRefreshKey') refreshKey: number = 0
|
|
86
|
+
|
|
87
|
+
build() {
|
|
88
|
+
Column() {
|
|
89
|
+
Text(`Current: ${this.currentLanguage}`)
|
|
90
|
+
}
|
|
91
|
+
.id('settings_' + this.refreshKey)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// V1 任意页面
|
|
96
|
+
@Entry
|
|
97
|
+
@Component
|
|
98
|
+
struct AnyPageV1 {
|
|
99
|
+
@StorageLink('languageRefreshKey') refreshKey: number = 0
|
|
100
|
+
|
|
101
|
+
build() {
|
|
102
|
+
Column() {
|
|
103
|
+
Text($r('app.string.any_string'))
|
|
104
|
+
}
|
|
105
|
+
.id('page_' + this.refreshKey)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**问题**:
|
|
111
|
+
- key 拼写错误(如 `'lanugageRefreshKey'`)静默失效
|
|
112
|
+
- 无类型保护(值是 Object)
|
|
113
|
+
- 字段加减需改多处
|
|
114
|
+
|
|
115
|
+
**V2 重构**(推荐,见 [`dynamic-language-switch.md`](./dynamic-language-switch.md) 的"全局 LocaleModel"段):
|
|
116
|
+
- 单一 `@ObservedV2 LocaleModel` 封装所有 locale 状态
|
|
117
|
+
- 任意组件 `@Local locale = AppStorageV2.connect(LocaleModel, 'locale', () => new LocaleModel())!`
|
|
118
|
+
- 访问 `this.locale.currentLanguage` / `this.locale.refreshKey`
|
|
119
|
+
- 编译期类型检查 + IDE 重命名安全
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## V1 子组件接收只读 Prop
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
@Component
|
|
127
|
+
export struct ColumnsDialogV1 {
|
|
128
|
+
@Prop currentColumns: number = 3 // V1:单向只读(API 12+ 必须初始化)
|
|
129
|
+
|
|
130
|
+
build() {
|
|
131
|
+
Text(`Columns: ${this.currentColumns}`)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**V2 等价写法**(见 [`code-examples.md`](./code-examples.md) 的 V2 ColumnsDialog):
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
@ComponentV2
|
|
140
|
+
export struct ColumnsDialog {
|
|
141
|
+
@Param @Once currentColumns: number = 3 // V2:单向只读(编译期检查)
|
|
142
|
+
|
|
143
|
+
build() {
|
|
144
|
+
Text(`Columns: ${this.currentColumns}`)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## V1 监听语言变化(@Watch)
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
@Component
|
|
155
|
+
struct PageV1 {
|
|
156
|
+
@StorageLink('currentLanguage') @Watch('onLangChange') currentLanguage: string = 'zh'
|
|
157
|
+
|
|
158
|
+
onLangChange(propName: string): void {
|
|
159
|
+
console.info(`Language changed: ${this.currentLanguage}`)
|
|
160
|
+
// 副作用:埋点、清缓存等
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
build() { Column() { Text($r('app.string.hello')) } }
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**V2 等价**:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
@ComponentV2
|
|
171
|
+
struct Page {
|
|
172
|
+
@Local locale: LocaleModel = AppStorageV2.connect(
|
|
173
|
+
LocaleModel, 'locale', () => new LocaleModel()
|
|
174
|
+
)!
|
|
175
|
+
|
|
176
|
+
@Monitor('locale.currentLanguage')
|
|
177
|
+
onLangChange(monitor: IMonitor): void {
|
|
178
|
+
console.info(`Language changed: ${this.locale.currentLanguage}`)
|
|
179
|
+
// 副作用
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
build() { Column() { Text($r('app.string.hello')) } }
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## V1 持久化语言偏好(PersistentStorage.persistProp)
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// V1:双层模式(AppStorage + Preferences)
|
|
192
|
+
PersistentStorage.persistProp('currentLanguage', 'zh')
|
|
193
|
+
|
|
194
|
+
@Component
|
|
195
|
+
struct PageV1 {
|
|
196
|
+
@StorageLink('currentLanguage') currentLanguage: string = 'zh'
|
|
197
|
+
// 修改 currentLanguage 自动落盘 + UI 刷新
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**V2 等价**(一站式):
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
@ObservedV2
|
|
205
|
+
class LocaleModel {
|
|
206
|
+
@Trace currentLanguage: string = 'zh'
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@ComponentV2
|
|
210
|
+
struct Page {
|
|
211
|
+
@Local locale: LocaleModel = PersistenceV2.globalConnect({
|
|
212
|
+
type: LocaleModel,
|
|
213
|
+
key: 'app_locale',
|
|
214
|
+
defaultCreator: () => new LocaleModel()
|
|
215
|
+
})!
|
|
216
|
+
// 修改 this.locale.currentLanguage 自动落盘 + UI 刷新(无需双层)
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## V1 → V2 迁移建议
|
|
223
|
+
|
|
224
|
+
1. **先升级 SKILL.md / 主参考的代码模板**(已完成 — 见本目录其他文件)
|
|
225
|
+
2. **逐文件迁移老代码**:从最常用的 LanguageSettings / Settings 页面开始
|
|
226
|
+
3. **抽取 LocaleModel**:把所有 `@StorageLink('currentLanguage' | 'languageRefreshKey' | ...)` 整合到一个 `@ObservedV2 LocaleModel` 类
|
|
227
|
+
4. **替换装饰器**:
|
|
228
|
+
- `@Component` → `@ComponentV2`
|
|
229
|
+
- `@State` → `@Local`
|
|
230
|
+
- `@StorageLink('xxx') xxx: T = default` → `@Local locale: LocaleModel = AppStorageV2.connect(LocaleModel, 'locale', () => new LocaleModel())!`,访问 `this.locale.xxx`
|
|
231
|
+
- `@Prop` → `@Param @Once`(只读)/ `@Param`(可改本地副本)
|
|
232
|
+
- `@Watch` → `@Monitor`
|
|
233
|
+
- `PersistentStorage.persistProp` → `PersistenceV2.globalConnect`
|
|
234
|
+
5. **同 struct 内不混用 V1/V2 装饰器**(编译报错)
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 跨文档参考
|
|
239
|
+
|
|
240
|
+
- [`SKILL.md`](../SKILL.md) — V2 优先决策树与陷阱
|
|
241
|
+
- [`dynamic-language-switch.md`](./dynamic-language-switch.md) — V2 完整动态切换模板
|
|
242
|
+
- [`code-examples.md`](./code-examples.md) — V2 ColumnsDialog 实战示例
|
|
243
|
+
- [`common-pitfalls.md`](./common-pitfalls.md) — V2 i18n 避坑
|
|
244
|
+
- 跨 Skill:[`arkts-mvvm-architecture/SKILL.md`](../../arkts-mvvm-architecture/SKILL.md) — 当前工程的 V2 状态管理、组件和架构规范
|