Получить языки приложений - программирование
Подтвердить что ты не робот

Получить языки приложений

Возможно ли во время выполнения знать, какие языки ресурсов встроены в мое приложение?

Присутствие этих папок:

values-en
values-de
values-fr
...
4b9b3361

Ответ 1

AssetManager.getLocales() на самом деле способ сделать это. Однако из публичного API каждый созданный AssetManager также имеет ресурсы фреймворка, включенные в его путь поиска... поэтому, когда вы вызываете AssetManager.getLocales(), вы также увидите любые локали, которые являются частью ресурсов фреймворка. Невозможно обойти это с помощью SDK, извините.

Ответ 2

Это сложно, потому что даже если у вас есть папка с именем 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>

значения-де:

<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: ru_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 РАЗНОЕ LOCALE (5667): 58: Hallo Welt! Привет мир! de_CH LOCALE (5667): 59: fr_CH LOCALE (5667): 60: fi_FI

Ответ 3

Вдохновленный решением Мендхака, я создал нечто более чистым:

    defaultConfig {
        ....

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

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

Затем в Java используйте:

BuildConfig.TRANSLATION_ARRAY

Адвокаты этого метода:

  • Меньший apk-resConfigs вырезает ресурсы из библиотек, которые вам не нужны (некоторые из них сотни)
  • Быстрый - не нужно анализировать конфигурации ресурсов.

Ответ 4

Для тех, кто использует 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

Итак, после выполнения вышеуказанной задачи (в prebuild) BuildConfig.TRANSLATION_ARRAY имеет свой список локалей.

Я не эксперт Gradle/Groovy, поэтому это определенно может быть немного опрятным.

Рассуждение - я столкнулся с множеством проблем, реализующих решение pawelzieba, у меня не было надежных строк для сравнения, поскольку переводы были краудсорсированы. Самый простой способ - это посмотреть на доступные папки "ценности-бла".

Ответ 5

Вдохновленный ответами выше, я создал простой способ получить все языки приложений на основе предоставленных переводов:

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?"

Может быть, это поможет кому-то...

Ответ 6

эти res-lang фактически зависят от Locales, поэтому вам нужно получить локаль с устройства, и вы можете получить, какой язык будет отображаться в локали.

Locale myPhoneLocale = Locale.getDefault();

Затем вы можете вызвать getDisplayLanguage(), чтобы узнать, какой язык отображается.

Ссылка: Locale

Ответ 7

Вы об этом говорите?

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

Ответ 8

Попробуйте позвонить AssetManager.getLocales():

Получить локали, для которых этот менеджер активов содержит данные.

Или вы можете попробовать, если вы можете получить список, используя list().

Возвращает массив String всех активов по заданному пути.

Ответ 9

Вы имеете в виду:

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

Это позволит вам получить язык, который имеет ваше устройство.

Ответ 10

Вдохновленный кодом @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

Ответ 11

LocaleList или LocaleListCompat - один из способов получения языков, поддерживаемых вашим приложением.

LocaleList был представлен в API 24.

При использовании LocaleListCompat следует учитывать, что для API <24 будет использоваться только первый языковой тег.