ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

鸿蒙系统语言跟随切换 — ArkTS技术实现

鸿蒙系统语言跟随切换 — ArkTS技术实现 一、业务需求为什么这么设计本应用是系列的收官之作回答App 语言听谁的这个终极问题。产品是一个设置中心的语言管理页需要支持三种能力的演示读取系统信息系统语言、系统地区、系统时区——i18n.System系列 API语言策略切换跟随系统Toggle 开vs 应用内覆盖Toggle 关 手动选语言双语言实时对比模拟系统语言变化观察设置项文案在两种策略下的不同表现。核心知识点是**“生效语言”activeLang的推导**它不是单一状态而是跟随开关 × 系统语言 × 用户选择三个变量的函数。本文记录完整技术方案所有代码与SystemLanguagePage.ets一一对应。二、总体架构┌─ 系统层i18n.System.getSystemLanguage/getSystemRegion i18n.getTimeZone ├─ 策略层followSystem 开关 activeLang() 生效语言推导核心 ├─ 文案层STRINGS 5 语言表 t(code, key) 三级降级 ├─ 模拟层simSystemLang 模拟系统语言真机无法直接改系统语言 └─ 状态层StorageLink currentLocale State followSystem / simSystemLang架构核心是双源取词currentLocale用户手动选择的 App 语言与simSystemLang模拟的系统语言是两个独立状态activeLang()按策略合成真正用于渲染的语言——全页文案只从这一个函数取词。三、系统信息 APIi18n.SystemprivatesysLangName():string{try{returni18n.System.getSystemLanguage();// zh-CN | en-US | ...}catch(err){returnzh-CN;}}privatesysRegionName():string{try{returni18n.System.getSystemRegion();// CN | US | ...}catch(err){returnCN;}}privatesysTzName():string{try{returni18n.getTimeZone().getID();// Asia/Shanghai | ...}catch(err){returnAsia/Shanghai;}}三个 API 的语义API返回示例用途getSystemLanguage()BCP-47 语言标签zh-CN界面跟随的基准getSystemRegion()ISO 3166 地区码CN地区化规则日期/单位i18n.getTimeZone().getID()IANA 时区名Asia/Shanghai时间显示基准注意getSystemLanguage()返回的是zh-CN连字符而系列其他应用的 locale 用zh_CN下划线——两者格式不同但语义等价。本页模拟器的语言码zh_CN与系统 API 返回值zh-CN格式不同因此模拟器语言不直接喂给系统 API而是走 STRINGS 表取词——这是刻意设计的边界系统 API 读真实值、STRINGS 表管界面渲染互不混用。四、核心activeLang()生效语言推导StorageLink(STORAGE_LOCALE)currentLocale:stringDEFAULT_LOCALE;StatefollowSystem:booleantrue;StatesimSystemLang:stringzh_CN;/** 生效语言跟随系统 → 模拟系统语言否则 → 用户手动选择 */privateactiveLang():string{returnthis.followSystem?this.simSystemLang:this.currentLocale;}privateT(key:string):string{returnt(this.activeLang(),key);}这是本应用最重要的 3 行代码。生效语言的真值表followSystemsimSystemLangcurrentLocaleactiveLang()界面语言trueja_JPzh_CNja_JP日语跟随模拟系统trueen_USzh_CNen_US英语falseja_JPzh_CNzh_CN中文用户选择无视模拟器falseja_JPko_KRko_KR韩语用户选择两个关键设计默认followSystem true真实设备上跟随系统的 App 在用户改系统语言后需要重新进入页面或页面 onShow才能看到新语言——本页用simSystemLang模拟这个外部变量让变化即时可见currentLocale仍持久化即使跟随系统手动选择关闭跟随时的选择也要记住——用户下次关闭跟随回到上次的语言不丢失偏好。五、双源取词的边界标题 vs 内容页面里两套取词路径并存这是容易踩坑的地方// 标题栏/区块标题始终跟随 currentLocaleApp 界面语言Text(t(this.currentLocale,K.title))Text(t(this.currentLocale,K.sysInfo))// 设置项内容跟随 activeLang()生效语言Text(t(this.activeLang(),key))为什么标题不跟随模拟器标题是当前页面的语言的自我说明——如果模拟器切到日文、标题也变日文用户会困惑我到底在看什么语言。标题保持 currentLocale用户永远知道App 现在的语言是中文而下面列表在模拟日语系统下的表现。元信息页面语言与演示内容模拟语言分源是教学页面的正确边界。六、模拟器真机限制下的教学妥协privatelangLabel(code:string):string{if(codezh_CN)return 简体中文;if(codeen_US)return English;if(codeja_JP)return 日本語;if(codeko_KR)return 한국어;returncode;}// 模拟器徽章改 simSystemLangForEach([zh_CN,en_US,ja_JP,ko_KR]asstring[],(code:string){Text(this.langLabel(code))....onClick((){this.simSystemLangcode;})},(code:string)code)真实产品怎么做系统语言变化会触发资源重匹配12 的资源限定符自动完成且页面在onPageShow时重新读取系统语言。旧版本有i18n.System.on(languageChange)监听已废弃——现在推荐的做法是页面 onShow 重新取getSystemLanguage() 资源自动重匹配。本页用模拟器演示同样的效果hint 文案诚实说明“真实设备上系统语言变化会自动触发资源重匹配本页用模拟器演示’跟随’与’覆盖’的差异。”七、状态联动与重渲染aboutToAppear():void{if(!AppStorage.getstring(STORAGE_LOCALE)){AppStorage.setOrCreate(STORAGE_LOCALE,DEFAULT_LOCALE);}PersistentStorage.persistProp(STORAGE_LOCALE,DEFAULT_LOCALE);}三个状态的联动关系followSystem变化 →activeLang()切换取词源 → 设置列表整块重渲染跟随关时还额外渲染手动语言徽章区simSystemLang变化 →activeLang()返回值变 → 设置列表内容变跟随开时currentLocale变化 → 标题/区块标题/系统信息标签变同时若跟随关闭设置列表内容也变。没有当前界面语言这个缓存状态——activeLang()每次 build 现算三变量一变即得新结果不会出现开关动了但文案没变的陈旧状态 bug。八、数据流复盘一次完整交互启动 → aboutToAppear 初始化 persistProp → followSystemtrue、simSystemLangzh_CN → 标题语言设置中文、系统信息真实值 zh-CN/CN/Asia/Shanghai → 设置列表无线网络/蓝牙/电池/存储/关于本机中文 用户把模拟器切到 日本語 → simSystemLang ja_JP → activeLang() ja_JP跟随开 → 设置列表标题变 设置 ( 日本語) → 5 行设置项变日文Wi-Fi / Bluetooth / バッテリー / ストレージ / このデバイスについて → 标题栏不变仍中文——两个取词源各司其职 用户关闭跟随系统开关 → followSystem false → 手动语言徽章区展开4 个选中 zh_CN → activeLang() currentLocale zh_CN → 设置列表回到中文模拟器被无视——覆盖生效 用户点 한국어 徽章 → currentLocale ko_KRAppStorage 落盘 → 标题栏变韩文设置列表变韩文覆盖模式 → 重启 AppcurrentLocale 恢复 ko_KR、followSystem 恢复 true未持久化九、ArkTS 兼容要点catch (err)不带类型注解所有i18n.System调用包 try/catch数据缺失兜底ForEach([zh_CN, ...] as string[], ...)数组字面量断言ForEach([wifi, bluetooth, ...] as string[], (key: string) key)设置项 key 列表作为 ForEach 数据源t(activeLang(), key)在回调内取词——key 既是数据标识又是文案键天然唯一Toggle({ type: ToggleType.Switch, isOn: this.followSystem })isOn单向绑定 onChange回写避免双向绑定类型问题langLabel()if 链返回字符串无联合类型问题对象字面量显式接口KeysSTRINGS 构建走buildStrings()工厂。十、性能与内存每次 build 调用t()约 20 次Map 查找毫秒级i18n.System只调 3 次且是轻量读取无定时器、无监听器旧System.on已弃用无内存泄漏activeLang()是纯函数无缓存需求真实产品的性能注意若页面极复杂可在onPageShow缓存系统语言避免每次 build 读系统 API。十一、小结本应用用 274 行代码收束了整个系列i18n.System读取设备信息、activeLang()合成生效语言、双源取词划分元信息与内容、模拟器把真机限制变成教学优势。它演示的语言策略正是真实产品微信、Chrome、Office都在用的模式——默认跟随系统高级选项允许覆盖。应用深化维度01应用内语言切换纯手动方案12资源限定符跟随系统的基础设施14跟随系统 vs 应用内覆盖策略层← 本文给生产环境的三条铁律① 默认跟随系统用户零操作即正确本地化覆盖作为高级选项② 用户的手动选择必须持久化且与系统语言独立存储③ 系统语言变化后在onPageShow刷新界面替代已废弃的监听 API——配合资源限定符自动重匹配做到用户改系统设置App 立即响应。
返回列表