如何从Android中的不同语言环境获取字符串?


76

因此,无论设备/应用程序当前的语言环境设置如何,我都希望在多个语言环境中获取String的值。我该怎么办?

基本上我需要的是功能getString(int id, String locale)而不是功能getString(int id)

我该怎么办?

谢谢


1
您实际上是如何实现的?请回复:)
Rakeeb Rajbhandari 2014年

作为公认的答案
阳2014年

ResourceBundle应该是指资产?还是他们可以访问我们的res文件夹?
Rakeeb Rajbhandari 2014年

@chengyang请更改接受的答案
jonathanrz

您需要指定比平常其他的语言吗?如果您使用不同的语言资源,则在执行操作时getString(R.strings.text),将获得用户语言中的字符串(如果用户语言是没有文件夹,则为默认值)
Lucas Queiroz Ribeiro

Answers:


139

注意如果您的最低API为17+,请直接跳至此答案的底部。否则,请继续阅读...

注意如果使用的是App Bundle,则需要确保禁用语言拆分或动态安装其他语言。请参阅https://stackoverflow.com/a/51054393。如果不这样做,它将始终使用后备。

如果您有用于不同语言环境的各种res文件夹,则可以执行以下操作:

Configuration conf = getResources().getConfiguration();
conf.locale = new Locale("pl");
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
Resources resources = new Resources(getAssets(), metrics, conf);
String str = resources.getString(id);

另外,您也可以使用@jyotiprakash指向的方法重新开始活动。

注意Resources像这样调用构造函数会在Android内部进行一些更改。您必须使用原始语言环境调用构造函数,以使事情恢复原样。

编辑从特定语言环境中检索资源的方法略有不同(且更为简洁):

Resources res = getResources();
Configuration conf = res.getConfiguration();
Locale savedLocale = conf.locale;
conf.locale = desiredLocale; // whatever you want here
res.updateConfiguration(conf, null); // second arg null means don't change

// retrieve resources from desired locale
String str = res.getString(id);

// restore original locale
conf.locale = savedLocale;
res.updateConfiguration(conf, null);

从API级别17开始,您应该使用conf.setLocale()而不是直接设置conf.locale。如果您恰巧在从右到左和从左到右的语言环境之间进行切换,这将正确更新配置的布局方向。(布局方向在17中介绍。)

创建新Configuration对象(如@Nulano在评论中建议的那样)没有任何意义,因为调用updateConfiguration将更改通过调用获得的原始配置res.getConfiguration()

getString(int id, String locale)如果您要为区域设置加载多个字符串资源,我会毫不犹豫地将其捆绑为一个方法。更改语言环境(使用任何一种方法)都要求框架进行大量重新绑定所有资源的工作。最好一次更新区域设置,检索所需的所有内容,然后再设置区域设置。

编辑(感谢@Mygod):

如果您的最低API级别为17+,则有更好的方法,如另一个线程上的此答案所示。例如,您可以使用以下Resource对象创建多个对象,每个对象分别用于所需的语言环境:

@NonNull Resources getLocalizedResources(Context context, Locale desiredLocale) {
    Configuration conf = context.getResources().getConfiguration();
    conf = new Configuration(conf);
    conf.setLocale(desiredLocale);
    Context localizedContext = context.createConfigurationContext(conf);
    return localizedContext.getResources();
}

然后,只需Resource从此方法返回的本地化对象中检索所需的资源即可。检索资源后,无需重置任何内容。


1
您不应该从返回的配置中进行新配置getResources().getConfiguration()吗?根据GrepCode,它返回存储在资源中的本地实例。之后更改语言环境字段可能是Android感到困惑的真正原因。您可能应该conf = new Configuration(conf);在第一行和第二行之间执行(克隆返回的配置)。
Nulano

@Nulano-值得尝试,但是我不认为这就是为什么Android感到“困惑”的根源(如您所说)。查看Resources构造函数的源代码,您将看到创建这样的新Resources对象会更改流程资产(显然是单例)中的内容。一旦我意识到需要重新设置一切,我就不必费心寻找确切的原因。构造新Resources对象的另一种方法(也许更清洁)是resources.updateConfiguration(conf, null)在更改区域设置后调用。
Ted Hopp

1
API级别17+中有更好的API:stackoverflow.com/a/33629163/2245107
Mygod

@Mygod-是的,这似乎是正确的方法。我将更新答案以表明这一点。谢谢!
Ted Hopp

1
在答案中编辑了有关默认情况下打破捆绑功能的应用捆绑包的注释,因为捆绑包用户仅会接受一种语言。有关如何解决此问题,请参阅stackoverflow.com/a/51054393
卡斯滕·哈格曼

31

这是Ted Hopp描述的方法的组合版本。这样,该代码可用于任何Android版本:

public static String getLocaleStringResource(Locale requestedLocale, int resourceId, Context context) {
    String result;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { // use latest api
        Configuration config = new Configuration(context.getResources().getConfiguration());
        config.setLocale(requestedLocale);
        result = context.createConfigurationContext(config).getText(resourceId).toString();
    }
    else { // support older android versions
        Resources resources = context.getResources();
        Configuration conf = resources.getConfiguration();
        Locale savedLocale = conf.locale;
        conf.locale = requestedLocale;
        resources.updateConfiguration(conf, null);

        // retrieve resources from desired locale
        result = resources.getString(resourceId);

        // restore original locale
        conf.locale = savedLocale;
        resources.updateConfiguration(conf, null);
    }

    return result;
}

用法示例:

String englishName = getLocaleStringResource(new Locale("en"), R.string.name, context);

注意

如原始答案中所述,用单个配置更改和多个resource.getString()调用替换上述代码的多个调用可能会更有效。


2

根据以上答案,这些功能很棒但有点复杂。试试这个简单的功能:

public String getResStringLanguage(int id, String lang){
    //Get default locale to back it
    Resources res = getResources();
    Configuration conf = res.getConfiguration();
    Locale savedLocale = conf.locale;
    //Retrieve resources from desired locale
    Configuration confAr = getResources().getConfiguration();
    confAr.locale = new Locale(lang);
    DisplayMetrics metrics = new DisplayMetrics();
    Resources resources = new Resources(getAssets(), metrics, confAr);
    //Get string which you want
    String string = resources.getString(id);
    //Restore default locale
    conf.locale = savedLocale;
    res.updateConfiguration(conf, null);
    //return the string that you want
    return string;
}

然后简单地调用它: String str = getResStringLanguage(R.string.any_string, "en");

快乐的代码:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.