@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.
Files changed (126) hide show
  1. package/.claude-plugin/marketplace.json +15 -13
  2. package/.claude-plugin/plugin.json +13 -7
  3. package/AGENTS.md +5 -5
  4. package/README.md +212 -212
  5. package/agents/android-to-hmos-00-orchestrator.md +318 -318
  6. package/agents/d2h.md +157 -157
  7. package/dist/bin/install-opencode.js +30 -30
  8. package/docs/environment-check.md +86 -86
  9. package/install-opencode.sh +160 -160
  10. package/opencode/agents.json +16 -16
  11. package/opencode/vscode-d2h-package.json +7 -7
  12. package/opencode/vscode-d2h-plugin.mjs +29 -29
  13. package/package.json +54 -54
  14. package/schemas/android-source-manifest.schema.json +25 -25
  15. package/schemas/checkpoint-provenance.schema.json +67 -67
  16. package/schemas/final-acceptance.schema.json +29 -29
  17. package/schemas/managed-evidence-index.schema.json +15 -15
  18. package/schemas/managed-evidence.schema.json +114 -114
  19. package/schemas/migration-config.schema.json +51 -51
  20. package/schemas/migration-report-index.schema.json +39 -39
  21. package/schemas/migration-report-item.schema.json +51 -51
  22. package/schemas/migration-report-summary.schema.json +25 -25
  23. package/schemas/migration-status.schema.json +202 -202
  24. package/schemas/preflight.schema.json +60 -60
  25. package/schemas/source-order-audit.schema.json +16 -16
  26. package/schemas/source-provenance-event.schema.json +19 -19
  27. package/schemas/spec-app-shard.schema.json +45 -45
  28. package/schemas/spec-fact-corrections-shard.schema.json +13 -13
  29. package/schemas/spec-features-shard.schema.json +43 -43
  30. package/schemas/spec-index.schema.json +26 -26
  31. package/schemas/spec-interactions-shard.schema.json +40 -40
  32. package/schemas/spec-page.schema.json +98 -98
  33. package/schemas/spec-pages-index.schema.json +1 -1
  34. package/schemas/spec-unresolved-shard.schema.json +1 -1
  35. package/schemas/task-envelope.schema.json +109 -109
  36. package/schemas/task-plan.schema.json +341 -341
  37. package/scripts/check-environment.mjs +320 -320
  38. package/skills/android2hmos_resources_convert/SKILL.md +180 -180
  39. package/skills/android2hmos_resources_convert/references/image-conversion-rules.md +230 -230
  40. package/skills/android2hmos_resources_convert/references/svg-fix-patterns.md +175 -175
  41. package/skills/android2hmos_resources_convert/references/xml-drawable-to-svg-rules.md +513 -513
  42. package/skills/arkts-app-identity/SKILL.md +238 -238
  43. package/skills/arkts-i18n/SKILL.md +496 -496
  44. package/skills/arkts-i18n/evals/evals.json +84 -84
  45. package/skills/arkts-i18n/references/code-examples.md +302 -302
  46. package/skills/arkts-i18n/references/common-pitfalls.md +391 -391
  47. package/skills/arkts-i18n/references/dynamic-language-switch.md +604 -604
  48. package/skills/arkts-i18n/references/hardcoded-string-scanner.md +348 -348
  49. package/skills/arkts-i18n/references/language-codes.md +104 -104
  50. package/skills/arkts-i18n/references/resource-file-structure.md +775 -775
  51. package/skills/arkts-i18n/references/static-vs-dynamic.md +242 -242
  52. package/skills/arkts-i18n/references/v1-compat.md +244 -244
  53. package/skills/arkts-i18n/scripts/audit_i18n_completeness.sh +174 -174
  54. package/skills/arkts-icon-sizing/SKILL.md +211 -211
  55. package/skills/arkts-icon-sizing/scripts/icon_audit.py +131 -131
  56. package/skills/arkts-icon-sizing/scripts/icon_autofix.py +88 -88
  57. package/skills/arkts-icon-sizing/scripts/icon_dims.py +179 -179
  58. package/skills/arkts-icon-sizing/scripts/icon_fix.py +119 -119
  59. package/skills/arkts-mvvm-architecture/SKILL.md +613 -613
  60. package/skills/d2h-hypium-forge/SKILL.md +309 -309
  61. package/skills/d2h-hypium-forge/references/functional-spec-template.md +140 -140
  62. package/skills/d2h-hypium-forge/references/official-api.md +135 -135
  63. package/skills/d2h-hypium-forge/references/pitfalls.md +98 -98
  64. package/skills/d2h-hypium-forge/references/testability-template.md +71 -71
  65. package/skills/d2h-hypium-forge/scripts/_common_template.py +659 -659
  66. package/skills/d2h-hypium-forge/scripts/analyze_results.py +165 -165
  67. package/skills/d2h-hypium-forge/scripts/assert_audit.py +107 -107
  68. package/skills/d2h-hypium-forge/scripts/collect_runtime_pages.py +169 -169
  69. package/skills/d2h-hypium-forge/scripts/forge_report.py +325 -325
  70. package/skills/d2h-hypium-forge/scripts/inject_resource_ids.py +114 -114
  71. package/skills/d2h-hypium-forge/scripts/lint_asserts.py +80 -80
  72. package/skills/d2h-hypium-forge/scripts/lint_locate.py +60 -60
  73. package/skills/d2h-hypium-forge/scripts/merge_appgraph.py +249 -249
  74. package/skills/d2h-hypium-forge/scripts/precondition.py +140 -140
  75. package/skills/d2h-hypium-forge/scripts/preinject_ids.py +232 -232
  76. package/skills/d2h-hypium-forge/scripts/probe.py +197 -197
  77. package/skills/d2h-hypium-forge/scripts/run_direct.py +823 -823
  78. package/skills/d2h-hypium-forge/scripts/run_parallel.py +121 -121
  79. package/skills/d2h-hypium-forge/scripts/scan_features.py +255 -255
  80. package/skills/d2h-hypium-forge/scripts/upgrade_asserts.py +66 -66
  81. package/skills/d2h-hypium-forge/scripts/validate_scenarios.py +84 -84
  82. package/skills/d2h-page-develop/SKILL.md +112 -112
  83. package/skills/d2h-page-develop/agents/openai.yaml +7 -7
  84. package/skills/d2h-page-spec-generate/SKILL.md +206 -206
  85. package/skills/d2h-page-spec-generate/scripts/build_batch_report.py +227 -227
  86. package/skills/d2h-utg-ai-generate/SKILL.md +128 -128
  87. package/skills/d2h-utg-ai-generate/references/click-paths-schema.json +76 -76
  88. package/skills/d2h-utg-ai-generate/references/extraction-guide.md +34 -34
  89. package/skills/d2h-utg-ai-generate/references/facts-contract.md +96 -96
  90. package/skills/d2h-utg-ai-generate/references/page-schema.json +61 -61
  91. package/skills/d2h-utg-ai-generate/references/utg-schema.json +89 -89
  92. package/skills/d2h-utg-ai-generate/scripts/build_page_json.py +314 -314
  93. package/skills/d2h-utg-ai-generate/scripts/build_utg.py +123 -123
  94. package/skills/d2h-utg-ai-generate/scripts/capture_from_page_json.ts +280 -280
  95. package/skills/d2h-utg-ai-generate/scripts/utg_common.py +524 -524
  96. package/skills/d2h-utg-ai-generate/scripts/utg_html.py +489 -489
  97. package/skills/d2h-utg-ai-generate/scripts/validate_utg.py +69 -69
  98. package/skills/d2h-utg-ai-generate/scripts/vendor/D3-LICENSE +13 -13
  99. package/skills/d2h-utg-ai-generate/scripts/vendor/d3-7.9.0.min.js +2 -2
  100. package/skills/d2h-utg-ai-generate/tests/test_pipeline.py +369 -369
  101. package/skills/d2h-utg-static-generate/SKILL.md +73 -73
  102. package/skills/d2h-utg-static-generate/references/discoveries.md +38 -38
  103. package/skills/d2h-utg-static-generate/scripts/generate.py +499 -499
  104. package/skills/d2h-utg-static-generate/tests/test_static.py +335 -335
  105. package/skills/d2h-utg-static-generate/tests/verify-offline-html.py +60 -60
  106. package/skills/d2h-utg-static-generate/tests/verify-produced-fixture.py +131 -131
  107. package/skills/harmonyos-migration-playbook/SKILL.md +83 -83
  108. package/skills/harmonyos-migration-playbook/agents/openai.yaml +7 -7
  109. package/skills/harmonyos-migration-playbook/references/arkts-compile.md +24 -24
  110. package/skills/harmonyos-migration-playbook/references/harmony-runtime.md +53 -53
  111. package/skills/harmonyos-migration-playbook/references/lesson-lifecycle.md +45 -45
  112. package/skills/harmonyos-migration-playbook/references/protocol-e2e.md +23 -23
  113. package/skills/harmonyos-migration-playbook/references/ui-automation.md +53 -53
  114. package/skills/harmonyos-migration-playbook/references/windows-environment.md +38 -38
  115. package/skills/maintaining-migration-report/SKILL.md +144 -144
  116. package/skills/maintaining-migration-report/references/final-acceptance.md +48 -48
  117. package/skills/maintaining-migration-report/references/source-provenance.md +66 -66
  118. package/skills/managing-d2h-toolchain/SKILL.md +24 -24
  119. package/skills/managing-d2h-toolchain/environment-requirements.json +16 -16
  120. package/skills/managing-d2h-toolchain/scripts/manage-toolchain.mjs +98 -98
  121. package/skills/managing-d2h-toolchain/toolchain.json +16 -16
  122. package/skills/native-library-substitution/SKILL.md +384 -384
  123. package/skills/native-library-substitution/references/native-library-substitution.json +56905 -56905
  124. package/skills/native-library-substitution/references/native-library-substitution.md +163 -163
  125. package/skills/preparing-migration-workspace/SKILL.md +131 -131
  126. 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 状态管理、组件和架构规范