Internacionalização (i18n) em Kotlin: Guia Completo com Exemplos
\n\nInternacionalização (i18n) é o processo de projetar e desenvolver software para que ele possa ser adaptado a diferentes idiomas e regiões sem alterações no código-fonte. No ecossistema Kotlin, seja em aplicativos Android, projetos de servidor com Ktor ou soluções multiplataforma com Kotlin Multiplatform, a implementação correta de i18n é fundamental para o sucesso global do produto. Neste artigo, abordaremos as principais abordagens, ferramentas e melhores práticas para internacionalizar aplicações Kotlin.
\n\nPor que i18n é importante em Kotlin?
\nKotlin, sendo uma linguagem moderna totalmente compatível com Java, herda todos os recursos de localização do Java, mas também oferece soluções únicas. A internacionalização adequada permite:
\n- \n
- Expandir significativamente o público do seu aplicativo \n
- Melhorar a experiência do usuário para falantes de diferentes idiomas \n
- Cumprir requisitos legais de diferentes países (por exemplo, relacionados a moedas ou formatos de data) \n
- Simplificar o processo de adição de novos idiomas no futuro \n
Principais abordagens para i18n em Kotlin
\n1. Uso de Resource Bundle (abordagem compatível com Java)
\nA maneira mais comum e simples é usar os padrões ResourceBundle e arquivos de propriedades (.properties). Este método é ideal para aplicações de console e projetos de servidor em Kotlin.
// messages_en.properties\ngreeting=Hello, {0}!\nfarewell=Goodbye\n\n// messages_ru.properties\ngreeting=Привет, {0}!\nfarewell=До свидания\n\nimport java.util.ResourceBundle\nimport java.text.MessageFormat\n\nfun main() {\n val bundle = ResourceBundle.getBundle("messages", Locale("ru"))\n val greeting = MessageFormat.format(bundle.getString("greeting"), "Мир")\n println(greeting) // Выведет: Привет, Мир!\n \n println(bundle.getString("farewell")) // Выведет: До свидания\n}\n\n2. Abordagem específica do Kotlin com funções de extensão
\nKotlin permite criar uma API mais concisa e segura para trabalhar com localização, usando funções de extensão e propriedades delegadas.
\n\nimport java.util.*\nimport kotlin.properties.ReadOnlyProperty\nimport kotlin.reflect.KProperty\n\nclass I18n(private val baseName: String) {\n private val bundle: ResourceBundle\n get() = ResourceBundle.getBundle(baseName)\n \n operator fun provideDelegate(\n thisRef: Any?, \n prop: KProperty<*>\n ): ReadOnlyProperty {\n return ReadOnlyProperty { _, _ -> bundle.getString(prop.name) }\n }\n}\n\nobject Strings {\n val i18n = I18n("messages")\n \n val greeting by i18n\n val farewell by i18n\n}\n\nfun main() {\n // Automatisch verwendet die Systemsprache\n println(Strings.greeting) // Exibe o valor correspondente do arquivo de propriedades\n println(Strings.farewell)\n} \n\nFerramentas para localização em Kotlin
\n1. Kotlin Multiplatform (KMP) e expect/actual
\nPara projetos multiplataforma, Kotlin oferece um poderoso mecanismo expect/actual, permitindo declarar uma API comum para i18n e implementá-la separadamente para cada plataforma.
// No código comum (commonMain)\nexpect class PlatformStringResources {\n fun getString(key: String, vararg args: Any?): String\n}\n\n// No Android (androidMain)\nactual class PlatformStringResources {\n private val context: Context = // obtém o contexto\n \n actual fun getString(key: String, vararg args: Any?): String {\n val resId = context.resources.getIdentifier(key, "string", context.packageName)\n return context.getString(resId, *args)\n }\n}\n\n// No iOS (iosMain)\nactual class PlatformStringResources {\n actual fun getString(key: String, vararg args: Any?): Str