是否有可能在运行时知道我的应用中嵌入了哪些资源语言?
即存在此文件夹:
values-en
values-de
values-fr
...
答案 0 :(得分:13)
这很复杂,因为即使你有一个名为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 DIFFERENT LOCALE(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不同 LOCALE(5667):58:Hallo Welt!你好,世界! de_CH LOCALE(5667):59: fr_CH LOCALE(5667):60:fi_FI
答案 1 :(得分:10)
AssetManager.getLocales()实际上就是这样做的方法。但是,从公共API开始,您创建的每个AssetManager都会在其搜索路径中包含框架资源...因此,当您调用AssetManager.getLocales()时,您还将看到属于框架资源的任何区域设置。抱歉,没有办法解决这个问题。
答案 2 :(得分:5)
受到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
推广此方法:
答案 3 :(得分:3)
对于任何使用Gradle的人,我都这样做,它会遍历所有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解决方案的问题,我没有可靠的字符串来比较&#39;因为翻译是众包的。最简单的方法是实际查看可用的值 - 文件夹。
答案 4 :(得分:2)
受上述答案的启发,我创建了一种基于提供的翻译获取所有应用程序语言的简单方法:
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;
}
id
arg应使用R.string.some_message
所有翻译中提供的"Do you really want to delete the object?"
并包含明确可区分的文字,例如Imports System
Imports System.Reflection
Module M
Sub Main()
AddHandler C1.Bang, AddressOf SomeAction
C1.Test()
AddHandler C2.Boom, AddressOf SomeAction
C2.Test()
' Check which GetRaiseMethod find something
Dim bangRaiseAccessor As MethodInfo = GetType(C1).GetEvent("Bang").GetRaiseMethod(True)
Dim boomRaiseAccessor As MethodInfo = GetType(C2).GetEvent("Boom").GetRaiseMethod(True)
Console.WriteLine("M: GetRaiseMethod(True) for C1.Bang: {0}",
If(bangRaiseAccessor, DirectCast("<none>", Object))
)
Console.WriteLine("M: GetRaiseMethod(True) for C2.Boom: {0}",
If(boomRaiseAccessor, DirectCast("<none>", Object))
)
End Sub
Private Sub SomeAction()
Console.WriteLine("M: Inside 'SomeAction'.")
End Sub
End Module
Class C1
' auto-event; backing delegate type, backing field and accessor methods are compiler-generated
Shared Event Bang()
Private Shared Sub OnBang() Handles Me.Bang
Console.WriteLine("C1: Inside 'OnBang'.")
End Sub
Shared Sub Test()
Console.WriteLine("C1: Test firing event Bang.")
RaiseEvent Bang()
Console.WriteLine("C1: Test finished.")
End Sub
End Class
Class C2
Shared Custom Event Boom As Action
AddHandler(value As Action)
Console.WriteLine("C2: Inside custom AddHandler accessor, 'value' contains '{0}'.",
If(value = Nothing, "<none>", value.Method.ToString())
)
' TODO: use parameter, for example aggregate "value" in field with delegate combination
End AddHandler
RemoveHandler(value As Action)
Console.WriteLine("C2: Inside custom RemoveHandler accessor, 'value' contains '{0}'.",
If(value = Nothing, "<none>", value.Method.ToString())
)
' TODO: use parameter, for example subtract "value" from field with delegate removal
End RemoveHandler
RaiseEvent()
Console.WriteLine("C2: Inside custom RaiseEvent accessor.")
End RaiseEvent
End Event
Private Shared Sub OnBoom() Handles Me.Boom
Console.WriteLine("C2: Inside 'OnBoom'.")
End Sub
Shared Sub Test()
Console.WriteLine("C2: Test firing event Boom.")
RaiseEvent Boom()
Console.WriteLine("C2: Test finished.")
End Sub
End Class
也许这对某人有帮助......
答案 5 :(得分:1)
这些res-lang实际上依赖于Locales,因此您需要从设备获取区域设置,并且您可以从区域设置中获取显示的语言..
Locale myPhoneLocale = Locale.getDefault();
然后,您可以调用getDisplayLanguage()来了解要显示的语言。
参考:Locale
答案 6 :(得分:0)
你在说这个吗?
String language = Locale.getDefault().getDisplayLanguage();
答案 7 :(得分:0)
答案 8 :(得分:0)
你的意思是:
String[] locales = getAssets().getLocales();
这样可以让您获得设备所具有的语言。
答案 9 :(得分:0)
受@ 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,那么第一件事就是
答案 10 :(得分:0)
LocaleList
或LocaleListCompat
是获得应用程序支持的语言的一种方法。
LocaleList在API 24中引入。
使用LocaleListCompat时要考虑的事情是对于API <24,仅会使用第一个语言标记。