语言地区选择器-鸿蒙ArkTS国际化页面设计
·


一、设计目标
几乎所有面向全球的 App 都有这个注册环节:“选择你的国家/地区和语言”。它看似简单,却是本地化体验的第一道门——选错了,后面所有体验都是错的。本应用把"创建账户"的第一步做成三步向导,UI 设计要回答三个问题:
- 三步选择如何零困惑:国家/地区 → 语言 → 货币,每一步的选项、默认值、联动关系都要让用户一眼看懂;
- "建议值"如何表达:选了日本,语言自动建议日语、货币自动建议日元——但用户有权改。UI 既要体现"智能联动",又不能绑架用户选择;
- 选择结果如何即时验证:底部本地化预览卡实时展示"所选 locale 下的日期格式与数字格式"——用户不用等注册完成,当场看到选择的效果。
因此本页 UI 的核心原则是:选择即预览,联动可覆盖——每个选择都立刻产生可见结果(日期/数字预览),所有自动建议都可被用户手动改掉。
二、页面信息架构(组件树)
LocaleRegionPicker(@Entry 根组件)
└─ Scroll(整页滚动,背景 #F8FAFC)
└─ Column(宽 100%)
├─ Row:标题栏("创建账户" + 副标题 + 🌍 图标)
├─ Flex:界面语言徽章组(简中/繁中/EN/日/韩,选中绿色高亮)
├─ Text + Flex:第 1 步 国家/地区(8 个徽章:🇨🇳 中国 / 🇺🇸 美国 / 🇯🇵 日本 …)
├─ Text + Flex:第 2 步 语言(8 个徽章:简体中文 / 繁體中文 / English …)
├─ Text + Flex:第 3 步 货币(8 个徽章:🇨🇳 CNY / 🇺🇸 USD / 🇯🇵 JPY …)
├─ Text + Column:本地化预览卡(浅绿底 #F0FDF4)
│ ├─ 完整 locale:zh-Hans-CN · CNY
│ ├─ 日期格式:2026年8月19日星期三
│ └─ 数字格式:1,234,567.89
└─ Button:完成注册(全宽绿色)
架构上严格遵循**“自上而下的流程感”**:界面语言开关在最上(控制整个页面的语言)、三个步骤依次向下、预览卡承接结果、完成按钮收尾——用户心智模型与页面结构完全一致。
三、色彩与字号规范
本页主题色为绿色系(#15803D)——注册/成功/确认的语义,与系列其他应用的蓝/橙/紫/靛蓝区分:
| 元素 | 色值 | 字号 | 字重 |
|---|---|---|---|
| 页面标题 | #1F2937 | 22 | Bold |
| 副标题 | #9CA3AF | 12 | Normal |
| 步骤标题(1./2./3.) | #1F2937 | 14 | Bold |
| 选中徽章 | 文字 #FFF / 底 #15803D | 12 | Normal |
| 未选中徽章 | 文字 #374151 / 底 #E5E7EB | 12 | Normal |
| 预览卡 locale 行 | #15803D | 12 | Normal |
| 预览标签(日期/数字) | #6B7280 | 13 | Normal |
| 预览值 | #1F2937 | 13 | Normal |
| 完成按钮 | 文字 #FFF / 底 #15803D | 15 | Normal |
| 预览卡背景 | #F0FDF4 | — | — |
色彩规则延续系列:绿 = 选中/强调。绿色同时用于界面语言徽章、三步徽章、预览卡 locale 行、完成按钮——“当前生效/可确认"的语义贯穿全页,用户看到绿色即知"这是我当前的选择”。
四、第 1 步:国家/地区——名称本地化的展示
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
ForEach(REGIONS, (r: Region, idx: number) => {
Text(`${r.flag} ${this.regionName(r.code)}`)
.fontSize(12).padding({ left: 10, right: 10, top: 6, bottom: 6 }).borderRadius(16)
.backgroundColor(this.regionIdx === idx ? '#15803D' : '#E5E7EB')
.fontColor(this.regionIdx === idx ? Color.White : '#374151')
.onClick(() => { this.selectRegion(idx); })
}, (r: Region) => r.code)
}
.width('94%').margin({ top: 6 })
private regionName(code: string): string {
try {
return i18n.getDisplayCountry(code, this.currentLocale, true);
} catch (err) {
return code;
}
}
设计要点:
- 地区名走
i18n.getDisplayCountry():界面语言是中文时显示"中国/美国/日本/法国/德国/英国/印度",切英文界面自动变 “China / United States / Japan / France / Germany / United Kingdom / India”——国家名不是翻译的,是本地化的(与 11 应用的国家名同一机制); - flag emoji 辅助识别:🇨🇳🇺🇸🇯🇵🇰🇷🇫🇷🇩🇪🇬🇧🇮🇳 快速定位,不依赖文字;
- FlexWrap 自动换行:8 个地区徽章在窄屏折行,360dp 下两到三排;
- 点击即联动:
selectRegion(idx)不只是高亮地区,还会自动设置建议语言与货币(见技术篇)——一次点击,三步联动。
五、第 2 步:语言——建议值与自由选择
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
ForEach(LANGS, (l: string, idx: number) => {
Text(this.langName(l))
.fontSize(12).padding({ left: 10, right: 10, top: 6, bottom: 6 }).borderRadius(16)
.backgroundColor(this.langIdx === idx ? '#15803D' : '#E5E7EB')
.fontColor(this.langIdx === idx ? Color.White : '#374151')
.onClick(() => { this.langIdx = idx; })
}, (l: string) => l)
}
.width('94%').margin({ top: 6 })
private langName(code: string): string {
try {
return i18n.getDisplayLanguage(code, this.currentLocale, true);
} catch (err) {
return code;
}
}
设计要点:
- 语言名本地化:
getDisplayLanguage('zh-Hans', 'en_US')→ “Simplified Chinese”、('ja', 'zh_CN')→ “日语”——8 种语言名随界面语言变化; - 联动默认值:选了日本地区后,语言徽章自动选中"日语"(
selectRegion里的findIndex逻辑)——但用户仍可自由改选,联动只是建议不是锁定; - 8 种语言覆盖主要市场:zh-Hans/zh-Hant/en/ja/ko/fr/de/hi(简中/繁中/英/日/韩/法/德/印地语);
- 界面语言 ≠ 账户语言:界面语言徽章(顶部 5 种)只控制"这个页面用什么语言显示",第 2 步的语言是"账户默认语言"——两个语言维度并存,是本页最容易被新手混淆的点,视觉上用位置区分(顶部一行 vs 步骤区)。
六、第 3 步:货币——按地区分组展示
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
ForEach(REGIONS, (r: Region, idx: number) => {
Text(`${r.flag} ${r.currency}`)
.fontSize(12).padding({ left: 10, right: 10, top: 6, bottom: 6 }).borderRadius(16)
.backgroundColor(this.currencyIdx === idx ? '#15803D' : '#E5E7EB')
.fontColor(this.currencyIdx === idx ? Color.White : '#374151')
.onClick(() => { this.currencyIdx = idx; })
}, (r: Region, idx: number) => `${r.code}-${idx}`)
}
.width('94%').margin({ top: 6 })
设计要点:
- 货币用"地区 × 币种"双信息徽章:
🇨🇳 CNY/🇺🇸 USD/🇯🇵 JPY/🇰🇷 KRW/🇫🇷 EUR/🇩🇪 EUR/🇬🇧 GBP/🇮🇳 INR——注意法国与德国共用 EUR,同一币种出现两次,这正是货币与地区多对多关系的体现; - ForEach key 用
`${r.code}-${idx}`:地区码本身唯一(CN/US…),但货币列表也遍历 REGIONS,key 需要区分场景——加 idx 双保险; - 货币联动:选地区后自动选中该地区币种(
findIndex按 currency 匹配,法国/德国都命中 EUR)。
七、本地化预览卡:选择即所见
Column({ space: 8 }) {
Text(`${this.fullLocale()} · ${this.curRegion().currency}`)
.fontSize(12).fontColor('#15803D').width('100%')
Row() {
Text(`${this.T(K.dateFmt)}:`).fontSize(13).fontColor('#6B7280').layoutWeight(1)
Text(this.fmtDate()).fontSize(13).fontColor('#1F2937')
}.width('100%')
Row() {
Text(`${this.T(K.numFmt)}:`).fontSize(13).fontColor('#6B7280').layoutWeight(1)
Text(this.fmtNum()).fontSize(13).fontColor('#1F2937')
}.width('100%')
}
.width('94%').padding(14).backgroundColor('#F0FDF4').borderRadius(14).margin({ top: 8 })
设计要点:
- 完整 locale 展示:
zh-Hans-CN · CNY——把"语言_地区_币种"的组合直接显示给用户,这是本页的数据核心; - 日期格式预览:
intl.DateTimeFormat(fullLocale, { dateStyle: 'full' })输出所选组合下的完整日期——中文"2026年8月19日星期三"、日语"2026年8月19日水曜日"、法语 “mercredi 19 août 2026”; - 数字格式预览:
1234567.89在英文下 “1,234,567.89”、德语 “1.234.567,89”、印地语 “१२,३४,५६७.८९”(印度数字分组)——同样的数字,完全不同的写法; - 预览卡浅绿底 #F0FDF4:与强调色同族,形成"结果区"的视觉容器感——用户每次改选择,这里立即刷新,即时反馈是表单设计的黄金法则。
八、完成按钮与注册反馈
Button(this.T(K.done))
.fontSize(15).width('94%').height(44).margin({ top: 14, bottom: 16 })
.backgroundColor('#15803D')
.onClick(() => { this.onDone(); })
private onDone(): void {
const r = this.curRegion();
promptAction.showToast({
message: `${this.T(K.complete)}: ${this.regionName(r.code)} · ${this.langName(this.curLang())} · ${r.currency}`
});
}
- 全宽 44dp 按钮符合移动端触控规范,绿色延续"确认"语义;
- 点击后 Toast 汇总三步选择(地区名 + 语言名 + 币种),全部走本地化函数——用户看到的是"注册配置: 日本 · 日本語 · JPY"这样的完整确认。
九、排版验证清单(多语言下自查)
| 检查项 | 方法 | 验证结果 |
|---|---|---|
| 地区名随界面语言 | getDisplayCountry(code, currentLocale, true) |
中文"美国"/英文"United States" |
| 语言名随界面语言 | getDisplayLanguage(code, currentLocale, true) |
中文"日语"/日文"日本語" |
| 地区→语言联动 | selectRegion() 内 findIndex |
选日本自动选中日语 |
| 地区→货币联动 | 按 currency 匹配 | 法/德都自动选 EUR |
| 日期随完整 locale | fullLocale() 拼合 |
zh-Hans-CN 输出中文完整日期 |
| 数字随完整 locale | NumberFormat |
德语 1.234.567,89 / 印地语印度分组 |
| 货币重复不冲突 | ForEach key `${code}-${idx}` |
EUR 徽章两个都正常渲染 |
| 窄屏不溢出 | 徽章 FlexWrap | 8 地区徽章自动折行 |
十、可访问性(多语言 UI 加分项)
- 选中态三重编码:绿底 + 白字 + 徽章文字本身(国旗/语言名/币种码),色弱用户可辨识;
- 对比度:绿 #15803D on 白 ≈ 5.2:1、正文 #1F2937 ≈ 15:1、预览标签 #6B7280 ≈ 7:1,满足 WCAG AA;
- 步骤编号显式:步骤标题带"1. 国家/地区 / 2. 语言 / 3. 货币"——屏幕朗读器按编号读,流程感清晰;
- 预览值可朗读:日期/数字格式化结果本身就是完整字符串,朗读器读出 “2026年8月19日星期三” 而非原始时间戳;
- 联动变化可感知:选地区后语言/货币徽章自动高亮,视觉焦点变化明确,用户知道"系统帮我选了什么"。
十一、小结
本页 UI 把"注册第一步"做成了 i18n 的浓缩课堂:getDisplayCountry/getDisplayLanguage 名称本地化、地区→语言→货币三步联动、完整 locale 的日期数字预览——一个表单页面覆盖了"选什么、默认什么、结果是什么"的完整闭环。设计上最值得记的模式是**“联动可覆盖 + 选择即预览”**:系统给建议,用户有自由,结果立刻可见。这套三步向导 + 预览卡的结构,可直接迁移到任何"初始配置"流程(注册、设置向导、多语言初始化)。下一篇文章深入技术实现,讲解 fullLocale() 的拼合规则与 selectRegion() 的联动算法。
更多推荐


所有评论(0)