Как получить строку из разных локалей в Android?

Поэтому я хочу получить значение String в нескольких локалях независимо от текущей настройки локали устройства / приложения. Как мне это сделать?

В основном мне нужна функция getString(int id, String locale) скорее, чем getString(int id)

Как я мог это сделать?

Спасибо

9 ответов

Решение

ПРИМЕЧАНИЕ Если ваш минимальный API 17+, перейдите прямо к нижней части этого ответа. В противном случае читайте дальше...

Если у вас есть разные папки res для разных локалей, вы можете сделать что-то вроде этого:

Configuration conf = getResources().getConfiguration();
conf.locale = new Locale("pl");
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
Resources resources = new Resources(getAssets(), metrics, conf);
String str = resources.getString(id);

Кроме того, вы можете просто возобновить свою деятельность, используя метод, на который указывает @jyotiprakash.

ПРИМЕЧАНИЕ Вызов Resources конструктор, как это меняет что-то внутренне в Android. Вам придется вызывать конструктор с исходным языком, чтобы вернуть вещи такими, какими они были.

РЕДАКТИРОВАТЬ Немного другой (и несколько более чистый) рецепт для извлечения ресурсов из определенной локали:

Resources res = getResources();
Configuration conf = res.getConfiguration();
Locale savedLocale = conf.locale;
conf.locale = desiredLocale; // whatever you want here
res.updateConfiguration(conf, null); // second arg null means don't change

// retrieve resources from desired locale
String str = res.getString(id);

// restore original locale
conf.locale = savedLocale;
res.updateConfiguration(conf, null);

Начиная с уровня API 17, вы должны использовать conf.setLocale() вместо прямой настройки conf.locale, Это правильно обновит направление компоновки конфигурации, если вы переключаетесь между языками справа налево и слева направо. (Направление расположения было введено в 17).

Нет смысла создавать новый Configuration объект (как @Nulano предлагает в комментарии), потому что вызов updateConfiguration собирается изменить исходную конфигурацию, полученную путем вызова res.getConfiguration(),

Я не хотел бы связать это в getString(int id, String locale) метод, если вы собираетесь загружать несколько строковых ресурсов для локали. Изменение локалей (с использованием любого рецепта) требует от каркаса много работы, связывая все ресурсы. Гораздо лучше обновить локали один раз, извлечь все, что вам нужно, а затем вернуть локаль обратно.

РЕДАКТИРОВАТЬ (благодаря @Mygod):

Если ваш минимальный уровень API 17+, есть гораздо лучший подход, как показано в этом ответе в другом потоке. Например, вы можете создать несколько Resource объекты, по одному на каждую нужную локаль, с:

@NonNull Resources getLocalizedResources(Context context, Locale desiredLocale) {
    Configuration conf = context.getResources().getConfiguration();
    conf = new Configuration(conf);
    conf.setLocale(desiredLocale);
    Context localizedContext = context.createConfigurationContext(conf);
    return localizedContext.getResources();
}

Затем просто получите нужные вам ресурсы из локализованного Resource объект, возвращаемый этим методом. Там нет необходимости сбрасывать что-либо, как только вы получили ресурсы.

Вот комбинированная версия подходов, описанных Тедом Хоппом. Таким образом, код работает для любой версии Android:

public static String getLocaleStringResource(Locale requestedLocale, int resourceId, Context context) {
    String result;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { // use latest api
        Configuration config = new Configuration(context.getResources().getConfiguration());
        config.setLocale(requestedLocale);
        result = context.createConfigurationContext(config).getText(resourceId).toString();
    }
    else { // support older android versions
        Resources resources = context.getResources();
        Configuration conf = resources.getConfiguration();
        Locale savedLocale = conf.locale;
        conf.locale = requestedLocale;
        resources.updateConfiguration(conf, null);

        // retrieve resources from desired locale
        result = resources.getString(resourceId);

        // restore original locale
        conf.locale = savedLocale;
        resources.updateConfiguration(conf, null);
    }

    return result;
}

Пример использования:

String englishName = getLocaleStringResource(new Locale("en"), R.string.name, context);

Заметка

Как уже указывалось в исходном ответе, может быть более эффективным заменить несколько вызовов вышеуказанного кода одним изменением конфигурации и несколькими вызовами resources.getString().

Основываясь на приведенных выше ответах, которые удивительны, но немного сложны. попробуйте эту простую функцию:

public String getResStringLanguage(int id, String lang){
    //Get default locale to back it
    Resources res = getResources();
    Configuration conf = res.getConfiguration();
    Locale savedLocale = conf.locale;
    //Retrieve resources from desired locale
    Configuration confAr = getResources().getConfiguration();
    confAr.locale = new Locale(lang);
    DisplayMetrics metrics = new DisplayMetrics();
    Resources resources = new Resources(getAssets(), metrics, confAr);
    //Get string which you want
    String string = resources.getString(id);
    //Restore default locale
    conf.locale = savedLocale;
    res.updateConfiguration(conf, null);
    //return the string that you want
    return string;
}

Тогда просто назовите это: String str = getResStringLanguage(R.string.any_string, "en");

Счастливый код:)

поместите эту функцию расширения Kotlin в свой код и используйте ее следующим образом:

getLocaleStringResource(Locale.ENGLISH,R.string.app_name)

      fun Context.getLocaleStringResource(
requestedLocale: Locale?,
resourceId: Int,
): String {
val result: String
val config =
    Configuration(resources.configuration)
config.setLocale(requestedLocale)
result = createConfigurationContext(config).getText(resourceId).toString()

return result
}
      object Language {

    var locale: Locale? = null



    fun getLocaleStringResource(
        resourceId: Int,
        requestedLocale: Locale? = locale,
    ): String = with(game.activity) { Configuration(resources.configuration).run {
        setLocale(requestedLocale)
        createConfigurationContext(this).getText(resourceId).toString()
    } }

}

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

      fun Context.getLocaleStringResource(
localeName: String,
resourceId: Int,
): String {
    val config = Configuration(resources.configuration)
    config.setLocale(Locale(localeName))

    return createConfigurationContext(config).getText(resourceId).toString()
}

Затем позвоните:

      getLocaleStringResource("en", R.string.app_name)

Я создал эти две функции расширения для Kotlin:

      fun Context.getString(locale: Locale, @StringRes resId: Int, vararg formatArgs: Any): String {
    var conf: Configuration = resources.configuration
    conf = Configuration(conf)
    conf.setLocale(locale)
    val localizedContext = createConfigurationContext(conf)
    return localizedContext.resources.getString(resId, *formatArgs)
}

fun Context.getString(locale: Locale, @StringRes resId: Int): String {
    var conf: Configuration = resources.configuration
    conf = Configuration(conf)
    conf.setLocale(locale)
    val localizedContext = createConfigurationContext(conf)
    return localizedContext.resources.getString(resId)
}

И вы можете использовать его следующим образом:

      getString(Locale("PT"), R.string.some_string, foo, bar)
getString(Locale.FRANCE, R.string.some_other_string)

Можно ли это сделать, например?

      String stringFormat = getString(stringId);
String string = String.format(Locale.ENGLISH, stringFormat, 6);

То, что вы ищете, называется классом ResourceBundle. Вот ссылка:

Документы Google для ResourceBundle

Другие вопросы по тегам