added support for overriding locales

This commit is contained in:
Fabian Freund
2025-10-20 16:21:10 +02:00
parent aca0767d9a
commit 1c7e9ec741
66 changed files with 1679 additions and 7 deletions
@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="eu.weblibre.locale_resolver">
</manifest>
@@ -0,0 +1,20 @@
package eu.weblibre.locale_resolver
import eu.weblibre.locale_resolver.pigeons.LocaleResolver
import eu.weblibre.locale_resolver.pigeons.LocalizedResult
import java.util.Locale
class LocaleResolverImpl : LocaleResolver {
override fun resolve(languageTag: String, targetLangouageTag: String): LocalizedResult {
val deviceLocale = Locale.forLanguageTag(targetLangouageTag)
val targetLocale = Locale.forLanguageTag(languageTag)
val languageName = targetLocale.getDisplayLanguage(deviceLocale)
val countryName = targetLocale.getDisplayCountry(deviceLocale)
return LocalizedResult(
languageName,
countryName.ifBlank { null }
)
}
}
@@ -0,0 +1,19 @@
package eu.weblibre.locale_resolver
import eu.weblibre.locale_resolver.pigeons.LocaleResolver
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
/** LocaleResolverPlugin */
class LocaleResolverPlugin : FlutterPlugin {
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
LocaleResolver.setUp(flutterPluginBinding.binaryMessenger, LocaleResolverImpl())
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
}
}
@@ -0,0 +1,166 @@
// Autogenerated from Pigeon (v26.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
package eu.weblibre.locale_resolver.pigeons
import android.util.Log
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MessageCodec
import io.flutter.plugin.common.StandardMethodCodec
import io.flutter.plugin.common.StandardMessageCodec
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
private object LocalesPigeonUtils {
fun wrapResult(result: Any?): List<Any?> {
return listOf(result)
}
fun wrapError(exception: Throwable): List<Any?> {
return if (exception is FlutterError) {
listOf(
exception.code,
exception.message,
exception.details
)
} else {
listOf(
exception.javaClass.simpleName,
exception.toString(),
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)
)
}
}
fun deepEquals(a: Any?, b: Any?): Boolean {
if (a is ByteArray && b is ByteArray) {
return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
return a.contentEquals(b)
}
if (a is Array<*> && b is Array<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is List<*> && b is List<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is Map<*, *> && b is Map<*, *>) {
return a.size == b.size && a.all {
(b as Map<Any?, Any?>).containsKey(it.key) &&
deepEquals(it.value, b[it.key])
}
}
return a == b
}
}
/**
* Error class for passing custom error details to Flutter via a thrown PlatformException.
* @property code The error code.
* @property message The error message.
* @property details The error details. Must be a datatype supported by the api codec.
*/
class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
) : Throwable()
/** Generated class from Pigeon that represents data sent in messages. */
data class LocalizedResult (
val languageName: String,
val countryName: String? = null
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): LocalizedResult {
val languageName = pigeonVar_list[0] as String
val countryName = pigeonVar_list[1] as String?
return LocalizedResult(languageName, countryName)
}
}
fun toList(): List<Any?> {
return listOf(
languageName,
countryName,
)
}
override fun equals(other: Any?): Boolean {
if (other !is LocalizedResult) {
return false
}
if (this === other) {
return true
}
return LocalesPigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
}
private open class LocalesPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
129.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
LocalizedResult.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
when (value) {
is LocalizedResult -> {
stream.write(129)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface LocaleResolver {
fun resolve(languageTag: String, targetLangouageTag: String): LocalizedResult
companion object {
/** The codec used by LocaleResolver. */
val codec: MessageCodec<Any?> by lazy {
LocalesPigeonCodec()
}
/** Sets up an instance of `LocaleResolver` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: LocaleResolver?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.locale_resolver.LocaleResolver.resolve$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val languageTagArg = args[0] as String
val targetLangouageTagArg = args[1] as String
val wrapped: List<Any?> = try {
listOf(api.resolve(languageTagArg, targetLangouageTagArg))
} catch (exception: Throwable) {
LocalesPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
@@ -0,0 +1,27 @@
package eu.weblibre.locale_resolver
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import org.mockito.Mockito
import kotlin.test.Test
/*
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
*
* Once you have built the plugin's example app, you can run these tests from the command
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
* you can run them directly from IDEs that support JUnit such as Android Studio.
*/
internal class LocaleResolverPluginTest {
@Test
fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
val plugin = LocaleResolverPlugin()
val call = MethodCall("getPlatformVersion", null)
val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
plugin.onMethodCall(call, mockResult)
Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
}
}