多语言资源路径配置法-鸿蒙ArkTS版本


一、设计目标
本应用是 HarmonyOS 官方资源方案的演示器——前 11 个应用都用"运行时文案表"(STRINGS Map)做多语言,而本应用展示另一条正统路线:资源限定符目录 + $r() 引用。UI 设计要回答三个问题:
- 资源目录结构怎么展示才不枯燥:base/zh_CN/en_US/ja_JP/ko_KR 的树形关系是这套方案的心脏,用户必须先看懂它;
- 静态引用与动态读取的区别怎么可视化:
$r('app.string.xxx')跟随系统语言自动匹配(零代码),resourceManager.getStringSync按参数显式取——两种方式的差异要在 UI 上"看得见"; - 语言匹配规则怎么演示:选择某个语言时,资源表给出匹配结果;选择未覆盖语言时展示 base 兜底——降级路径本身就是教学内容。
因此本页 UI 的核心原则是:把"资源匹配"变成一个可交互的实验台——用户拨动语言开关,看资源如何被选中、如何兜底,而不是只看静态文档。
二、页面信息架构(组件树)
ResourceQualifierPage(@Entry 根组件)
└─ Scroll(整页滚动,背景 #F8FAFC)
└─ Column(宽 100%)
├─ Row:标题栏("多语言资源" + 副标题 + 🗂️ 图标)
├─ Flex:界面语言徽章组(简中/繁中/EN/日/韩,选中靛蓝高亮)
├─ Text + Column:资源目录结构卡(树形文本,monospace 靛蓝,浅靛底 #EEF2FF)
│ └─ resources/ ├─ base ← 默认 ├─ zh_CN ├─ en_US ├─ ja_JP └─ ko_KR
├─ Text + Column:$r() 静态引用卡(白色)
│ └─ 5 行:key(左灰,宽 110) + 当前语言资源值(右)
├─ Text + Column:语言匹配模拟器卡(浅靛底)
│ ├─ Flex 徽章:zh_CN / en_US / ja_JP / ko_KR / base(🌐)
│ └─ 匹配结果:5 行 key = 值(加粗靛蓝)
└─ Text:底部提示(真实设备 $r() 自动切换,本页用动态读取模拟)
与前面应用的区别:本页没有独立的"内容区",四个区块全部围绕"资源如何被取用"展开——这是教学型演示 App 的典型结构:概念(目录)→ 机制(静态)→ 实验(模拟器)→ 结论(提示)。
三、色彩与字号规范
本页主题色为靛蓝色系(Indigo)——开发工具/官方文档的气质,与 09 橙、10 紫、11 深蓝区分:
| 元素 | 色值 | 字号 | 字重 |
|---|---|---|---|
| 页面标题 | #1F2937 | 22 | Bold |
| 副标题 | #9CA3AF | 12 | Normal |
| 区块标题 | #1F2937 | 14 | Bold |
| 目录树文本 | #4F46E5 | 11 | Normal(monospace) |
| 资源 key | #6B7280 / #9CA3AF | 12 | Normal |
| 资源值(静态卡) | #1F2937 | 13 | Normal |
| 资源值(模拟器) | #4F46E5 | 14 | Bold |
| 选中徽章 | 文字 #FFFFFF / 底 #4F46E5 | 11 | Normal |
| 未选中徽章 | 文字 #374151 / 底 #E5E7EB | 11 | Normal |
| 浅靛卡片背景 | #EEF2FF | — | — |
色彩语义延续系列:靛蓝 = 选中/强调、灰 = 未选中。两个紫色系(10 紫 #9333EA 与 12 靛蓝 #4F46E5)色相相邻但一暖一冷,同屏不混淆,跨应用一眼可辨。
四、资源目录结构卡:把"文件系统"画成 UI
Column({ space: 2 }) {
ForEach(DIR_TREE, (line: string, idx: number) => {
Text(line).fontSize(11).fontColor('#4F46E5').width('100%').fontFamily('monospace')
}, (line: string, idx: number) => `${idx}-${line}`)
}
.width('94%').padding(14).backgroundColor('#EEF2FF').borderRadius(14).margin({ top: 8 })
展示内容:
resources/
├─ base/element/string.json ← 默认(所有语言兜底)
├─ zh_CN/element/string.json ← 简体中文
├─ en_US/element/string.json ← 美式英语
├─ ja_JP/element/string.json ← 日语
└─ ko_KR/element/string.json ← 韩语
设计要点:
- monospace 等宽字体 + 树形字符:
├─/└─是 ASCII 艺术,等宽字体保证对齐,一眼看出目录层级; - base 加
← 默认注释:直接点破"base 是兜底"这个最容易被误解的概念; - 靛蓝文字 on 浅靛底:整卡像一张"代码截图",与普通内容卡片形成视觉类型区分——用户一看就知道"这里是结构说明";
- 真实工程对应:
entry/src/main/resources/下就是这样的目录,本卡是它的抽象镜像。
五、$r() 静态引用卡:自动匹配的演示
ForEach(RES_TABLE, (e: ResEntry) => {
Row() {
Text(e.key).fontSize(12).fontColor('#6B7280').width('110')
Text(this.resFor(this.currentLocale, e.key))
.fontSize(13).fontColor('#1F2937').layoutWeight(1)
}.width('100%')
}, (e: ResEntry) => e.key)
- 左侧固定宽 110 显示资源 key(
app_name/greeting/btn_ok/btn_cancel/status_loading),右侧显示当前界面语言下的资源值; - key 与值分离:模拟的是
$r('app.string.app_name')的语义——代码里写 key,运行时系统按语言解析; - 切换界面语言,整卡 5 行值即时变化——演示"$r() 在真实设备上随系统语言自动切换"的效果;
- 静态卡用普通字重(区别于模拟器的加粗),因为它是"系统自动行为"的展示,不是用户可控实验。
六、语言匹配模拟器:用户可控的"实验台"
这是本页交互核心——用户可以指定"系统语言"并观察匹配结果:
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
ForEach(['zh_CN', 'en_US', 'ja_JP', 'ko_KR', 'base'] as string[], (code: string) => {
Text(this.langLabel(code))
.fontSize(11).padding({ left: 8, right: 8, top: 5, bottom: 5 }).borderRadius(12)
.backgroundColor(this.simLang === code ? '#4F46E5' : '#E5E7EB')
.fontColor(this.simLang === code ? Color.White : '#374151')
.onClick(() => { this.simLang = code; })
}, (code: string) => code)
}.width('100%').margin({ top: 6 })
Text(`${this.T(K.matchResult)}:`).fontSize(12).fontColor('#6B7280').width('100%').margin({ top: 10 })
ForEach(RES_TABLE, (e: ResEntry) => {
Row() {
Text(`${e.key} =`).fontSize(12).fontColor('#9CA3AF').width('110')
Text(this.resFor(this.simLang, e.key))
.fontSize(14).fontWeight(FontWeight.Bold).fontColor('#4F46E5').layoutWeight(1)
}.width('100%').margin({ top: 4 })
}, (e: ResEntry) => `sim-${e.key}`)
设计决策:
- 5 个徽章含
🌐 base:把"兜底目录"做成一个可选项——用户选base时看到所有 key 回退到默认值,兜底机制变成主动实验而不是被动意外; - 模拟语言与界面语言独立:
simLang是独立状态,界面语言切英文、模拟器仍可模拟日文系统——两个开关互相不污染,教学场景下能同时演示"系统语言 zh_CN + 界面语言 en_US"的组合; - 匹配结果行 key = 值:
app_name = 资源演示用等号连接,加粗靛蓝——结果区永远是全卡视觉终点; - ForEach key 加
sim-前缀:与静态卡的 key 区分,两个 ForEach 渲染同一 RES_TABLE 也不冲突。
七、底部提示:把"模拟"与"真实"的边界讲清楚
Text(this.T(K.hint))
.fontSize(11).fontColor('#9CA3AF').width('90%').margin({ top: 12, bottom: 16 })
.textAlign(TextAlign.Center)
提示文案:“真实设备上 $r() 会随系统语言自动切换;本页用动态读取模拟效果。”——教学型 App 的诚实条款:模拟器不会真去改系统语言,它只是复现了资源匹配的算法。这个提示防止用户误以为"改模拟器=改了系统",是演示工具应有的严谨。
八、排版验证清单(多语言下自查)
| 检查项 | 方法 | 验证结果 |
|---|---|---|
| 树形对齐 | monospace 等宽字体 | ├─└─ 字符不歪 |
| key 列对齐 | 固定宽 110 | 5 行 key 左缘一致 |
| 静态卡随界面语言 | resFor(currentLocale, key) |
切英文整卡变英文 |
| 模拟器独立于界面语言 | simLang 独立状态 |
界面中文 + 模拟日文互不干扰 |
| base 兜底 | resFor('base', key) |
所有 key 回退默认值 |
| 长文案不溢出 | 值 layoutWeight(1) |
日文"こんにちは、おかえりなさい"完整显示 |
| 窄屏不溢出 | 徽章 FlexWrap | 5 个语言徽章自动折行 |
九、可访问性(多语言 UI 加分项)
- 模拟器选中态三重编码:靛蓝底 + 白字 + 徽章文案本身(语言码),不单靠颜色;
- 对比度:正文 #1F2937 ≈ 15:1、靛蓝 #4F46E5 on 白 ≈ 6.3:1、浅靛底 #EEF2FF 上靛蓝文字 ≈ 5.5:1,均满足 WCAG AA;
- 树形文本可朗读:
├─ base/element/string.json ← 默认的完整路径文本,朗读器按行读出,不依赖图形; - key 列固定宽度:屏幕朗读器按行读取时结构稳定,不会因换行错乱;
- 提示文字居中且字号 11:作为"脚注"存在,不干扰主内容层级。
十、小结
本页 UI 把"资源限定符"从文档概念变成了可操作实验:目录树卡建立心智模型、静态引用卡演示自动行为、模拟器卡提供可控实验、底部提示划清模拟边界。四个区块层层递进,用户 30 秒内理解"base 兜底 + 语言限定符匹配"的完整机制。这套"概念 → 演示 → 实验 → 结论"的四段式布局,是任何教学型演示 App 的通用模板,也为第 14 应用(系统语言跟随)的"策略 + 模拟器"结构埋下了伏笔。下一篇文章深入技术实现,讲解 $r() 与 resourceManager 两种取资源的完整链路与匹配优先级算法。
更多推荐




所有评论(0)