Использование 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