This sample demonstrates how to use Coherent GT's localization facility and have the text of certain elements in your HTML page translated according to your own needs.
The sample solution is based on a minimal game framework that provides basic functionality. The sample is already configured and you only have to compile and run it.
The output will be in the Coherent/bin directory.
This sample builds upon the HelloGT sample and assumes that you understand it.
CSVLocalizationManager
is an custom implementation of Coherent::UIGT::LocalizationManager that knows how to read the data out of several csv files.The sample shows a simple vertical menu, each button of which has the data-l10n-id
attribute as well as dynamically inserting one more button in the same menu. This demonstrates how Coherent GT uses the custom CSVLocalizationManager
to set the text content of each button. Additionally, the sample shows how to change the language at runtime and update the UI to match.
We start off by creating each of the localization files. For instance localization/en.csv contains:
New Game, Start a new game Load Game, Load game Settings, Settings Quit, Quit
The other files under localization exhibit the same structure. Note that each file must be encoded in UTF-8 so that all symbols are preserved.
Next, we add the data-l10n-id
attribute to any element that needs translation:
<button data-l10n-id="New Game"></button><button data-l10n-id="Load Game"></button><button data-l10n-id="Settings"></button><button data-l10n-id="Quit"></button>
We will implement the CSVLocalizationManager
step by step.
Start by adding some data members that hold our translation table, the directory containing the localization files and an extra string that lets the strings returned from Translate
outlive the method.
// Coherent GT requires that this class is thread-safe{private:const std::string m_LocalizationDirectory;std::unordered_map<std::string, std::wstring> m_CurrentTranslations;// The string returned from Translate must outlive the function so// we'll use a data member to make sure this happens.std::string m_CurrentTextContainer;};
Initially, we load the translation table for English and store the directory containing our CSVs.
CSVLocalizationManager::CSVLocalizationManager(): m_LocalizationDirectory("localizations/"){// If you change the default language, you'll see that the page// will load with the proper translations the next time you start the sampleChangeLanguage("en");}
We expose a ChangeLanguage
method that causes a new translation table to be loaded from the matching CSV file. We take special care to load all data in wide strings to preserve the Unicode encoding.
void CSVLocalizationManager::ChangeLanguage(const std::string& language){const std::string validLanguages[] = { "en", "fr", "bg", "ch", "mi" };auto isValid = std::find(std::begin(validLanguages), std::end(validLanguages), language) != std::end(validLanguages);assert(isValid);std::string localizationFilename = language + ".csv";LoadTranslations(localizationFilename);}void CSVLocalizationManager::LoadTranslations(const std::string& localizationFilename){std::string localizationFilepath = m_LocalizationDirectory + localizationFilename;std::wifstream file(localizationFilepath);assert(file);// Take special care to handle UTF-8const std::locale empty_locale = std::locale::empty();// the locale is responsible for calling the matching delete from its own destructorconst std::codecvt_utf8<wchar_t>* converter = new std::codecvt_utf8<wchar_t>;const std::locale utf8_locale = std::locale(empty_locale, converter);file.imbue(utf8_locale);std::wstring line;while (std::getline(file, line)){auto firstCommaIndex = line.find(',');if (firstCommaIndex == std::wstring::npos){continue;}auto key = line.substr(0, firstCommaIndex);// It's safe to assume that the keys are ASCII-encoded// so conversion via std::string's consturctor is acceptablestd::string keyStr(key.begin(), key.end());auto value = line.substr(firstCommaIndex + 1);m_CurrentTranslations[keyStr] = value;}}
Finally, override Coherent::UIGT::LocalizationManager::Translate so that it lookups the required translation in the current translation table and returns it UTF8-encoded.
const char* CSVLocalizationManager::Translate(const char* text){auto translation = m_CurrentTranslations.find(text);assert(translation != m_CurrentTranslations.end());std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;m_CurrentTextContainer.assign(converter.to_bytes(translation->second));return m_CurrentTextContainer.c_str();}
We now need to setup the localization manager and our system:
Options options = {0};CSVLocalizationManager localizationManager;options.LocalizationManagerInstance = &localizationManager;// System initialization is hidden inside app.InitializeApplication app(options);App.initialize(width, height, "Sample_Localization", false);
To finish the sample, we need to setup our JavaScript code to call CSVLocalizationManager::ChangeLanguage
.
Bind the method:
view->BindCall("ChangeLanguage",Coherent::UIGT::MakeHandler(&localizationManager, &CSVLocalizationManager::ChangeLanguage));
Next, add the buttons that will let us change the language. We'll store the language the button sets in the data-language
attribute.
<div id="change-localization-menu"><h3>Select language:</h3></br><button data-language="en">English</button><button data-language="fr">Français (French)</button><button data-language="bg">Български (Bulgarian)</button><button data-language="ch">中国 (Mandarin)</button><button data-language="mi">Maori</button></div>
When any of the buttons is clicked, call ChangeLanguage
and when that's done, update all localized elements using engine.reloadLocalization
.
var changeLanguage = function (language) {engine.call('ChangeLanguage', language).then(function () {engine.reloadLocalization();});};var onLanguageChanged = function (eventArgs) {var button = eventArgs.target;// Change the current language to the value of// data-language of the current buttonchangeLanguage(button.dataset.language);};var localizationChangers = document.querySelectorAll('#change-localization-menu button');for (var i = 0; i < localizationChangers.length; i++) {var button = localizationChangers.item(i);button.addEventListener('click', onLanguageChanged);}
This completes the tutorial - clicking on the language buttons will change the active language and update the translated text.