在某些设备上,以编程方式更改语言环境无法正常工作

10

我有下面这段代码:

/**
 * Sets a new Locale for the APP.
 * @param newLocale - Valid new locale.
 */
private static void setLocale( String newLocale )
{
    Locale locale = new Locale( newLocale );
    Locale.setDefault( locale );

    Configuration config = new Configuration();
    config.locale = locale;

    context.getResources().updateConfiguration( config, context.getResources().getDisplayMetrics() );
}

简单。

然而,当我在一个智能手机(4.1.1)上运行它时,它完美地工作。设备会更改字符串以匹配语言。

但是在平板电脑(4.3)上,它不起作用。如果我输出像这样的内容:

Log.d("TAG",Locale.getDefault());

语言环境在两个设备上都被更改了,但是字符串没有被翻译成正确的语言。我已经进行了大量的调试,并且发现了对象之间的差异:

查看4.1.1上的配置对象:

enter image description here

然后再看看平板电脑(4.3)上的配置对象:

enter image description here

可以看到,唯一显著的区别是平板电脑上的 userSetLocale 设置为 False。

因此,我查看了 Google SourceCode (https://github.com/android/platform_frameworks_base/blob/master/core/java/android/content/res/Configuration.java),它指出:

 /**
 * Locale should persist on setting.  This is hidden because it is really
 * questionable whether this is the right way to expose the functionality.
 * @hide
 */
public boolean userSetLocale;

看起来这个问题正在影响我。因此,由于无法通过getter / setter或公共访问来访问此值,我使用了反射来更改它。

然而,在用反射更改它之后,即使我已经看到它在内部更改了(布尔值在反射后被设置为false),仍然存在相同的问题。

你们有什么建议吗?

与此同时,我会继续测试。

谢谢。 测试:

  • Nexus 10 - 4.4.2 - 正常
  • Nexus 5 - 4.4.2 - 正常
  • 平板电脑 320 dpi - 4.4.2 - 正常
  • 智能手机 480 dpi - 4.3 - 正常
  • 智能手机 160 dpi - 4.1.1 - 正常
  • 平板电脑 160 dpi - 4.3 - 不正常
  • 智能手机 320 dpi - 4.1.1 - 正常

好的,我已经完成了测试。我使用Genymotion模拟器和两个真实设备进行了测试。正如你所看到的,存在问题的那个设备似乎是160dpi和4.3英寸的平板电脑。我不知道这是否是该版本的一个错误。我将继续测试其他设备。 - Reinherd
当编译时没有包含所有语言时,这就是一个问题。这就是为什么过去有像 locale 这样的应用程序来解决这个问题。Locale 将被设置,但大部分文本将保持未翻译状态。这个问题没有通用的解决方案,只有解决方法。你唯一能做的就是为该设备自己编译带有适当语言的 Android。你可以在 Android 设置菜单中检查安装和可用的语言。 - Alex van den Hoogen
什么?我猜我没有解释好。我有几个文件夹为每个语言。values-pl,values-zh,values-es,values-en等等。问题是使用我向您展示的方法设置区域设置对于几乎所有设备都有效,因此文本使用正确的值文件夹,但对于某些设备,它被忽略了。 - Reinherd
也许我没有理解问题的复杂性。但是你的意思是在你的应用程序范围内吗?如果你有所有可用的翻译(就像你所说的那样),那么一切都应该改变。在系统级别上,可能会出现自定义区域设置的问题。 - Alex van den Hoogen
是的。翻译没问题,其他设备都可以无缝使用它们。这很奇怪。我已经使用Locale.getAvailableLocales()检查了可用的语言环境,并且有几个语言环境与我的新语言环境匹配,例如es_ES。下周我将尝试弄清楚这是否仅发生在单个设备(Genymotion模拟器)上,还是在真实设备上也会发生。同时,如果您有一些想法,欢迎分享 =) - Reinherd
我在一个与你使用相同配置的GeniMotion模拟器上测试了你的代码,并且它完美运行。我的猜测是你在应用程序中调用方法的位置不正确。 - Emanuel Moecklin
2个回答

5

这是我在本地化方面使用的代码。它被100万人使用,从未听说过任何关于未更改字符串的抱怨,所以我希望它也适用于您:

在类顶部:

Locale myLocale;

功能:

    public void setLocale(String lang) { 
        myLocale = new Locale(lang); 
        Resources res = getResources(); 
        DisplayMetrics dm = res.getDisplayMetrics(); 
        Configuration conf = res.getConfiguration(); 
        conf.locale = myLocale; 
        res.updateConfiguration(conf, dm);
        reloadUI(); // you may not need this, in my activity ui must be refreshed immediately so it has a function like this.
    }

函数调用:

//example for setting English
setLocale("en_gb");

方法有点儿一模一样 :) 创建全新的配置或更新当前配置之间没有区别。正如我所说,这个问题只发生在一个设备上。我猜测ROM根本不正确。 - Reinherd
是的,我知道它们看起来很相似,但并不是“完全”相同。你创建新的配置,我从资源中获取它。尝试这个函数不会有任何损失,它很容易上手^^就像我说的,对于我的项目,我没有收到任何关于Locale的投诉。想和你分享一下。 - canova
你好。我刚刚尝试了一下。同样的情况发生了,我尝试过从创建新的Locale到获取当前Locale并更改它。Configuration也是如此。请检查模拟器,它无法正常工作:http://i.imgur.com/TQtm5iq.png 也许你可以在这个设备上尝试你的APP(这是一个Genymotion模拟器)。 - Reinherd
创建新的配置和更新当前配置并不相同。如果您创建新的配置,您将失去旧值。例如,大文本可访问性设置将不会应用于您的应用程序(菜单和设置字体大小将不反映该设置,这对于视力问题的用户非常有用)。 - Emanuel Moecklin

1

好的,

用户Sir SC提供了一个可行的答案。但是我的代码也可以工作。我们面临的问题是有一个设备忽略了这个语言环境的更改。据我所知,这只是一个设备的问题,可能是由于有缺陷的ROM,因为它是一个Genymotion模拟器。

总的来说,答案是:

  • OP发布的代码是有效且可用的。Sir SC发表的代码也是如此。

干杯。


这不是正确的回答方式。如果一个人已经发布了有效的代码,请将其标记为答案,并在其下面写下您的评论。 - Irshu

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