Android 无Bug版 多语言设计方案!

出海业务为什么要做多语言?

1.市场扩大与本地化需求:

通过支持多种语言,出海项目可以触及更广泛的国际用户群体,进而扩大其市场份额。

本地化是吸引国际用户的重要策略之一,而语言本地化是其中的核心。使用用户的母语能够提供更好的用户体验,并增加用户黏性。

2.文化敏感性和尊重:

不同的语言往往代表着不同的文化和习惯。通过提供多语言支持,出海项目能够表现出对目标市场文化的敏感性和尊重,从而建立更好的品牌形象。

3.提高用户满意度和参与度:

使用用户的母语进行交流可以消除语言障碍,使用户更容易理解和使用产品。

这有助于提高用户的满意度和参与度,进而增加用户留存和转化率。

所以,出海应用适配多语言是业务开展过程中的重中之重,建议大家App都要实现多语言功能,感受其带来的好处。  

多语言常见问题

1. Android N版本适配问题

2. 切换系统导航,更改深色模式导致多语言无法适配问题

3. 系统授权弹窗导致ApplicationContext中的Local被还原

4. 切换语言,系统通知栏显示不是当前设置的语言

5. Service服务中Toast不适配

6. 如何正确获取系统当前语言

7. WebView第一次加载多语言不适配

功能虽不太难,但遇到的问题还是比较多的,下面给大家分享我们在用的多语言方案,有问题还希望大家积极指出。

无Bug版 多语言设计方案

1.多语言方案基本原理:

实现多国语言的原理是根据用户选择的语言或者手机系统设置的语言来加载相应的语言资源文件。当用户切换语言时,应用程序会重新加载对应语言的资源文件,从而显示相应的文本内容。

2.无Bug版 多语言设计方案实践

如果您应用内内置了所有的语言文本,则只需要根据系统语言切换即可,实现方式也较为简单。如果您只兼容几种语言,要根据用户选择来切换App语言,就较为复杂一些,下面我们分别来讲一下。

(1) 跟随系统切换

通过Android Studio,(当然如果知道语言的缩写可以直接在res目录下建立不同名称的values文件例如中文values-zh),右击res->New->Android Resource File 会打开一个新的弹窗,在File name 输入框填写strings,如下图在红色圈中区域找到Local 点击>> 后就可以选择相关的国语言,点击OK会在res目录下生成一个新的values-xx目录,接下来就可以在该目录的strings.xml 添加相关语言的文案即可

图片

图片

打开手机的设置,切换系统语言(例如你项目的默认语言是中文,你上一步添加的是values-en目录,切换语言到英文),这是重新打开App,你看到App上的显示的就是英文了。

(2) App 内设置切换语言

以上2个步骤就可以简单的实现了系统切换多语言功能,但是产品为了让用户更好的使用产品,App内会有一个设置切换语言的功能,让用户自己选择App内的语言(往往我们无法支持所有的语言)。

对于这种需求我们如何设计呢?

图片

主要代码如下,文章末尾会给出github地址:

‍基类复写attachBaseContext设置上下文

abstract class BaseForLanguageActivity : Activity() {  override fun attachBaseContext(newBase: Context) {    super.attachBaseContext(LanguageUtil.wrap(newBase, LanguageUtil.getLocaleByLanguage()))}}

获取用户设置的默认语言,如果没有设置获取本地设备的默认语言(Android 7.0以及以上需要获取本地语言列表)

private fun getLanguage(): String {  val defaultLanguage = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {    Resources.getSystem().configuration.locales[0].language  } else {    Locale.getDefault().language  }    return getInstance()[KEY_LANGUAGE, defaultLanguage]}

通过第二步获取的语言来判断设置的Local类型​​​​​​​

fun getLocaleByLanguage(): Locale {  val locale = if (getLanguage().equals(LanguageType.ENGLISH.language, ignoreCase = true)) {    Locale.ENGLISH  } else if (getLanguage().equals(LanguageType.BANGLADESH.language, ignoreCase = true)) {    Locale(LanguageType.BANGLADESH.language)  } else {    Locale(LanguageType.DEFAULT.language)  }  return locale}

根据Locale(Android 7.0以及以上需要设置本地语言列表)重新包装上下文Context,在Activity的attachBaseContext方法会用到​​​​​​​

fun wrap(context: Context, newLocale: Locale): Context {
  var context = context  val res = context.resources  val configuration = res.configuration  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {    configuration.setLocale(newLocale)    val localeList = LocaleList(newLocale)    LocaleList.setDefault(localeList)    configuration.setLocales(localeList)    context = context.createConfigurationContext(configuration)  } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    configuration.setLocale(newLocale)    context = context.createConfigurationContext(configuration)  }  return ContextWrapper(context)}

保存用户设置的语言​​​​​​​

private fun setLanguage(language: String?) {  getInstance().put(KEY_LANGUAGE, language)}
fun saveChange(language: String) {  setLanguage(language)}

应用内获取string资源使用以下方法getString,确保每次获取的上下文里的Local是当前应该显示的语言​​​​​​​

object Extentions {  fun getString(@StringRes resId: Int) = getContext().getString(resId)    private fun getContext(): Context {    return LanguageUtil.getLanguageContext()  }}

LanguageContext是一个枚举类 通过这个可以获取相关语言的上下文,并获取相关语言下的资源文件​​​​​​​

enum class LanguageContext(val languageType: LanguageType) {  DEFAULT(LanguageType.DEFAULT) {    private var context: Context = LanguageUtil.wrap(Extentions.getApp(), Locale(languageType.language))        override fun getContext(): Context {                return context              }    },        ENGLISH(LanguageType.ENGLISH) {        private var context: Context = LanguageUtil.wrap(Extentions.getApp(), Locale(languageType.language))                override fun getContext(): Context {                return context              }    },        BANGLADESH(LanguageType.BANGLADESH) {        private var context: Context = LanguageUtil.wrap(Extentions.getApp(), Locale(languageType.language))                override fun getContext(): Context {                return context              }    };        abstract fun getContext(): Context        }}

讲到这里,出海项目的多语言适配就结束了,本Demo解决了开头提出的所有问题。Gitgub地址如下,欢迎大家下载体验:https://github.com/loveAndroidAndroid/OveraeaDemos  

推荐阅读

GooglePlay账号关联审查机制详解

另类封号!别让你的Google老账号为你的粗心买单

Google Play开发者组织身份验证(个人转组织)详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/881747.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言字符函数

1,字符分类函数: 例如:写一个代码将字符串中的小写字母转化成大写字母 就可以用到上述islower函数判断字符是否是小写 2.字符转换函数 c语言提供了两个字符转换函数 1.int tolower (int c); //将输入进去的大写字母转化成小写 2,int …

IRP默认最小流程

IRP是Windows内核中的一种非常重要的数据结构。上层应用程序与底层驱动程序通信时,应用程序会发出I/O请求,操作系统将相应的I/O请求转换成相应的IRP,不同的IRP会根据类型被分派到不同的派遣例程中进行处理。 irp相当于R3下的消息&#xff0c…

rtsp协议:rtsp协议参数介绍

目的: 实时流协议(RTSP)用于建立和控制单个或多个时间同步的连续媒体流,例如音频和视频。RTSP 通常不负责实际传输这些连续的媒体流,但可以将连续媒体流与控制流进行交错传输(参见第 10.12 节)。…

【K8S系列】Kubernetes 集群中的网络常见面试题

在 Kubernetes 面试中,网络是一个重要的主题。理解 Kubernetes 网络模型、服务发现、网络策略等概念对候选人来说至关重要。以下是一些常见的 Kubernetes 网络面试题及其答案,帮助你准备面试。 1. Kubernetes 的网络模型是什么样的? 问题: Kubernetes 的网络模型是怎样的?…

学习Redisson实现分布式锁

官网&#xff1a;https://redisson.org/ 官方文档&#xff1a;https://redisson.org/docs/getting-started/ 官方中文文档&#xff1a;https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95 1、引入依赖 <!--redisson--> <dependency><groupId>or…

金融大数据平台总体技术

目录 金融大数据平台应用场景风险管理 场景描述解决方案​​​​​​​市场营销 ​​​​​​​场景描述解决方案​​​​​​​金融大数据信息价值链​​​​​​​金融大数据平台总体目标金融大数据平台功能技术要求​​​​​​​ ​​​​​​​概述数据接入功能要求 ​​…

Git 根据远程分支拉取并创建本地分支

文章目录 1 关联远程仓库2 获取最新更改&#xff0c;并创建分支3 clone时直接指定远程分支 1 关联远程仓库 git remote add remote_repo ssh:git***.git2 获取最新更改&#xff0c;并创建分支 查看本地分支和远程分支 git branch -a获取最新更改 git fetch remote_repo根据…

创建读取比特币1P类型地址

创建读取比特币1P类型地址 比特币的地址类型有多种&#xff0c;其中 P2TR&#xff08;Pay-to-Taproot&#xff09;地址是基于最近的升级&#xff08;Taproot&#xff09;引入的一个新类型。本文将介绍如何创建和读取比特币的 1P 类型地址&#xff0c;主要通过 JavaScript 和相…

谁在窥探我们的网络数据?——在未经许可下获取用户上网数据的情形与维权指南

在数字化时代&#xff0c;网络数据不仅是商业价值的金矿&#xff0c;更是用户隐私的敏感部分。然而&#xff0c;有时用户的上网数据可能会在未经知情与允许的情况下被收集甚至滥用。这篇文章将详细探讨哪些机构在何种情况下可以合法获取用户上网数据、用户如何通过法律手段维护…

吐槽kotlin之垃圾设计

本文重点在于吐槽垃圾设计&#xff0c;基本直只说缺点。 一.没有static关键字 static其实不是很面向对象&#xff0c;但是是很有必要和方便的。 kotlin为了实现java的static功能&#xff0c;必须使用伴生类&#xff0c;一般情况下没啥问题&#xff0c;但是反编译之后的class多…

ES6字符串 全局替换

字符串替换 部分替换replace 全部替换 replaceAll aabbcc.replace(b, _) // aa_bcc如果要替换所有的匹配&#xff0c;不得不使用正则表达式的g修饰符。 aabbcc.replace(/b/g, _) // aa__cc

Github学生包的JetBrains认证过期/idea认证过期如何解决?

官网通过Github更新状态即可JetBrains Account 注意要到邮箱走流程

C++面试速通宝典——26

478. 你了解的网络攻击方式有哪些&#xff1f;SYN攻击的防范方法&#xff1f; 网络攻击方式包括&#xff1a; Dos/DDos攻击&#xff1a;通过大量请求耗尽目标资源。Main-in-the-Middle攻击&#xff1a;攻击者拦截和篡改双方通信。Phishing&#xff1a;通过假冒网站或通信骗取…

SQL Server LocalDB 表数据中文乱码问题

--查看数据库设置 SELECT name, collation_name FROM sys.databases;--出现了The database could not be exclusively locked to perform the operation这个错误&#xff0c; --无法修改字符集为Chinese_PRC_CI_AS&#xff1b;所以需要先设置为单用户模式 ALTER DATABASE MySma…

初试PostgreSQL数据库

文章目录 一、PostgreSQL数据库概述1.1 PostgreSQL的历史1.2 PostgreSQL安装1.3 安装PostgreSQL二、PostgreSQL起步2.1 连接数据库2.1.1 SQL Shell2.1.2 执行SQL语句2.2 pgAdmin 42.2.1 打开pgAdmin 42.2.2 查找数据库2.2.3 打开查询工具2.2.4 执行SQL语句三、实战小结文章目录…

日本AZBIL山武燃烧控制器AUR450C42350D0

顺序定时 (在室温、湿度和额定电压下)火焰电压输出范围火焰电压范围 (在额定电压、室温和湿度下)推荐火焰电压额定电源电压允许电压范围功耗介电强度页序&#xff0c;如果发生火修非循环操作629279484士1秒&#xff0c;8士2秒可根据型号选择)仅限《行员7.52.5秒主要审判73秒火老…

大一计算机课程之线性代数

《大一计算机课程之线性代数》 在大一的计算机课程中&#xff0c;线性代数是一门极为重要的基础学科&#xff0c;它就像一把神奇的钥匙&#xff0c;为计算机科学领域的诸多方面开启了智慧之门。 线性代数主要研究线性方程组、向量空间、线性变换等内容。对于计算机专业的学生…

主动降噪技术:原理、方法与应用的深度解析

目录 一、主动降噪的原理二、主动降噪的技术分类三、主动降噪中的核心算法四、主动降噪的应用领域五、主动降噪技术的挑战与未来发展六、结论 主动降噪&#xff08;Active Noise Cancellation&#xff0c;ANC&#xff09;是当前音频技术中的重要应用&#xff0c;广泛用于耳机、…

HCIP-HarmonyOS Application Developer 习题(九)

(多选) 1、HarmonyOS多窗口交互能力提供了以下哪几种交互方式&#xff1f; A. 全局消息通知 B.平行视界 C.悬浮窗 D.分屏 答案&#xff1a;BCD 分析&#xff1a;系统提供了悬浮窗、分屏、平行视界三种多窗口交互&#xff0c;为用户在大屏幕设备上的多任务并行、便捷的临时任务…

【已解决】黑群晖绕过双重认证(2FA)登录(终极方案)

黑群晖绕过双重认证&#xff08;2FA&#xff09;登录&#xff08;终极方案&#xff09; 黑裙版本7.x&#xff0c;之前设置了双重认证&#xff0c;但是由于更换设备导致卡在2FA登录界面&#xff0c;无法登录&#xff0c;之前也没开SSH&#xff0c;网上找了很多方法&#xff0c;…