Skip to main content

Kotlin Multiplatform i18n: Sameiginleg staðfærsla þvert á verkvanga

Skrifaðu þýðingarnar einu sinni í sameiginlegum Kotlin-kóða. Dreifðu þeim á Android, iOS og vefinn með réttum varaleitarkeðjum staðfærslna.

1

Grunnstilltu Gradle fyrir KMP i18n

Bættu i18n-stoðpökkunum við commonMain-frumkóðamengi sameiginlegu einingarinnar. Þú getur valið moko-resources fyrir XML-byggða strengi, Lyricist fyrir tegundarörugga Compose-strengi eða hvort tveggja. kmp-localechain bætir snjallri varaleit staðfærslna ofan á bæði söfnin.

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")
            }
        }
    }
}
Öll þrjú söfnin eru gefin út á Maven Central. Bættu þeim við stoðpakka commonMain svo þau séu tiltæk á öllum markverkvöngum (Android, iOS, JS).
2

Skilgreindu sameiginlegar strengjategundir

Búðu til Kotlin-gagnaflokka í commonMain sem geyma alla þýðanlega strengi. Þetta er eini uppruni sannleikans — allir verkvangar lesa sömu tegundaröruggu skilgreiningarnar. Engar tvíteknar strengjaskrár og ekkert ósamræmi milli verkvanga.

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.
Notaðu lambdaeiginleika fyrir fleirtölu í stað aðskilinna lykla fyrir eintölu og fleirtölu. Lambdafallið tekur við fjöldanum og skilar réttri mynd. Þannig helst fleirtölurökvísi í Kotlin þar sem þýðandinn getur sannreynt hann.
3

Tengdu Android

Í androidMain skaltu innleiða expect/actual-mynstrið til að lesa staðfærslu tækisins með java.util.Locale. Android getur notað sameiginlega Kotlin-strengi fyrir viðskiptarökvísi samhliða stöðluðu values/strings.xml fyrir kerfishluta notandaviðmóts á borð við tilkynningar og viðmótseiningar.

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() skilar IETF-merkjum á borð við "pt-BR" en sumar Android-útgáfur skila "pt-rBR" úr eldri forritaskilum. Notaðu alltaf toLanguageTag() (API 21 eða nýrra) til að fá samræmda niðurstöðu.
4

Tengdu iOS

Í iosMain skaltu innleiða currentLocale() með NSLocale úr Foundation. Sameiginlegi KMP-verkramminn flytur strengjaskilgreiningarnar út í Swift svo SwiftUI-sýnir geti kallað beint á þær gegnum myndaða Kotlin-verkrammann.

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)
Þegar KMP-verkramminn er fluttur út í Xcode skaltu tryggja að einingin sem veitir strengina sé einnig flutt út. Láttu i18n-pakkann fylgja í Podspec- eða XCFramework-grunnstillingunni svo Swift-kóði geti flutt hann inn.
5

Tengdu JS/vafrann

Í jsMain skaltu lesa staðfærslu vafrans úr window.navigator.language. Þetta nær bæði yfir Kotlin/JS-vefforrit og Compose for Web-markverkvanga. Sömu sameiginlegu strengirnir eru myndgerðir í vafranum án tvítekningar.

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
}
Fyrir Kotlin/JS á þjóninum (Node.js) skaltu lesa staðfærsluna úr Accept-Language-hausnum eða grunnstillingarbreytu í stað window.navigator.language.
6

Lyricist fyrir Compose Multiplatform

Lyricist veitir i18n-leið sem er innbyggð í Compose. Merktu strengjahlutina með @LyricistStrings og Lyricist býr til CompositionLocal-veitu. Skiptu um tungumál við keyrslu með því að breyta languageTag — notandaviðmótið er sjálfkrafa sett saman að nýju.

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 styður innskot breytugilda í strengi, fleirtölu með lambdaföllum og falda strengjahópa. Það virkar á Android, iOS (gegnum Compose for iOS), Desktop og Web.
7

moko-resources fyrir XML-strengi

moko-resources notar XML-strengjaskrár í Android-stíl sem uppruna sannleikans og býr til tegundarörugga aðgangsaðila. Skilgreindu strengi í commonMain/resources/MR/base/ (enska) og bættu við staðfærslumöppu fyrir hvert tungumál. Myndaði MR-hluturinn veitir aðgang sem er sannreyndur við þýðingu.

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 krefst Gradle-viðbótarinnar til að búa til kóða. Ef þú sérð 'Unresolved reference: MR' skaltu fyrst samstilla Gradle. Kóðagerðinni verður að ljúka áður en þróunarumhverfið sér MR-aðgangsaðilana.
8

Snjöll varaleit staðfærslna með kmp-localechain

i18n-söfn KMP skortir stillanlegar varaleitarkeðjur. Þegar pt-BR-þýðingar vantar sleppa þau pt-PT alfarið og sýna ensku. kmp-localechain lagar þetta með sjálfstæðu hjálparverkfæri sem sameinar skilaboð. Það tekur við flötum Map&lt;String, String&gt;-skilaboðum fyrir hverja staðfærslu og skilar sameinuðu korti þar sem forgangsröð varaleitarkeðjunnar hefur verið virkjuð.

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 vinnur með flöt Map&lt;String, String&gt;-kort. Ef skilaboðin eru falin skaltu fletja þau út áður en þau eru gefin resolve(). Safnið styður ekki djúpsameiningu falinnar gagnaskipanar.
9

Sjálfvirknivæddu þýðingar

Þegar KMP i18n-uppsetningunni er lokið skaltu sjálfvirknivæða þýðingar með gervigreind. Þýddu sameiginlegu strengjaskrárnar — hvort sem þær eru Kotlin-gagnaflokkar, XML-tilföng eða JSON — beint úr þróunarumhverfinu eða CI/CD-vinnslurásinni.

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
Þýddu í áföngum. Þegar þú bætir nýjum lyklum við ensku frumskrána skaltu aðeins þýða breytingarnar. Þannig varðveitast þýðingar sem fólk hefur yfirfarið og ekki þarf að endurgera heilar skrár.

Sjálfvirknivæddu gæðaprófun þýðinga

Finndu lykla sem vantar og skemmda staðgengla áður en þeir fara í útgáfu með i18n-validate. Prófaðu notandaviðmótið með gerviþýðingum úr i18n-pseudo áður en raunverulegar þýðingar berast.

Algengar gildrur

Ósamræmi milli expect og actual

Sérhver expect-yfirlýsing í commonMain þarf actual-innleiðingu á öllum markverkvöngum (androidMain, iosMain, jsMain). Ef þú bætir síðar við nýjum markverkvangi tilkynnir þýðandinn villu þar til actual-innleiðingin er til staðar. Notaðu skyndilagfæringar þróunarumhverfisins til að mynda stoðgrindur.

Harðkóðaður fleirtölurökvísi

Notaðu aldrei count == 1 til að greina eintölumyndir. Franska fer með 0 sem eintölu. Arabíska hefur sex fleirtölumyndir. Rússneska notar mismunandi myndir fyrir tölur sem enda á 1, 2-4 og 5-20. Notaðu söfn sem þekkja CLDR (moko-resources) eða skýr lambdaföll fyrir hverja staðfærslu.

Falin kort í kmp-localechain

kmp-localechain vinnur með flöt Map&lt;String, String&gt;-kort. Ef þú gefur því falin kort sameinar varaleitarúrlausnin ekki innri lykla rétt. Flettu skilaboðin út með lyklum í punktaritun (t.d. "nav.home") áður en þú kallar á resolve().

Myndaðan kóða vantar eftir að moko-resources er bætt við

MR-hluturinn er myndaður af Gradle-viðbót. Þegar moko-resources-strengjum hefur verið bætt við skaltu samstilla Gradle áður en þú notar MR.strings.* í kóðanum. Ef þróunarumhverfið sýnir enn villur skaltu prófa Build > Rebuild Project.

Ráðlögð verkefnaskipan

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

Prófaðu i18n Agent núna

Slepptu þýðingarskránni þinni hér

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

eða smelltu til að fletta

Markmál

Engin skráning nauðsynlegKostnaðaráætlun samstundis

Algengar spurningar