Android загружает значения из файла строк по умолчанию (strings.xml) после изменения локали во второй раз
Я работаю над приложением для Android, где я меняю локаль (с английского на арабский) на главном экране с помощью одной кнопки. Он отлично работает на главном экране, но проблема возникает, когда я меняю язык более одного раза. Следующие шаги для регенерации:
- Текущий язык на главном экране (логин)
English
и я изменяю это наArabic
, (работает отлично) - Перейдите на страницу регистрации или забыли пароль, и язык изменился. (
Arabic
) - Вернитесь на главный экран и измените локаль обратно на
English
отArabic
, (Работает на экране входа в систему) - Перейдите на страницу регистрации, и теперь направление изменилось, но строка загружается с арабского языка. (Текущий язык
English
)
Вот мой код для изменения локали.
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.preference.PreferenceManager;
import android.support.v4.text.TextUtilsCompat;
import android.support.v4.view.ViewCompat;
import android.view.View;
import java.util.Locale;
public class LocaleSettings {
public static final String LANGUAGE_ENGLISH = "en";
public static final String LANGUAGE_ARABIC = "ar";
public static final String CURRENT_LANGUAGE = "currentLanguage";
/**
* Loads the current language of application
*
* @param context current context, pass "this" for current view context
*/
public static void loadLocal(Context context) {
setLocal(context, PreferenceManager.getDefaultSharedPreferences(context).getString(CURRENT_LANGUAGE, ""));
}
/**
* This fucntion sets the application language
*
* @param context - current context. pass "this" for current view context
* @param lang Language String, i.e. "en" or "ar"
*/
public static void setLocal(Context context, String lang) {
Locale locale = new Locale(lang);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.setLocale(locale);
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = pref.edit();
editor.putString(CURRENT_LANGUAGE, lang);
editor.apply();
editor.commit();
}
/**
* Use to change application language using current context
*
* @param context pass "this" for current view context
*/
public static void switchLanguage(Context context) {
if (getCurrentLanguage(context).equals(LANGUAGE_ENGLISH))
setLocal(context, LANGUAGE_ARABIC);
else
setLocal(context, LANGUAGE_ENGLISH);
}
/**
* Get application current active language
*
* @param context pass "this" for current view context
* @return String - language string i.e. en or ar
*/
public static String getCurrentLanguage(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getString(CURRENT_LANGUAGE, "");
}
public static boolean isRTL(String locale) {
return TextUtilsCompat.getLayoutDirectionFromLocale(new Locale(locale)) == ViewCompat.LAYOUT_DIRECTION_RTL ? true : false;
}
public static void enforceDirectionIfRTL(Context context){
if(isRTL(getCurrentLanguage(context))){
((Activity) context).getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
}
}
}
Вот код для входа в систему
public class LoginActivity extends AppCompatActivity {
private Button loginButton = null;
private EditText account_no = null;
private EditText password = null;
final UserApi userApi = JoezdanServiceGenerator.createService(UserApi.class);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LocaleSettings.loadLocal(this);
setContentView(R.layout.activity_login);
configureLanaguageButton();
}
private void configureLanaguageButton() {
final ImageButton selectLocale = (ImageButton) findViewById(R.id.btnSelectLanguage);
selectLocale.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LocaleSettings.switchLanguage(LoginActivity.this);
recreate();
}
});
}
... eliminating irrelevant code
}
Это мое первое приложение для Android, так что извините, если есть ошибки. Заранее спасибо.
2 ответа
Прежде всего вам нужно убедиться, что после смены пользователя вы закрываете все действия и перезапускаете приложение, что-то вроде этого
Intent intent = new Intent(AcSettingsView.this, MainActivityView.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finishAffinity();
Еще одна вещь, на которую нужно обратить внимание, это убедиться, что вы устанавливаете свои местные жители каждый раз, когда приложение запускается на первом экране, как это
helper = new PreferenceHelper(this);
String lang = helper.getData(Constants.LANGUAGE_CODE);
if (eng) {
Utility.setLocale(getBaseContext(), Constants.ENGLISH_CODE);
} else {
Utility.setLocale(getBaseContext(), Constants.ARABIC_CODE);
}
Из документации Android:
Android по умолчанию использует локаль устройства для выбора соответствующих языковых ресурсов. И в большинстве случаев такого поведения достаточно для обычных приложений.
Внутреннее изменение языка является исключением.
Во-первых, пожалуйста, прочитайте эту документацию и признайте недостатки дизайна.
Подводя итог, вот две вещи, которые я хочу упомянуть:
updateConfiguration
устарела, поэтому нам нужна другая версия для поддержки обратной совместимости.- Нам нужно переопределить
attachBaseContext
для каждой деятельности, чтобы отразить изменения.
Вот реализация:
@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Configuration configuration = context.getResources().getConfiguration();
configuration.setLocale(locale);
configuration.setLayoutDirection(locale);
return context.createConfigurationContext(configuration);
}
@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, String language) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
configuration.locale = locale;
configuration.setLayoutDirection(locale);
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
return context;
}
Чтобы поддерживать обратную совместимость, проверьте версию перед сменой языка:
public static Context setLocale(Context context, String language) {
// You can save SharedPreference here
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return updateResources(context, language);
}
return updateResourcesLegacy(context, language);
}
В вашем LoginActivity
после изменения языкового стандарта вам не нужно заново создавать действие, вы можете получить ресурс, а затем изменять каждый TextView
вручную.
Context context = LocaleUtils.setLocale(this, lang);
Resources resources = context.getResources();
yourFirstTextView.setText(resources.getString(R.string.your_first_text_res)
// ... yourSecondTextView....
В каждое действие, чтобы отразить изменения, добавьте эту функцию:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(LocaleUtils.onAttach(newBase));
}
Кстати, есть ошибка, вы не можете изменить язык заголовка Toolbar
, В вашем onCreate()
вызовите эту функцию вручную, setTitle("your Title")
Я знаю, что такие проблемы ужасны, а решения немного хакерские. Но давайте попробуем. Дайте мне знать, если это поможет вам.:)
Полный исходный код можно найти здесь: https://github.com/gunhansancar/ChangeLanguageExample/blob/master/app/src/main/java/com/gunhansancar/changelanguageexample/helper/LocaleHelper.java
с большой статьей: https://gunhansancar.com/change-language-programmatically-in-android/