6.9 KiB
title | layout | root | idx | marked_text_encoding | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Translation (i18n / l10n) | default | ../.. | 8.05 |
|
Introduction
Adding support for translation to your mods and games allows more people to enjoy them. According to Google Play, 64% of Minetest Android users don't have English as their primary language. Minetest doesn't track stats for user languages across all platforms, but there's likely to be a high proportion of non-English speaking users.
Minetest allows you to translate your mods and games into different languages by writing your text in English, and using translation files to map into other languages. Translation is done on each player's client, allowing each player to see a different language.
- How does client-side translation work?
- Format strings
- Best practices and Common Falsehoods about Translation
- Server-side translations
- Conclusion
How does client-side translation work?
Marked text
The server needs to tell clients how to translate text. This is done by marking
text as translatable using a translator function (S()
), returned by
minetest.get_translator(textdomain)
:
local S = minetest.get_translator("mymod")
minetest.register_craftitem("mymod:item", {
description = S("My Item"),
})
The first argument of get_translator
is the textdomain
, which acts as a
namespace. Rather than having all translations for a language stored in the same
file, translations are separated into textdomains, with a file per textdomain
per language. The textdomain should be the same as the mod name, as it helps
avoid mod conflicts.
Marked text can be used in most places where human-readable text is accepted,
including formspecs, item def fields, infotext, and more. When including marked
text in formspecs, you need to escape the text using
minetest.formspec_escape
.
When the client encounters marked text, such as that passed to description
, it
looks it up in the player's language's translation file. If a translation cannot
be found, it falls back to the English translation.
Marked text contains the English source text, the textdomain, and any additional
arguments passed to S()
. It's essentially a text encoding of the S
call,
containing all the required information.
{% include notice.html notice=page.marked_text_encoding %}
Translation files
Translation files are media files that can be found in the locale
folder for
each mod. Currently, the only supported format is .tr
, but support for more
common formats is likely in the future. Translation files must be named
in the following way: [textdomain].[lang].tr
.
Files in the .tr
start with a comment specifying the textdomain, and then
further lines mapping from the English source text to the translation.
For example, mymod.fr.tr
:
# textdomain: mymod
Hello everyone!=Bonjour à tous !
I like grapefruit=J'aime le pamplemousse
You should create translation files based on your mod/game's source code,
using a tool like
update_translations.
This tool will look for S(
in your Lua code, and automatically create a
template that translators can use to translate into their language.
It also handles updating the translation files when your source changes.
Format strings
It's common to need to include variable information within a translation string. It's important that text isn't just concatenated, as that prevents translators from changing the order of variables within a sentence. Instead, you should use the translation system's format/arguments system:
minetest.register_on_joinplayer(function(player)
minetest.chat_send_all(S("Everyone, say hi to @1!", player:get_player_name()))
end)
If you want to include a literal @
in your translation, you'll need to escape
by writing @@
.
You should avoid concatenation within a sentence, but it's recommended that you join multiple sentences using concatenation. This helps translators by keeping strings smaller.
S("Hwllo @1!", player_name) .. " " .. S("You have @1 new messages.", #msgs)
Best practices and Common Falsehoods about Translation
- Avoid concatenating text and use format arguments instead. This gives translators full control over changing the order of things.
- Create translation files automatically, using update_translations.
- It's common for variables to change the surrounding text, for example, with gender and pluralisation. This is often hard to deal with, so is frequently glossed over or worked around with gender neutral phrasings.
- Translations may be much longer or much smaller than the English text. Make sure to leave plenty of space.
- Other languages may write numbers in a different way, for example, with commas
as decimal points.
1.000,23
,1'000'000,32
- Don't assume that other languages use capitalisation in the same way.
Server-side translations
Sometimes you need to know the translation of text on the server, for example,
to sort or search text. You can use get_player_information
to get a player's
lang,uage and get_translated_string
to translate marked text.
local list = {
S("Hello world!"),
S("Potato")
}
minetest.register_chatcommand("find", {
func = function(name, param)
local info = minetest.get_player_information(name)
local language = info and info.language or "en"
for _, line in ipairs(list) do
local trans = minetest.get_translated_string(language, line)
if trans:contains(query) then
return line
end
end
end,
})
Conclusion
The translation API allows making mods and games more accessible, but care is needed in order to use it correctly.
Minetest is continuously improving, and the translation API is likey to be extended in the future. For example, support for gettext translation files will allow common translator tools and platforms (like weblate) to be used, and there's likely to be support for pluralisation and gender added.