In this article, you will learn how to implement EmberJS i18n (internationalization) into your application. Internationalization is a part of an application's development strategy to facilitate normalizing the app for a different region or culture, including the language. In the world of coding, internationalization is often referred to as i18n simply because of the term's 20-character length.
The underlying purpose of app i18n is to ensure that it remains intuitive and user-friendly across a wide range of countries and regions.
A well-executed i18n strategy is a vital first step in the broader localization process, which further tailors the application to specific cultural and linguistic nuances.
In this context, using translation keys can streamline the adaptation process. For instance, the word "internationalization" itself is spelled differently in various countries. North Americans spell it with a 'z', while UK English speakers replace that 'z' with an 's'. Similarly, i18n is also necessary to make sure apps adapt to a multitude of formulations used in different languages and countries.
In this EmberJS i18n article, we'll cover the following topics:
Setting up an ember-intl module.
Translating and internationalizing your application using ember-intl.
EmberJS is a modern JavaScript framework that is designed to enhance the web app creation experience for professional developers. It reduces small differences between apps, so they are more functional. Most importantly, this is all done by adding a single light layer of code on top of the native JS. It also offers forward and backward compatibility so organizations can always have the latest Ember version.
Prerequisites for integrating EmberJS i18n
In order to fully understand this tutorial, you need to meet the following prerequisites:
Working familiarity with core HTML, CSS, and JavaScript.
NPM and Node.js on the machine you're going to use for development.
A basic understanding of JS modules, classes, and fundamental ES6 syntax such as template strings, arrow functions, and destructuring.
How to install Ember CLI
Ember CLI provides you with a native method to create and work on EmberJS projects. Before you go any further, you are required to install Ember CLI from NPM by typing the following command:
npm install -g ember-cli
Once you have installed Ember on your development machine, you will have the option to use the ember binary. This can be accessed through your terminal to create, serve, and develop new projects.
Creating a new app with EmberJS
To build a new application with EmberJS i18n support, you first need to create a new directory that will contain the scaffolding for your new app. Before you create a new directory, ensure that you have navigated to somewhere suitable in the terminal prior to writing the code. You can either create it on your desktop or in documents directories so the app can be found easily.
ember new demoapp
Enter the below if you are using Windows:
npx ember-cli new demoapp
This creates a production-ready environment for app development that covers a wide variety of default features. These include the development server, plug-in architecture, the latest JS, automated testing environment, minification, transpilation, and conventions, among others.
Now you are ready to create a new project with the new command. Your command will look like this:
ember new ember-demo-app
You can use any valid name you wish; we have named it ember-demo-app for the purposes of this guide. You can navigate inside your app's root folder using the cd command:
cd ember-demo-app
Now, you are in a position to utilize a wide variety of Ember commands to work with your app. For instance, you can serve the app using the serve command:
ember serve
After you have reached this point, you can start implementing Ember i18n by adding ember-intl.
EmberJS i18n with ember-intl example
Setting up and configuring ember-intl
If you haven't installed ember-intl, the easiest and quickest way to do it is by using ember-cli, like so:
ember install ember-intl
This will add Format.JS, ember-intl.js, and en-us.yaml files to your app, as well as config and translations directories, respectively. Now you can initiate the server by using the ember serve command. That being said, keep in mind that Ember is quite a particular framework that uses a lint tool to analyze your code style.
This means that as soon as you initiate the command, you will see a message related to the 'no-bare-strings' rule. You will need to configure it when using ember-intl. You can prevent this warning by including the following code in the template-lintrc.js:
rules: { 'no-bare-strings': true}
This indicates that you will need to use the {{t 'translation.id'}} helper instead of plain text in your templates. If you do use plain text, please note that it won't be translated. The helper will give you the option to use the following as valid parameters:
You can convert the template with the following bar helper; however, it won't give you any translations and will return an error message. This is only because you haven't added any translation files yet.
<h1>{{t "hello world"}}</h1>{{outlet}}
Creating language files and defining translations for EmberJS i18n
You will have to create a language file for the source language of your app and the one you want it to be translated into: your target. To create the language files, you can use the generate locale command along with the abbreviations of the languages you want to add (e.g. 'de' for German), as shown below:
ember generate locale enember generate locale de
These files or locales contain all translatable strings and are used in your app templates and code. The format of the code is quite easy to follow:
// app/locales/en.jsexport default { "greeting": "Hello User", "task-create": "Create new task", "task-delete": "Delete task", "task-open": "You have open tasks"};
To define your translations, you will have to put your intended translation files in app/locales/[locale]/translations.js. Every translation file should export an object. Note that if the values are in the form of functions, they will be executed as they are but if they are in the form of strings, they will need to go through a compilation process using the following:
Once you have gone through all the above steps, you are now ready to add your first translation. In order to do that, you will need to change the application.hbs in the following way:
<h1>{{t "hello.world"}}</h1>{{outlet}}
Now, if you run the ember serve command again, your application will return an error saying:
Missing translation "hello.world" for locale "en-us"
That's because you have not included any translations yet. At this point, open translations/en-us.yaml and change it to the following:
hello: world: Hello world!
What you see here is that EmberJS relies on a period (.) to define a separation between subentries when you are working in a YAML file. Now you can refresh the page to see the following:
Hello world!
Handling JSON and YAML files
When working with ember-intl, the framework also supports JSON files, but it all comes down to your personal preference. You can choose either of the two. YAML is comparatively compact if you are looking to write the code on your own and it doesn't have a lot of restrictions. This is especially true in terms of using additional commas in your lists, which returns errors if you are working with JSON files.
For this EmberJS i18n tutorial, we are going to continue to use YAML as the default. Moreover, you might already know that there are a variety of tools available on the net that can convert between YAML and JSON files. There isn't a wrong format here.
Adding a new language
Since we are already using German for this demo app, we can continue with it. You can use any language or languages you want. In order to do this, use the following script:
ember create translation de-de
You can also create the file as shown above. It is a slightly different method but achieves the same result. If you want to create a translation file, here is the code:
hello: world: Hallo Welt!
Switching languages
Once you have learned to add translation files and languages, you need to know how to switch them. When it comes to switching a language in EmberJS i18n, you can do it in two different ways:
Specifying the language on app startup
Switching languages dynamically or at runtime
Specifying the language on app startup
First, let's take a look at how you'd set a specific language on app startup. You will need to create the app/routes/application.js including the content mentioned below. This code will switch the language to the German, or de-de, file that you created by adding a new language file.
import { inject as service } from '@ember/service';import Route from '@ember/routing/route';export default Route.extend({ intl: service(), beforeModel() { this.get('intl').setLocale(['de-de']); }});
Now if you run the app, you will see text change to "Hallo Welt!".
Switching languages dynamically or at runtime
For this to work, you will need to create and add an application controller inside the app/controllers/application.js file.
After you have created the controller, you need to add the following code to enable your app to change the language at runtime:
import config from '../config/environment';import Controller from '@ember/controller';import { computed, get } from '@ember/object';import { inject as service } from '@ember/service';import { lookupByFactoryType } from 'ember-intl/hydrate';const { modulePrefix } = config;export default Controller.extend({ intl: service(), activeLocale: computed.readOnly('intl.locale'), locales: computed(function() { return lookupByFactoryType('translations', modulePrefix).map(moduleName => moduleName.split('/').pop()); }).readOnly(), selections: computed('locales.[]', 'activeLocale', function() { let active = get(this, 'activeLocale'); return get(this, 'locales').map(locale => { return { locale: locale, active: active.indexOf(locale) > -1 }; }); }).readOnly(), actions: { changeLocale(locale) { return get(this, 'intl').set('locale', locale); } }});
The changeLocale is used to call the template in order to enable a locale (language) change upon button click. This script also delivers various properties to acquire the currently enabled language, a list of accessible languages, and a list that includes the language name and flag. The following template can be used to generate a list of click buttons with the languages that are available.
Add the code mentioned below to app/templates/application.hbs to generate a click button for every language, in this case it is German:
If you want to dress up your buttons, you can use your CSS skills in app/styles/app.css to highlight the language that is currently selected. This will give your buttons a more aesthetic feel but it's not exactly within the scope of this tutorial.
Defining parameters, selections, and pluralization
Since your translations must sound natural and not robotic, you will need further control over them. This being in terms of defining different language parameters and ensuring pluralization occurs accurately. We are not going to discuss all the scripts here, but some of the simple and most used parameters and pluralization rules are as follows.
Defining parameters
You will need to add the following code to application.hbs:
<h1>{{t "greeting" name="John"}}</h1>
Once you have done that, add the following to your language files i.e. de-de.yaml and en-us.yaml:
The app will now use the provided value in the name parameter to replace {name}. For example:
{{t "greeting" name="John"}}
Defining selections
If you want to change the translation depending on the parameters introduced, you can do so by relying on the ICU syntax included in ember-intl. This particular syntax will enable you to choose various strings and you will need to make changes inside application.hbs.
If we take the greeting translation example, the syntax will resemble the below script:
Download {type, select,pro { {name} (full version) }trial { the free trial of {name} }other { {name} }} from our web page!
If you are using select, note that it can take 3 comma-separated parameters including the following:
the syntax select
the variable name being used for selection
a list of probable values along with the text in {}
You also have the option to include extra variables in {} in translation texts, such as the {name} in the provided example. Now you can add the following code to en-us.yaml:
download: |-Download {type, select,pro { {name} (full version) }trial { the free trial of {name} }other { {name} }} from our web page!
de-de.yaml:
download: |-Laden sie {type, select,pro { {name} Professional}trial {die Test-Version von {name}}other { {name} }} von unserer Webseite!
Pluralization
In EmberJS, you have the capability to modify translation text based on numbers. For instance:
No cars
One car
2 Cars
and so on
To do this, you will need to add the following script in application.hbs:
You have {itemCount, plural,=0 {no cars}one {one car}other {{itemCount} cars}}.
Three comma-separated values are used in plural syntax. These values include:
plural syntax
count of items
a list of probable values along with the text in {}
The probable value options are listed below:
zero
one, two
few, many
other
=value
Therefore, you can add the following code to en-us.yaml:
flowers: |- You have {itemCount, plural, =0 {no flowers} one {one flower} other {{itemCount} flowers}}.
and this to de-de.yaml:
flowers: |- Du hast {itemCount, plural, =0 {keine Blumen} one {eine Blume} other {{itemCount} Blumen}}.
Compiling your EmberJS i18n translations
The ember-intl framework has a default compiler that plays the role of Handlebars and is compatible with interpolations. It generates strings that have been designated as HTML-safe. If there are any interpolated values, the compiler marks them as HTML-unsafe. If you want HTML-safe interpolations, this can be achieved using the following two methods.
export default { 'info.see-other-user': "Please see {{{userLink}}}"};
Ideally, using the first method is recommended since it makes it more difficult to introduce any XSS vulnerabilities by mistake.
Adding right-to-left language support
If you want to introduce right-to-left or RTL support to your translations, this can be done by introducing Unicode RTL markers around your output translations where required by the language. You have the option to override this by setting rtl in the language configuration file (Arabic in this case):
When you call the t function with a key that does not exist, it returns the following with the context and key as arguments.
util:i18n/missing-message
The default way is to return a "Missing translation: [key]". However, you can change this via function override. The following script will return the key accompanying the values of the arguments passed:
When there is a missing translation, the i18n service also encounters a missing event with the context and the key. You can utilize these to implement other missing-translation behaviors. For instance, logging your keys somewhere else with this script:
By now you are probably thinking that supporting multiple languages on a sizeable website is probably going to be a pain. And, honestly, you are right. Luckily, there is a solution to this problem: Lokalise – the platform that makes working with localization files much simpler. Let me guide you through the initial setup, which is not too complex really:
while providing your generated token and project ID (on Windows you may also need to provide the full path to the file). This should upload the English translation to Lokalise.
Navigate back to the project overview page. You should see all your translation keys and values there. Of course, it is possible to edit or delete them, as well as add new ones. Here you may also filter the keys and, for example, find any untranslated ones which is really convenient.
After you are done editing the translations, download them by running
Lokalise has many more features including support for dozens of platforms and formats, the ability to order translations from professionals, and even the possibility to upload screenshots and read text from them. So, stick with Lokalise and make your life easier!
Conclusion
Once you have gone through the above steps, you will be in a much better position to manage the internationalization of your apps using EmberJS. Before you launch the app, ensure that you test it again and again to iron out any bugs and make it as perfect as possible.
Arthur is a full stack developer forming part of the product team at Lokalise. He found his passion for technology at the age of 7 when he fully reinstalled Windows 98 all by himself. When he is not programming, he also enjoys making music, photography, shooting videos, VFX, and gaming.
Arthur is a full stack developer forming part of the product team at Lokalise. He found his passion for technology at the age of 7 when he fully reinstalled Windows 98 all by himself. When he is not programming, he also enjoys making music, photography, shooting videos, VFX, and gaming.
Libraries and frameworks to translate JavaScript apps
In our previous discussions, we explored localization strategies for backend frameworks like Rails and Phoenix. Today, we shift our focus to the front-end and talk about JavaScript translation and localization. The landscape here is packed with options, which makes many developers a
An SRT file is a plain text file used to add subtitles to videos. It’s one of the simplest and most common formats out there. If you’ve ever turned on captions on a YouTube video, there’s a good chance it was using an SRT file behind the scenes. People use SRT files for all kinds of things: social media clips, online courses, interviews, films, you name it. They’re easy to make, easy to edit, and they work pretty much everywhere without hassle. In this post, we’ll
Syncing Lokalise translations with GitLab pipelines
In this guide, we’ll walk through building a fully automated translation pipeline using GitLab CI/CD and Lokalise. From upload to download, with tagging, version control, and merge requests. Here’s the high-level flow: Upload your source language files (e.g. English JSON files) to Lokalise from GitLab using a CI pipeline.Tag each uploaded key with your Git branch name. This helps keep translations isolated per feature or pull request