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;
mInputMethodInfoCache = new InputMethodInfoCache(mImm, context.getPackageName());
// Initialize subtype utils.
SubtypeLocaleUtils.init(context);
// Initialize the current input method subtype and the shortcut IME.
refreshSubtypeCaches();
}

View file

@ -8,10 +8,10 @@ package helium314.keyboard.latin.common
import android.content.Context
import android.content.res.Resources
import helium314.keyboard.compat.locale
import helium314.keyboard.latin.BuildConfig
import helium314.keyboard.latin.R
import helium314.keyboard.latin.utils.ScriptUtils.script
import helium314.keyboard.latin.utils.SubtypeLocaleUtils
import helium314.keyboard.latin.utils.runInLocale
import java.util.Locale
/**
@ -171,32 +171,34 @@ object LocaleUtils {
}
}
fun Locale.localizedDisplayName(context: Context) =
getLocaleDisplayNameInLocale(this, context.resources, context.resources.configuration.locale())
fun Locale.localizedDisplayName(resources: Resources, displayLocale: Locale? = null): String {
val languageTag = toLanguageTag()
if (languageTag == SubtypeLocaleUtils.NO_LANGUAGE)
return resources.getString(R.string.subtype_no_language) // todo: remove the (Alphabet)
@JvmStatic
fun getLocaleDisplayNameInLocale(locale: Locale, resources: Resources, displayLocale: Locale): String {
val languageTag = locale.toLanguageTag()
if (languageTag == SubtypeLocaleUtils.NO_LANGUAGE) return resources.getString(R.string.subtype_no_language)
if (hasNonDefaultScript(locale) || doesNotHaveAndroidName(locale.language)) {
// supply our own name for the language instead of using name provided by the system
val resId = resources.getIdentifier(
"subtype_${languageTag.replace("-", "_")}",
"string",
BuildConfig.APPLICATION_ID // replaces context.packageName, see https://stackoverflow.com/a/24525379
)
if (resId != 0) return resources.getString(resId)
val overrideResId = when (languageTag) {
"en-US" -> R.string.subtype_en_US
"en-GB" -> R.string.subtype_en_GB
"es-US" -> R.string.subtype_es_US
"hi-Latn" -> R.string.subtype_hi_Latn
"sr-Latn" -> R.string.subtype_sr_Latn
"mns" -> R.string.subtype_mns
"xdq" -> R.string.subtype_xdq
"dru" -> R.string.subtype_xdq
"st" -> R.string.subtype_st
"dag" -> R.string.subtype_dag
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) {
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 {
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
enabledImis.forEach { imi ->
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()) {
enabledSubtypes.add(imi to null)
} else {
@ -45,7 +45,7 @@ fun createInputMethodPickerDialog(latinIme: LatinIME, richImm: RichInputMethodMa
for (imiAndSubtype in enabledSubtypes) {
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)
val title = SpannableString(subtypeName?.ifBlank { imi.loadLabel(pm) } ?: 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.common.Constants.Subtype.ExtraValue
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.StringUtils
import helium314.keyboard.latin.utils.LayoutType.Companion.getMainLayoutFromExtraValue
@ -157,7 +156,7 @@ object SubtypeLocaleUtils {
val displayName = if (exceptionalNameResId != null) {
runInLocale(resources, displayLocale) { res: Resources -> res.getString(exceptionalNameResId) }
} else {
getLocaleDisplayNameInLocale(locale, resources, displayLocale)
locale.localizedDisplayName(resources, displayLocale)
}
return StringUtils.capitalizeFirstCodePoint(displayName, displayLocale)
}
@ -233,10 +232,10 @@ object SubtypeLocaleUtils {
if (LayoutUtilsCustom.isCustomLayout(layoutName)) LayoutUtilsCustom.getDisplayName(layoutName)
else keyboardLayoutToDisplayName[layoutName]
fun InputMethodSubtype.displayName(context: Context): String {
fun InputMethodSubtype.displayName(): String {
val layoutName = mainLayoutNameOrQwerty()
if (LayoutUtilsCustom.isCustomLayout(layoutName))
return "${locale().localizedDisplayName(context)} (${LayoutUtilsCustom.getDisplayName(layoutName)})"
return "${locale().localizedDisplayName(resources)} (${LayoutUtilsCustom.getDisplayName(layoutName)})"
return getSubtypeDisplayNameInSystemLocale(this)
}

View file

@ -50,6 +50,7 @@ import helium314.keyboard.settings.previewDark
import helium314.keyboard.settings.screens.getUserAndInternalDictionaries
import java.io.File
import java.util.Locale
import androidx.compose.ui.platform.LocalConfiguration
@Composable
fun DictionaryDialog(
@ -66,7 +67,7 @@ fun DictionaryDialog(
onConfirmed = {},
confirmButtonText = null,
cancelButtonText = stringResource(R.string.dialog_close),
title = { Text(locale.localizedDisplayName(ctx)) },
title = { Text(locale.localizedDisplayName(ctx.resources)) },
content = {
val state = rememberScrollState()
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
Text(
header.info(LocalContext.current.resources.configuration.locale()),
header.info(LocalConfiguration.current.locale()),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(horizontal = 10.dp)
)

View file

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

View file

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

View file

@ -75,7 +75,7 @@ fun LanguageScreen(
},
filteredItems = { term ->
sortedSubtypes.filter {
it.displayName(ctx).replace("(", "")
it.displayName().replace("(", "")
.splitOnWhitespace().any { it.startsWith(term, true) }
}
},
@ -91,10 +91,10 @@ fun LanguageScreen(
) {
var showNoDictDialog by remember { mutableStateOf(false) }
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 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" } ?: "")
} else 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
else it.locale == SubtypeLocaleUtils.NO_LANGUAGE
},
{ it.displayName(context) }
{ it.displayName() }
)
return SubtypeSettings.getAllAvailableSubtypes().sortedWith(subtypeSortComparator)
}

View file

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

View file

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