Texts can be translated client-side with the help of minetest.translate and translation files.

Consider using the script util/ in the Minetest repository to generate and update translation files automatically from the Lua sources. See util/ for an explanation.

Translating a string

Two functions are provided to translate strings: minetest.translate and minetest.get_translator.

  • minetest.get_translator(textdomain) is a simple wrapper around minetest.translate, and minetest.get_translator(textdomain)(str, ...) is equivalent to minetest.translate(textdomain, str, ...). It is intended to be used in the following way, so that it avoids verbose repetitions of minetest.translate:
local S = minetest.get_translator(textdomain)
S(str, ...)

As an extra commodity, if textdomain is nil, it is assumed to be "" instead.

  • minetest.translate(textdomain, str, ...) translates the string str with the given textdomain for disambiguation. The textdomain must match the textdomain specified in the translation file in order to get the string translated. This can be used so that a string is translated differently in different contexts. It is advised to use the name of the mod as textdomain whenever possible, to avoid clashes with other mods. This function must be given a number of arguments equal to the number of arguments the translated string expects. Arguments are literal strings -- they will not be translated.

For instance, suppose we want to greet players when they join. We can do the following:

local S = minetest.get_translator("hello")
    local name = player:get_player_name()
    minetest.chat_send_player(name, S("Hello @1, how are you today?", name))

When someone called "CoolGuy" joins the game with an old client or a client that does not have localization enabled, they will see Hello CoolGuy, how are you today?

However, if we have for instance a translation file named containing the following:

# textdomain: hello
Hello @1, how are you today?=Hallo @1, wie geht es dir heute?

and CoolGuy has set a German locale, they will see Hallo CoolGuy, wie geht es dir heute?

Operations on translated strings

The output of minetest.translate is a string, with escape sequences adding additional information to that string so that it can be translated on the different clients. In particular, you can't expect operations like string.length to work on them like you would expect them to, or string.gsub to work in the expected manner. However, string concatenation will still work as expected (note that you should only use this for things like formspecs; do not translate sentences by breaking them into parts; arguments should be used instead), and operations such as minetest.colorize which are also concatenation.

Translation file format

A translation file has the suffix .[lang].tr, where [lang] is the language it corresponds to. It must be put into the locale subdirectory of the mod. The file should be a text file, with the following format:

  • Lines beginning with # textdomain: (the space is significant) can be used to specify the text domain of all following translations in the file.
  • All other empty lines or lines beginning with # are ignored.
  • Other lines should be in the format original=translated. Both original and translated can contain escape sequences beginning with @ to insert arguments, literal @, = or newline (See [Escapes] below). There must be no extraneous whitespace around the = or at the beginning or the end of the line.


Strings that need to be translated can contain several escapes, preceded by @.

  • @@ acts as a literal @.
  • @n, where n is a digit between 1 and 9, is an argument for the translated string that will be inlined when translated. Due to how translations are implemented, the original translation string must have its arguments in increasing order, without gaps or repetitions, starting from 1.
  • @= acts as a literal =. It is not required in strings given to minetest.translate, but is in translation files to avoid being confused with the = separating the original from the translation.
  • @\n (where the \n is a literal newline) acts as a literal newline. As with @=, this escape is not required in strings given to minetest.translate, but is in translation files.
  • @n acts as a literal newline as well.

Server side translations

On some specific cases, server translation could be useful. For example, filter a list on labels and send results to client. A method is supplied to achieve that:

minetest.get_translated_string(lang_code, string): resolves translations in the given string just like the client would, using the translation files for lang_code. For this to have any effect, the string needs to contain translation markup, e.g. minetest.get_translated_string("fr", S("Hello")).

The lang_code to use for a given player can be retrieved from the table returned by minetest.get_player_information(name).

IMPORTANT: This functionality should only be used for sorting, filtering or similar purposes. You do not need to use this to get translated strings to show up on the client.

Translating content meta

You can translate content meta, such as title and description, by placing translations in a locale/ file. The textdomain defaults to the content name, but can be customised using textdomain in the content's .conf.

Mods and Texture Packs

Say you have a mod called mymod with a short description in mod.conf:

description = This is the short description

Minetest will look for translations in the mymod textdomain as there's no textdomain specified in mod.conf. For example, mymod/locale/

# textdomain:mymod
This is the short description=Voici la description succincte

Games and Modpacks

For games and modpacks, Minetest will look for the textdomain in all mods.

Say you have a game called mygame with the following game.conf:

description = This is the game's short description
textdomain = mygame

Minetest will then look for the textdomain mygame in all mods, for example, mygame/mods/anymod/locale/ Note that it is still recommended that your textdomain match the mod name, but this isn't required.