Multi-lingual Login Page for Mendix Apps
Many of you would already know that Mendix allows us to build multi-lingual application out of the box. There are many apps out there which do just that and there are many clients which have such requirements. During one such requirement, I got thinking. I already know how to enable an application to support multiple languages but up until that point I had not really built any application which would support multi-lingual login pages. So today, we are going to do just that.
Before we start, it is good to know that any solution can be designed in multiple ways. But we will look at one of the ways of how you could achieve it.
What is i18n?
Internationalization, sometimes referenced as i18n, is the process of designing and preparing your project for use in different locales around the world. Localization is the process of building versions of your project for different locales.
The localization process includes the following actions:
· Extract text for translation into different languages
· Format data for a specific locale
A locale identifies a region in which people speak a particular language or language variant. Possible regions includes countries and geographical regions. A locale determines the formatting and parsing of the following details:
· Measurement units including date and time, numbers, and currencies
· Translated names including time zones, languages, and countries
Pre-requisites
· Mendix Studio Pro 8.12.5 version but you could just easily use a different version. Do note that in such cases you might have to tweak based on the folder structure of the application.
· Visual Studio code but once more you could easily use an editor of your choice.
· Security of the application should be turned ON.
Let’s get started
In order to have the solution in place we will follow some steps:
- Locate the file login.js and login_i18n.js
To find these files in your project directory you will need to run the application at least once. As we will find these files in our deployment directory. The deployment directory gets generated once you run your application locally.
Once you run the application, go to Project -> Show Project Directory in Explorer
Right click on the project folder and open the entire project in an editor of your choice.
Navigate to deployment -> web -> js folder and notice the highlighted files:
2. Copy the Files
Now that you’ve successfully identified the files, let’s move to the next step where we will add the translations.
First, lets copy the required files from the deployment directory to our theme folder. Create a folder js under theme folder and add the files login_i18n.js and login.js files to the js folder. Once you do, you should see something as below:
3. Customize the Login.html file
This step is optional, but if you’d like to understand what really happens if you introduce a new element then the step is helpful.
You can find the login.html file under the theme folder of the application. Add a new label with ID login-local-label as shown below:
<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. Adding translations and displaying based on users browser language
We will assume that we want to have 3 languages in the application — Dutch, German and finally English language.
Replace the content of the file with below. The code itself is self explanatory. But in essence we identify users (preferred) language from the browser and essentially set the different fields in that specific language.
TIP: If you add any new elements on your login.html page then they should have a relevant translation available. Add a key-value for any additional element that you’d like to get translated. A further change would be required in login.js and I’ll show that in the next step.
I’ve already selected a value called login-local-label
//Customized login_i18n.js file to support multiple language logins// Identify the language of the users browservar language = navigator.language.toLowerCase();// Dutch languageif (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 languageelse 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 languageelse {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. Modify the login.js file to capture translations
If you don’t change your login.html file then you can skip this step. However, if you do modify the file and add a new element then this step is relevant for you.
The relevant changes have been marked with Steps and explanation.
(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 controlloginlocallabel = 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 controlloginlocallabelText = 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 elementif (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. View the Application in Browser & Change language
Now it’s time to check out our results.
To do so, we would need to change the browser language and re-open the login page of our application. Follow the steps below and view the differences in your login page! We will be doing it on Chrome.
- Ensure that you’ve added languages to the browser
Navigate to chrome://settings -> Advanced -> Languages
2. Toggle between the languages and open your login page of the application
You can do so by clicking on the 3 dots against a language and select Display Google Chrome in this language.
3. Refresh the page to view the results
Login page in Dutch language
Login page in German language
Login page in default English language
Read More:
From the Publisher -
If you enjoyed this article you can find more like it at our Medium page.
For the makers looking to get started with the Mendix platform, you can sign up for a free account, and get instant access to learning with our Academy.
Interested in getting more involved with our community? You can join us in our Slack community channel or for those who want to be more involved, look into joining one of our Meet ups.