Skip to main content

Kotlin Multiplatform i18n: kopīga lokalizācija visās platformās

Uzrakstiet tulkojumus vienreiz kopīgajā Kotlin kodā. Izlaidiet tos Android, iOS un tīmeklī ar pareizām lokalizāciju atkāpšanās ķēdēm.

1

Konfigurēt Gradle KMP i18n

Pievienojiet i18n atkarības kopīgā moduļa commonMain avotu kopai. Varat izvēlēties moko-resources uz XML balstītām virknēm, Lyricist tipu drošām Compose virknēm vai abus. kmp-localechain pievieno viedu lokalizācijas atkāpšanos virs jebkura no tiem.

build.gradle.kts
// build.gradle.kts (shared module)
plugins {
    kotlin("multiplatform")
    id("com.android.library")
}

kotlin {
    androidTarget()
    iosArm64()
    iosSimulatorArm64()
    js(IR) { browser(); nodejs() }

    sourceSets {
        val commonMain by getting {
            dependencies {
                // Option A: moko-resources (code-gen from XML)
                implementation("dev.icerock.moko:resources:0.24.4")

                // Option B: Lyricist (type-safe Compose strings)
                implementation("cafe.adriel.lyricist:lyricist:1.7.0")

                // Locale fallback chains (works with any library)
                implementation("com.i18nagent:locale-chain-kmp:0.1.0")
            }
        }
    }
}
Visas trīs bibliotēkas tiek publicētas Maven Central. Pievienojiet tās commonMain atkarībām, lai tās būtu pieejamas katrā mērķī (Android, iOS, JS).
2

Definēt kopīgus virkņu tipus

Izveidojiet Kotlin datu klases commonMain, kurās glabājas visas tulkojamās virknes. Tas ir vienīgais patiesības avots: katra platforma nolasa vienas un tās pašas tipu drošās definīcijas. Bez dublētiem virkņu failiem vai novirzes starp platformām.

commonMain/.../Strings.kt
// commonMain/kotlin/com/myapp/Strings.kt
package com.myapp.i18n

/**
 * Shared string definitions — the single source of truth.
 * Each platform reads from the same keys.
 */
data class AppStrings(
    val greeting: String,
    val farewell: String,
    val itemCount: (count: Int) -> String,
    val nav: NavStrings,
)

data class NavStrings(
    val home: String,
    val settings: String,
    val about: String,
)

// English defaults
val EnStrings = AppStrings(
    greeting = "Hello!",
    farewell = "Goodbye!",
    itemCount = { count ->
        if (count == 1) "$count item" else "$count items"
    },
    nav = NavStrings(
        home = "Home",
        settings = "Settings",
        about = "About",
    ),
)

// Japanese
val JaStrings = AppStrings(
    greeting = "こんにちは!",
    farewell = "さようなら!",
    itemCount = { count -> "${count}個のアイテム" },
    nav = NavStrings(
        home = "ホーム",
        settings = "設定",
        about = "概要",
    ),
)

// Add more locales following the same pattern: DeStrings, EsStrings, etc.
Daudzskaitlim izmantojiet lambda rekvizītus, nevis atsevišķas vienskaitļa un daudzskaitļa atslēgas. Lambda saņem skaitu un atgriež pareizo formu. Tas uztur daudzskaitļa loģiku Kotlin kodā, kur to var pārbaudīt kompilators.
3

Savienot Android

androidMain vidē ieviesiet expect/actual modeli ierīces lokalizācijas nolasīšanai ar java.util.Locale. Android var izmantot kopīgās Kotlin virknes biznesa loģikai līdzās standarta values/strings.xml sistēmas UI elementiem, piemēram, paziņojumiem un logrīkiem.

androidMain/.../StringProvider.kt
// androidMain/kotlin/com/myapp/StringProvider.kt
package com.myapp.i18n

import java.util.Locale

actual fun currentLocale(): String =
    Locale.getDefault().toLanguageTag()  // e.g. "pt-BR"

// Android can also use standard resources/values-*/strings.xml
// alongside the shared Kotlin definitions.
// Use shared strings for business logic, XML for system UI.

// In your Activity or Compose screen:
@Composable
fun GreetingScreen() {
    val strings = rememberStrings()  // resolves via locale
    Text(text = strings.greeting)
    Text(text = strings.itemCount(cartSize))
}
Locale.getDefault().toLanguageTag() atgriež IETF tagus, piemēram, „pt-BR“, taču dažas Android versijas no vecākām API atgriež „pt-rBR“. Konsekventiem rezultātiem vienmēr izmantojiet toLanguageTag() (API 21+).
4

Savienot iOS

iosMain vidē ieviesiet currentLocale(), izmantojot NSLocale no Foundation. Kopīgā KMP sistēma eksportē virkņu definīcijas uz Swift, tādēļ SwiftUI skati var tās izsaukt tieši caur ģenerēto Kotlin sistēmu.

iosMain/.../StringProvider.kt
// iosMain/kotlin/com/myapp/StringProvider.kt
package com.myapp.i18n

import platform.Foundation.NSLocale
import platform.Foundation.currentLocale
import platform.Foundation.languageCode
import platform.Foundation.countryCode

actual fun currentLocale(): String {
    val locale = NSLocale.currentLocale
    val lang = locale.languageCode
    val country = locale.countryCode
    return if (country != null) "$lang-$country" else lang
}

// In SwiftUI (via KMP exported framework):
// let strings = StringProviderKt.stringsFor(locale: "ja")
// Text(strings.greeting)
Eksportējot KMP sistēmu uz Xcode, pārliecinieties, ka eksportējat virkņu nodrošinātāja moduli. Podspec vai XCFramework konfigurācijā iekļaujiet i18n pakotni, lai Swift kods varētu to importēt.
5

Savienot JS / pārlūku

jsMain vidē nolasiet pārlūka lokalizāciju no window.navigator.language. Tas aptver gan Kotlin/JS tīmekļa lietotnes, gan Compose for Web mērķus. Tās pašas kopīgās virknes tiek atveidotas pārlūkā bez dublēšanas.

jsMain/.../StringProvider.kt
// jsMain/kotlin/com/myapp/StringProvider.kt
package com.myapp.i18n

import kotlinx.browser.window

actual fun currentLocale(): String =
    window.navigator.language  // e.g. "en-US", "pt-BR"

// In a Kotlin/JS or Compose for Web app:
fun main() {
    val locale = currentLocale()
    val strings = stringsFor(locale)
    document.getElementById("greeting")?.textContent = strings.greeting
}
Serverpuses Kotlin/JS (Node.js) gadījumā nolasiet lokalizāciju no galvenes Accept-Language vai konfigurācijas mainīgā, nevis window.navigator.language.
6

Lyricist Compose Multiplatform videi

Lyricist nodrošina Compose vietējo i18n pieeju. Anotējiet virkņu objektus ar @LyricistStrings, un Lyricist ģenerēs CompositionLocal nodrošinātāju. Pārslēdziet valodas izpildlaikā, mainot languageTag — UI automātiski pārkomponējas.

Lyricist integration
// Using Lyricist for Compose Multiplatform
// build.gradle.kts
plugins {
    id("cafe.adriel.lyricist") version "1.7.0"
}

// Define strings with @LyricistStrings annotation
@LyricistStrings(languageTag = Locales.EN, default = true)
val EnStrings = Strings(
    greeting = "Hello!",
    farewell = "Goodbye!",
    itemCount = { count ->
        if (count == 1) "$count item" else "$count items"
    },
)

@LyricistStrings(languageTag = Locales.JA)
val JaStrings = Strings(
    greeting = "こんにちは!",
    farewell = "さようなら!",
    itemCount = { count -> "${count}個のアイテム" },
)

// In your Compose UI
@Composable
fun App() {
    // Lyricist provides the strings via CompositionLocal
    ProvideStrings {
        val lyricist = LocalStrings.current
        Text(text = lyricist.greeting)
    }
}

// Switch language at runtime
val lyricist = rememberLyricist(
    defaultLanguageTag = Locales.EN,
)
lyricist.languageTag = Locales.JA  // UI recomposes automatically
Lyricist atbalsta virkņu interpolāciju, daudzskaitli ar lambda funkcijām un ligzdotas virkņu grupas. Tas darbojas Android, iOS (ar Compose for iOS), darbvirsmas un tīmekļa mērķos.
7

moko-resources XML virknēm

moko-resources izmanto Android stila XML virkņu failus kā vienīgo patiesības avotu un ģenerē tipu drošus piekļuves rīkus. Definējiet virknes direktorijā commonMain/resources/MR/base/ (angļu) un pievienojiet lokalizācijas mapes katrai valodai. Ģenerētais MR objekts nodrošina kompilēšanas laikā pārbaudītu piekļuvi.

moko-resources setup
// Using moko-resources for XML-based string management
// build.gradle.kts
plugins {
    id("dev.icerock.mobile.multiplatform-resources") version "0.24.4"
}

multiplatformResources {
    resourcesPackage.set("com.myapp")
}

// commonMain/resources/MR/base/strings.xml (English - default)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="greeting">Hello!</string>
    <string name="farewell">Goodbye!</string>
    <plurals name="item_count">
        <item quantity="one">%d item</item>
        <item quantity="other">%d items</item>
    </plurals>
</resources>

// commonMain/resources/MR/ja/strings.xml (Japanese)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="greeting">こんにちは!</string>
    <string name="farewell">さようなら!</string>
    <plurals name="item_count">
        <item quantity="other">%d個のアイテム</item>
    </plurals>
</resources>

// Usage in shared Kotlin code
val greeting = MR.strings.greeting.desc()
val items = MR.plurals.item_count.format(count)
moko-resources koda ģenerēšanai vajadzīgs Gradle spraudnis. Ja redzat „Unresolved reference: MR“, vispirms palaidiet Gradle sinhronizāciju. Koda ģenerēšanas solim jābūt pabeigtam, pirms IDE redz MR piekļuves rīkus.
8

Vieda lokalizācijas atkāpšanās ar kmp-localechain

KMP i18n bibliotēkām nav konfigurējamu atkāpšanās ķēžu. Ja trūkst pt-BR tulkojumu, tās pilnībā izlaiž pt-PT un rāda angļu valodu. kmp-localechain to novērš ar patstāvīgu ziņojumu sapludināšanas utilītu. Tā pieņem plakanus Map&lt;String, String&gt; ziņojumus katrai lokalizācijai un atgriež sapludinātu karti ar piemērotu atkāpšanās ķēdes prioritāti.

LocaleChain usage
// Using kmp-localechain for smart locale fallback
import com.i18nagent.localechain.LocaleChain

// 1. Configure once at app startup
LocaleChain.configure()  // uses built-in fallback chains

// 2. Load your messages as flat maps
val messages = mapOf(
    "en" to mapOf("greeting" to "Hello", "farewell" to "Goodbye"),
    "pt" to mapOf("greeting" to "Olá", "farewell" to "Adeus"),
    "pt-PT" to mapOf("greeting" to "Olá (PT)"),
    "pt-BR" to mapOf("greeting" to "Oi"),
)

// 3. Resolve with chain priority
val resolved = LocaleChain.resolve("pt-BR", messages)
// "greeting" -> "Oi"       (from pt-BR, most specific)
// "farewell" -> "Adeus"    (from pt, next in chain)

// Without LocaleChain, pt-BR users would see English "Goodbye"
// because pt-BR has no "farewell" key.
Custom configuration
// Custom fallback configuration
LocaleChain.configure(
    defaultLocale = "en",
    overrides = mapOf(
        "es-MX" to listOf("es-419", "es"),
        "fr-CA" to listOf("fr"),
    )
)

// Inspect any chain
LocaleChain.chainFor("pt-BR")
// Returns: ["pt-BR", "pt-PT", "pt", "en"]

// Async resolve (lazy loading from network/disk)
val resolved = LocaleChain.resolve("pt-BR") { localeTag ->
    api.fetchMessages(localeTag)  // returns Map<String, String>?
}
kmp-localechain darbojas ar plakanām Map&lt;String, String&gt; kartēm. Ja ziņojumi ir ligzdoti, saplaciniet tos pirms nodošanas resolve(). Bibliotēka neatbalsta ligzdotu struktūru dziļo sapludināšanu.
9

Automatizēt tulkošanu

Kad KMP i18n iestatīšana ir pabeigta, automatizējiet tulkošanu ar MI. Tulkojiet kopīgos virkņu failus — Kotlin datu klases, XML resursus vai JSON — tieši no IDE vai CI/CD konveijera.

Terminal
# Translate your shared string files with i18n Agent
# Works with JSON, XML (moko-resources), or any i18n format

# From your IDE (Claude Code, Cursor, VS Code):
> Translate commonMain/resources/MR/base/strings.xml to Japanese, German, and Spanish

✓ MR/ja/strings.xml created (1.2s)
✓ MR/de/strings.xml created (1.1s)
✓ MR/es/strings.xml created (1.3s)

# Or use the CLI in CI/CD:
npx i18n-agent translate resources/base/strings.xml --lang ja,de,es
Tulkojiet pakāpeniski. Pievienojot angļu avotam jaunas atslēgas, tulkojiet tikai izmaiņas. Tas saglabā cilvēku pārskatītos tulkojumus un novērš visu failu ģenerēšanu no jauna.

Automatizēt tulkojumu kvalitāti

Ar i18n-validate pirms izlaišanas atrodiet trūkstošās atslēgas un bojātos vietturus. Kamēr īstie tulkojumi vēl nav gatavi, pārbaudiet UI ar i18n-pseudo pseidotulkojumiem.

Biežākās kļūdas

expect/actual neatbilstība

Katrai expect deklarācijai commonMain vajadzīgs actual ieviesums katrā mērķī (androidMain, iosMain, jsMain). Ja vēlāk pievienojat jaunu mērķi, kompilators rādīs kļūdu, līdz nodrošināsiet actual. Izmantojiet IDE ātros labojumus sagatavju ģenerēšanai.

Tieši ierakstīta daudzskaitļa loģika

Vienskaitļa formu noteikšanai nekad neizmantojiet count == 1. Franču valodā 0 uzskata par vienskaitli. Arābu valodā ir sešas daudzskaitļa formas. Krievu valodā izmanto dažādas formas skaitļiem, kas beidzas ar 1, 2-4 un 5-20. Izmantojiet CLDR apzinošas bibliotēkas (moko-resources) vai skaidras lambda funkcijas katrai lokalizācijai.

Ligzdotas kartes kmp-localechain

kmp-localechain darbojas ar plakanu Map&lt;String, String&gt;. Ja nododat ligzdotas kartes, atkāpšanās atrisināšana pareizi nesapludinās iekšējās atslēgas. Pirms resolve() izsaukšanas saplaciniet ziņojumus ar punktu notācijas atslēgām (piemēram, „nav.home“).

Pēc moko-resources pievienošanas trūkst ģenerētā koda

MR objektu ģenerē Gradle spraudnis. Pēc moko-resources virkņu pievienošanas palaidiet Gradle sinhronizāciju pirms MR.strings.* lietošanas kodā. Ja IDE joprojām rāda kļūdas, izmēģiniet Build > Rebuild Project.

Ieteicamā projekta struktūra

Project Structure
my-kmp-app/
├── shared/
│   ├── build.gradle.kts
│   └── src/
│       ├── commonMain/
│       │   ├── kotlin/com/myapp/i18n/
│       │   │   ├── Strings.kt           # Shared string definitions
│       │   │   ├── StringProvider.kt     # expect fun currentLocale()
│       │   │   └── LocaleSetup.kt       # LocaleChain configuration
│       │   └── resources/MR/            # moko-resources XML (optional)
│       │       ├── base/strings.xml     # English (default)
│       │       ├── ja/strings.xml
│       │       ├── de/strings.xml
│       │       └── es/strings.xml
│       ├── androidMain/
│       │   └── kotlin/com/myapp/i18n/
│       │       └── StringProvider.kt     # actual fun currentLocale()
│       ├── iosMain/
│       │   └── kotlin/com/myapp/i18n/
│       │       └── StringProvider.kt     # actual fun currentLocale()
│       └── jsMain/
│           └── kotlin/com/myapp/i18n/
│               └── StringProvider.kt     # actual fun currentLocale()
├── androidApp/
│   └── src/main/res/values/strings.xml   # Android-specific overrides
├── iosApp/
│   └── iosApp/Localizable.strings        # iOS-specific overrides
└── settings.gradle.kts

Izmēģiniet i18n Agent tūlīt

Nometiet tulkošanas failu šeit

JSON, YAML, PO, XML, CSV, Markdown, Properties

vai noklikšķiniet, lai izvēlētos

Mērķa valodas

Reģistrācija nav vajadzīgaTūlītēja tāme

Bieži uzdotie jautājumi