Как заставить другой язык локали для android приложения? - PullRequest
1 голос
/ 06 мая 2020

Независимо от языка ОС устройства, мне нужно заставить языковой стандарт приложения соответствовать моим потребностям, а именно: переведенные строки и макет rtl / ltr для каждого варианта приложения.
Хотелось бы знать, как это правильно сделать. как мы видим, в сети много путаницы, и нет официального ответа на это.

1 Ответ

0 голосов
/ 06 мая 2020

Самый правильный подход - сначала понять концепцию:

  1. Locale
  2. Configuration
  3. Ресурсы
  4. BaseContext и ContextWrapper

Обратите внимание, что: Там представляют собой 3 типа слоев [Context.getResources]:

  1. ресурсы верхнего уровня (например, название действия манифеста)
  2. ресурсы приложения
  3. ресурсы действий

Таким образом, изменение уровня приложения не повлияет на уровень активности.

И:
Если вы sh поддержите Android 6, вы следует использовать файл .apk, а не .aab (пакет приложений android). Это связано с тем, что в Android 6 вы можете выбрать только одну локаль по умолчанию в настройках, а затем .aab загрузит ТОЛЬКО необходимые ресурсы конфигурации:
Предположим, мы используем строки. xml на английском sh в качестве нашего языка по умолчанию и переведите его на иврит, используя другие строки-iw. xml
Если устройство Android 6 настроено на английском sh в качестве основного и единственного языка, .aab будет доставить только обычный ресурс Engli sh strings. xml. ИЛИ:
Если возможно, вы можете использовать только одну строку по умолчанию. xml с требуемым языком.

Решение:

В вашем BaseActivity, а также в вашем классе приложения:

abstract class BaseActivity : AppCompatActivity() {

    override fun attachBaseContext(newBase: Context) {
        val constrainedBaseCtx = LocaleUtil.constrainConfigurationLocale(newBase)
        super.attachBaseContext(constrainedBaseCtx)
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        val constrainedConfiguration = LocaleUtil.constrainConfigurationLocale(newConfig)
        super.onConfigurationChanged(constrainedConfiguration)
    }

    override fun createConfigurationContext(overrideConfiguration: Configuration): Context {
        val constrainedConf = LocaleUtil.constrainConfigurationLocale(overrideConfiguration)
        return super.createConfigurationContext(constrainedConf)
    }
}

Используйте вашу локальную утилиту:

/**
 * Helps to change locales configuration for [Context] objects.
 * Remember that there are 3 types of [Context.getResources] layers:
 *
 * 1. Top-level resources (ex: manifest activity name)
 *
 * 2. Application resources
 *
 * 3. Activity resources
 *
 * So, changing the Application layer won't affect the activity layer.
 */
object LocaleUtil {

const val DEFAULT_LANGUAGE = "iw"
const val DEFAULT_COUNTRY = "il"

/**
 * Constraint This [context] Locale.
 * @param constrainedCountry - the country to match the activity for
 * @param constrainedLanguage - the language inside that country to match the activity for
 * @return new / same instance configured [Context]. (depends on Android OS version)
 */
fun constrainConfigurationLocale(
    context: Context,
    constrainedCountry: String = DEFAULT_COUNTRY,
    constrainedLanguage: String = DEFAULT_LANGUAGE
) : Context {
    val newConf = constrainConfigurationLocale(
        context.resources.configuration,
        constrainedCountry,
        constrainedLanguage
    )
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
        context.createConfigurationContext(newConf)
    else
        context
}

/**
 * Constraint This [configuration] Locale.
 * @param constrainedCountry - the country to match the activity for
 * @param constrainedLanguage - the language inside that country to match the activity for
 * @return new / same instance of [Configuration]. (depends on Android OS version)
 */
fun constrainConfigurationLocale(
    currentConfiguration: Configuration,
    constrainedCountry: String = DEFAULT_COUNTRY,
    constrainedLanguage: String = DEFAULT_LANGUAGE
) : Configuration {

    val configuration = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
        Configuration(currentConfiguration)
    else
        currentConfiguration
    val synthesizedLocale = Locale(constrainedLanguage, constrainedCountry)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        val oldLocales = configuration.locales
        @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
        if (!oldLocales.isEmpty) {
            if (!oldLocales[0].language!!.contentEquals(synthesizedLocale.language)) {
                var newLocales = arrayOfNulls<Locale>(oldLocales.size() + 1)
                newLocales[0] = synthesizedLocale // first locale determines layout direction
                var deductionCount = 0
                for (i in 0 until oldLocales.size()) {
                    if (newLocales[0]?.language?.contentEquals(oldLocales[i].language) != true) // add only different locale if not null
                        newLocales[i + 1 - deductionCount] = oldLocales[i]
                    else {
                        val temp = arrayOfNulls<Locale>(newLocales.size - 1)
                        for (j in 0..i) {
                            temp[j] = newLocales[j]
                        }
                        newLocales = temp
                        deductionCount++
                    }
                }
                configuration.locales = LocaleList(*newLocales)
            }
        } else {
            configuration.locales = LocaleList(synthesizedLocale)
        }
    } else {
        @Suppress("DEPRECATION", "UNNECESSARY_NOT_NULL_ASSERTION")
        if (configuration.locale == null || !synthesizedLocale.language!!.contentEquals(configuration.locale.language!!))
            configuration.setLocale(synthesizedLocale)
    }
    return configuration
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...