i18n4k
Internationalization for Kotlin
Home: github.com/comahe-de/i18n4k
Lastest release version: 0.10.0
Table of contents
- About
- Supported platforms
- Artefact repository
- Gradle dependencies
- Gradle plugin
- Code generation
- Runtime configuration
- Hints for Android
- Hints for Compose-Multiplatform
- Hints for IntelJ usage
- Message format
- Further dokumentation
- Example
- Example projects
- Contribute
- Status
About
i18n4k is a multiplatform (JVM, JS, native) library and code generator for Kotlin to handle internationalisation (i18n) in your program.
It provides
Locale
class to store the selected languageLocalizedString
class that stores the reference to the translatable message. ThetoString()
will return the message string in the currently selected language/locale.- Parameter support via
LocalizedStringFatory*
that creates aLocalizedString
with the supplied parameters using a parameter format like “Hello, {0}!” - Code generators that creates…
- … access objects with a constant per message key
- … objects for inline storing of messages of specified locales (no need of loading resources at runtime)
- … optimized message files for loading message resources at runtime
- The code generators currently can load Java Properties files (but can be extended for additional formats).
- Gradle plugin to start the code generator
Supported platforms
- Java (JVM)
- Android (Min. SDK 21)
- JS (IR backend)
- WASM (JS & WASI)
- Native:
- iosArm64
- iosX64
- iosSimulatorArm64
- macosX64
- macosArm64
- mingwX64
- linuxX64
- tvosArm64
- tvosX64
- tvosSimulatorArm64
- watchosArm64
- watchosX86
- watchosX64
- watchosSimulatorArm64
Artefact repository
Ensure that you have Maven-Central (mavenCentral()
) in your repository list
repositories {
mavenCentral()
}
Gradle dependencies
For multiplatform projects: add de.comahe.i18n4k:i18n4k-core:<VERSION>
to commonMain
source set.
val commonMain by getting {
dependencies {
implementation("de.comahe.i18n4k:i18n4k-core:0.10.0")
}
}
For Kotlin/JS: add de.comahe.i18n4k:i18n4k-core-js:<VERSION>
to the dependencies
dependencies {
implementation("de.comahe.i18n4k:i18n4k-core-js:0.10.0")
}
For Kotlin/Jvm: add de.comahe.i18n4k:i18n4k-core-jvm:<VERSION>
to the dependencies
dependencies {
implementation("de.comahe.i18n4k:i18n4k-core-jvm:0.10.0")
}
For Kotlin/Android: add de.comahe.i18n4k:i18n4k-core-android:<VERSION>
to the dependencies
dependencies {
implementation("de.comahe.i18n4k:i18n4k-core-android:0.10.0")
}
Gradle plugin
Apply the plugin “de.comahe.i18n4k”, e.g:
plugins {
id("de.comahe.i18n4k") version "0.10.0"
}
The configuration is done via the i18n4k
object, e.g.:
i18n4k {
sourceCodeLocales = listOf("en", "de")
}
For the full list of parameters, see I18n4kExtension
Code generation
The Gradle plugin can generate code to access the message via constants instead of string keys or similar.
Adding message bundles
By default, the language files of the message bundles are searched in the path src/main/i18n
(normal projects) respectively src/commonMain/i18
(for multiplatform projects). See configuration
for other folder locations.
Any subfolder in this directory will be converted to a package in the Kotlin code.
Inline storing of translations
To avoid loading of translations at runtime, there is also the possibility to include the messages in the source code. So the translations are always available and no need for platform-specific loading of resources is needed. Drawback is that the messages are hold in memory all the time. So only the most important translations should be stored in the source code.
Optimized message files
i18n4k has an internal format to store message files to be loaded at runtime. It is index-based instead of key-bases as e.g. Java-Property files. This has the advantage that no memory is wasted for storing the key in each language.
More details are described here MessagesProviderViaLoadingText
Runtime configuration
The current locale and other parameters are stored in the global variable i184k of type I18n4kConfig
Predefined implementations of I18n4kConfig
are:
The configuration can be changed by assigning (and editing) one of these implementation to
the i184k
variable.
Hints for Android
Generated resource files are not added to the “Java resource”, but as “raw Android resources”. As Android does not allow subfolders or uppercase letters, the resource name is adapted: packages names are prefixed to the resource name and concatenated by “_”. Also, camel case names are converted to sneak-case, e.g. “/x/y/MyMessages_fr.i18n4k.txt” will be changed to “x_y_my_messages_fr_i18n4k”.
Generated raw resources can be loaded in the following way:
MyMessages.registerTranslation(
MessagesProviderViaText(
text = String(
context.resources.openRawResource(
R.raw.x_y_my_messages_fr_i18n4k
).readBytes()
)
)
)
Hints for Compose-Multiplatform
The Compose resources plugin currently does not support multiple directories for one source-set. Therefore, the I18n4k-Plugin cannot add the generated folder automatically to the resource source-set! To add generated resource files to the Compose-Multiplatform app, set the path of the output directory to be inside the resource folder of “commonMain” source set.
E.g.:
i18n4k {
languageFilesOutputDirectory = "{projectDir}/src/commonMain/composeResources/files/i18n"
}
Hints for IntelJ usage
IntelJ default settings for properties-files do not handle Unicode characters correctly. I18n4k supports properties-files with UTF-8 encoding or ISO-8859-1 encoding with escape sequences for characters outside the 7-bit ASCII character set. See here for more information
Message format
The default message format is similar to the Java-MessageFormat or the ICU-MessageFormat. E.g. the text “Hello, {0}” has one parameter. Any string can be used as parameter name.
The parameter values can also be formatted, e.g. “{0,number, %.2}” formats parameter 0 as number with max. 2 fraction digits. See Formatters for more information.
For messages with parameters, the generator plugin creates special LocalizedStringFactories where the parameters must be supplied as arguments to get the resulting string.
Other message formatters can be implemented and be configured in
I18n4kConfig.messageFormatter
The escape character is '
.
It’s recommended to use the real apostrophe character ’ (U+2019) for human-readable text
and the ASCII apostrophe '
(U+0027) for program syntax (escaping or quoting).
See here for more information.
Further dokumentation
For more advanced features, have a look at the documenation files
Example
Source files are the following message bundle as Java-Properties files located in
the src/main/i18n/x/y/
folder
MyMessages_en.properties
sayHello=Hello, {0}!
title=Internationalisation example \uD83C\uDDEC\uD83C\uDDE7
MyMessages_de.properties
sayHello=Hallo, {0}!
title=Internationalisierung Beispiel \uD83C\uDDE9\uD83C\uDDEA
In the Gradle script, “en” is defined as source code locale (to be stored in source code)
i18n4k {
sourceCodeLocaleCodes = listOf("en")
}
This results in the following generate Kotlin code
package x.y
import de.comahe.i18n4k.Locale
import de.comahe.i18n4k.messages.MessageBundle
import de.comahe.i18n4k.messages.providers.MessagesProvider
import de.comahe.i18n4k.strings.LocalizedString
import de.comahe.i18n4k.strings.LocalizedStringFactory1
import kotlin.Array
import kotlin.Int
import kotlin.String
/**
* Massage constants for bundle 'MyMessages'. Generated by i18n4k.
*/
public object MyMessages : MessageBundle("MyMessages", "x.y") {
/**
* Hello, {0}!
*/
public val sayHello: LocalizedStringFactory1 = getLocalizedStringFactory1("sayHello", 0)
/**
* Internationalisation example 🇬🇧
*/
public val title: LocalizedString = getLocalizedString0("title", 1)
init {
registerTranslation(MyMessages_en)
}
}
/**
* Translation of message bundle 'MyMessages' for locale 'en'. Generated by i18n4k.
*/
private object MyMessages_en : MessagesProvider {
private val _data: Array<String?> = arrayOf(
"Hello, {0}!",
"Internationalisation example 🇬🇧"
)
public override val locale: Locale = Locale("en")
public override val size: Int = _data.size
public override fun `get`(index: Int): String? = _data[index]
}
And the following message file:
MyMessages_de.i18n4k.txt
de
^
Hallo, {0}!
^
Internationalisierung Beispiel 🇩🇪
^
The messages can than be accessed like this
println(MyMessages.sayHello("i18n4k"))
which prints
Hello, i18n4k!
The German message file can be loaded at runtime, e.g. like this (for JVM plattform)
MyMessages.registerTranslation(MessagesProviderViaResource(pathToResource = "/x/y/MyMessages_de.i18n4k.txt"))
Changing the locale can be done like this:
val i18n4kConfig = I18n4kConfigDefault()
i18n4k = i18n4kConfig
i18n4kConfig.locale = Locale("de")
Afterwards the expression from above prints
Hallo, i18n4k!
Example projects
Please also check the examples projects in the examples folder!
Contribute
Status
The library is under development. So the API is not stable. Enhancements and feature request are very welcome.