як отримати рядок з різних мов в Android?


78

Отже, я хочу отримати значення рядка в декількох мовах, незалежно від поточних налаштувань мовних параметрів пристрою / програми. Як мені це зробити?

В основному мені потрібна функція, getString(int id, String locale)а неgetString(int id)

Як я міг це зробити?

Дякую


1
як ти насправді це реалізував ?? Будь ласка, дайте відповідь :)
Rakeeb Rajbhandari

як прийнята відповідь
cheng yang

які ResourceBundleповинні ставитися до активів ?? або вони можуть отримати доступ до нашої папки res?
Rakeeb Rajbhandari

@chengyang, будь ласка, змініть прийняту відповідь
jonathanrz

Вам потрібно вказати іншу мову, ніж звичайну? Якщо ви працюєте з різними мовними ресурсами, коли ви це зробите, getString(R.strings.text)ви отримаєте рядок на мові користувачів (або за замовчуванням, якщо мова користувачів не має папки)
Лукас Квейроз Рібейро,

Відповіді:


142

ПРИМІТКА Якщо ваш мінімальний API становить 17+, перейдіть до кінця цієї відповіді. В іншому випадку читайте далі ...

ПРИМІТКА Якщо ви використовуєте набори програм, вам потрібно переконатися, що ви вимкнули розділення мови або динамічно встановили іншу мову. Див. Https://stackoverflow.com/a/51054393 для цього. Якщо ви цього не зробите, він завжди використовуватиме запасний варіант.

Якщо у вас є різні папки 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об’єкта, поверненого цим методом. Не потрібно нічого скидати після того, як ви отримали ресурси.


1
Чи не слід вам зробити нову конфігурацію з тієї, яку повернув getResources().getConfiguration()? За даними GrepCode, він повертає локальний екземпляр, що зберігається в Ресурсах. Зміна поля мови після цього, мабуть, є справжньою причиною розгубленості Android. Ймовірно, вам слід це зробити conf = new Configuration(conf);(щоб клонувати повернуту конфігурацію) між першим і другим рядком.
Нулано

@Nulano - Варто спробувати, але я не думаю, що це джерело того, чому Android "заплутаний" (як ви сказали). Подивіться на джерело Resourcesконструктора, і ви побачите, що створення нового такого Resourcesоб’єкта змінює речі глибоко в активах процесу (мабуть, синглтон). Як тільки я зрозумів, що речі потрібно буде перезавантажити, я не потрудився відстежувати, чому саме. Альтернативним (можливо, більш чистим) підходом до побудови нового Resourcesоб’єкта є виклик resources.updateConfiguration(conf, null)після зміни локалей.
Тед Хопп

1
Там це кращий API рівня API 17+: stackoverflow.com/a/33629163/2245107
Mygod

@Mygod - Так, це здається правильним шляхом. Я оновлю свою відповідь, щоб вказати це. Дякую!
Тед Хопп,

1
Відповідь відредаговано приміткою про набори додатків, що порушують цю функцію за замовчуванням, оскільки з наборами користувач отримуватиме лише одну мову. Про те, як це виправити, див. Stackoverflow.com/a/51054393 .
Карстен Хагеманн

32

Ось комбінована версія підходів, описаних Тедом Хоппом . Таким чином, код працює для будь-якої версії 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 ().


2

Грунтуючись на наведених вище відповідях, які дивовижні, але трохи складні. спробуйте цю просту функцію:

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");

Щасливого коду :)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.