Подтвердить что ты не робот

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

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

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

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

Спасибо

4b9b3361

Ответ 1

ПРИМЕЧАНИЕ Если ваш минимальный 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), если вы собираетесь загружать несколько строковых ресурсов для локали. Изменение локалей (с использованием любого из рецептов) требует, чтобы структура выполняла большую работу, восстанавливая все ресурсы. Гораздо лучше обновить локали один раз, получить все, что вам нужно, а затем вернуть локаль.

EDIT (благодаря @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, возвращаемого этим методом. Нет необходимости reset что-либо, как только вы извлекли ресурсы.

Ответ 2

Вот комбинированная версия подходов, описанных Тедом Хоппом. Таким образом, код работает для любой версии 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().

Ответ 3

Не было бы проще с одной строкой кода?

String.format(Locale("en"), getString(R.string.your_string))

И у вас есть доступ к строкам из ваших переводов без каких-либо изменений в конфигурации и других волшебных вещей.