关键词:
关于App国际化,之前有讲到国际化资源、字符换、布局相关,想要了解的猛戳用力抱一下APP国际化。借着本次重构多语言想跟大家聊一下多语言切换,多语言切换对于一款国际化App来讲是重中之重,并非难事,但是若要做好也是一件不容易的事情。
问题
- Android N版本适配问题
- AndroidX不同版本兼容问题
- 一些界面局部适配突然失效
- 切换系统导航,更改深色模式导致多语言无法适配
- 系统授权弹窗导致ApplicationContext中的Local被还原
- 切换语言,系统通知栏显示未翻译,重启后正常
- Service服务中Toast不适配
- 系统Local.getDefault()之伤,如何正确获取系统当前语言
- WebView第一次加载多语言不适配
- 系统广播中的获取context中的Local信息显示异常
上面我随手列出了项目中常见遇到的问题,有一些是随着Android版本升级而未做出相应兼容性调整造成的,有一些则是局部失效寻找原因所得。我们先了解下应用中一般多语言切换适配的方案,从中会提到这些问题相应的解决方案。
Andorid 13 语言偏好设置
最近Android 13发布了,讲多语言切换之前,我们先了解一下这个新平台多语言新特性。Android 13 在手机设置页面中新增了一个集中设置应用语言的选项,用于设置各个应用语言首选语言,如果你的应用存在多语言,谷歌强烈建议在设置中进行多语言切换,这样就无须在应用中去做多语言选择切换的功能,页面由设置中的应用语言界面统一管理,具体使用如下:
1. 如何让应用app显示在设置中的应用语言中
- 创建一个名为
res/xml/locales_config.xml
的文件,并指定您的应用的语言,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="ja"/>
<locale android:name="fr"/>
<locale android:name="en"/>
</locale-config>
- 在清单中,添加一行指向这个新文件的代码:
<manifest
...
<application
...
android:localeConfig="@xml/locales_config">
</application>
</manifest>
2. 如何处理设置中的语言偏好
对于具有或想要使用应用内语言选择器的应用,请使用这些新 API(而非自定义应用逻辑)来处理相关设置和获取用户对应用的首选语言设置。
- 使用 AndroidX 支持库来实现
使用 Appcompat 1.6.0-alpha04 或更高版本中的setApplicationLocales()
方法。
// 如需设置用户的首选语言,您需要让用户在语言选择器中选择语言区域,然后在系统中设置该值
LocaleListCompat appLocale = LocaleListCompat.forLanguageTags("xx-YY");
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale);
- 使用 Android 框架 API 来实现
// 1. Inside an activity, in-app language picker gets an input locale "xx-YY"
// 2. App calls the API to set its locale
mContext.getSystemService(LocaleManager.class).setApplicationLocales(newLocaleList(Locale.forLanguageTag("xx-YY")));
// 3. The system updates the locale and restarts the app, including any configuration updates
// 4. The app is now displayed in "xx-YY" language
- 获取用户当前的首选语言
// 1. App calls the API to get the preferred locale
LocaleList currentAppLocales =
mContext.getSystemService(LocaleManager.class).getApplicationLocales();
// 2. App uses the returned LocaleList to display languages to the user
举个栗子,手机系统如果是中文,设置界面中的应用语言如果首选英文,app如果已启动,那么需要自己监听 onConfigurationChanged
来切换应用内部语言,如果未启动,第一次启动时候需要先去读取设置中的语言然后设置给当前应用。亦或是如果你的应用保留了内部切换语言的方案,那么语言切换是也应该调用以上API把当前语言刷到系统设置应用语言中,以保持同步。
讲完Andorid 13 多语言新特性,想要了解更多猛戳,我们继续回到本文的重点,应用内多语言切换如何去做适配。
多语言适配整体部分
1. Application的适配
我们为什么要适配Application,原因很简单,对于多语言来讲,我们其实最关心的是切换语言后,界面或者Toast等等显示是否已经翻译成所选择的语言,但是一般我们项目中都会直接或者间接用到ApplicationContext,比如Application中一些三方控件的初始化,还有一些项目中封装的工具类,为了方便全局一次行初始化,有可能甚至用到单例模式,当我们用到ApplicationContxt去getString(@StringRes int id),在切换语言后,如果不重启整个应用或者刷新ApplicaitonContext的local,那么肯定是无效的。
我们在启动APP时候,应该对Application中的context进行当前应用语言Local适配。
@Override
protected void attachBaseContext(Context newBase)
super.attachBaseContext(LanguageUtil.attachBaseContext(newBase));
当我们做了系统的配置更改,比如说切换了系统导航或者说更改了深色模式,那么我们一般的处理是也是要对Application作出处理。
@Override
public void onConfigurationChanged(Configuration newConfig)
super.onConfigurationChanged(newConfig);
// 系统资源配置发生更改,例如主题模式,需要重新刷新多语言
LanguageUtil.attachBaseContext(this);
如果项目中有用到ApplicationContext去getString(@StringRes int id)实现加载的提示语,那么如果只是单纯的重启界面则无法让当前的提示语跟随当前切换的语言,所以我们要么重启整个应用,要么对ApplicationContext中的Local也作出相应的更新方可,这里有一点问题,虽然Android N之后updateConfiguration是过时方法,官方给出使用createConfigurationContext代替,但是更新ApplicationContext的Local发现无效使用老版本updateConfiguration正常。
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale = getLanguageLocale(newLanguage);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
// apply locale
configuration.setLocales(new LocaleList(locale));
else
configuration.setLocale(locale);
DisplayMetrics dm = resources.getDisplayMetrics();
resources.updateConfiguration(configuration, dm);
如果你发现你的应用广播通知栏适配无效,那就是context中的Local在切换语言是并未及时更新Local,这里调试一下便知,如果是Applicaiton注册的广播,那么多半情况下是没有更新ApplicationContext的Local所导致的。
2. Service适配
如果你的Service有用到Toast提示或者UI相关的东西,你必须要对Service也进行适配,这时候Service中也需要重写attachBaseContext进行语言适配,否则语言适配也是无效的。
@Override
protected void attachBaseContext(Context newBase)
super.attachBaseContext(LanguageUtil.getNewLocalContext(newBase));
3. Activity适配
Activity是我们最主要的适配的界面,正常的情况下我们直接在基类BaseActivity中去处理即可,但是值得注意的一点是如果我们使用的是Androidx而非support库,那么不同的版本适配有点区别,这也是官方组件的问题.记得一些第三方界面如果不是继承我们的BaseActivity需要单独处理即可。
@Override
protected void attachBaseContext(Context newBase)
if(isSupportMultiLanguage())
// 多语言适配
super.attachBaseContext(LanguageUtil.getNewLocalContext(newBase));
else
super.attachBaseContext(newBase);
多语言适配基本步骤大概就是如此了,下面看一下适配的细节问题。
适配部分细节
1. Andorid N 适配
Android N开始,由于系统的API变更,updateConfiguration已经被沦为过时的方法。但是有一点需要大家注意,网上几乎全部的判断都是有问题的,API已经明确说明是在API25过时的,不等价于Build.VERSION_CODES.N
,所以你的项目用对了嘛,详情可参考下图。
还有一点Android N之后,手机系统的语言配置选项已经不是单选了,改为一个列表了,具体可以参考手机设置中的语言和输入法,所以setLocal(@Nullable Locale loc)
方法建议不要再使用了,我相信很多人还在用,正确的用法应该是setLocals(@Nullable LocaleList locales)
,需要传递一个集合。
public static Context attachBaseContext(Context context)
String language = LanguageSp.getLanguage(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
return createConfigurationContext(context, language);
else
return updateConfiguration(context, language);
// 注意此处不是Build.VERSION_CODES.N
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
private static Context createConfigurationContext(Context context, String language)
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale = getLanguageLocale(language);
Log.d(TAG, "current Language locale = " + locale);
LocaleList localeList = new LocaleList(locale);
// 注意此处setLocales
configuration.setLocales(localeList);
return context.createConfigurationContext(configuration);
private static Context updateConfiguration(Context context, String language)
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale = getLanguageLocale(language);
Log.e(TAG, "updateLocalApiLow==== " + locale.getLanguage());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
// apply locale 注意此处是setLocales
configuration.setLocales(new LocaleList(locale));
else
// updateConfiguration
configuration.locale = locale;
DisplayMetrics dm = resources.getDisplayMetrics();
resources.updateConfiguration(configuration, dm);
return context;
2. 关于AndroidX版本兼容问题
当你的应用使用的是androidx.appcompat:appcompat:1.1.0时,BaseActivity中需要实现下面方法。
@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration)
// 兼容androidX在部分手机切换语言失败问题
if (overrideConfiguration != null)
int uiMode = overrideConfiguration.uiMode;
overrideConfiguration.setTo(getBaseContext().getResources().getConfiguration());
overrideConfiguration.uiMode = uiMode;
super.applyOverrideConfiguration(overrideConfiguration);
当你的应用使用的是androidx.appcompat:appcompat:1.2.0及以上时,BaseActivity中需要实现下面方法。
@Override
protected void attachBaseContext(Context newBase)
if (isSupportMultiLanguage())
String language = LanguageSp.getLanguage(newBase);
Context context = LanguageUtil.attachBaseContext(newBase, language);
final Configuration configuration = context.getResources().getConfiguration();
final ContextThemeWrapper wrappedContext = new ContextThemeWrapper(context,
R.style.Theme_AppCompat_Empty)
@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration)
if (overrideConfiguration != null)
overrideConfiguration.setTo(configuration);
super.applyOverrideConfiguration(overrideConfiguration);
;
super.attachBaseContext(wrappedContext);
else
super.attachBaseContext(newBase);
3. 系统授权弹框导致Local失效
我们惊奇的发现,当我们首次进入APP选择语言后,当首页检查系统权限弹框的时候,Local被莫名其妙的重置了,我在想,可能因为google授权弹框他有自己的多语言翻译,所以不会采取我们的,所以把ApplicationContext中的Local给重置了,所以当我们点击允许或者仅在使用此应用时允许后需要再次把Application中的Local修改掉。
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray)
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
// 更新Application中的local
LanguageUtil.updateApplicationLocale(AppApplication.getAppContext(),LanguageSp.getLanguage(mContext))
4. 如何真正的获取系统语言
我们有可能会存在这个场景,当我们的APP不跟随系统语言的时候,使用的APP内部语言,我们去检测系统语言的时候如何去判断,是不是很多人在此跌倒了,无论是Local.getDefault()
还是LocalList.get(0)
始终获取的语言是错误的,应该通过以下渠道获取当前的系统语言。
// 第一种方式
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
return Resources.getSystem().getConfiguration().getLocales().get(0).getLanguage();//解决了获取系统默认错误的问题
else
return Locale.getDefault().getLanguage();
// 第二种方式(推荐)
return ConfigurationCompat.getLocales(Resources.getSystem().getConfiguration()).get(0).getLanguage();
5. 关于WebView适配
在原来的低版本切换语言中,我们会发现WebView第一次加载时,适配是无效的,再次加载则正常适配,所以网上也有了一道方案如下:
@Override public void onCreate(Bundle savedInstanceState)
// TODO 解决含有webView控件导致切换语言失效
~~new WebView(this).destroy(); ~~
super.onCreate(savedInstanceState);
这套方案目前不在推荐,直接去替换attatchBaseContext()中的context则可,经过测试是完全正常的。
工具类
以下则是多语言操作的工具类,现在提供出来,需要的朋友可以自行进行改造。
/**
* @author : le.hu
* e-mail : 暂无
* time : 2021/11/26/16:08
* desc : 多语言适配方案,适配各种版本,核心未替换上下文Context中的Local
*/
public class LanguageUtil
private static final String TAG = "LanguageUtil";
/**
* 默认支持的语言,英语、法语、阿拉伯语
*/
private static HashMap<String, Locale> supportLanguage = new HashMap<String, Locale>(4)
put(Language.ENGLISH, Locale.ENGLISH);
put(Language.FRANCE, Locale.FRANCE);
put(Language.ARABIC, new Locale("ar", "", ""));
;
/**
* 应用多语言切换,重写BaseActivity中的attachBaseContext即可
* 采用本地SP存储的语言
*
* @param context 上下文
* @return context
*/
public static Context attachBaseContext(Context context)
String language = LanguageSp.getLanguage(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
return createConfigurationContext(context, language);
else
return updateConfiguration(context, language);
/**
* 应用多语言切换,重写BaseActivity中的attachBaseContext即可
*
* @param context 上下文
* @param language 语言
* @return context
*/
public static Context attachBaseContext(Context context, String language)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
return createConfigurationContext(context, language);
else
return updateConfiguration(context, language);
/**
* 获取Local,根据language
*
* @param language 语言
* @return Locale
*/
private static Locale getLanguageLocale(String language)
if (supportLanguage.containsKey(language))
return supportLanguage.get(language);
else
Locale systemLocal = getSystemLocal();
for (String languageKey : supportLanguage.keySet())
if (TextUtils.equals(supportLanguage.get(languageKey).getLanguage(), systemLocal.getLanguage()))
return systemLocal;
return Locale.ENGLISH;
/**
* 获取当前的Local,默认英语
*
* @param context context
* @return Locale
*/
public static Locale getCurrentLocale(Context context)
String language = LanguageSp.getLanguage(context);
if (supportLanguage.containsKey(language))
return supportLanguage.get(language);
else
Locale systemLocal = getSystemLocal();
for (String languageKey : supportLanguage.keySet())
if (TextUtils.equals(supportLanguage.get(languageKey).getLanguage(), systemLocal.getLanguage()))
return systemLocal;
return Locale.ENGLISH;
/**
* 获取系统的Local
*
* @return Locale
*/
private static Locale getSystemLocal()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
return Resources.getSystem().getConfiguration().getLocales().get(0);
else
return Locale.getDefault();
/**
* Android 7.1 以下通过 updateConfiguration
*
* @param context context
* @param language 语言
* @return Context
*/
private static Context updateConfiguration(Context context, String language)
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale = getLanguageLocale(language);
Log.e(TAG, "updateLocalApiLow==== " + locale.getLanguage());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
// apply locale
configuration.setLocales(new LocaleList(locale));
else
// updateConfiguration
configuration.locale = locale;
DisplayMetrics dm = resources.getDisplayMetrics();
resources.updateConfiguration(configuration, dm);
return context;
/**
* Android 7.1以上通过createConfigurationContext
* N增加了通过config.setLocales去修改多语言
*
* @param context 上下文
* @param language 语言
* @return context
*/
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
private static Context createConfigurationContext(Context context, String language)
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale = getLanguageLocale(language);
Log.d(TAG, "current Language locale = " + locale);
LocaleList localeList = new LocaleList(locale);
configuration.setLocales(localeList);
return context.createConfigurationContext(configuration);
/**
* 切换语言
*
* @param language 语言
* @param activity 当前界面
* @param cls 跳转的界面
*/
public static void switchLanguage(String language, Activity activity, Class<?> cls)
LanguageSp.setLanguage(activity, language);
Intent intent = new Intent(activity, cls);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
activity.startActivity(intent);
activity.finish();
/**
* 切换语言,携带传递数据
*
* @param language 语言
* @param activity 当前界面
* @param cls 跳转的界面
*/
public static void switchLanguage(String language, Activity activity, Class<?> cls, Bundle bundle)
LanguageSp.setLanguage(activity, language);
Intent intent = new Intent(activity, cls);
if (bundle != null)
intent.putExtras(bundle);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
activity.startActivity(intent);
activity.finish();
/**
* 获取新语言的 Context,修复了androidx.appCompact 1.2.0的问题
*
* @param newBase newBase
* @return Context
*/
public static Context getNewLocalContext(Context newBase)
try
// 多语言适配
Context context = LanguageUtil.attachBaseContext(newBase);
// 兼容appcompat 1.2.0后切换语言失效问题
final Configuration configuration = context.getResources().getConfiguration();
return new ContextThemeWrapper(context, R.style.Theme_AppCompat_Empty)
@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration)
if (overrideConfiguration != null)
overrideConfiguration.setTo(configuration);
super.applyOverrideConfiguration(overrideConfiguration);
;
catch (Exception e)
e.printStackTrace();
return newBase;
/**
* 更新Application的Resource local,应用不重启的情况才调用,因为部分会用到application中的context
* 切记不能走新api createConfigurationContext,亲测
* @param context context
* @param newLanguage newLanguage
*/
public static void updateApplicationLocale(Context context, String newLanguage)
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale locale = getLanguageLocale(newLanguage);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
// apply locale
configuration.setLocales(new LocaleList(locale));
else
configuration.setLocale(locale);
DisplayMetrics dm = resources.getDisplayMetrics();
resources.updateConfiguration(configuration, dm);
qtapplets-国际化多语言设置(代码片段)
QtApplets-国际化多语言设置用了Qt搞了多久的开发,一直没有国际化,也就是多语言设置。今天来简单研究一下。文章目录QtApplets-国际化多语言设置1制作一个简单的界面2在Pro文件中加入翻译模块3制作TS文件4Linguist中打... 查看详情
react项目多语言国际化:react-i18next插件实现——本地数据篇(代码片段)
如何理解多语言国际化?图片中下拉部分已经清楚的说明了多语言国际化是什么了。个人理解:它就是我们在网站上可以通过切换语言类型来实现同一功能的不同语言展示效果。react-i18next介绍react-i18next是一个强大的React/ReactNativ... 查看详情
django国际化(多语言)(代码片段)
1settings.pyMIDDLEWARE=(‘django.contrib.sessions.middleware.SessionMiddleware‘,#‘corsheaders.middleware.CorsMiddleware‘,‘django.middleware.locale.LocaleMiddleware‘,#中间件加上Django国际化中间件‘django.middleware 查看详情
android实现应用内语言切换(包括不重启应用方式)(代码片段)
...#xff0c;可能不仅仅是面向一个国家的用户,所以多语言国际化是移动应用开发中比较常见的一个功能;正常实现多语言国际化,我们只需要在资源目录下res/下创建需要支持的国家values目录,命名格式为values-语言... 查看详情
android:应用多语言切换,国际化实现
参考技术A生成多种语言的string.xml,里面放置对应的语言,修改配置(Configuration),重启之后就会加载对应语言的string.xml。1:在res目录下,生成对应的语言包,比如英语:在res目录下生成了可看到生成了:<stringname="hello&q... 查看详情
javafx:多语言适配(代码片段)
JavaFX:多语言适配JDK国际化:ResourceBundle.html其他资源:TornadoFX编程指南,第10章,FXML和国际化、JavaFX的ResourceBundle使用创建ResourceBundle资源ResourceBundle获取资源publicclassResourceBundleUtilprivatestati 查看详情
低代码平台多语言国际化(i18n)技术方案
国际化(Internationalization,简称i18n):指软件开发应当具备支持多种语言和地区的功能。也就是说能够具备切换页面显示语言的功能。i18n,其中“I”和“n”分别为首末字符,18则为中间的字符数。低代码平台/零代码平台中使用... 查看详情
#前后端国际化多语言配置(代码片段)
前后端国际化多语言配置前端(VueElementUI)项目前端使用Vue+Elementui编写i18n.js在这个js中引入ElementUI的多语言资源,引入本地的多语言资源//I18nimportVueI18nfrom'vue-i18n'importVuefrom'vue'importlocalefrom'element-ui/l... 查看详情
vuedata中使用i18n多语言配置-切换语言不生效-解决computed(代码片段)
写在data初始化的时候拿到这些被国际化的值,并不能响应变化。官方的解决办法是,建议我们将表达式写到computed属性里,不要写到data中使用<div>$t('k.state')</div>//可以动态改变data()returndyh:this.$t('k.sta... 查看详情
国际化intlflutter国际化多语言实践(代码片段)
目标:实现flutter国际化提示:这里参考一下几个链接例如:https://github.com/ThinkerWing/languagehttps://juejin.cn/post/6844903823119482888这篇也很详细,还有包括兼容中文的繁体简体…可以看看feat/use-Flutter-Intl该分支对应的提交... 查看详情
ios国际化(多语言)(代码片段)
一、应用程序国际化包括app名称和各种权限的提示文字。1.1创建工程,再在“PROJECT”的“Info”里面,添加所需语言。1.2从代码中分离出文本创建一个“.strings”扩展名的文件来本地化字符串,需要把这些字符串全部... 查看详情
android通过代码实现多语言切换createconfigurationcontextattachbasecontextgetresourcesupdateconfiguration(代码片段)
updateConfiguration过时兼容处理@OverridepublicResourcesgetResources()//此方法会多次调用Configurationconfiguration=newConfiguration();configuration.smallestScreenWidthDp=900;//updateConfiguration过时兼容处理if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N_MR1)ret... 查看详情
android通过代码实现多语言切换createconfigurationcontextattachbasecontextgetresourcesupdateconfiguration(代码片段)
updateConfiguration过时兼容处理@OverridepublicResourcesgetResources()//此方法会多次调用Configurationconfiguration=newConfiguration();configuration.smallestScreenWidthDp=900;//updateConfiguration过时兼容处理if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N_MR1)ret... 查看详情
多语言国际化(代码片段)
国际化多语言支持是现在系统通常都要具备的功能,Vue对国际化提供了很好的支持。1.安装依赖首先需要安装国际化组件,执行yarnaddvue-i18n命令,安装i18n依赖。2.添加配置在src下新建i18n目录,并创建一个index.js.importVuefrom‘vue‘im... 查看详情
android8.0app内切换语言不生效的问题记录(代码片段)
...应该都只做了中文简体版,但是有部分项目需要面向国际化,甚至可能就是主打国外市场。因此我们有时候会遇到需要APP内做多语言切换的功能需求。如何做多语言切换,网上资料还是很多的,本文也不是记录如... 查看详情
yii2api接口实现国际化多语言设置(代码片段)
1)在/config/main.php下添加如下代码:‘components‘=>[‘language‘=>‘zh-CN‘,‘i18n‘=>[‘translations‘=>[‘*‘=>[‘class‘=>‘yii\\i18n\\PhpMessageSource‘,‘basePath‘=>‘@application/messages‘,//ap 查看详情
[java中实现国际化]-配合thymeleaf实现中英文自动切换(多语言)
MOOC该链接第三章第二节尚硅谷SpringBoot全集web开发国际化 xjbo (7天,过期可以留言索取)resources下建立文件上到下为:默认的,英语(美国),中文(中国)enlogin.btn=SignInlogin.password=PassWordlogin.remember=RememberMelogin.tip=Pleasesigninlogin.usern 查看详情
ios多语言本地化(国际化)设置
...f0c;切换下)—>Info—>Localizations—>设置多语言环境2.国际化应用名称(1)创建InfoPlist.string,并进行Localization配置:在项目中点击New 查看详情