Android获取设备语言环境

56
在安装我的Android程序时,我会检查设备的语言环境:
String deviceLocale=Locale.getDefault().getLanguage();

如果设备语言在我支持的语言范围内(英语、法语、德语),则我不会更改语言设置。

但是,比如说,如果我不支持设备语言,例如西班牙语。
我会将当前语言环境设置为英语,因为大多数人可以部分理解英语。

Locale locale = new Locale("en");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
pContext.getResources().updateConfiguration(config, null);

但是在其他方法中,当我像这样检查设备的语言环境时:

String deviceLocale=Locale.getDefault().getLanguage();

我的结果显示为“英语”。但设备的区域设置是西班牙语。

getLanguage()方法是否提供当前应用程序的区域设置?
我该如何获取设备的区域设置?

编辑:在应用程序第一次运行时,可以选择保存设备区域设置。但是,如果用户在保存后更改了设备区域设置,则我无法知道设备的新区域设置。我只能知道我在应用安装中保存的区域设置。


如果在设置默认语言环境之后获取它,你会得到你所设置的那个。为了以后需要返回时可以恢复,保存在改变语言环境之前(例如SharedPreference)可能是一个选项。 - Phantômaxx
但是当我回去加载我保存的语言环境值时,我得到最新已知的设备语言环境。但是在保存之后,如果用户更改了设备的语言环境,我就无法知道设备当前的语言环境? - trante
这是一个很好的观点。我的方法有点像是一个hack。我仍然相信,在手机寿命内多次更改设备语言设置并不会带来太多乐趣...或者更“有趣”的说法是,一天内多次更改。无论如何,你是对的 - 我的hack并没有真正解决问题。 - Phantômaxx
2
通常最好修改现有对象而不是创建自己的对象,只需修改现有对象中的字段即可。 当您创建新的“Configuration”对象时,构造函数会在内部调用“setToDefaults()”。 如果您不小心,这可能会覆盖您在其他地方对配置所做的一些更改。 这与您的问题无关,但这只是一个好的经验法则。 因此,不要创建新对象,而是调用“getResources()。getConfiguration()”。 - telkins
您可以通过监听LOCALE_CHANGED广播来检测区域设置的更改。但是,该意图似乎不包括新的Locale,因此您将不得不依赖@shoe的答案来获取新的Locale。 - naw
7个回答

95

有一种比使用反射或解析某些系统属性更简单、更清洁的方法来实现这一点。

当你在应用程序中设置默认语言环境后,你就无法再访问系统默认语言环境了。你在应用程序中设置的默认语言环境只在应用程序生命周期内有效。无论你在Locale.setDefault(Locale) 中设置什么都会在进程终止时消失。当应用程序重新启动时,你将能够再次读取系统默认语言环境。

因此,你所需要做的就是在应用程序启动时检索系统默认语言环境,只要应用程序运行,就将其记住,并在用户决定在Android设置中更改语言时进行更新。因为我们只需要这个信息在应用程序运行的时间内,所以我们可以将它简单地存储在一个静态变量中,该变量可以从应用程序的任何位置访问。

以下是如何实现:

public class MyApplication extends Application {
    
    public static String sDefSystemLanguage;
    
    @Override
    public void onCreate() {
        super.onCreate();

        sDefSystemLanguage = Locale.getDefault().getLanguage();
    }

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

        sDefSystemLanguage = newConfig.locale.getLanguage();
    }

}

使用一个应用程序(不要忘记在您的清单文件中定义它),我们可以在应用启动时(onCreate())获取默认语言环境,并在用户在Android设置中更改语言时(onConfigurationChanged(Configuration))更新它。这就是全部。

每当您需要知道在使用setDefault调用之前系统默认语言是什么,sDefSystemLanguage将为您提供答案。

我在您的代码中发现了一个问题。当您设置新的Locale时,您所做的是:

Configuration config = new Configuration();
config.locale = locale;
pContext.getResources().updateConfiguration(config, null);

当你这样做时,你会覆盖所有可能想要保留的配置信息。例如,Configuration.fontScale反映了辅助功能设置中“大号字体”的设置。通过设置语言并且失去其他所有的配置信息,你的应用程序将不再反映“大号字体”设置,这意味着文本比应该小(如果用户已启用大号字体设置)。

正确的方法是:

Resources res = pContext.getResources();
Configuration config = res.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    configuration.setLocale(locale);
}
else {
    configuration.locale = locale;
}
res.updateConfiguration(config, null);
所以,我们不创建新的Configuration对象,而是更新当前的配置对象。

2
谢谢您提供有关 new Configuration() 问题的信息和额外信息。 - trante
这真的很详细。喜欢这些细节,样例随处可见! - sud007

58

更新:如评论中所指出,“locale”字段已过时,您需要使用getLocales()代替。

defaultLocale = Resources.getSystem().getConfiguration().getLocales().get(0);

您可以通过以下方式访问全局区域设置 -

defaultLocale = Resources.getSystem().getConfiguration().locale;

请查看http://developer.android.com/reference/android/content/res/Resources.html#getSystem() -

返回一个全局共享的Resources对象,该对象提供对仅系统资源(无应用程序资源)的访问。


3
这是正确的解决方案!Locale.getDefault().getLanguage()将给出应用程序设置的语言而不是手机的语言。 - nizam.sp
找到这个评论花了我太长时间了!这就是我要找的,如何获取设备的默认语言,然后根据此更改应用程序的语言。谢谢! - Mikkel Larsen

8

设计应用程序的最佳方式是使用默认语言,例如英语,在values/下,并且您可以在values-XX/下添加其他语言。这样当Android不支持某种语言时,就会回退到您的默认语言,即英语。让操作系统为您完成这项工作 :) 但是,如果更改区域设置,则会获取上次的设置,因此必须将该信息保存在某个地方。


3

当您通过编程方式更改应用程序语言,例如:Application language programatically

Locale locale = new Locale("en");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
pContext.getResources().updateConfiguration(config, null);

And

But after that, in other methods, when I check device's locale like this:

String deviceLocale=Locale.getDefault().getLanguage();
I get result as "English". But device's locale is Spanish.

所以,不要使用那个代码,而是使用下面的代码来获取设备的本地信息。
try {
    Process exec = Runtime.getRuntime().exec(new String[]{"getprop", "persist.sys.language"});
    String locale = new BufferedReader(new InputStreamReader(exec.getInputStream())).readLine();
    exec.destroy();
    Log.e("", "Device locale: "+locale);
} catch (IOException e) {
    e.printStackTrace();
}
输出: 西班牙语 查看这个 希望这正是您所寻找的。

2

您应该使用String deviceLocale= Locale.getDefault().getDisplayLanguage();来显示语言,而不是

String deviceLocale=Locale.getDefault().getLanguage();

如果上面的方法不起作用,可以查看这个答案,它可能会对你有所帮助。 点击此处


1
尽管@user2944616的回答在政治上是正确的,但这并没有回答实际提出的问题。
因此,如果我真的需要知道用户设置的系统区域设置,我会使用反射(目前不知道更好的选择):
private String getSystemPropertyValue(String name) {
    try {
        Class<?> systemProperties = Class.forName("android.os.SystemProperties");
        try {
            Method get = systemProperties.getMethod("get", String.class, String.class);
            if (get == null) {
                return "Failure!?";
            }
            try {
                return (String)get.invoke(systemProperties, name, "");
            } catch (IllegalAccessException e) {
                return "IllegalAccessException";
            } catch (IllegalArgumentException e) {
                return "IllegalArgumentException";
            } catch (InvocationTargetException e) {
                return "InvocationTargetException";
            }
        } catch (NoSuchMethodException e) {
            return "SystemProperties.get(String key, String def) method is not found";
        }
    } catch (ClassNotFoundException e) {
        return "SystemProperties class is not found";
    }
}

给定这个条件,并将设备语言设置为西班牙语(美国)/Español (Estados Unidos),以下字符串。
<string name="system_locale">System locale: <xliff:g id="profile_name">%1$s</xliff:g>&#95;<xliff:g id="device_name">%2$s</xliff:g></string>

和这段代码

private static final String SYS_COUNTRY = "persist.sys.country";
private static final String SYS_LANG = "persist.sys.language";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TextView tv = (TextView)findViewById(R.id.locale);
    tv.setText(getString(R.string.system_locale, getSystemPropertyValue(SYS_LANG),
            getSystemPropertyValue(SYS_COUNTRY)));
}

产生以下屏幕:

System locale screenshot

如果需要的话,也可以轻松地使用上述方法构建Locale实例:
Locale locale = new Locale(getSystemPropertyValue(SYS_LANG),
        getSystemPropertyValue(SYS_COUNTRY));
Log.d(TAG, "Language: " + locale.getLanguage());
Log.d(TAG, "Country: " + locale.getCountry());

日志输出:

D/GetSystemLocale(5697): Language: es
D/GetSystemLocale(5697): Country: US

希望这有所帮助。

1
对我来说,这似乎是最好的方法。避免使用反射的一种方式是仅执行getprop命令并解析输出。您还可以获取TTS系统的国家语言 - naw
TTS 引擎的默认语言可能与系统区域设置不同。 - ozbek

-1

要获取设备的语言环境,请使用以下代码

Locale current = context.getResources().getConfiguration().locale;

current.toString() 将会返回你 "en"、"ar" 等内容


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接