improve localizedDisplayName

don't use resoruces.getIdentifier
use override names e.g. for English (UK) for consistent layout names
merge with getLocaleDisplayNameInLocale
This commit is contained in:
Helium314 2025-05-24 11:35:58 +02:00
parent d1120807d3
commit 69540b8d9f
11 changed files with 45 additions and 47 deletions

View file

@ -92,9 +92,6 @@ public class RichInputMethodManager {
mContext = context; mContext = context;
mInputMethodInfoCache = new InputMethodInfoCache(mImm, context.getPackageName()); mInputMethodInfoCache = new InputMethodInfoCache(mImm, context.getPackageName());
// Initialize subtype utils.
SubtypeLocaleUtils.init(context);
// Initialize the current input method subtype and the shortcut IME. // Initialize the current input method subtype and the shortcut IME.
refreshSubtypeCaches(); refreshSubtypeCaches();
} }

View file

@ -8,10 +8,10 @@ package helium314.keyboard.latin.common
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import helium314.keyboard.compat.locale import helium314.keyboard.compat.locale
import helium314.keyboard.latin.BuildConfig
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.utils.ScriptUtils.script import helium314.keyboard.latin.utils.ScriptUtils.script
import helium314.keyboard.latin.utils.SubtypeLocaleUtils import helium314.keyboard.latin.utils.SubtypeLocaleUtils
import helium314.keyboard.latin.utils.runInLocale
import java.util.Locale import java.util.Locale
/** /**
@ -171,32 +171,34 @@ object LocaleUtils {
} }
} }
fun Locale.localizedDisplayName(context: Context) = fun Locale.localizedDisplayName(resources: Resources, displayLocale: Locale? = null): String {
getLocaleDisplayNameInLocale(this, context.resources, context.resources.configuration.locale()) val languageTag = toLanguageTag()
if (languageTag == SubtypeLocaleUtils.NO_LANGUAGE)
return resources.getString(R.string.subtype_no_language) // todo: remove the (Alphabet)
@JvmStatic val overrideResId = when (languageTag) {
fun getLocaleDisplayNameInLocale(locale: Locale, resources: Resources, displayLocale: Locale): String { "en-US" -> R.string.subtype_en_US
val languageTag = locale.toLanguageTag() "en-GB" -> R.string.subtype_en_GB
if (languageTag == SubtypeLocaleUtils.NO_LANGUAGE) return resources.getString(R.string.subtype_no_language) "es-US" -> R.string.subtype_es_US
if (hasNonDefaultScript(locale) || doesNotHaveAndroidName(locale.language)) { "hi-Latn" -> R.string.subtype_hi_Latn
// supply our own name for the language instead of using name provided by the system "sr-Latn" -> R.string.subtype_sr_Latn
val resId = resources.getIdentifier( "mns" -> R.string.subtype_mns
"subtype_${languageTag.replace("-", "_")}", "xdq" -> R.string.subtype_xdq
"string", "dru" -> R.string.subtype_xdq
BuildConfig.APPLICATION_ID // replaces context.packageName, see https://stackoverflow.com/a/24525379 "st" -> R.string.subtype_st
) "dag" -> R.string.subtype_dag
if (resId != 0) return resources.getString(resId) else -> 0
} }
val localeDisplayName = locale.getDisplayName(displayLocale) if (overrideResId != 0) {
return if (displayLocale == null) resources.getString(overrideResId)
else runInLocale(resources, displayLocale) { it.getString(overrideResId) }
}
val localeDisplayName = getDisplayName(displayLocale ?: resources.configuration.locale())
return if (localeDisplayName == languageTag) { return if (localeDisplayName == languageTag) {
locale.getDisplayName(Locale.US) // try fallback to English name, relevant e.g. fpr pms, see https://github.com/Helium314/HeliBoard/pull/748 getDisplayName(Locale.US) // try fallback to English name, relevant e.g. fpr pms, see https://github.com/Helium314/HeliBoard/pull/748
} else { } else {
localeDisplayName localeDisplayName
} }
} }
private fun hasNonDefaultScript(locale: Locale) = locale.script() != locale.language.constructLocale().script()
private fun doesNotHaveAndroidName(language: String) =
language == "mns" || language == "xdq" || language=="dru" || language == "st" || language == "dag"
} }

View file

@ -27,7 +27,7 @@ fun createInputMethodPickerDialog(latinIme: LatinIME, richImm: RichInputMethodMa
var currentSubtypeIndex = 0 var currentSubtypeIndex = 0
enabledImis.forEach { imi -> enabledImis.forEach { imi ->
val subtypes = if (imi != thisImi) richImm.getEnabledInputMethodSubtypeList(imi, true) val subtypes = if (imi != thisImi) richImm.getEnabledInputMethodSubtypeList(imi, true)
else richImm.getEnabledInputMethodSubtypeList(imi, true).sortedBy { it.displayName(latinIme).toString() } else richImm.getEnabledInputMethodSubtypeList(imi, true).sortedBy { it.displayName() }
if (subtypes.isEmpty()) { if (subtypes.isEmpty()) {
enabledSubtypes.add(imi to null) enabledSubtypes.add(imi to null)
} else { } else {
@ -45,7 +45,7 @@ fun createInputMethodPickerDialog(latinIme: LatinIME, richImm: RichInputMethodMa
for (imiAndSubtype in enabledSubtypes) { for (imiAndSubtype in enabledSubtypes) {
val (imi, subtype) = imiAndSubtype val (imi, subtype) = imiAndSubtype
val subtypeName = if (imi == thisImi) subtype?.displayName(latinIme) val subtypeName = if (imi == thisImi) subtype?.displayName()
else subtype?.getDisplayName(latinIme, imi.packageName, imi.serviceInfo.applicationInfo) else subtype?.getDisplayName(latinIme, imi.packageName, imi.serviceInfo.applicationInfo)
val title = SpannableString(subtypeName?.ifBlank { imi.loadLabel(pm) } ?: imi.loadLabel(pm)) val title = SpannableString(subtypeName?.ifBlank { imi.loadLabel(pm) } ?: imi.loadLabel(pm))
val subtitle = SpannableString(if (subtype == null) "" else "\n${imi.loadLabel(pm)}") val subtitle = SpannableString(if (subtype == null) "" else "\n${imi.loadLabel(pm)}")

View file

@ -12,7 +12,6 @@ import helium314.keyboard.compat.locale
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
import helium314.keyboard.latin.common.LocaleUtils.constructLocale import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import helium314.keyboard.latin.common.LocaleUtils.getLocaleDisplayNameInLocale
import helium314.keyboard.latin.common.LocaleUtils.localizedDisplayName import helium314.keyboard.latin.common.LocaleUtils.localizedDisplayName
import helium314.keyboard.latin.common.StringUtils import helium314.keyboard.latin.common.StringUtils
import helium314.keyboard.latin.utils.LayoutType.Companion.getMainLayoutFromExtraValue import helium314.keyboard.latin.utils.LayoutType.Companion.getMainLayoutFromExtraValue
@ -157,7 +156,7 @@ object SubtypeLocaleUtils {
val displayName = if (exceptionalNameResId != null) { val displayName = if (exceptionalNameResId != null) {
runInLocale(resources, displayLocale) { res: Resources -> res.getString(exceptionalNameResId) } runInLocale(resources, displayLocale) { res: Resources -> res.getString(exceptionalNameResId) }
} else { } else {
getLocaleDisplayNameInLocale(locale, resources, displayLocale) locale.localizedDisplayName(resources, displayLocale)
} }
return StringUtils.capitalizeFirstCodePoint(displayName, displayLocale) return StringUtils.capitalizeFirstCodePoint(displayName, displayLocale)
} }
@ -233,10 +232,10 @@ object SubtypeLocaleUtils {
if (LayoutUtilsCustom.isCustomLayout(layoutName)) LayoutUtilsCustom.getDisplayName(layoutName) if (LayoutUtilsCustom.isCustomLayout(layoutName)) LayoutUtilsCustom.getDisplayName(layoutName)
else keyboardLayoutToDisplayName[layoutName] else keyboardLayoutToDisplayName[layoutName]
fun InputMethodSubtype.displayName(context: Context): String { fun InputMethodSubtype.displayName(): String {
val layoutName = mainLayoutNameOrQwerty() val layoutName = mainLayoutNameOrQwerty()
if (LayoutUtilsCustom.isCustomLayout(layoutName)) if (LayoutUtilsCustom.isCustomLayout(layoutName))
return "${locale().localizedDisplayName(context)} (${LayoutUtilsCustom.getDisplayName(layoutName)})" return "${locale().localizedDisplayName(resources)} (${LayoutUtilsCustom.getDisplayName(layoutName)})"
return getSubtypeDisplayNameInSystemLocale(this) return getSubtypeDisplayNameInSystemLocale(this)
} }

View file

@ -50,6 +50,7 @@ import helium314.keyboard.settings.previewDark
import helium314.keyboard.settings.screens.getUserAndInternalDictionaries import helium314.keyboard.settings.screens.getUserAndInternalDictionaries
import java.io.File import java.io.File
import java.util.Locale import java.util.Locale
import androidx.compose.ui.platform.LocalConfiguration
@Composable @Composable
fun DictionaryDialog( fun DictionaryDialog(
@ -66,7 +67,7 @@ fun DictionaryDialog(
onConfirmed = {}, onConfirmed = {},
confirmButtonText = null, confirmButtonText = null,
cancelButtonText = stringResource(R.string.dialog_close), cancelButtonText = stringResource(R.string.dialog_close),
title = { Text(locale.localizedDisplayName(ctx)) }, title = { Text(locale.localizedDisplayName(ctx.resources)) },
content = { content = {
val state = rememberScrollState() val state = rememberScrollState()
Column(Modifier.verticalScroll(state)) { Column(Modifier.verticalScroll(state)) {
@ -117,7 +118,7 @@ private fun DictionaryDetails(dict: File) {
} }
AnimatedVisibility(showDetails, enter = fadeIn(), exit = fadeOut()) { // default animation looks better, but makes the dialog flash AnimatedVisibility(showDetails, enter = fadeIn(), exit = fadeOut()) { // default animation looks better, but makes the dialog flash
Text( Text(
header.info(LocalContext.current.resources.configuration.locale()), header.info(LocalConfiguration.current.locale()),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(horizontal = 10.dp) modifier = Modifier.padding(horizontal = 10.dp)
) )

View file

@ -81,7 +81,7 @@ fun NewDictionaryDialog(
selectedItem = locale, selectedItem = locale,
onSelected = { locale = it }, onSelected = { locale = it },
items = locales items = locales
) { Text(it.localizedDisplayName(ctx)) } ) { Text(it.localizedDisplayName(ctx.resources)) }
} }
if (locale.script() != dictLocale.script()) { if (locale.script() != dictLocale.script()) {
// whatever, still allow it if the user wants // whatever, still allow it if the user wants

View file

@ -55,7 +55,7 @@ fun DictionaryScreen(
) { ) {
val ctx = LocalContext.current val ctx = LocalContext.current
val enabledLanguages = SubtypeSettings.getEnabledSubtypes(true).map { it.locale().language } val enabledLanguages = SubtypeSettings.getEnabledSubtypes(true).map { it.locale().language }
val cachedDictFolders = DictionaryInfoUtils.getCacheDirectories(ctx).orEmpty().map { it.name } val cachedDictFolders = DictionaryInfoUtils.getCacheDirectories(ctx).map { it.name }
val comparer = compareBy<Locale>({ it.language !in enabledLanguages }, { it.toLanguageTag() !in cachedDictFolders}, { it.displayName }) val comparer = compareBy<Locale>({ it.language !in enabledLanguages }, { it.toLanguageTag() !in cachedDictFolders}, { it.displayName })
val dictionaryLocales = getDictionaryLocales(ctx).sortedWith(comparer).toMutableList() val dictionaryLocales = getDictionaryLocales(ctx).sortedWith(comparer).toMutableList()
dictionaryLocales.add(0, Locale(SubtypeLocaleUtils.NO_LANGUAGE)) dictionaryLocales.add(0, Locale(SubtypeLocaleUtils.NO_LANGUAGE))
@ -69,7 +69,7 @@ fun DictionaryScreen(
if (term.isBlank()) dictionaryLocales if (term.isBlank()) dictionaryLocales
else dictionaryLocales.filter { loc -> else dictionaryLocales.filter { loc ->
loc.language != SubtypeLocaleUtils.NO_LANGUAGE loc.language != SubtypeLocaleUtils.NO_LANGUAGE
&& loc.localizedDisplayName(ctx).replace("(", "") && loc.localizedDisplayName(ctx.resources).replace("(", "")
.splitOnWhitespace().any { it.startsWith(term, true) } .splitOnWhitespace().any { it.startsWith(term, true) }
} }
}, },
@ -98,7 +98,7 @@ fun DictionaryScreen(
val types = dicts.mapTo(mutableListOf()) { it.name.substringBefore("_${DictionaryInfoUtils.USER_DICTIONARY_SUFFIX}") } val types = dicts.mapTo(mutableListOf()) { it.name.substringBefore("_${DictionaryInfoUtils.USER_DICTIONARY_SUFFIX}") }
if (hasInternal && !types.contains(Dictionary.TYPE_MAIN)) if (hasInternal && !types.contains(Dictionary.TYPE_MAIN))
types.add(0, stringResource(R.string.internal_dictionary_summary)) types.add(0, stringResource(R.string.internal_dictionary_summary))
Text(locale.localizedDisplayName(ctx)) Text(locale.localizedDisplayName(ctx.resources))
Text( Text(
types.joinToString(", "), types.joinToString(", "),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,

View file

@ -75,7 +75,7 @@ fun LanguageScreen(
}, },
filteredItems = { term -> filteredItems = { term ->
sortedSubtypes.filter { sortedSubtypes.filter {
it.displayName(ctx).replace("(", "") it.displayName().replace("(", "")
.splitOnWhitespace().any { it.startsWith(term, true) } .splitOnWhitespace().any { it.startsWith(term, true) }
} }
}, },
@ -91,10 +91,10 @@ fun LanguageScreen(
) { ) {
var showNoDictDialog by remember { mutableStateOf(false) } var showNoDictDialog by remember { mutableStateOf(false) }
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text(item.displayName(ctx), style = MaterialTheme.typography.bodyLarge) Text(item.displayName(), style = MaterialTheme.typography.bodyLarge)
val description = if (SubtypeSettings.isAdditionalSubtype(item)) { val description = if (SubtypeSettings.isAdditionalSubtype(item)) {
val secondaryLocales = item.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)?.split(Separators.KV) val secondaryLocales = item.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)?.split(Separators.KV)
?.joinToString(", ") { it.constructLocale().localizedDisplayName(ctx) } ?.joinToString(", ") { it.constructLocale().localizedDisplayName(ctx.resources) }
stringResource(R.string.custom_subtype) + (secondaryLocales?.let { "\n$it" } ?: "") stringResource(R.string.custom_subtype) + (secondaryLocales?.let { "\n$it" } ?: "")
} else null } else null
if (description != null) if (description != null)
@ -153,7 +153,7 @@ private fun getSortedSubtypes(context: Context): List<InputMethodSubtype> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) it.languageTag == SubtypeLocaleUtils.NO_LANGUAGE if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) it.languageTag == SubtypeLocaleUtils.NO_LANGUAGE
else it.locale == SubtypeLocaleUtils.NO_LANGUAGE else it.locale == SubtypeLocaleUtils.NO_LANGUAGE
}, },
{ it.displayName(context) } { it.displayName() }
) )
return SubtypeSettings.getAllAvailableSubtypes().sortedWith(subtypeSortComparator) return SubtypeSettings.getAllAvailableSubtypes().sortedWith(subtypeSortComparator)
} }

View file

@ -41,7 +41,6 @@ fun MainSettingsScreen(
onClickDictionaries: () -> Unit, onClickDictionaries: () -> Unit,
onClickBack: () -> Unit, onClickBack: () -> Unit,
) { ) {
val ctx = LocalContext.current
SearchSettingsScreen( SearchSettingsScreen(
onClickBack = onClickBack, onClickBack = onClickBack,
title = stringResource(R.string.ime_settings), title = stringResource(R.string.ime_settings),
@ -54,7 +53,7 @@ fun MainSettingsScreen(
) { ) {
Preference( Preference(
name = stringResource(R.string.language_and_layouts_title), name = stringResource(R.string.language_and_layouts_title),
description = enabledSubtypes.joinToString(", ") { it.displayName(ctx) }, description = enabledSubtypes.joinToString(", ") { it.displayName() },
onClick = onClickLanguage, onClick = onClickLanguage,
icon = R.drawable.ic_settings_languages icon = R.drawable.ic_settings_languages
) { NextScreenIcon() } ) { NextScreenIcon() }

View file

@ -243,7 +243,7 @@ private fun getSpecificallySortedLocales(firstLocale: Locale?): List<Locale?> {
} }
fun Locale?.getLocaleDisplayNameForUserDictSettings(context: Context) = fun Locale?.getLocaleDisplayNameForUserDictSettings(context: Context) =
this?.localizedDisplayName(context) ?: context.resources.getString(R.string.user_dict_settings_all_languages) this?.localizedDisplayName(context.resources) ?: context.resources.getString(R.string.user_dict_settings_all_languages)
// weight is frequency but different name towards user // weight is frequency but different name towards user
private data class Word(val word: String, val shortcut: String?, val weight: Int?) private data class Word(val word: String, val shortcut: String?, val weight: Int?)

View file

@ -141,7 +141,7 @@ fun SubtypeScreen(
SubtypeSettings.removeEnabledSubtype(ctx, currentSubtype.toAdditionalSubtype()) SubtypeSettings.removeEnabledSubtype(ctx, currentSubtype.toAdditionalSubtype())
onClickBack() onClickBack()
} }, } },
title = { Text(currentSubtype.toAdditionalSubtype().displayName(ctx)) }, title = { Text(currentSubtype.toAdditionalSubtype().displayName()) },
itemContent = { }, itemContent = { },
filteredItems = { emptyList<String>() } filteredItems = { emptyList<String>() }
) { ) {
@ -158,7 +158,7 @@ fun SubtypeScreen(
WithSmallTitle(stringResource(R.string.secondary_locale)) { WithSmallTitle(stringResource(R.string.secondary_locale)) {
TextButton(onClick = { showSecondaryLocaleDialog = true }) { TextButton(onClick = { showSecondaryLocaleDialog = true }) {
val text = getSecondaryLocales(currentSubtype.extraValues).joinToString(", ") { val text = getSecondaryLocales(currentSubtype.extraValues).joinToString(", ") {
it.localizedDisplayName(ctx) it.localizedDisplayName(ctx.resources)
}.ifEmpty { stringResource(R.string.action_none) } }.ifEmpty { stringResource(R.string.action_none) }
Text(text, Modifier.fillMaxWidth()) Text(text, Modifier.fillMaxWidth())
} }
@ -282,7 +282,7 @@ fun SubtypeScreen(
items = availableLocalesForScript, items = availableLocalesForScript,
initialSelection = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES) initialSelection = currentSubtype.getExtraValueOf(ExtraValue.SECONDARY_LOCALES)
?.split(Separators.KV)?.map { it.constructLocale() }.orEmpty(), ?.split(Separators.KV)?.map { it.constructLocale() }.orEmpty(),
getItemName = { it.localizedDisplayName(ctx) } getItemName = { it.localizedDisplayName(ctx.resources) }
) )
if (showKeyOrderDialog) { if (showKeyOrderDialog) {
val setting = currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER) val setting = currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER)