Intro
Introduction to the API.
The Dokka documentation is available from the external Dokka link here.
I18N
The core of the API is the I18N<T>
class, with T
representing the type of value that a translation
operation creates. You can create an I18N<T>
instance using various I18N.Builder<T>
implementations.
The current I18N.Builder<T>
implementations by module:
glossa-adventure
MiniMessageI18N.Builder
makesMiniMessageI18N
:I18N<Component>
This document will cover behaviour common across all I18N
s - it will use the MiniMessageI18N
.
Hello, World
- Create an I18N builder.
val builder = MiniMessageI18N.Builder()
You can override this default locale later, using withLocale
.
- Register a translation
val builder = MiniMessageI18N.Builder().apply {
translation(Locale.US) {
value("hello_world", "Hello world!")
}
}
- Generate a translation
val i18n: I18N<Component> = builder.build(Locale.US, MiniMessage.miniMessage())
i18n.make("hello_world")
// > Hello world!
Register translations
You can register translations for different locales - these will merge on top of one another.
Locale.forLanguageTag
is what you should use to create a Locale
from a string:
documentation here.
val english = Locale.forLanguageTag("en-US")
val german = Locale.forLanguageTag("de-DE")
val i18n = MiniMessageI18N.Builder().apply {
translation(english) {
value("greeting", "Hello!")
}
translation(german) {
value("greeting", "Hallo!")
}
}.build(english, MiniMessage.miniMessage())
// `.withLocale` returns a wrapper around the I18N with a new locale
i18n.withLocale(english).make("greeting")
// > Hello!
i18n.withLocale(german).make("greeting")
// > Hallo!
// providing no locale, we generate for the fallback `english`, or `en-US`
i18n.make("greeting")
// > Hello!
The locale passed to the builder will determine the fallback locale - which locale a message is generated for, if a key in the desired locale does not exist.
val i18n = MiniMessageI18N.Builder().apply {
translation(english) {
value("english_key", "This is only in English")
}
translation(german) {
value("german_key", "This is only in German")
}
}
i18n.withLocale(english).make("english_key")
// > This is only in English
i18n.withLocale(german).make("german_key")
// > This is only in German
i18n.withLocale(german).make("english_key")
// > This is only in English
i18n.withLocale(english).make("german_key")
// > (null)
The priority for locales is:
- Current locale (create a copy of the I18N with a new current locale using
.withLocale
) - Default locale (defined on build)
Locale.ROOT
, represented asroot
in configuration files
Safe calls
Note that i18n.make
returns a List<T>?
- nullable. If the message to be created could not be found at all,
not even in the fallback locales, the function will return null.
In situations when you require a non-null value, you can use i18n.safe(...)
. This will
guarantee a non-null value, however what this does exactly is implementation detail.
For a MiniMessageI18N
, it will return a list of a single component: the key passed in.
i18n.safe("some_unknown_key")
// > some_unknown_key
Single-line calls
Since i18n.make
and .safe
return lists, you may require a message which is not a list and is just a T
or T?
.
Use makeOne
or safeOne
for these purposes. This will join the resulting list of elements into one element, done
by the implementation.
val component: Component = i18n.safeOne("some_message") {
// args...
}
You can also define the T
separator to use when joining the messages.
val component: Component = i18n.safeOne("some_message", i18n.newline) {
// args...
}
Translation sections
Translations are stored in a node structure, where a node can either:
- hold children (a section node)
- hold a value (a value node)
Sections are logical colections of translations, and are separated by the .
character.
They are defined in the translation DSL like so:
MiniMessageI18N.Builder().apply {
translation(english) {
section("hud") {
value("health", "Health: ...")
value("money", "Money: ...")
section("inventory") {
value("carrying", "Carrying weight: ...")
value("carry_max", "Max carrying weight: ...")
}
}
}
}
Add arguments
Glossa provides a DSL for adding arguments to i18n.make
and i18n.safe
calls, using the
I18NArgs.Scope
class. In practice:
val i18n = MiniMessageI18N.Builder().apply {
translation(english) {
value("cart_items",
"Items in cart: {items, number}",
"Last item added: <last_item>")
}
}
i18n.make("cart_items") {
// DSL scope here
icu("items", 4) // ICU argument
subst("last_item", text("Some Item")) // Substitution argument
}
Items in cart: 4
Last item added: Some Item
List arguments
Use list
inside the arguments DSL to create a substitution argument for a list of
T
s:
en-US: {
list_separator: ", "
authors: "Authors: <authors>
}
i18n.make("authors") {
list("authors", listOf(
text("AuthorOne"),
text("AuthorTwo")
))
}
// > Authors: AuthorOne, AuthorTwo
The special message key list_separator
is placed in between each T
element.
Naming convention
- In message keys:
- Use
a-z0-9_
for individual segments - Use
.
as a separator between categories - Use the singular form for categories
- Use the plural form for the leaf value if it represents multiple values, otherwise singular form
- Examples
message.chat.incoming_message
message.chat.total_outgoing_messages
- Use
- In argument keys:
- Use only
a-z0-9_
- Use the singular form for a single value
- Use the plural form for a collection or number of values
- Examples
item_name
total_cost
- Use only