String internationalisation

Overview

For consistency across all of the Totara products, the front end experience produced by Tui needs to be fully translatable.

In order to achieve this without introducing duplication we use the existing translation system within Totara Core.

Implementation (Totara 19+)

The Tui component exposes an i18n (internationalisation) module and integrates with the Tui framework in order to support translatable strings within Tui components.

The main API for this is getString from tui/i18n. This takes the string key, component, and an optional dynamic value. Inside a Vue component, you can use $str to access language strings. This is an alias of getString.

This is what that looks like in practice:

file.js
import { getString } from 'tui/i18n'; const options = [ { id: 'all', label: getString('all', 'core') }, { id: 'none', label: getString('none', 'core') }, ];
Component.vue
<template> <div> <h2>{{ $str('welcome', 'totara_tui') }}</h2> <p>{{ $str('hello_x', 'totara_tui', username) }}</p> </div> </template>

Calls to getString are replaced with the actual value of the language string when the built JS is served to the client. For this reason, when calling getString, the first argument must be either a string or a ternary with two string values, and the second argument must be a string.

For dynamic language strings, where the value is not known ahead of time, they may be loaded asynchronously using the loadLangStrings API from tui/i18n:

import { langString, loadLangStrings } from 'tui/i18n'; async function getMessage(message) { const str = langString('message:' + messageId, 'totara_tui'); await loadLangStrings([str]); return str.toString(); }

Implementation (Totara 13-18)

Totara 13-18 use a slightly different internationalisation system, that requires declaring the language strings that will be used in a separate section of the component.

Requiring strings within a component

Tui has defined a custom <lang-strings> block that can appear in a single component file.

Strings you want to use must be declared upfront in the <lang-strings> block, and will be loaded ahead of time, before the component is mounted.

Strings can be retrieved and formatted in the template using $str(), which is also available in the script block as this.$str().

In order for strings in imported components to work, each imported component used by a component must be declared within the components: {} section, even if you are using <component :is="" />. If that isn't possible, you can load the component as an async component, or call tui.loadRequirements() with the component definition to load strings.

If you have a requirement to load strings outside of the regular <lang-strings> block definition, you can use the langString() and loadLangStrings() APIs from tui/i18n.

Synchronous example

The following is a basic example illustrating how to require a string in the lang-strings block, and how to use the string within the template block.

Asynchronous example

This is how things look if you have a component that is loaded asynchronously.

ComponentA.vue



ComponentB.vue

Manual loading example

If you need to load language strings manually, you can do something like this:



API

this.$str(key, component, [param])

Get a localised string. In development mode, this will log a warning to the console if the string was not declared in <lang-strings>.

this.$tryStr(key, component, [param])

Get a localised string. If the string is not loaded, returns null. This method does not check for the presence of the string in <lang-strings>.

this.$hasStr(key, component)

Check if the provided string has been loaded.

Tips and known limitations

  • You will likely need to purge caches to get new language strings to show up.

  • Don't use language strings from other Totara components that your plugin does not specify as a requirement.