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

时间:2022-02-20 08:51:50

起因

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

效果

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

思路

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

实现

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

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

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

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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语言存入本地。下次启动应用,设置即可。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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同时进行了是否需要切换语言的判定。如果当前语言和要选择的一致,则无需再做处理)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
public class ActivityManager {
private static final Stack<Activity> sActivityStack = new Stack<>();
private static ActivityManager sActivityManager;
 
private ActivityManager() {
}
 
public Stack<Activity> 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<?> cls) {
  for (Activity activity : sActivityStack) {
    if (activity.getClass().equals(cls)) {
      finishActivity(activity);
      return;
    }
  }
 
}
 
//获取指定类名的Activity
public Activity getActivity(Class<?> 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 < size; i++) {
    if (null != sActivityStack.get(i)) {
      sActivityStack.get(i).finish();
    }
  }
  sActivityStack.clear();
}
 
public void finishAllOtherActivity(Activity activity) {
  for (int i = 0, size = sActivityStack.size(); i < size; i++) {
    if (null != sActivityStack.get(i) && sActivityStack.get(i) != activity) {
      sActivityStack.get(i).finish();
    }
  }
  sActivityStack.clear();
}
 
public void recreateAllOtherActivity(Activity activity) {
  for (int i = 0, size = sActivityStack.size(); i < size; i++) {
    if (null != sActivityStack.get(i) && sActivityStack.get(i) != activity) {
      sActivityStack.get(i).recreate();
    }
  }
}
 
/**
 * 退出应用程序
 */
public void AppExit() {
  try {
    finishAllActivity();
    System.exit(0);
  } catch (Exception e) {
  }
  }
  }

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

?
1
2
3
4
5
6
7
8
9
10
11
@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添加)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@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

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

原文链接:https://www.jianshu.com/p/b9e32fad36a2