Использование Locale, чтобы заставить Android использовать определенный файл strings.xml для не поддерживаемого языка

... и если да, то как?

Мы создаем специализированное Android-устройство для использования в промышленной среде. Это в основном планшет, но только с одним приложением. Пользователь не должен получать доступ к каким-либо другим функциям устройства и даже к системным настройкам, например, к настройкам WiFi и времени через наше приложение, а не через виджет Android Settings. Таким образом, в основном каждая кнопка и сообщение, которое они видят, используют наш strings.xml файл.

В настоящее время все наши клиенты довольны использованием настроек по умолчанию в США по-умолчанию, но вскоре у нас появятся некоторые клиенты, которые хотят локальных языков и предоставили нам файлы перевода. В настоящее время один из них - румынский, который не является языком с какой-либо нативной поддержкой этого устройства (вкладка Samsung Galaxy 4); другой - чешский.

Итак, мы хотим добавить файлы strings.xml в соответствующие папки res, для неанглийских языков и выпадающее меню, чтобы выбрать, какой язык мы используем. Программно мы думаем, что мы можем использовать Locale для установки файла strings.xml, который он использует, например, если румынский был выбран из раскрывающегося списка, мы будем использовать Locale, чтобы установить планшет на румынский язык, чтобы весь наш пользовательский интерфейс приложения используйте румынский strings.xml файл.

Наши настройки, включая новое раскрывающееся меню, недоступны для клиентов - они настроены на сайте заказчика инженером по обслуживанию полетов.

Вопросы:

  • Будет ли это работать? I.e., можем ли мы контролировать, какой файл strings.xml он использует через Locale, даже если у устройства нет встроенной поддержки этого языка?
  • Поскольку румынский язык не является родным языком с этим устройством, мы предполагаем, что системные сообщения все равно появятся на английском языке. Это правда? (это не проблема, если это так - системные сообщения встречаются редко с нашим приложением, и пользователи наших продуктов обучаются обращаться в службу поддержки, если это происходит. Я просто хочу убедиться, что если мы установим Locale на румынский или чешский или какой-либо другой язык без встроенной поддержки, он не повредит планшет, если он попытается выпустить системное сообщение).

Ответ 1

Будет ли это работать? I.e., можем ли мы контролировать, какой файл strings.xml он использует через Locale, даже если у устройства нет встроенной поддержки этого языка?

Да, вы можете, обновив Locale в Configuration (см. пример ниже). Если вы попытаетесь использовать локаль, для которой нет соответствующих ресурсов (в вашем приложении или системе), строковые ресурсы по умолчанию (res/values ​​/strings.xml) вашего приложения.

Поскольку румынский язык не является родным языком с этим устройством, мы предполагаем, что системные сообщения все равно появятся на английском языке. Это правда?

Это правда, если английский - это текущий системный язык.

Я просто хочу убедиться, что если мы установим Locale на румынский, или чешский или какой-либо другой язык без встроенной поддержки, он не повредит планшет, если попытается выпустить системное сообщение.

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

Пример, чтобы ответить "если да, как?" Этот метод можно использовать для проверки изменений локали, пока работает Activity *.

public static void changeLocale(Context context, String locale) {
    Resources res = context.getResources();
    Configuration conf = res.getConfiguration();
    conf.locale = new Locale(locale);
    res.updateConfiguration(conf, res.getDisplayMetrics());
}

* Возможно, вы захотите вызвать recreate(), чтобы увидеть изменения в ресурсах строк "на лету".

Ответ 2

Лучший способ сделать это - установить локаль устройства. Код для этого -

Class<?> activityManagerNative = Class.forName("android.app.ActivityManagerNative");
Object am = activityManagerNative.getMethod("getDefault").invoke(activityManagerNative);
Object config = am.getClass().getMethod("getConfiguration").invoke(am);
config.getClass().getDeclaredField("locale").set(config, item.getLocale());
config.getClass().getDeclaredField("userSetLocale").setBoolean(config, true);
am.getClass().getMethod("updateConfiguration", android.content.res.Configuration.class).invoke(am, config);

ActivityManagerNative.java

package android.app;

public abstract class ActivityManagerNative implements IActivityManager {

    public static IActivityManager getDefault(){
        return null;
    }

}

IActivityManager

package android.app;

import android.content.res.Configuration;
import android.os.RemoteException;

public interface IActivityManager {
    public abstract Configuration getConfiguration () throws RemoteException;
    public abstract void updateConfiguration (Configuration configuration) throws RemoteException;
}

Таким образом вы установите локаль устройства и пусть все изменится через обычные пути. Вам понадобится разрешение android:name="android.permission.CHANGE_CONFIGURATION" в вашем манифесте. Это безопасное разрешение, но установка себя как системного приложения не должна быть проблемой для вас.

Ответ 3

Да, вы можете определенно переключить локаль одного приложения. Для этого вам нужно продлить каждое действие из базового класса следующим образом:

public abstract class MyLangActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        Locale locale = // get the locale to use...
        Configuration conf = getResources().getConfiguration();
        if (Build.VERSION.SDK_INT >= 17) {
            conf.setLocale(locale);
        } else {
            conf.locale = locale;
        }

        DisplayMetrics metrics = getResources().getDisplayMetrics();
        getResources().updateConfiguration(conf, metrics);
        super.onCreate(savedInstanceState);
    }
}

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

Ответ 4

Заменить getResources в приложении и BaseActivity

@Override
    public Resources getResources() {
        if(mRes == null)
        mRes = new PowerfulResources(getAssets(),new DisplayMetrics(), null);
        return mRes;
    }

    public static class PowerfulResources extends Resources{

        /**
         * Create a new Resources object on top of an existing set of assets in an
         * AssetManager.
         *
         * @param assets  Previously created AssetManager.
         * @param metrics Current display metrics to consider when
         *                selecting/computing resource values.
         * @param config  Desired device configuration to consider when
         */
        public PowerfulResources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
            super(assets, metrics, config);
        }

        @NonNull
        @Override
        public String getString(int id) throws NotFoundException {
            //do your stuff here
            return super.getString(id);
        }
    }

также читайте this