Многие уже наверняка знают, что в 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.