Skip to content

Internationalization and localization

Blender's ultimate goal is to adapt to the different languages and regional differences of its many users. However, its current state offers many language translations but does not perform other localization.

Default Locale

Although a Dutch project, Blender's default locale is "English (United States" (en-US). Even when the display language is changed, all other locale-specific preferences are assumed to be in this locale. One exception is system of measurement, which is a separate user setting.

  • Capitalization is simple Latin text-only
  • Numerals are Western Arabic
  • Collation (text sorting) is ASCII
  • Interface flow is left-to-right
  • Decimal separator is a baseline dot.
  • Digit grouping (thousands separator) is the comma.
  • Date format is MDY
  • Time format is 12-hour
  • Keyboard shortcut mnemonics in English (ctrl-S for Save)
  • Western color symbolism

Many of the above could be addressed and improved to become locale-specific or user preferences. Exceptions to this are numeral set, decimal separator, and numerical grouping character as these would complicate compatibility between Blender and Python and between users (script sharing for example).

The following sections are all related to language translation.

Automated Translation

Most (in fact, nearly all) translations are detected and done automatically by Blender’s RNA system.

So when you define a RNA property, the name and label of a panel, menu or operator, etc., you have nothing special to do, everything is handled automatically. Well, not the translation itself, of course, you’ll have to wait for the translating teams to do their job!

Apart from RNA, here is a list of functions that will automatically translate their string(s) (and which string can be caught by our fake py-xgettext code – please note that only regular strings are caught by this tool, so do not expect strings involving macro magic and the like to work here):

  • BKE_report(ReportList *reports, ReportType type, const char *message).
  • BKE_reportf(ReportList *reports, ReportType type, const char *format, ...).
  • BKE_reports_prepend(ReportList *reports, const char *prepend).
  • BKE_reports_prependf(ReportList *reports, const char *prepend, ...).
  • CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg).
  • BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg).
  • modifier_setError(struct ModifierData *md, const char *format, ...).

Please note that “printf-like” functions only translate the “format” string, it’s up to you to manage the parameters translation if needed (see below)!

Translation Categories

Translations are subdivided into a few categories. This makes it possbile to, for example, have the interface in English (to follow along with English tutorials) but have tooltips translated to another language.

Interface:
Main interface elements, such as titles, labels, buttons, etc.
Tooltips:
Tooltips and other longer / more complex explanations for which a translation to native is desirable.
Reports:
Info / warning / error messages.
Data:
For data-block names like "Object", "Action", etc. These are only translated when a new data-block of that type is created, and the translated string is stored as its name. After that, the name should be shown as-is, and not translated any more.

Translatable Strings in C++ code

There are various macros to work with translatable strings. These all act as markers for xgettext, and most also call the appropriate function to do the actual translation. These macros are defined in blentranslation/BLT_translation.hh.

IFACE_
For translations in the "Interface" category. Calls UI_translate_do_iface(), which will translate the message if the User Preferences’ use_translate_interface is set.
TIP_
For translations in the "Tooltip" category. Calls UI_translate_do_tooltip(), which will translate the message if the User Preferences’ use_translate_tooltips is set.
DATA_

For translations in the "Data" category. Calls UI_translate_do_new_dataname(), which will translate the message if the User Preferences’ use_translate_new_dataname is set.

WARNING: This macro should only be used when naming a new data-block. After that, the name should never be translated, and just shown as-is.

RPT_
For translations in the "Report" category. Usually this is not necessary to call directly, as BKE_report() already uses this macro internally.
N_
Marker-only macro. In other words, it does strictly nothing in the code. It’s just here to tag a string as translatable, so it will be extracted by the xgettext tool, but it does not actually replace the string with a translated version. For that, it is assumed the code receiving the string handles the translation. Use it e.g. when you use more than one string, based on conditional checks (draw_my_message(is_foo ? N_("This is a foo") : N_("This is a bar"));, where draw_my_message() calls the translation system to do the actual string replacement).

Additionally, you may have to edit CMakeLists.txt to add ../blentranslation to the include paths, and to add the -DWITH_INTERNATIONAL definition.

Note that those macros are defined as no-op when i18n is disabled at build time.

Adding a new language in Blender

The only file to edit is the release/scripts/module/bl_i18n_utils/settings.py one, LANGUAGES var (format is quite self-explanatory). This will be used by the update_languages_menu.py script in the same dir to generate the locale/languages text file, used by Blender to know which translations are available and to generate the relevant menu…

So your main task will be to gather a team of motivated translators (currently, there are more than 19k messages, above 500k signs…)!

Contexts

Gettext’s contexts are optional strings attached to a given text to translate, designed to avoid ambiguity (as some words in a language can have different translations in another, depending on… context!).

By default, all translated strings in Blender have the default NULL xgettext context (except for operators’ names, which have the "Operator" one). You should nearly never have to bother about contexts! We are trying to keep their uses as low as possible…

If you nonetheless need to use a context, you could directly give a literal string. However, this is not a good practice, for at least two reasons:

  • A typo would go unnoticed, e.g. creating two contexts where only one should exists.
  • It’s quite hard to know whether a same (or similar) context already exists!
  • And last but not least, it would not fit into our Python i18n API!

To address this, our message searching tools support a very limited “pre-processor” feature: you can use context defines instead of literals. Here is how it works:

  • In blenfont/BLF_translation.h, bottom of the file, the contexts are defined.
  • In the same file, they are added to the BLF_I18NCONTEXTS_DESC macro, used by the py API (see below).
  • You then can use those defines as context values everywhere in code.

You can specify a context for a given RNA structure or property with the RNA define’s void RNA_def_struct_translation_context(StructRNA *srna, const char *context) and void RNA_def_property_translation_context(PropertyRNA *prop, const char *context) functions. Please note that RNA context always only affects the name (or GUI label) of the element, never its description (or GUI tooltip), which is assumed detailed enough to avoid any confusion!

For non-RNA translation, you have the CTX_N_(), CTX_IFACE_(), CTX_TIP_() and CTX_DATA_() macros, which take as first parameter a context string (as a define, as explained above), and as second one the text to translate. Otherwise, they do the same thing as their context-less counterparts described above.

About default context

Default context is a bit tricky to handle, as it has to be NULL on gettext side, but RNA/Py does not handle well NULL strings, so here BLF_I18NCONTEXT_DEFAULT_BPYRNA is used, which is defined t "*". No other context should use that char as first one! The conversion is handled internally, and you should anyway never have to use default context yourself.

Defining multiple contexts for a single message

The typical use case is the "New" message, which is used for objects, textures, materials, particles, etc. It often translates as an adjective in foreign languages, and adjectives are often made agreed in gender, so we need a context for each kind of data.

To achieve this, the BLF_I18N_MSGID_MULTI_CTXT(msgid, ...) macro was created. It does nothing, it’s only a declarative one (as e.g. the N_(msgid) one), it just says the i18n tools that the given msgid must be defined for all the contexts given.

Warning

Due to Python regex limitations, you cannot specify more than 16 contexts in one “call” to this macro – but you can call it several times with the same msgid!

Python Translation API

Blender’s translations API is also exposed in Python (bpy.app.translations), to be used by UI scripts and addons!

Python translations

Translations of all “internal” scripts, as well as for OFFICIAL addons, is handled by the main (core) translations project (bf-translation). Other addons have to handle their translations themselves. See this page for more info.

Please note that here too, most messages are detected automatically. In particular, text parameter of all bpy.types.UILayout’s functions is handled as expected (most of the time, this is a complex area!). For these functions, you may also manually specify a translation context through the text_ctxt parameter.

As in C code, please use pre-defined contexts (accessible through the named tuple bpy.app.translations.contexts), as much as possible.

When you have complex strings generation (formatting, etc.), you may use the bpy.app.translations.pgettext family of functions, which mimics the matching macros described above. Note that you can import those functions as shorten names (_(), iface_(), tip_(), and data_()), which are also understood by messages extraction tools. And we obviously do not have context/context-less variants in python, context parameter is just in second position and optional!

See Also