mirror of
https://github.com/Stypox/dicio-android.git
synced 2026-01-09 06:12:01 +08:00
Merge pull request #348 from Inhishonor/language-supported-function
This commit is contained in:
commit
68ea25e7c2
@ -71,7 +71,7 @@ class LocaleManager @Inject constructor(
|
||||
|
||||
private fun getSentencesLocale(language: Language): LocaleUtils.LocaleResolutionResult {
|
||||
return try {
|
||||
LocaleUtils.resolveSupportedLocale(
|
||||
LocaleUtils.resolveSupportedLocaleOrThrow(
|
||||
getAvailableLocalesFromLanguage(language),
|
||||
Sentences.languages
|
||||
)
|
||||
|
||||
@ -21,7 +21,6 @@ package org.stypox.dicio.io.input.vosk
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -110,15 +109,7 @@ class VoskInputDevice(
|
||||
|
||||
private fun init(locale: Locale): VoskState {
|
||||
// choose the model url based on the locale
|
||||
val modelUrl = try {
|
||||
val localeResolutionResult = LocaleUtils.resolveSupportedLocale(
|
||||
LocaleListCompat.create(locale),
|
||||
MODEL_URLS.keys
|
||||
)
|
||||
MODEL_URLS[localeResolutionResult.supportedLocaleString]
|
||||
} catch (_: LocaleUtils.UnsupportedLocaleException) {
|
||||
null
|
||||
}
|
||||
val modelUrl = LocaleUtils.resolveValueForSupportedLocale(locale, MODEL_URLS)
|
||||
|
||||
// the model url may change if the user changes app language, or in case of model updates
|
||||
val modelUrlChanged = try {
|
||||
|
||||
@ -5,7 +5,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.EmojiEmotions
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import org.dicio.skill.context.SkillContext
|
||||
import org.dicio.skill.skill.Skill
|
||||
import org.dicio.skill.skill.SkillInfo
|
||||
@ -25,16 +24,8 @@ object JokeInfo : SkillInfo("Joke") {
|
||||
rememberVectorPainter(Icons.Default.EmojiEmotions)
|
||||
|
||||
override fun isAvailable(ctx: SkillContext): Boolean {
|
||||
val hasSupportedLocale = try {
|
||||
LocaleUtils.resolveSupportedLocale(
|
||||
LocaleListCompat.create(ctx.locale),
|
||||
JokeSkill.JOKE_SUPPORTED_LOCALES
|
||||
)
|
||||
true
|
||||
} catch (ignored: LocaleUtils.UnsupportedLocaleException) {
|
||||
false
|
||||
}
|
||||
return (Sentences.Joke[ctx.sentencesLanguage] != null) && hasSupportedLocale
|
||||
return (Sentences.Joke[ctx.sentencesLanguage] != null) &&
|
||||
LocaleUtils.isLocaleSupported(ctx.locale, JokeSkill.JOKE_SUPPORTED_LOCALES)
|
||||
}
|
||||
|
||||
override fun build(ctx: SkillContext): Skill<*> {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package org.stypox.dicio.skills.joke
|
||||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import org.dicio.skill.context.SkillContext
|
||||
import org.dicio.skill.skill.SkillInfo
|
||||
import org.dicio.skill.skill.SkillOutput
|
||||
@ -14,15 +13,9 @@ import org.stypox.dicio.util.LocaleUtils
|
||||
class JokeSkill(correspondingSkillInfo: SkillInfo, data: StandardRecognizerData<Joke>)
|
||||
: StandardRecognizerSkill<Joke>(correspondingSkillInfo, data) {
|
||||
override suspend fun generateOutput(ctx: SkillContext, inputData: Joke): SkillOutput {
|
||||
var resolvedLocale: LocaleUtils.LocaleResolutionResult? = null
|
||||
try {
|
||||
resolvedLocale = LocaleUtils.resolveSupportedLocale(
|
||||
LocaleListCompat.create(ctx.locale),
|
||||
JOKE_SUPPORTED_LOCALES
|
||||
)
|
||||
} catch (ignored: LocaleUtils.UnsupportedLocaleException) {
|
||||
}
|
||||
val locale = resolvedLocale?.supportedLocaleString ?: ""
|
||||
// we can use !! because the JokeInfo would have declared this skill unavailable
|
||||
// if the current locale was not among the supported ones
|
||||
val locale = LocaleUtils.resolveSupportedLocale(ctx.locale, JOKE_SUPPORTED_LOCALES)!!
|
||||
|
||||
if (locale == "en") {
|
||||
val joke: JSONObject = ConnectionUtils.getPageJson(RANDOM_JOKE_URL_EN)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package org.stypox.dicio.skills.search
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import org.dicio.skill.context.SkillContext
|
||||
import org.dicio.skill.skill.SkillInfo
|
||||
import org.dicio.skill.skill.SkillOutput
|
||||
@ -32,19 +31,20 @@ private val DUCK_DUCK_GO_SUPPORTED_LOCALES = listOf(
|
||||
"it-it", "jp-jp", "kr-kr", "lv-lv", "lt-lt", "my-en", "mx-es", "nl-nl", "nz-en",
|
||||
"no-no", "pk-en", "pe-es", "ph-en", "pl-pl", "pt-pt", "ro-ro", "ru-ru", "xa-ar",
|
||||
"sg-en", "sk-sk", "sl-sl", "za-en", "es-ca", "es-es", "se-sv", "ch-de", "ch-fr",
|
||||
"tw-tz", "th-en", "tr-tr", "us-en", "us-es", "ua-uk", "uk-en", "vn-en"
|
||||
"tw-tz", "th-en", "tr-tr", /*"us-en",*/ "us-es", "ua-uk", "uk-en", "vn-en"
|
||||
)
|
||||
|
||||
internal fun searchOnDuckDuckGo(ctx: SkillContext, query: String): List<SearchOutput.Data> {
|
||||
// find the locale supported by DuckDuckGo that matches the user locale the most
|
||||
var resolvedLocale: LocaleUtils.LocaleResolutionResult? = null
|
||||
try {
|
||||
resolvedLocale = LocaleUtils.resolveSupportedLocale(
|
||||
LocaleListCompat.create(ctx.locale), DUCK_DUCK_GO_SUPPORTED_LOCALES
|
||||
)
|
||||
} catch (_: LocaleUtils.UnsupportedLocaleException) {
|
||||
}
|
||||
val locale = resolvedLocale?.supportedLocaleString ?: ""
|
||||
val locale = LocaleUtils.resolveValueForSupportedLocale(
|
||||
ctx.locale,
|
||||
DUCK_DUCK_GO_SUPPORTED_LOCALES.associateBy {
|
||||
// DuckDuckGo locale names have first the country and then the language, but the locale
|
||||
// selection function assumes the opposite
|
||||
it.split("-").reversed().joinToString(separator = "_")
|
||||
}
|
||||
// default to English when no locale is supported
|
||||
) ?: "us-en"
|
||||
|
||||
// make request using headers
|
||||
val html: String = ConnectionUtils.getPage(
|
||||
|
||||
@ -5,7 +5,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Language
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import org.dicio.skill.context.SkillContext
|
||||
import org.dicio.skill.skill.Skill
|
||||
import org.dicio.skill.skill.SkillInfo
|
||||
@ -25,16 +24,8 @@ object TranslationInfo : SkillInfo("translation") {
|
||||
rememberVectorPainter(Icons.Default.Language)
|
||||
|
||||
override fun isAvailable(ctx: SkillContext): Boolean {
|
||||
val hasSupportedLocale = try {
|
||||
LocaleUtils.resolveSupportedLocale(
|
||||
LocaleListCompat.create(ctx.locale),
|
||||
TranslationSkill.TRANSLATE_SUPPORTED_LOCALES
|
||||
)
|
||||
true
|
||||
} catch (ignored: LocaleUtils.UnsupportedLocaleException) {
|
||||
false
|
||||
}
|
||||
return (Sentences.Translation[ctx.sentencesLanguage] != null) && hasSupportedLocale
|
||||
return (Sentences.Translation[ctx.sentencesLanguage] != null) &&
|
||||
LocaleUtils.isLocaleSupported(ctx.locale, TranslationSkill.TRANSLATE_SUPPORTED_LOCALES)
|
||||
}
|
||||
|
||||
override fun build(ctx: SkillContext): Skill<*> {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package org.stypox.dicio.skills.translation
|
||||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import org.dicio.skill.context.SkillContext
|
||||
import org.dicio.skill.skill.SkillInfo
|
||||
import org.dicio.skill.skill.SkillOutput
|
||||
@ -18,19 +17,6 @@ import org.stypox.dicio.util.getLocaleByLanguageName
|
||||
class TranslationSkill(correspondingSkillInfo: SkillInfo, data: StandardRecognizerData<Translation>)
|
||||
: StandardRecognizerSkill<Translation>(correspondingSkillInfo, data) {
|
||||
|
||||
private fun determineCurrentLocale(ctx: SkillContext): String {
|
||||
var resolvedLocale: LocaleUtils.LocaleResolutionResult? = null
|
||||
try {
|
||||
resolvedLocale = LocaleUtils.resolveSupportedLocale(
|
||||
LocaleListCompat.create(ctx.locale),
|
||||
TRANSLATE_SUPPORTED_LOCALES
|
||||
)
|
||||
} catch (_: LocaleUtils.UnsupportedLocaleException) {
|
||||
}
|
||||
val locale = resolvedLocale?.supportedLocaleString ?: ""
|
||||
return locale
|
||||
}
|
||||
|
||||
private fun findCodeInSupportedLocales(language: LocaleAndTranslation): String? {
|
||||
return TRANSLATE_SUPPORTED_LOCALES.firstOrNull { it.lowercase() == language.locale }
|
||||
?: TRANSLATE_SUPPORTED_LOCALES.firstOrNull { language.locale.startsWith(it.lowercase()) }
|
||||
@ -40,7 +26,12 @@ class TranslationSkill(correspondingSkillInfo: SkillInfo, data: StandardRecogniz
|
||||
// TODO: Add more servers in like Libre Translate or DeepL
|
||||
override suspend fun generateOutput(ctx: SkillContext, inputData: Translation): SkillOutput {
|
||||
val input = when (inputData) { is Translate -> inputData }
|
||||
val currentLocale = determineCurrentLocale(ctx)
|
||||
// we can use !! because the TranslationInfo would have declared this skill unavailable
|
||||
// if the current locale was not among the supported ones
|
||||
val currentLocale = LocaleUtils.resolveSupportedLocale(
|
||||
ctx.locale, TRANSLATE_SUPPORTED_LOCALES)!!
|
||||
// we can use !! here because `CldrLanguages` is generated by the `unicode-cldr-plugin`
|
||||
// based on the locales supported by the app, and `ctx.locale` is surely such a locale
|
||||
val cldr = CldrLanguages[ctx.locale.language]!!
|
||||
|
||||
// extract the query from the input
|
||||
|
||||
@ -4,6 +4,7 @@ import androidx.core.os.LocaleListCompat
|
||||
import java.util.Locale
|
||||
|
||||
object LocaleUtils {
|
||||
|
||||
/**
|
||||
* Basically implements Android locale resolution (not sure if exactly the same, probably,
|
||||
* though), so it tries, in this order:<br></br>
|
||||
@ -23,7 +24,7 @@ object LocaleUtils {
|
||||
* @throws UnsupportedLocaleException if the locale resolution failed.
|
||||
*/
|
||||
@Throws(UnsupportedLocaleException::class)
|
||||
fun resolveSupportedLocale(
|
||||
fun resolveSupportedLocaleOrThrow(
|
||||
availableLocales: LocaleListCompat,
|
||||
supportedLocales: Collection<String>
|
||||
): LocaleResolutionResult {
|
||||
@ -48,7 +49,7 @@ object LocaleUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see resolveSupportedLocale
|
||||
* @see resolveSupportedLocaleOrThrow
|
||||
*/
|
||||
@Throws(UnsupportedLocaleException::class)
|
||||
fun resolveLocaleString(
|
||||
@ -95,12 +96,74 @@ object LocaleUtils {
|
||||
.toTypedArray()
|
||||
|
||||
return if (languageCountryArr.size == 1) {
|
||||
Locale(languageCountryArr[0])
|
||||
Locale.Builder()
|
||||
.setLanguage(languageCountryArr[0])
|
||||
.build()
|
||||
} else {
|
||||
Locale(languageCountryArr[0], languageCountryArr[1])
|
||||
Locale.Builder()
|
||||
.setLanguage(languageCountryArr[0])
|
||||
.setRegion(languageCountryArr[1])
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like [resolveSupportedLocaleOrThrow], but returns null instead of throwing an exception.
|
||||
*/
|
||||
fun resolveSupportedLocale(
|
||||
availableLocales: LocaleListCompat,
|
||||
supportedLocales: Collection<String>
|
||||
): LocaleResolutionResult? {
|
||||
return try {
|
||||
resolveSupportedLocaleOrThrow(availableLocales, supportedLocales)
|
||||
} catch (_: UnsupportedLocaleException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses [resolveSupportedLocaleOrThrow] to find a supported locale string in [supportedLocales]
|
||||
* matching [currentLocale], and returns it. This is NOT meant to be used for locale resolution
|
||||
* when the app starts, but only to select the correct item from a list using the app's current
|
||||
* locale (that has already been determined, hence the parameter name [currentLocale]).
|
||||
*/
|
||||
fun resolveSupportedLocale(
|
||||
currentLocale: Locale,
|
||||
supportedLocales: Collection<String>
|
||||
): String? {
|
||||
return resolveSupportedLocale(
|
||||
availableLocales = LocaleListCompat.create(currentLocale),
|
||||
supportedLocales = supportedLocales
|
||||
)?.supportedLocaleString
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses [resolveSupportedLocale] to find a supported locale string matching [currentLocale] in
|
||||
* the keys of [supportedLocalesAndValues], and returns the corresponding value.
|
||||
*/
|
||||
fun <T> resolveValueForSupportedLocale(
|
||||
currentLocale: Locale,
|
||||
supportedLocalesAndValues: Map<String, T>
|
||||
): T? {
|
||||
return resolveSupportedLocale(
|
||||
availableLocales = LocaleListCompat.create(currentLocale),
|
||||
supportedLocales = supportedLocalesAndValues.keys
|
||||
)?.let {
|
||||
supportedLocalesAndValues[it.supportedLocaleString]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the [currentLocale] matches with any of the [supportedLocales] using
|
||||
* [resolveSupportedLocale].
|
||||
*/
|
||||
fun isLocaleSupported(currentLocale: Locale, supportedLocales: List<String>): Boolean {
|
||||
return resolveSupportedLocale(
|
||||
LocaleListCompat.create(currentLocale),
|
||||
supportedLocales
|
||||
) != null
|
||||
}
|
||||
|
||||
class UnsupportedLocaleException : Exception {
|
||||
constructor(locale: Locale) : super("Unsupported locale: $locale")
|
||||
constructor() : super("No locales provided")
|
||||
|
||||
@ -33,7 +33,7 @@ private fun assertLocaleNotFound(locale: String, vararg supportedLocales: String
|
||||
val localeString: String
|
||||
try {
|
||||
localeString = getLocaleString(locale, *supportedLocales)
|
||||
} catch (e: UnsupportedLocaleException) {
|
||||
} catch (_: UnsupportedLocaleException) {
|
||||
return
|
||||
}
|
||||
error("The locale \"$locale\" should not have been found: $localeString")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user