热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Android支持国际化多语言那点事(支持8.0+)

我们在开发app可能会拓展国外市场,那么对包含英语在内的其它语言支持就很有必要了。这篇文章主要介绍了Android支持国际化多语言那点事(支持8.0+),具有一定的参考价值,感兴趣的小伙伴们可以参考一下

起因

我们在开发app可能会拓展国外市场,那么对包含英语在内的其它语言支持就很有必要了。

效果


思路

一:添加相关资源文件,并引用。
二:设置configuration,configuration里面指定语言类型。
三:在需要时候更换configuration即可。

实现

在res的values文件夹下新建相关语言类型的资源文件

右键新建资源文件,选择Locale,点击 >> 按钮

选择Language,以及地区(any region)即可


最后 文件名字和其他语言文件名字一样,strings即可。

在MyApplication里面的onCreate和onConfigurationChanged方法里面添加语言相关处理(onConfigurationChanged是为了处理横竖屏切换问题),给应用上下文对象添加configuration,configuration里面指定了当前语言。

public class MyApplication extends Application {
@Override
public void onCreate() {
  super.onCreate();
  languageWork();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  languageWork();
}

private void languageWork() {
  //自己写的工具包(如下)
  Locale locale = LanguageUtil.getLocale(this);
  LanguageUtil.updateLocale(this, locale);
}
}

LanguageUtil如下(没整理过的小伙伴直接用即可),为了保证语言从A切换到B,在之后启动应用依旧使用B语言,我们需要将B语言存入本地。下次启动应用,设置即可。

public class LanguageUtil {
/**
 * 中文
 */
public static final Locale LOCALE_CHINESE = Locale.CHINESE;
/**
 * 英文
 */
public static final Locale LOCALE_ENGLISH = Locale.ENGLISH;
/**
 * 俄文
 */
public static final Locale LOCALE_RUSSIAN = new Locale("ru");

private static final String LOCALE_SP = "LOCALE_SP";
private static final String LOCALE_SP_KEY = "LOCALE_SP_KEY";

 public static Locale getLocale(Context context) {
  SharedPreferences spLocale = context.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE);
  String localeJson = spLocale.getString(LOCALE_SP_KEY, "");
  Gson gson = new Gson();
  return gson.fromJson(localeJson, Locale.class);
}

pivate static void setLocale(Context pContext, Locale pUserLocale) {
  SharedPreferences spLocal = pContext.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE);
  SharedPreferences.Editor edit = spLocal.edit();
  String json = new Gson().toJson(pUserLocale);
  edit.putString(LOCALE_SP_KEY, json);
  edit.apply();
}

public static boolean updateLocale(Context context, Locale locale) {
  if (needUpdateLocale(context, locale)) {
    Configuration cOnfiguration= context.getResources().getConfiguration();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      configuration.setLocale(locale);
    } else {
      configuration.locale = locale;
    }
    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    context.getResources().updateConfiguration(configuration, displayMetrics);
    setLocale(context, locale);
    return true;
  }
  return false;
}

public static boolean needUpdateLocale(Context pContext, Locale newUserLocale) {
  return newUserLocale != null && !getCurrentLocale(pContext).equals(newUserLocale);
}
public static Locale getCurrentLocale(Context context) {
  Locale locale;
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //7.0有多语言设置获取顶部的语言
    locale = context.getResources().getConfiguration().getLocales().get(0);
  } else {
    locale = context.getResources().getConfiguration().locale;
  }
  return locale;
}
}

进行切换,主要触发动作是activity的recreate()(切换使用新的configuration)。所有的activity在activityManager里面进行管理。只需将其他(除了当前语言选择activity)的所有activity进行recreate(),即可。languageUtil同时进行了是否需要切换语言的判定。如果当前语言和要选择的一致,则无需再做处理)

 public void onClick(View view) {
  boolean need = false;
  switch (view.getId()) {
    case R.id.chinese:
      need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_CHINESE);
      if (need) {
        //自己写的常用activity管理工具
        ActivityManager.getInstance().recreateAllOtherActivity(this);
        Toast.makeText(this, "change to chinese", Toast.LENGTH_SHORT).show();
      } else {
        Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show();
      }
      break;
    case R.id.english:
      need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_ENGLISH);
      if (need) {
        ActivityManager.getInstance().recreateAllOtherActivity(this);
        Toast.makeText(this, "change to english", Toast.LENGTH_SHORT).show();
      } else {
        Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show();
      }
      break;
    case R.id.russian:
      need = LanguageUtil.updateLocale(this, LanguageUtil.LOCALE_RUSSIAN);
      if (need) {
        ActivityManager.getInstance().recreateAllOtherActivity(this);
        Toast.makeText(this, "change to russian", Toast.LENGTH_SHORT).show();
      } else {
        Toast.makeText(this, "no need", Toast.LENGTH_SHORT).show();
      }
      break;
  }
}

ActivityManager如下

 public class ActivityManager {
private static final Stack sActivityStack = new Stack<>();
private static ActivityManager sActivityManager;

private ActivityManager() {
}

public Stack getActivityStack() {
  return sActivityStack;
}

/**
 * 单一实例
 */
public static ActivityManager getInstance() {
  if (sActivityManager == null) {
    synchronized (ActivityManager.class) {
      sActivityManager = new ActivityManager();
    }
  }
  return sActivityManager;
}

/**
 * 添加Activity到堆栈
 */
public void addActivity(Activity activity) {
  sActivityStack.add(activity);
}

/**
 * 删除堆栈中的Activity
 */
public void removeActivity(Activity activity) {
  if (sActivityStack.isEmpty()) {
    return;
  }
  sActivityStack.remove(activity);
}

/**
 * 获取当前Activity(堆栈中最后一个压入的)
 */
public Activity currentActivity() {

  Activity activity = sActivityStack.lastElement();
  return activity;
}

/**
 * 结束当前Activity(堆栈中最后一个压入的)
 */
public void finishActivity() {
  Activity activity = sActivityStack.lastElement();
  finishActivity(activity);
}

/**
 * 结束指定的Activity
 */
public void finishActivity(Activity activity) {
  if (activity != null) {
    sActivityStack.remove(activity);
    activity.finish();
  }
}

/**
 * 结束指定类名的Activity
 */
public void finishActivity(Class<&#63;> cls) {
  for (Activity activity : sActivityStack) {
    if (activity.getClass().equals(cls)) {
      finishActivity(activity);
      return;
    }
  }

}

//获取指定类名的Activity
public Activity getActivity(Class<&#63;> cls) {
  for (Activity activity : sActivityStack) {
    if (activity.getClass().equals(cls)) {
      return activity;
    }
  }
  return null;
}

/**
 * 结束所有Activity
 */
public void finishAllActivity() {
  for (int i = 0, size = sActivityStack.size(); i 

将app的所有acitivity进行添加和移除,可以在BaseActivity里面进行。

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ActivityManager.getInstance().addActivity(this);
}

@Override
protected void onDestroy() {
  super.onDestroy();
  ActivityManager.getInstance().removeActivity(this);
}

以上步骤,我们的语言切换算是完成了。但是,在API 26+以上版本,我们需要额外添加如下代码做兼容,没啥说的,SDK变动而已,跟着SDK走咯~(在activity或者BaseActivity添加)

 @Override
protected void attachBaseContext(Context newBase) {
  Context cOntext= languageWork(newBase);
  super.attachBaseContext(context);

 }

private Context languageWork(Context context) {
  // 8.0及以上使用createConfigurationContext设置configuration
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    return updateResources(context);
  } else {
    return context;
  }
  }

@RequiresApi(api = Build.VERSION_CODES.O)
private Context updateResources(Context context) {
  Resources resources = context.getResources();
  Locale locale = LanguageUtil.getLocale(context);
  if (locale==null) {
    return context;
  }
  Configuration cOnfiguration= resources.getConfiguration();
  configuration.setLocale(locale);
  configuration.setLocales(new LocaleList(locale));
  return context.createConfigurationContext(configuration);
  }

完工~

地址:https://github.com/HoldMyOwn/MultiLanguage

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 使用IntelliJ IDEA高效开发与运行Shell脚本
    本文介绍了如何利用IntelliJ IDEA中的BashSupport插件来增强Shell脚本的开发体验,包括插件的安装、配置以及脚本的运行方法。 ... [详细]
  • 深入解析Nacos服务自动注册机制
    本文将探讨Nacos服务自动注册的具体实现方法,特别是如何通过Spring事件机制完成服务注册。通过对Nacos源码的详细分析,帮助读者理解其背后的原理。 ... [详细]
  • 本文探讨了如何在Sitecore 9环境中通过Postman使用API密钥发送请求,包括解决常见错误的方法。 ... [详细]
  • iOS 小组件开发指南
    本文详细介绍了iOS小部件(Widget)的开发流程,从环境搭建、证书配置到业务逻辑实现,提供了一系列实用的技术指导与代码示例。 ... [详细]
  • 本文详细记录了在Mac操作系统中安装Hexo时遇到的权限错误,并提供了有效的解决方案。 ... [详细]
  • 本文将详细介绍如何配置并整合MVP架构、Retrofit网络请求库、Dagger2依赖注入框架以及RxAndroid响应式编程库,构建高效、模块化的Android应用。 ... [详细]
  • Git版本控制基础解析
    本文探讨了Git作为版本控制工具的基本概念及其重要性,不仅限于代码管理,还包括文件的历史记录与版本切换功能。通过对比Git与SVN,进一步阐述了分布式版本控制系统的独特优势。 ... [详细]
  • Kubernetes Services详解
    本文深入探讨了Kubernetes中的服务(Services)概念,解释了如何通过Services实现Pods之间的稳定通信,以及如何管理没有选择器的服务。 ... [详细]
  • 探索将Python Spyder与GitHub连接的方法,了解当前的技术状态及未来可能的发展方向。 ... [详细]
  • 本文档提供了在Windows 10操作系统中安装Python 3及Scrapy框架的完整指南,包括必要的依赖库如wheel、lxml、pyOpenSSL、Twisted和pywin32的安装方法。 ... [详细]
  • 本文深入探讨了微信小程序直播中点赞动画的实现方法,特别是如何利用三阶贝塞尔曲线使点赞图标沿预设路径移动,以及相关的数学计算与代码实现。 ... [详细]
  • 2023年1月28日网络安全热点
    涵盖最新的网络安全动态,包括OpenSSH和WordPress的安全更新、VirtualBox提权漏洞、以及谷歌推出的新证书验证机制等内容。 ... [详细]
  • 本文介绍了如何利用 Apache NiFi 的灵活性和扩展性,通过自定义组件来解决标准组件无法满足的特定业务需求。文章不仅涵盖了自定义处理器的基本步骤,还讨论了调试自定义组件时可能遇到的问题及解决方案。 ... [详细]
  • 页面预渲染适用于主要包含静态内容的页面。对于依赖大量API调用的动态页面,建议采用SSR(服务器端渲染),如Nuxt等框架。更多优化策略可参见:https://github.com/HaoChuan9421/vue-cli3-optimization ... [详细]
  • 本文旨在探讨Swift中的Closure与Objective-C中的Block之间的区别与联系,通过定义、使用方式以及外部变量捕获等方面的比较,帮助开发者更好地理解这两种机制的特点及应用场景。 ... [详细]
author-avatar
a734839433
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有