
Многие уже наверняка знают, что в Mendix встроены средства локализации приложений, причем многоязычность реализована во множестве проектов. Локализация — частое требование у клиентов. И вот однажды, получив такое требование, я задумался: я знаю, как реализовать поддержку нескольких языков в приложении, но пока что еще не сделал ни одного с многоязычной страницей входа. Так что сегодня именно этим мы и займемся.
Безусловно, почти любое решение можно реализовать несколькими способами, но мы выберем и рассмотрим только один.
Что такое интернационализация?
Интернационализация (i18n) — это процесс разработки и подготовки проекта к использованию в различных регионах по всему миру. Локализация — это процесс создания версий проекта для разных языков.
Локализация включает в себя:
Извлечение текста для перевода.
Применение определенного формата данных для каждого языкового стандарта (локали).
Локаль указывает на регион, в котором говорят на конкретном языке или варианте языка, и может соответствовать, например, стране или географическому региону. Локаль определяет то, как будут обрабатываться и отображаться:
единицы измерения, включая дату и время, числа и валюты,
переведенные названия, включая часовые пояса, языки и страны.

Что нам понадобится
Mendix Studio Pro 8.12.5 — подойдет и другая версия, но в этом случает может потребоваться адаптировать руководство в зависимости от структуры папок приложения.
Visual Studio Code, но можно использовать и любой другой удобный редактор.
Система безопасности для приложения (App Security) должна быть включена.
Приступим
Решать эту задачу будем поэтапно.
Поиск файлов login.js и login_i18n.js
Если приложение запускалось хотя бы раз, они будут в каталоге «deployment» проекта, который создается после первого локального запуска приложения.
Запустив приложение, нажмите «Project → Show Project Directory in Explorer» (Проект → Показать каталог проекта в Проводнике).
Щелкните правой кнопкой мыши папку проекта и откройте его в редакторе кода.
Перейдите в каталог «deployment -> web -> js». Нужные файлы на скриншоте выделены:

2. Копирование файлов
Файлы мы нашли — теперь будем добавлять переводы.
Создайте подпапку «js» в папке «theme» и скопируйте туда из каталога «deployment» файлы «login_i18n.js» и «login.js». Результат должен выглядеть примерно так:

3. Настройка файла login.html
Этот этап — необязателен, однако он поможет разобраться, что происходит, когда вы добавляете новый элемент.
Файл «login.html» находится в папке «theme» приложения. Добавьте новую метку с идентификатором «login-local-label» следующим образом:
<div> <!-- New field introduced --> <label id="login-local-label">Login in with your account</label> <div id="loginMessage" class="alert alert-danger"></div> <div class="form-group">
4. Добавление переводов и их отображение согласно языку браузера
Предположим, у нас будет три языка: голландский, немецкий и английский.
Замените содержимое файла «login_i18n.js» на приведенное ниже. Сам код пояснений не требует: мы просто получаем из браузера предпочитаемый язык пользователя и в соответствии с ним устанавливаем значение различных полей.
СОВЕТ. Если вы добавляете на страницу «login.html» новые элементы, у них должен быть перевод. Поэтому для каждого нового переводимого элемента добавляйте пару «ключ — значение». Файл «login.js» также нужно будет изменить — но это уже на следующем этапе.
В этом примере я уже выбрал значение «login-local-label».
//Customized login_i18n.js file to support multiple language logins // Identify the language of the users browser var language = navigator.language.toLowerCase(); // Dutch language if (language == "nl"){ window.i18nMap = { "username": "Gebruikersnaam", "password": "Wachtwoord", "loginButton": "Aanmelden", "http401": "De opgegeven gebruikersnaam of het opgegeven wachtwoord is onjuist.", "http404": "Server niet gevonden.", "http500": "Er is een interne serverfout opgetreden.", "http503": "Service niet beschikbaar.", "httpdefault": "Aanmelden mislukt.", "http402": "De huidige licentie staat niet toe dat er meer gebruikers inloggen.", "http460": "U bent uitgelogd, omdat u ergens anders hebt ingelogd.", "http419": "Uw sessie is verlopen. Vul uw gebruikersnaam en wachtwoord in om verder te gaan.", "goHomeButton": "Terug naar de startpagina", "http403": "U hebt niet genoeg rechten om deze pagina te openen. U kunt proberen aan te melden als een andere gebruiker.", "cancel": "Annuleren", "loginlocallabel": "Login in met uw account" } } // German language else if (language == "de"){ window.i18nMap = { "username": "Nutzername", "password": "Passwort", "loginButton": "Anmeldung", "http401": "Der von Ihnen eingegebene Benutzername oder Passwort ist falsch.", "http404": "Server nicht gefunden.", "http500": "Ein interner Serverfehler ist aufgetreten.", "http503": "Dienst nicht verfügbar.", "httpdefault": "Anmeldung fehlgeschlagen.", "http402": "Die aktuelle Lizenz erlaubt nicht mehr Benutzern, sich anzumelden.", "http460": "Sie wurden abgemeldet, weil Sie sich woanders angemeldet haben.", "http419": "Deine Sitzung ist abgelaufen. Bitte geben Sie Ihren Benutzernamen und Ihr Passwort ein, um mit der Arbeit fortzufahren.", "goHomeButton": "Zurück zur Startseite", "http403": "Sie haben nicht genügend Berechtigungen, um auf diese Seite zuzugreifen. Sie können versuchen, als anderer Benutzer zu loggen.", "cancel": "Stornieren", "loginlocallabel": "Melden Sie sich mit Ihrem Konto an" } } //Default is English language else { window.i18nMap = { "username": "Username", "password": "Password", "loginButton": "Login", "http401": "The username or password you entered is incorrect.", "http404": "Server not found.", "http500": "An internal server error occurred.", "http503": "Service not available.", "httpdefault": "Sign in failed.", "http402": "The current license does not allow more users to sign in.", "http460": "You were signed out, because you signed in somewhere else.", "http419": "Your session has expired. Please enter your user name and password to continue working.", "goHomeButton": "Back to homepage", "http403": "You don't have enough permissions to access this page. You may try to logic as a different user.", "cancel": "Cancel", "loginlocallabel": "Login with your account" } }
5. Получение переводов в файле «login.js»
Если вы не изменяете файл «login.html», это можно пропустить — в противном случае следуйте указаниям.
Соответствующие изменения разделены на этапы (STEP) и снабжены пояснениями.
(function() { var byId = function(id) { return document.getElementById(id); }; var loginForm = byId("loginForm"), loginMessage = byId("loginMessage"), usernameLabel = byId("usernameLabel"), usernameInput = byId("usernameInput"), passwordLabel = byId("passwordLabel"), passwordInput = byId("passwordInput"), loginButton = byId("loginButton"), goHomeButton = byId("goHomeButton"), // STEP 1: Get the control loginlocallabel = byId("login-local-label"); var showMessage = function(str) { loginMessage.textContent = str || ""; loginMessage.style.display = str ? "block" : "none"; }; var hideMessage = function() { showMessage(""); }; var removeMessageCode = function(search) { var searchParams = search.substring(1).split("&").filter(function(param) { return param.split("=")[0] !== "messageCode"; }); return searchParams.length > 0 ? "?" + searchParams.join("&") : ""; } var submit = function() { loginButton.setAttribute("disabled", "disabled"); var xhr = new XMLHttpRequest(), json = JSON.stringify({ action: "login", params: { username: usernameInput.value, password: passwordInput.value } }); xhr.open("POST", "xas/" , true); xhr.setRequestHeader("Content-type", "application/json"); xhr.onreadystatechange = function() { if (xhr.readyState != 4) return; var msg; switch (xhr.status) { case 200: var url = /login\.html/.test(window.location.pathname) ? "index.html" : "index3.html"; window.location = url + removeMessageCode(window.location.search) + window.location.hash; return; case 400: case 401: case 403: msg = i18nMap.http401; break; case 402: msg = i18nMap.http402; break; case 404: msg = i18nMap.http404; break; case 500: msg = i18nMap.http500; break; case 503: msg = i18nMap.http503; break; default: msg = i18nMap.httpdefault; } showMessage(msg); loginButton.removeAttribute("disabled"); } xhr.send(json); return false; }; var goHome = function() { var url = /login\.html/.test(window.location.pathname) ? "index.html" : "index3.html"; window.location = url; }; if (i18nMap) { var usernameText = i18nMap.username, passwordText = i18nMap.password, buttonText = i18nMap.loginButton, goHomeButtonText = i18nMap.goHomeButton; // Step 2 - Get the value for the control loginlocallabelText = i18nMap.loginlocallabel; if (usernameText) { usernameLabel.textContent = usernameText; usernameInput.setAttribute("placeholder", usernameText); } if (passwordText) { passwordLabel.textContent = passwordText; passwordInput.setAttribute("placeholder", passwordText); } if (buttonText) { loginButton.value = buttonText; } if (goHomeButton && goHomeButtonText) { goHomeButton.value = goHomeButtonText } // STEP 3a - Set the translated value for the element if (loginlocallabel) { loginlocallabel.innerHTML = loginlocallabelText; } } loginForm.onsubmit = submit; usernameInput.onkeydown = hideMessage; passwordInput.onkeydown = hideMessage; if (goHomeButton) { goHomeButton.onclick = goHome; goHomeButton.style.display = "none"; } usernameInput.focus(); if (window.location.search) { var messageCodeParameter = window.location.search.substring(1).split("&").filter(function(item) { return item.split("=")[0] === "messageCode"; })[0]; if (messageCodeParameter) { var messageCode = messageCodeParameter.split("=")[1]; showMessage(window.i18nMap["http" + messageCode]); if (messageCode === "403") goHomeButton.style.display = ""; } } var cookieParts = [ "originURI=" + location.pathname, "max-age=" + (60 * 60 * 24 * 365), ]; if (window.location.protocol === "https:") { cookieParts.push("SameSite=None", "Secure"); } document.cookie = cookieParts.join(";"); })();
6. Открытие приложения в браузере и смена языка
А теперь проверим, что у нас получилось.
Для этого нужно изменить язык браузера и открыть страницу входа в приложение. Следуйте указаниям ниже и посмотрите, как меняется страница входа. Мы будем использовать Chrome.
Добавьте в браузер соответствующие языки.
Откройте страницу chrome://settings и перейдите в раздел «Дополнительные → Языки».

2. Переключите язык и откройте страницу входа в приложение.
Это можно сделать, нажав три точки напротив языка и выбрав Отображать Google Chrome на этом языке.
3. Обновите страницу.
Страница входа на голландском языке

Страница входа на немецком языке

Страница входа на английском языке (по умолчанию)

О переводчике
Перевод статьи выполнен в Alconost.
Alconost занимается локализацией игр, приложений и сайтов на 70 языков. Переводчики-носители языка, лингвистическое тестирование, облачная платформа с API, непрерывная локализация, менеджеры проектов 24/7, любые форматы строковых ресурсов.
Мы также делаем рекламные и обучающие видеоролики — для сайтов, продающие, имиджевые, рекламные, обучающие, тизеры, эксплейнеры, трейлеры для Google Play и App Store.
