web-to-app 构建器 UI 语言切换机制:10 语言即时切换、DataStore 持久化与阿拉伯语 RTL 适配

📅 发布时间:2026/9/17 23:14:17
web-to-app 构建器 UI 语言切换机制:10 语言即时切换、DataStore 持久化与阿拉伯语 RTL 适配
web-to-app 构建器 UI 语言切换机制10 语言即时切换、DataStore 持久化与阿拉伯语 RTL 适配【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-appweb-to-app一个完全在手机上运行的 Web 转 APK 工坊的宿主界面完整本地化为 10 种语言。本文基于仓库文档 language.md 与对应源码实现讲清楚构建器 UI 语言选择器的入口位置、即时生效与确认提示的工作方式、语言偏好的持久化与系统语言回退策略、阿拉伯语完整 RTL 布局的实现以及构建器界面语言与生成应用内容语言之间的作用范围边界。读完本文你可以准确描述该语言功能的完整调用链并知道新增一条本地化字符串时应遵循的源码约定。入口在哪里顶栏语言按钮与首次启动语言选择页文档中的原始描述是我的应用 顶栏的语言按钮打开构建器 UI 的语言选择器。结合源码构建器实际上暴露了三个语言选择入口它们都调用同一个LanguageManager单例顶栏语言按钮主界面我的应用列表顶栏的语言图标按钮由 HomeScreen.kt 中挂载的 LanguageSelectorButton 渲染。点击后弹出LanguageSelectionDialog对话框列出全部 10 种语言的卡片式选项当前语言以高亮边框加对勾标记展示。首次启动语言选择页MainActivity.kt 通过languageManager.hasSelectedLanguageFlow判断用户是否已选择过语言若尚未选择language_selected标记不存在则在进入主导航之前先展示FirstLaunchLanguageScreen定义在 LanguageSelector.kt。该页面在用户做出选择之前用中英阿三语并行的方式显示欢迎语如Welcome / 欢迎 / مرحبا并针对 Android TV 环境自动放大图标与卡片间距。设置页语言卡片LanguageSettingsCard同文件以只读文本框 ExposedDropdownMenu下拉菜单的形式提供语言切换作为主界面的补充入口。三个入口最终都收敛到languageManager.setLanguage(language)这一条路径因此行为完全一致。支持的语言10 种语言的完整定义宿主界面完整本地化为10 种语言中文、英文、阿拉伯文完整 RTL、葡萄牙文、西班牙文、法文、德文、俄文、日文、韩文。这不是文档的口头承诺而是直接由枚举 AppLanguage 决定的。每个语言条目携带 6 个字段是理解整个语言机制的钥匙枚举值code原生名称是否 RTL备注CHINESEzh中文否Locale.CHINESEENGLISHenEnglish否Locale.ENGLISH同时是回退默认语言ARABICarالعربية是唯一的isRtl true条目PORTUGUESEptPortuguês否—SPANISHesEspañol否—FRENCHfrFrançais否—GERMANdeDeutsch否—RUSSIANruРусский否—JAPANESEja日本語否—KOREANko한국어否—两个值得注意的设计细节fromCode的回退策略AppLanguage.fromCode 在code匹配不到任何条目时返回CHINESE而不是抛异常——这与该应用以中文为默认宿主语言的定位一致。translationInProgress标记枚举支持翻译进行中徽章字段LanguageSelector.kt 中的LanguageDisplayNameWithBadge会据此在语言名后追加徽章。当前 10 种语言均为完整本地化因此该徽章默认不出现但它为未来新增语言预留了状态位。选择对话框中的每个选项显示nativeName原生名称如 العربية为主标题、displayName英文显示名如 Arabic为副标题这一点从 LanguageOption 的排版代码可以直接确认。工作方式即时应用、确认提示与持久化文档给出的用户视角行为有三条点击语言按钮并选择一种语言更改立即应用到整个构建器 UI并显示一条确认提示阿拉伯文会把布局切换为完整的从右到左。下面逐条对应到源码实现。即时应用的调用链LanguageSelectorButton内部的选中回调非常短LanguageSelector.ktonLanguageSelected { language - scope.launch { languageManager.setLanguage(language) onLanguageChanged() } showDialog false }setLanguage是一个 DataStore 写操作LanguageManager.ktsuspend fun setLanguage(language: AppLanguage) { context.languageDataStore.edit { prefs - prefs[LANGUAGE_KEY] language.code // 键 app_language prefs[LANGUAGE_SELECTED_KEY] true // 键 language_selected } }之所以立即生效而不需要重启应用是因为读取侧是一个响应式FlowLanguageManager.ktval currentLanguageFlow: FlowAppLanguage context.languageDataStore.data.map { prefs - val code prefs[LANGUAGE_KEY] ?: getSystemLanguageCode() AppLanguage.fromCode(code) }UI 侧用collectAsState订阅该 FlowDataStore 一写入Compose 状态即更新所有订阅了currentLanguage的组件语言按钮对话框、设置卡片、以及基于Strings.lang的文案随之重新组合。这就是更改立即应用到整个构建器 UI的底层机制单一数据源 Flow 响应式分发。确认提示的来源文档说会显示一条确认提示。在 HomeScreen.kt 中可以看到该提示的具体实现LanguageSelectorButton( onLanguageChanged { scope.launch { snackbarHostState.showSnackbar(Strings.msgLanguageChanged) } } )即切换成功后通过 Snackbar 弹出本地化文案Strings.msgLanguageChanged。注意这条文案本身也经过Strings本地化体系所以确认提示同样会跟随新语言显示。持久化键与系统语言回退语言偏好存储在名为language_settings的 Preferences DataStore 中LanguageManager.kt共两个键键名作用取值app_language用户选择的语言代码zh/en/ar/pt/es/fr/de/ru/ja/kolanguage_selected是否已完成过首次语言选择控制首启语言页是否再出现true当用户从未显式选择语言时getSystemLanguageCode 会读取设备系统语言并做白名单映射zh/ar/pt/es/fr/de/ru/ja/ko各归各其余任何语言如泰语、印尼语一律回退到en。这解释了为什么界面不会出现半支持的语言——要么命中 10 种之一要么显示英文。阿拉伯语完整 RTLisRtl与布局方向切换阿拉伯文是 10 种语言中唯一在枚举上标记isRtl true的条目。真正的切换发生在 applyLanguagefun applyLanguage(context: Context, language: AppLanguage): Context { val locale language.locale Locale.setDefault(locale) val config Configuration(context.resources.configuration) config.setLocale(locale) config.setLayoutDirection(locale) // 关键由 Locale 推导布局方向 return context.createConfigurationContext(config) }config.setLayoutDirection(locale)对ar会返回LAYOUT_DIRECTION_RTL配合createConfigurationContext派生出整个新的资源上下文。这就是文档所说阿拉伯文会把布局切换为完整的从右到左的实现位置——RTL 不是 UI 层手写镜像而是交给 Android 配置系统的标准能力。开发规范文档 i18n.md 也明确把这一点列为硬性规则阿拉伯文必须完整 RTL——验证布局正确镜像。从源码结构看applyLanguage派生的本地化Context由 Strings.attachContext 消费Strings对象同时持有fallbackContext和localizedContext两个上下文切换语言时通过contextVersionmutableIntStateOf自增版本号来触发 Compose 失效重组使所有依赖Strings.*的文本节点重新求值。作用范围边界构建器语言 ≠ 应用内容语言这是文档中最容易被忽略、但最实用的一条区分这是构建器的界面语言。你生成的应用的语言则按应用单独配置生成的应用还可提供页内翻译叠加层。用仓库内的代码佐证构建器语言由LanguageManagerlanguage_settingsDataStore 管理只影响 web-to-app 自身界面按钮、菜单、对话框、Snackbar 等全部文案收敛在 Strings.kt 这一个文件中。生成应用的语言是每个 App 项目独立的配置项随项目一起打包进导出的 APK与构建器当前界面语言无关。你可以在英文构建器里生成一个阿拉伯语应用反之亦然。此外生成的 Web 类应用还可以叠加页内翻译能力即 appearance.md 描述的翻译叠加层它作用于网页内容本身同样与构建器 UI 语言相互独立。三层语言构建器界面语言 / 生成应用的语言配置 / 生成应用的页内翻译彼此解耦这是理解该功能的完整心智模型。源码级补充新增一条本地化字符串的约定如果你要阅读或扩展这套本地化体系developer/i18n.md 给出了官方约定可与源码相互印证字符串全部集中在 Strings.kt。该文件约 6.7 万行Strings对象按字母区间拆分为StringsA…StringsE等内部拆分对象Strings自身只是委托层例如val languageSettings: String get() StringsA.languageSettings。必须覆盖全部 10 种语言且禁止使用else分支// 示意——匹配 Strings.kt 中实际的拆分对象风格 val myNewLabel: String get() when (Strings.lang) { AppLanguage.CHINESE - 我的标签 AppLanguage.ENGLISH - My label AppLanguage.ARABIC - ... // ... 全部 10 种绝不用 else }用穷尽的when代替else意味着编译器能强制检查每种语言是否都有文案漏译会在编译期暴露而不是运行时静默回退。不要在 Compose 界面中硬编码用户可见文本始终经由Strings引用——否则该文本将无法跟随语言切换也不会出现在本地化覆盖检查中。需要注意的是首次启动页 FirstLaunchLanguageScreen 中的欢迎语采用了内联的when (selectedLanguage)写法而非走Strings因为该页面在选择之前就需要同时展示多语言文案属于有意的例外场景。小结与关键文件索引web-to-app 的构建器语言功能是一个小而完整的国际化样本AppLanguage枚举定义 10 种语言及其 RTL 属性LanguageManager以 DataStore 为单一数据源配合Flow实现切换即时生效applyLanguage借助Configuration.setLayoutDirection完成阿拉伯语全量 RTLUI 侧由顶栏按钮、首启选择页、设置卡片三个入口共用同一调用链文案则全部收口在Strings.kt中按穷尽式when分发。文件职责LanguageManager.ktAppLanguage枚举、DataStore 持久化、系统语言回退、applyLanguage的 Locale/RTL 切换LanguageSelector.kt顶栏按钮、选择对话框、首启语言页、设置页下拉卡片HomeScreen.kt顶栏挂载语言按钮切换成功后弹出 Snackbar 确认提示MainActivity.kt依据hasSelectedLanguageFlow决定首启是否展示语言选择页Strings.kt全部宿主界面文案按Strings.lang穷尽分发i18n.md开发者侧的本地化规则10 语全覆盖、禁用else、RTL 验证【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考