2012-07-23 9 views
14

È possibile, in fase di runtime, sapere quali risorse sono incorporate nella mia app?ottenere le lingue delle risorse dell'applicazione

cioè la presenza di questo cartelle:

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

Solo curioso: ma di default non sapresti quali locali ci sono da quando li hai inseriti nell'app? –

+2

Hai ragione!ma sto creando una libreria (quindi gli sviluppatori finali possono aggiungere lingue) e ho bisogno di sapere a livello di programmazione quanti sono incorporati – VinceFR

risposta

10

AssetManager.getLocales() è in realtà il modo per farlo. Tuttavia, dall'API pubblica ogni AssetManager che crei ha anche le risorse del framework incluse nel suo percorso di ricerca ... quindi quando chiami AssetManager.getLocales() vedrai anche le impostazioni locali che fanno parte delle risorse del framework. Non c'è modo di aggirare questo con l'SDK, mi dispiace.

1

Stai parlando di questo?

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

no, questo metodo restituisce solo la lingua predefinita, voglio conoscere tutte le lingue specificate nella mia cartella di ricerca – VinceFR

2

questi res-lang in realtà dipende da locali, quindi è necessario ottenere locale dal dispositivo e si può ottenere che il linguaggio è sempre mostrata dalla locale ..

Locale myPhoneLocale = Locale.getDefault(); 

È quindi possibile chiamare getDisplayLanguage () per sapere quale lingua viene mostrata.

Riferimento: Locale

+0

stessa come utente370305, voglio conoscere tutte le lingue disponibili nella mia app – VinceFR

1

provare a chiamare AssetManager.getLocales():

Ricevere le impostazioni internazionali che questo asset manager contiene i dati per.

Oppure si può provare se è possibile ottenere un elenco utilizzando list().

Restituisce un array di stringhe di tutte le risorse nel percorso specificato.

+0

getLocales() restituiscimi la lingua disponibile sul mio dispositivo, non sulla mia app. L'elenco (percorso stringa) non fa il trucco – VinceFR

0

vuoi dire:

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

Questo potrebbe farvi ottenere la lingua che il dispositivo ha.

+1

Non voglio avere le lingue del mio dispositivo ma la lingua che la mia applicazione ha – VinceFR

11

È complicato perché anche se si dispone di una cartella denominata values-de, ciò non significa che ci siano risorse lì. Se hai string.xml in values-de, non significa che tu abbia il valore di stringa lì.

valori:

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

valori-de:

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

È possibile verificare se una risorsa per un locale specifico è diverso da quello predefinito:

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

ha uno errore: puoi controllare un valore indipendentemente dalla traduzione.

Il codice sporco sopra stamperà qualcosa del tipo:

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! Ciao mondo! de_DE LOCALE (5667): 55: ka_GE LOCALE (5667): 56: sv_SE LOCALE (5667): 57: bg_BG LOCALE (5667): 58: de_CH DIFFERENTE LOCALE (5667): 58: Hallo Welt! Ciao mondo!de_CH LOCALE (5667): 59: fr_CH LOCALE (5667): 60: fi_FI

+0

questa dovrebbe essere una risposta – injecteer

2

Ispirato alle risposte di cui sopra ho creato un metodo semplice per ottenere tutte le lingue di app in base a traduzioni fornite:

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

dove come id arg deve essere utilizzato un R.string.some_message che è fornito in tutte le traduzioni e contiene chiaramente distinguibili il testo, come "Do you really want to delete the object?"

Forse sarebbe d'aiuto a qualcuno ...

2

per chiunque utilizzi Gradle, l'ho fatto in questo modo sotto di esso attraversa tutto strings.xml , prende i nomi delle directory e scopre le impostazioni locali da lì. Si aggiunge un String[] a BuildConfig cui è possibile accedere come 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 

Così, dopo che si verifica l'operazione di cui sopra (sulla prebuild) il BuildConfig.TRANSLATION_ARRAY ha l'elenco delle zone.

Non sono un esperto di Gradle/Groovy quindi questo potrebbe sicuramente essere un po 'più ordinato.

Ragionamento: mi sono imbattuto in troppi problemi nell'implementazione della soluzione di pawelzieba, non ho avuto stringhe affidabili da "confrontare" in quanto le traduzioni erano in crowdsourcing. Il modo più semplice allora era di guardare effettivamente le cartelle dei valori-blah disponibili.

0

Ispirato con il codice @ Injecteer Ho fatto quanto segue:

per l'elenco delle lingue che i supporti app, è necessario passare la lingua predefinita, in quanto non è possibile rilevare

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

il risultato è un elenco map<key,value> delle lingue supportate dall'applicazione, la prima cosa è se si desidera utilizzare per popolare un listPreference

3

Ispirato Mend La soluzione di hak ho creato qualcosa di un po 'più pulito:

defaultConfig { 
     .... 

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

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

Poi in Java utilizzare:

BuildConfig.TRANSLATION_ARRAY 

Advatages di questo metodo:

  • Smaller apk - resConfigs taglierà risorse da librerie che non è necessario (alcuni ne hanno centinaia)
  • Veloce - Nessuna necessità di analizzare le configurazioni delle risorse
Problemi correlati