获取应用程序的资源语言

Vin*_*eFR 19 android

是否有可能在运行时知道我的应用程序中嵌入了哪些资源语言?

即存在这个文件夹:

values-en
values-de
values-fr
...
Run Code Online (Sandbox Code Playgroud)

paw*_*eba 13

它很复杂,因为即使你有一个名为values-de它的文件夹并不意味着你有任何资源.如果你有string.xmlvalues-de这并不意味着你有字符串值存在.

值:

<resources>
    <string name="app_name">LocTest</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
</resources>
Run Code Online (Sandbox Code Playgroud)

值-DE:

<resources>
    <string name="hello_world">Hallo Welt!</string>
</resources>
Run Code Online (Sandbox Code Playgroud)

您可以测试特定区域设置的资源是否与默认值不同:

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
Resources r = getResources();
Configuration c = r.getConfiguration();
String[] loc = r.getAssets().getLocales();
for (int i = 0; i < loc.length; i++) {
    Log.d("LOCALE", i + ": " + loc[i]);

    c.locale = new Locale(loc[i]);
    Resources res = new Resources(getAssets(), metrics, c);
    String s1 = res.getString(R.string.hello_world);
    c.locale = new Locale("");
    Resources res2 = new Resources(getAssets(), metrics, c);
    String s2 = res2.getString(R.string.hello_world);

    if(!s1.equals(s2)){
        Log.d("DIFFERENT LOCALE", i + ": "+ s1+" "+s2 +" "+ loc[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

它有一个错误 - 您可以检查一个值是否有翻译.

上面的脏代码将打印如下:

LOCALE(5667):51:en_NZ LOCALE(5667):52:uk_UA LOCALE(5667):53:nl_BE LOCALE(5667):54:de_DE不同地方(5667):54:Hallo Welt!你好,世界!de_DE LOCALE(5667):55:ka_GE LOCALE(5667):56:sv_SE LOCALE(5667):57:bg_BG LOCALE(5667):58:de_CH不同地方(5667):58:Hallo Welt!你好,世界!de_CH LOCALE(5667):59:fr_CH LOCALE(5667):60:fi_FI


hac*_*bod 10

AssetManager.getLocales()实际上就是这样做的方法.但是,从公共API开始,您创建的每个AssetManager都会在其搜索路径中包含框架资源...因此,当您调用AssetManager.getLocales()时,您还将看到属于框架资源的任何区域设置.抱歉,无法通过SDK解决这个问题.

  • 有`AssetManager.getNonSystemLocales()`,但是在JavaDoc中有我最喜欢的`@ hide`标签。这正是[正是Android用来确定要使用的语言环境的工具](https://android.googlesource.com/platform/frameworks/base/+/c37457799be3db0590a5d94832b2fef5f64ef439/core/java/android/content/res/ResourcesImpl.java#402 )访问您应用中的资源。此外,仅从牛轧糖开始才可用。 (2认同)

Men*_*hak 6

对于任何使用 Gradle 的人,我都是这样做的,它遍历 all strings.xml,获取目录名称并从那里找出语言环境。它增加了一个String[]BuildConfig,你可以作为访问BuildConfig.TRANSLATION_ARRAY

task buildTranslationArray << {
    def foundLocales = new StringBuilder()
    foundLocales.append("new String[]{")

    fileTree("src/main/res").visit { FileVisitDetails details ->
        if(details.file.path.endsWith("strings.xml")){
            def languageCode = details.file.parent.tokenize('/').last().replaceAll('values-','').replaceAll('-r','-')
            languageCode = (languageCode == "values") ? "en" : languageCode;
            foundLocales.append("\"").append(languageCode).append("\"").append(",")
        }
    }

    foundLocales.append("}")
    //Don't forget to remove the trailing comma
    def foundLocalesString = foundLocales.toString().replaceAll(',}','}')
    android.defaultConfig.buildConfigField "String[]", "TRANSLATION_ARRAY", foundLocalesString

}
preBuild.dependsOn buildTranslationArray
Run Code Online (Sandbox Code Playgroud)

因此,在上述任务发生后(在预构建时),就会BuildConfig.TRANSLATION_ARRAY有您的语言环境列表。

我不是 Gradle/Groovy 专家,所以这绝对可以更简洁一些。

推理 - 我在实施 pawelzieba 的解决方案时遇到了太多问题,我没有可靠的字符串来“比较”,因为翻译是众包的。最简单的方法是实际查看可用的 values-blah 文件夹。


Bob*_*ton 5

在Mendhak的解决方案的启发下,我创造了一些更清洁的东西:

    defaultConfig {
        ....

        def locales = ["en", "it", "pl", "fr", "es", "de", "ru"]

        buildConfigField "String[]", "TRANSLATION_ARRAY", "new String[]{\""+locales.join("\",\"")+"\"}"
        resConfigs locales
    }
Run Code Online (Sandbox Code Playgroud)

然后在Java中使用:

BuildConfig.TRANSLATION_ARRAY
Run Code Online (Sandbox Code Playgroud)

这种方法的优点:

  • 较小的apk - resConfigs将从您不需要的库中删除资源(有些有数百个)
  • 快速 - 无需解析资源配置