Gameface comes with its own localization interface, called via the cohtml::ILocalizationManager class. A sample implementation of this interface exists in the SampleLocalization project. The sample also uses the custom coh-font-fit-mode CSS property to make sure that text always fits its container.

Translating HTML Content

To localize HTML content, add a data-l10n-id attribute to any element.

<button data-l10n-id="TextStartGameBtn"></button>

Translating text is done through the cohtml::ILocalizationManager::Translate function. The method takes the key to the text that needs to be translated (the data-l10n-id attribute) and returns a string with the translation.

// IMPORTANT: This call MUST be thread-safe and callable from any thread
class CustomLocalizationManager : public cohtml::ILocalizationManager
    virtual const char* Translate(const char* text) override
        // Always make sure to return UTF-8 encoded text.
        // The interface copies the returned value upon resolving the Translate method.
        // You don't need to empty the allocated memory upon resolving the function.

        return ConvertToUTF8(TranslateTextAccordingToCurrentLocale(text));

// Later when initializing the system

auto library = cohtml::Library::Initialize(COHTML_LICENSE_KEY, params);
CustomLocalizationManager manager; // Make sure this object outlives the system
cohtml::SystemSettings settings;
settings.LocalizationManagerInstance = &manager;
auto system = library->CreateSystem(settings);

The translate function creates a pointer to the translated string. There is no need to keep track of that allocated memory; it can be freed at any time upon resolving the Translate function.

Nothing else is required to translate text. cohtml::ILocalizationManager::Translate("TextStartGameBtn") is called automatically during button creation. Creating elements dynamically also triggers translation:

var container = document.getElementById("container");
container.innerHTML = '<button data-l10n-id="TextForStartGame"></button>'

Translation on The Fly

The translated value of a key can also be obtained through JavaScript. This feature is useful when dynamically creating text elements.

var info = document.getElementById("ProfileInfo");
var translatedLabel = engine.translate("ContactNumber");
info.appendChild(document.createTextNode(translatedLabel + contactNumber));

To update all the localized elements after changing the locale, call the engine.reloadLocalization() method which acts by calling engine.translate on all elements with a data-l10n-id attribute.

Changing the Locale Dynamically

Cohtml must be notified whenever the application changes its locale in order to apply the new localization rules - the library keeps no track of the current locale and will not detect the need to reload the localized elements' content. Therefore you need to manually call engine.reloadLocalization. Example:

class CustomLocalizationManager : public cohtml::ILocalizationManager
    virtual const char* Translate(const char* text) override;
    void ChangeLanguage(const char*);

    void OnReadyForBindings(View* view)
        std::function<void(const std::string&)> handler = [this](const std::string& language)

        view->BindCall("ChangeLanguage", cohtml::MakeHandler(handler));

Use JavaScript to notify the UI that the language has changed:

engine.call("ChangeLanguage", "spanish").then(function () {
    // Use engine.reloadLocalization() to update the locale specific elements
    // after the call to ChangeLanguage has completed.


  • If no localization manager is provided, the data-l10n-id attribute will be ignored.
  • Text translation removes all children from the element - including all other text - and replaces them with the values returned from the localization manager. If a translation for the specified key is not found, the contents of the element are left unchanged. Thus, default text values can be set up to make for easier debugging of missing translations.
  • Translation will not work in the browser. Calling engine.translate(text) there will return the argument which it was called with. Use engine.reloadLocalization() to initialize any of the localized elements to their localization keys.
  • Translation of the values of input and textarea elements should be done manually by using engine.translate(text), instead of data-l10n-id, since the nature of those elements is dynamic, and there is a possibility of losing input data when reload of localization is triggered.
  • JavaScript frameworks that modify the content of HTML elements may conflict with the localization attribute data-l10n-id and result in undefined behavior. When using such a framework, engine.translate(text) should be called instead.