Android 仿微信多语言切换

Android 仿微信多语言切换_第1张图片
image

一、简介
二、效果预览
三、实现步骤
1、功能实现
2、配置多语言文件
四、MultiLanguageUtils分析
五、Demo地址
六、内容推荐


一、简介

我想搜到这篇文章的朋友应该不需要我多介绍,也明白多语言是用来干嘛。。。

当一个应用越做越大之后,用的人越来越多,要满足不同的群体所以都会有这一功能。

不过你会发现越到后面添加这功能会比较麻烦。所以前期做好准备为佳。

不扯这乱七八糟的东西了。。。。亮剑吧!!!

Android 仿微信多语言切换_第2张图片
image

二、效果预览

是不是要先看看大招是咋样的,万一是花拳绣腿。不满意,就浪费大家时间了。

image

大家可可能会奇怪,不是切换成英文了吗? 怎么还有中文字体。

其实我只是对首页的 标题底部导航栏 做了处理 其他的没有变

所以大家看效果的话 只需观察 那两处地方即可。

如果对这个功能有兴趣可以继续往下观察。。没兴趣的也请往下看 ,看完可能会更没兴趣。哈哈 开个玩笑

Android 仿微信多语言切换_第3张图片
image

三、实现步骤

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);
image.gif

上面的切换语言功能都已经封装成一个工具类,当需要执行切换语言的时候 只需调用一行代码即可。是不是很兴奋 ,其实更麻烦的在后面,先安慰一下大家。

要让切换语言起效果,还需要重启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、新增多语言文件

Android 仿微信多语言切换_第4张图片
image

可以手动创建,但要符合命名规范。(不推荐)

这里介绍androidStudio 新建多语言文本方法

Android 仿微信多语言切换_第5张图片
image

右击res——New——Android resource file

Android 仿微信多语言切换_第6张图片
image
Android 仿微信多语言切换_第7张图片
image

创建完文件后。。。剩下就是抽出文本进行翻译了。。

2、把项目中的文本都写到strings.xml文件中

Android 仿微信多语言切换_第8张图片
image

像我这样:

Android 仿微信多语言切换_第9张图片
image

如何使用这些文本?

UI中: android:text="@string/Title"

代码中:context.getString(R.string.Title)

快捷键使用:选中文本使用 Alt + Enter 打开Extract string resource

Android 仿微信多语言切换_第10张图片
image
Android 仿微信多语言切换_第11张图片
image

给文本命名 ——> 打钩所有的values——>点击OK 就可以自动生成到strings文件里面

接着翻译 values-en 文件中的文本。

Android 仿微信多语言切换_第12张图片
image

到这里差不多都介绍完了 ,若有代码遗落可查看源码 。毕竟已经实现过了 ,拿出来分析给大家,可能会有疏忽。

Android 仿微信多语言切换_第13张图片
image

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是否有保存信息来设置系统语言。

终于写完了,看了一下篇幅还是挺长,容我感慨一下。又熬夜了 ,大家要手下留

Android 仿微信多语言切换_第14张图片
image

好吧!!! 再见

五、Demo地址

https://github.com/DayorNight/BLCS

六、内容推荐

CSDN:https://blog.csdn.net/cs_lwb/article/details/88051709

《Android 仿微信全局字体大小调整》

《Android JUnit单元测试》

《Android Log日志封装》

《Android Rxjava+Retrofit网络请求框架封装(一)》

如果你觉得我写的不错或者对您有所帮助的话

不妨顶一个【微笑】,别忘了点赞、收藏、加关注哈

看在我花了这么多时间整理写成文章分享给大家的份上,记得手下留情哈

您的每个举动都是对我莫大的支持

Android 仿微信多语言切换_第15张图片
image

你可能感兴趣的:(Android 仿微信多语言切换)