2012-07-23 16 views
14

¿Es posible, en tiempo de ejecución, saber qué idiomas de recursos están incrustados en mi aplicación?obtener los lenguajes de recursos de la aplicación

es decir la presencia de este carpetas:

values-en 
values-de 
values-fr 
... 
+1

Simplemente curioso: pero, por defecto, ¿no sabrías qué configuraciones regionales hay allí desde que las pones en la aplicación? –

+2

¡Tienes razón!pero estoy creando una biblioteca (para que los desarrolladores finales puedan agregar idiomas) y necesito saber de forma programática cuántos están incrustados – VinceFR

Respuesta

10

AssetManager.getLocales() es en realidad la forma de hacerlo. Sin embargo, desde la API pública, cada AssetManager que usted crea también tiene los recursos de la infraestructura incluidos en su ruta de búsqueda ... de modo que cuando llame a AssetManager.getLocales() también verá las configuraciones regionales que son parte de los recursos de la infraestructura. No hay forma de evitar esto con el SDK, lo siento.

1

¿Estás hablando de esto?

String language = Locale.getDefault().getDisplayLanguage(); 
+0

no, este método simplemente devuelve el idioma predeterminado, quiero saber todos los idiomas especificados en mi carpeta de res – VinceFR

2

estos res-lang en realidad depende de variantes regionales, por lo que necesita para obtener la configuración regional del dispositivo y se puede obtener en qué idioma está consiguiendo muestra de locale ..

Locale myPhoneLocale = Locale.getDefault(); 

A continuación, puede llamar getDisplayLanguage () para saber qué idioma se está mostrando.

Referencia: Locale

+0

mismo como usuario370305, quiero saber todos los idiomas disponibles en mi aplicación – VinceFR

1

intente llamar AssetManager.getLocales():

Obtener los lugares que este gestor de activos contiene datos para.

O puede probar si se puede obtener una lista usando list().

Devuelve una matriz de cadenas de todos los recursos en la ruta especificada.

+0

getLocales() devuélvame el idioma disponible en mi dispositivo, no en mi aplicación. lista (ruta de cadena) no funciona – VinceFR

0

Qué quiere decir:

String[] locales = getAssets().getLocales(); 

Esto le permitiría obtener el idioma que el dispositivo tiene.

+1

No quiero tener los idiomas que mi dispositivo tiene pero el lenguaje que mi aplicación tiene – VinceFR

11

Es complicado porque incluso si tiene una carpeta llamada values-de, no significa que tenga recursos allí. Si tiene string.xml en values-de, no significa que tenga un valor de cadena allí.

valores:

<resources> 
    <string name="app_name">LocTest</string> 
    <string name="hello_world">Hello world!</string> 
    <string name="menu_settings">Settings</string> 
</resources> 

valores de:

<resources> 
    <string name="hello_world">Hallo Welt!</string> 
</resources> 

Se puede comprobar si un recurso para una configuración regional específica es diferente de la predeterminada:

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]); 
    } 
} 

Tiene uno falla: puede verificar un valor si tiene traducción.

El código sucio anteriormente imprimirá algo como:

LOCALE (5667): 51: en_NZ LOCALE (5667): 52: uk_UA LOCALE (5667): 53: nl_BE LOCALE (5667): 54 : de_DE DIFERENTE LOCALE (5667): 54: ¡Hola, Welt! ¡Hola mundo! de_DE LOCALE (5667): 55: ka_GE LOCALE (5667): 56: sv_SE LOCALE (5667): 57: bg_BG LOCALE (5667): 58: de_CH DIFERENTE LOCALE (5667): 58: ¡Hola Welt! ¡Hola Mundo!de_CH LOCALE (5667): 59: fr_CH LOCALE (5667): 60: fi_FI

+0

esto debería ser una respuesta – injecteer

2

Inspirado por las respuestas anteriores he creado un método sencillo para obtener todos los lenguajes de aplicaciones basado en traducciones proporcionadas:

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; 
} 

donde como id arg debe utilizar un R.string.some_message que se proporciona en todas las traducciones y contiene claramente distinguible texto, como "Do you really want to delete the object?"

tal vez sería ayudar a alguien ...

2

Para cualquier persona que utilice Gradle, lo hice como es abajo que atraviesa toda strings.xml , toma los nombres de directorio y calcula las configuraciones regionales desde allí. Se añade un String[] a BuildConfig que se puede acceder como 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 

Así se produce después de la tarea anterior (en prebuild) la BuildConfig.TRANSLATION_ARRAY tiene su lista de configuraciones regionales.

No soy un experto en Gradle/Groovy así que definitivamente podría ser un poco mejor.

Razonamiento: me encontré con demasiados problemas al implementar la solución de pawelzieba, no tenía cadenas confiables para 'comparar' ya que las traducciones eran de fuente abierta. La manera más fácil era mirar las carpetas de valores disponibles.

0

Inspirado por el código por @ Injecteer he hecho lo siguiente:

de la lista de idiomas que los soportes de aplicaciones, es necesario pasar el idioma por defecto, ya que no es posible detectar

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; 
} 

el resultado es una lista map<key,value> de idiomas soportados por la aplicación, la primera cosa es si usted desea utilizar para rellenar un listPreference

3

Inspirado por Mend La solución de hak he creado algo un poco más limpia:

defaultConfig { 
     .... 

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

     buildConfigField "String[]", "TRANSLATION_ARRAY", "new String[]{\""+locales.join("\",\"")+"\"}" 
     resConfigs locales 
    } 

Luego, en Java utilizan:

BuildConfig.TRANSLATION_ARRAY 

Advatages de este método:

  • apk Menor - resConfigs cortará los recursos de las bibliotecas de los cuales no es necesario (algunos tienen cientos)
  • Rápido: no es necesario analizar las configuraciones de recursos
Cuestiones relacionadas