是否有可能在运行时知道我的应用程序中嵌入了哪些资源语言?
即这个文件夹的存在:
values-en
values-de
values-fr
...
这很复杂,因为即使您有一个名为values-de
它的文件夹也不意味着您在那里有任何资源。如果你有它并不意味着你在那里有字符串值string.xml
。values-de
价值观:
<resources>
<string name="app_name">LocTest</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
</resources>
价值观-de:
<resources>
<string name="hello_world">Hallo Welt!</string>
</resources>
您可以测试特定语言环境的资源是否不同于默认值:
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]);
}
}
它有一个错误——你可以检查一个值是否有翻译。
上面的脏代码将打印如下内容:
LOCALE(5667): 51: en_NZ LOCALE(5667): 52: uk_UA LOCALE(5667): 53: nl_BE LOCALE(5667): 54: de_DE 不同地区(5667): 54: 你好世界!你好世界!de_DE 区域(5667):55:ka_GE 区域(5667):56:sv_SE 区域(5667):57:bg_BG 区域(5667):58:de_CH 不同区域(5667):58:你好世界!你好世界!de_CH LOCALE(5667):59:fr_CH LOCALE(5667):60:fi_FI
AssetManager.getLocales() 实际上就是这样做的方法。但是,从公共 API 中,您创建的每个 AssetManager 的搜索路径中也包含框架资源……因此,当您调用 AssetManager.getLocales() 时,您还将看到属于框架资源一部分的任何语言环境。抱歉,SDK 无法解决此问题。
对于使用 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
因此,在上述任务发生后(在预构建上),BuildConfig.TRANSLATION_ARRAY
您的语言环境列表就会出现。
我不是 Gradle/Groovy 专家,所以这肯定会更整洁一些。
推理 - 我在实施 pawelzieba 的解决方案时遇到了太多问题,因为翻译是众包的,所以我没有可靠的字符串来“比较”。最简单的方法是实际查看可用的 values-blah 文件夹。
受 Mendhak 解决方案的启发,我创建了一些更简洁的东西:
defaultConfig {
....
def locales = ["en", "it", "pl", "fr", "es", "de", "ru"]
buildConfigField "String[]", "TRANSLATION_ARRAY", "new String[]{\""+locales.join("\",\"")+"\"}"
resConfigs locales
}
然后在Java中使用:
BuildConfig.TRANSLATION_ARRAY
这种方法的优点:
受上述答案的启发,我创建了一个简单的方法来根据提供的翻译获取所有应用程序的语言:
public static Set<String> getAppLanguages( Context ctx, int id ) {
DisplayMetrics dm = ctx.getResources().getDisplayMetrics();
Configuration conf = ctx.getResources().getConfiguration();
Locale originalLocale = conf.locale;
conf.locale = Locale.ENGLISH;
final String reference = new Resources( ctx.getAssets(), dm, conf ).getString( id );
Set<String> result = new HashSet<>();
result.add( Locale.ENGLISH.getLanguage() );
for( String loc : ctx.getAssets().getLocales() ){
if( loc.isEmpty() ) continue;
Locale l = Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT_WATCH ? new Locale( loc.substring( 0, 2 ) ) : Locale.forLanguageTag( loc );
conf.locale = l;
if( !reference.equals( new Resources( ctx.getAssets(), dm, conf ).getString( id ) ) ) result.add( l.getLanguage() );
}
conf.locale = originalLocale;
return result;
}
其中 as id
arg 应该使用R.string.some_message
所有翻译中都提供并包含清晰可辨的文本,例如"Do you really want to delete the object?"
也许它会帮助某人......
LocaleList
或者LocaleListCompat
是获得应用程序支持的语言的一种方式。
LocaleList 是在 API 24 中引入的。
使用 LocaleListCompat 时要考虑的事情是,对于 API < 24,只会使用第一个语言标签。
这些 res-lang 实际上取决于语言环境,因此您需要从设备获取语言环境,并且可以从语言环境中获取显示的语言。
Locale myPhoneLocale = Locale.getDefault();
然后,您可以调用 getDisplayLanguage() 以了解正在显示哪种语言。
参考:语言环境
你在说这个吗?
String language = Locale.getDefault().getDisplayLanguage();
受@Injecteer 的代码启发,我做了以下工作:
对于应用程序支持的语言列表,必须通过默认语言,因为无法检测到
public static Map<String,String> getAppLanguages(Context context, String appDefaultLang) {
Map<String, String> listAppLocales = new LinkedHashMap<>();
listAppLocales.put("default","Auto");
DisplayMetrics metrics = new DisplayMetrics();
Resources res = context.getResources();
Configuration conf = res.getConfiguration();
String[] listLocates = res.getAssets().getLocales();
for (String locate : listLocates) {
conf.locale = new Locale(locate);
Resources res1 = new Resources(context.getAssets(), metrics, conf);
String s1 = res1.getString(R.string.title_itinerary);
String value = ucfirst(conf.locale.getDisplayName());
conf.locale = new Locale("");
Resources res2 = new Resources(context.getAssets(), metrics, conf);
String s2 = res2.getString(R.string.title_itinerary);
if (!s1.equals(s2)) {
listAppLocales.put(locate, value);
} else if (locate.equals(appDefaultLang)) {
listAppLocales.put(locate, value);
}
}
return listAppLocales;
}
结果是map<key,value>
应用程序支持的语言列表,第一件事是如果你想用来填充一个listPreference
你的意思是:
String[] locales = getAssets().getLocales();
这将使您获得设备所具有的语言。