Android загружает значения из файла строк по умолчанию (strings.xml) после изменения локали во второй раз

1

Я работаю над приложением для 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 ответа

0
Лучший ответ

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

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);
            }
  • 0
    в вашем случае вы должны проверить в SharedPreferences, какой lang вы используете, и вызвать LocaleSettings .setLocal и дать ключ
  • 0
    Спасибо, это работает сейчас, но так как оно перезапускает активность, изменение "перезапуск активности" заметно. есть ли способ, которым пользователь не испытывает перезапуск действия?
Показать ещё 1 комментарий
1

Из документации Android:

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

Внутреннее изменение языка является исключением.

Во-первых, пожалуйста, прочитайте эту документацию и признайте недостатки дизайна.

Подводя итог, вот две вещи, которые я хочу упомянуть:

  1. updateConfiguration устарела, поэтому нам нужна другая версия для поддержки обратной совместимости.
  2. Нам нужно переопределить 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 после изменения языкового стандарта вам не нужно 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-programmatics-in-android/

Ещё вопросы

Сообщество Overcoder
Наверх
Меню