一、简介
二、效果预览
三、实现步骤
1、功能实现
2、配置多语言文件
四、MultiLanguageUtils分析
五、Demo地址
六、内容推荐
一、简介
我想搜到这篇文章的朋友应该不需要我多介绍,也明白多语言是用来干嘛。。。
当一个应用越做越大之后,用的人越来越多,要满足不同的群体所以都会有这一功能。
不过你会发现越到后面添加这功能会比较麻烦。所以前期做好准备为佳。
不扯这乱七八糟的东西了。。。。亮剑吧!!!
二、效果预览
是不是要先看看大招是咋样的,万一是花拳绣腿。不满意,就浪费大家时间了。
大家可可能会奇怪,不是切换成英文了吗? 怎么还有中文字体。
其实我只是对首页的 标题 与 底部导航栏 做了处理 其他的没有变
所以大家看效果的话 只需观察 那两处地方即可。
如果对这个功能有兴趣可以继续往下观察。。没兴趣的也请往下看 ,看完可能会更没兴趣。哈哈 开个玩笑
三、实现步骤
1、功能实现
布局我就不解释了,就随便搭搭。源码地址就贴在最下面,想copy的同学自己去下载哈。对了,如果不错。别忘了 Star
主要的功能就在于当我选中某个语言时,点击保存(上图是“打钩”的图片)的时候去实现语言的切换。 那么,是怎么实现的呢?预知后事如何且看下文分解!!
上菜:点击保存执行事假
//区分是选中哪种语言
switch (datas.get(checkPos)) {
case "跟随系统"://切换到 跟随系统
//获取手机系统语言
Locale locale = MultiLanguageUtils.getSystemLanguage().get(0);
String language = locale.getLanguage();
String country = locale.getCountry();
//切换成手机系统语言 例:手机系统是中文则换成中文
MultiLanguageUtils.changeLanguage(activity,language, country);
//清空SP数据 ,用于当系统切换语言时 应用可以同步保持切换 例:系统转换成英文 则应用语言也会变成英文
MultiLanguageUtils.changeLanguage(activity,null,null);
break;
case "简体中文":// 切换到 中文
MultiLanguageUtils.changeLanguage(activity, "zh", "ZH");
break;
case "English"://切换到 英文
MultiLanguageUtils.changeLanguage(activity, "en", "US");
break;
default://默认切换成中文
MultiLanguageUtils.changeLanguage(activity, "zh", "ZH");
break;
}
//关闭应用所有Activity
//AppManager.getAppManager().finishAllActivity();
//启动 MainActivity
//IntentUtils.toActivity(activity, MainActivity.class,true);
上面的切换语言功能都已经封装成一个工具类,当需要执行切换语言的时候 只需调用一行代码即可。是不是很兴奋 ,其实更麻烦的在后面,先安慰一下大家。
要让切换语言起效果,还需要重启APP。
例:上面代码是先调用了个人封装的一个Activity管理类来关闭所有的页面,然后再重启MainActivity。大家可以根据情况自己写,也可以到源码地址找到相关工具类拿去用。
大餐来了 MultiLanguageUtils.class 先感谢下大神提供的这个类:https://blog.csdn.net/m0_38074457/article/details/84993366
个人做了调整,改的有点面目全非,现在分享给大家。如果还行。。。你们懂得 点个赞意思一下就行 ,,关注,分享,打赏 我是不敢想的。
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.LocaleList;
import android.support.v4.os.ConfigurationCompat;
import android.support.v4.os.LocaleListCompat;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import java.util.Locale;
import blcs.lwb.lwbtool.Constants;
/**
* Todo 多语言设置
* 来自:https://blog.csdn.net/m0_38074457/article/details/84993366
* 使用步骤:
* 1、Application中onCreate添加registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
@Override
protected void attachBaseContext(Context base) {
//系统语言等设置发生改变时会调用此方法,需要要重置app语言
super.attachBaseContext(MultiLanguageUtils.attachBaseContext(base));
}
* 2、改变应用语言调用MultiLanguageUtils.changeLanguage(activity,type,type);
*/
//public final static String SP_LANGUAGE="SP_LANGUAGE";
//public final static String SP_COUNTRY="SP_COUNTRY";
public class MultiLanguageUtils {
/**
* TODO 1、 修改应用内语言设置
* @param language 语言 zh/en
* @param area 地区
*/
public static void changeLanguage(Context context,String language, String area) {
if (TextUtils.isEmpty(language) && TextUtils.isEmpty(area)) {
//如果语言和地区都是空,那么跟随系统s
SPUtils.put(context, Constants.SP_LANGUAGE,"");
SPUtils.put(context, Constants.SP_COUNTRY,"");
} else {
//不为空,那么修改app语言,并true是把语言信息保存到sp中,false是不保存到sp中
Locale newLocale = new Locale(language, area);
setAppLanguage(context,newLocale);
saveLanguageSetting(context, newLocale);
}
}
/**
* Todo 更新应用语言
* @param context
* @param locale
*/
private static void setAppLanguage(Context context, Locale locale) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
Configuration configuration = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(locale);
configuration.setLocales(new LocaleList(locale));
context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(locale);
resources.updateConfiguration(configuration,metrics);
} else {
configuration.locale = locale;
resources.updateConfiguration(configuration,metrics);
}
}
/**
* TODO 3、 跟随系统语言
*/
public static Context attachBaseContext(Context context) {
String spLanguage = (String) SPUtils.get(context, Constants.SP_LANGUAGE,"");
String spCountry = (String) SPUtils.get(context, Constants.SP_COUNTRY,"");
if(!TextUtils.isEmpty(spLanguage)&&!TextUtils.isEmpty(spCountry)){
Locale locale = new Locale(spLanguage, spCountry);
setAppLanguage(context, locale);
}
return context;
}
/**
* 判断sp中和app中的多语言信息是否相同
*/
public static boolean isSameWithSetting(Context context) {
Locale locale = getAppLocale(context);
String language = locale.getLanguage();
String country = locale.getCountry();
String sp_language = (String) SPUtils.get(context, Constants.SP_LANGUAGE,"");
String sp_country = (String) SPUtils.get(context, Constants.SP_COUNTRY,"");
if (language.equals(sp_language) && country.equals(sp_country)) {
return true;
} else {
return false;
}
}
/**
* 保存多语言信息到sp中
*/
public static void saveLanguageSetting(Context context, Locale locale) {
SPUtils.put(context, Constants.SP_LANGUAGE,locale.getLanguage());
SPUtils.put(context, Constants.SP_COUNTRY,locale.getCountry());
}
/**
* 获取应用语言
*/
public static Locale getAppLocale(Context context){
Locale local;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
local =context.getResources().getConfiguration().getLocales().get(0);
} else {
local =context.getResources().getConfiguration().locale;
}
return local;
}
/**
* 获取系统语言
*/
public static LocaleListCompat getSystemLanguage(){
Configuration configuration = Resources.getSystem().getConfiguration();
LocaleListCompat locales = ConfigurationCompat.getLocales(configuration);
return locales;
}
//注册Activity生命周期监听回调,此部分一定加上,因为有些版本不加的话多语言切换不回来
//registerActivityLifecycleCallbacks(callbacks);
public static Application.ActivityLifecycleCallbacks callbacks = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
String language = (String) SPUtils.get(activity, Constants.SP_LANGUAGE,"");
String country = (String) SPUtils.get(activity, Constants.SP_COUNTRY,"");
LogUtils.e(language);
if (!TextUtils.isEmpty(language) && !TextUtils.isEmpty(country)) {
//强制修改应用语言
if (!isSameWithSetting(activity)) {
Locale locale = new Locale(language, country);
setAppLanguage(activity,locale);
}
}
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
};
}
这里可以能还需要一个封装的SP工具
import android.content.Context;
import android.content.SharedPreferences;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* SharedPreferences的封装
*/
public class SPUtils
{
public SPUtils()
{
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 保存在手机里面的文件名
*/
public static final String FILE_NAME = "share_data";
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*
* @param context
* @param key
* @param object
*/
public static void put(Context context, String key, Object object)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (object instanceof String)
{
editor.putString(key, (String) object);
}
else if (object instanceof Integer)
{
editor.putInt(key, (Integer) object);
}
else if (object instanceof Boolean)
{
editor.putBoolean(key, (Boolean) object);
}
else if (object instanceof Float)
{
editor.putFloat(key, (Float) object);
}
else if (object instanceof Long)
{
editor.putLong(key, (Long) object);
}
else
{
editor.putString(key, object.toString());
}
SharedPreferencesCompat.apply(editor);
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*
* @param context
* @param key
* @param defaultObject
* @return
*/
public static Object get(Context context, String key, Object defaultObject)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
if (defaultObject instanceof String)
{
return sp.getString(key, (String) defaultObject);
}
else if (defaultObject instanceof Integer)
{
return sp.getInt(key, (Integer) defaultObject);
}
else if (defaultObject instanceof Boolean)
{
return sp.getBoolean(key, (Boolean) defaultObject);
}
else if (defaultObject instanceof Float)
{
return sp.getFloat(key, (Float) defaultObject);
}
else if (defaultObject instanceof Long)
{
return sp.getLong(key, (Long) defaultObject);
}
return null;
}
/**
* 移除某个key值已经对应的值
*
* @param context
* @param key
*/
public static void remove(Context context, String key)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
* 清除所有数据
*
* @param context
*/
public static void clear(Context context)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
* 查询某个key是否已经存在
*
* @param context
* @param key
* @return
*/
public static boolean contains(Context context, String key)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
* 返回所有的键值对
*
* @param context
* @return
*/
public static Map getAll(Context context)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.getAll();
}
/**
* 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
* @author zhy
*
*/
private static class SharedPreferencesCompat
{
private static final Method sApplyMethod = findApplyMethod();
/**
* 反射查找apply的方法
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Method findApplyMethod()
{
try
{
Class clz = SharedPreferences.Editor.class;
return clz.getMethod("apply");
} catch (NoSuchMethodException e)
{
}
return null;
}
/**
* 如果找到则使用apply执行,否则使用commit
*
* @param editor
*/
public static void apply(SharedPreferences.Editor editor)
{
try
{
if (sApplyMethod != null)
{
sApplyMethod.invoke(editor);
return;
}
} catch (IllegalArgumentException e)
{
} catch (IllegalAccessException e)
{
} catch (InvocationTargetException e)
{
}
editor.commit();
}
}
}
如果你们以为有了这几个工具就可以出去吹牛逼,那么是你们天真了,而不是我想的太多。还有更麻烦的事情还没开始呢
在继承Application的类中onCreate方法内添加监听回调
@Override
public void onCreate() {
super.onCreate();
//多语言设置
registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
}
跟随系统语言也要在Application中的attachBaseContext配置(感觉可以去掉,本人亲测根本没有调用到。不知道是不是不同机型的原因。先保留着 ,后续若发现无用,可删掉。写出来主要是钱作者有写但描述不够详细)
@Override
protected void attachBaseContext(Context base) {
//系统语言等设置发生改变时会调用此方法,需要要重置app语言
super.attachBaseContext(MultiLanguageUtils.attachBaseContext(base));
}
2、配置多语言文件
最麻烦的工作来了,若前期没做好相关工作。那么你可以开始跟我一步步来实现了
1、新增多语言文件
可以手动创建,但要符合命名规范。(不推荐)
这里介绍androidStudio 新建多语言文本方法
右击res——New——Android resource file
创建完文件后。。。剩下就是抽出文本进行翻译了。。
2、把项目中的文本都写到strings.xml文件中
像我这样:
如何使用这些文本?
UI中: android:text="@string/Title"
代码中:context.getString(R.string.Title)
快捷键使用:选中文本使用 Alt + Enter 打开Extract string resource
给文本命名 ——> 打钩所有的values——>点击OK 就可以自动生成到strings文件里面
接着翻译 values-en 文件中的文本。
到这里差不多都介绍完了 ,若有代码遗落可查看源码 。毕竟已经实现过了 ,拿出来分析给大家,可能会有疏忽。
MultiLanguageUtils只加了简单注释,若对MultiLanguageUtils有什么不理解的地方 请继续往下看。
四、MultiLanguageUtils分析
我们切换语言只需调用:MultiLanguageUtils.changeLanguage(activity, "zh", "ZH");
1、changeLanguage(Context context,String language, String area):
public static void changeLanguage(Context context,String language, String area) {
if (TextUtils.isEmpty(language) && TextUtils.isEmpty(area)) {
//如果语言和地区都是空,那么跟随系统s
SPUtils.put(context, Constants.SP_LANGUAGE,"");
SPUtils.put(context, Constants.SP_COUNTRY,"");
} else {
//不为空,那么修改app语言,并true是把语言信息保存到sp中,false是不保存到sp中
Locale newLocale = new Locale(language, area);
setAppLanguage(context,newLocale);
saveLanguageSetting(context, newLocale);
}
}
首先判断language,area 是否为空
空:清空app本地存储多语言的sp,为什么要清空呢?
当启动APP时会回调 registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
该方法内部会绑定生命周期调用如下方法
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
String language = (String) SPUtils.get(activity, Constants.SP_LANGUAGE,"");
String country = (String) SPUtils.get(activity, Constants.SP_COUNTRY,"");
LogUtils.e(language);
if (!TextUtils.isEmpty(language) && !TextUtils.isEmpty(country)) {
//强制修改应用语言
if (!isSameWithSetting(activity)) {
Locale locale = new Locale(language, country);
setAppLanguage(activity,locale);
}
}
}
若sp有值则根据对应的值设置APP语言 ,若为空 ,则会默认取系统语言。
注:当选中“跟随系统语言”时,若不清空SP。则会造成当系统语言改变,App还是会根据SP的值来设置语言。
有值:根据传入的language,area 值切换成相对应的语言
2、setAppLanguage(Context context, Locale locale)
/**
* Todo 更新应用语言
* @param context
* @param locale
*/
private static void setAppLanguage(Context context, Locale locale) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
Configuration configuration = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(locale);
configuration.setLocales(new LocaleList(locale));
context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(locale);
resources.updateConfiguration(configuration,metrics);
} else {
configuration.locale = locale;
resources.updateConfiguration(configuration,metrics);
}
}
更改应用的语言主要还是通过更改App配置来实现,主要实现步骤如下:
1、先获取资源配置对象 2、更改资源对象属性 3、更新配置信息
多语言语言适配了Android N (7.0)
7.0以前更新配置信息使用
resources.updateConfiguration(configuration, metrics);
7.0以后更新配置信息使用
context.createConfigurationContext(configuration);
3、跟随系统语言实现思路分析
1、当保存跟随系统语言时,获取系统语言 ,并更新App语言。
2、当更改手机设置语言后,启动App的时候重新更改App语言(保存其它语言信息的时候,启动App是时候也需要根据保存信息重新设置)
这里主要分析第二点。第一点只要调用changeAppLanguage 就行了
当App启动的时候会回调registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
String language = (String) SPUtils.get(activity, Constants.SP_LANGUAGE,"");
String country = (String) SPUtils.get(activity, Constants.SP_COUNTRY,"");
LogUtils.e(language);
if (!TextUtils.isEmpty(language) && !TextUtils.isEmpty(country)) {
//强制修改应用语言
if (!isSameWithSetting(activity)) {
Locale locale = new Locale(language, country);
setLanguage(activity,locale);
}
}
}
也是通过Sp是否有保存信息来设置系统语言。
终于写完了,看了一下篇幅还是挺长,容我感慨一下。又熬夜了 ,大家要手下留
好吧!!! 再见
五、Demo地址
https://github.com/DayorNight/BLCS
六、内容推荐
CSDN:https://blog.csdn.net/cs_lwb/article/details/88051709
《Android 仿微信全局字体大小调整》
《Android JUnit单元测试》
《Android Log日志封装》
《Android Rxjava+Retrofit网络请求框架封装(一)》
如果你觉得我写的不错或者对您有所帮助的话
不妨顶一个【微笑】,别忘了点赞、收藏、加关注哈
看在我花了这么多时间整理写成文章分享给大家的份上,记得手下留情哈
您的每个举动都是对我莫大的支持