Internationalization, often written as i18n, is the process through which products can be prepared to be taken to other countries. It doesn’t just mean being able to change languages; instead it means being to accept different forms of data, different settings to match local customs and different strings of data and process it correctly.

These days, with so many websites to choose from, making applications available and user-friendly to a worldwide audience is important. In this article, we will focus on using the built-in i18n tool in Angular. So, let’s get started.

New Angular Project


# Install Angular CLI globally
npm install --global @angular/cli
# Create Angular project
ng new ng-internationalization
# Would you like to add Angular routing? N
# Which stylesheet format would you like to use? SCSS
# Go to project's directory
cd ng-internationalization
# Open this folder with your favourite editor
code . 
# Serve the application
ng serve -o

Translations

Angular’s default locale is set to en-US. To support more languages, we need to update the default configuration and add additional locales. You can find a list of various locale codes here.

Text Marking

To be able to translate the context in the application, we first need to mark the text with a custom attribute, named i18n. After the text marking, we will be able to translate the application into our desire languages. In our case el-GR and fr-FR. I will be using Google Translate to translate the text into French.

Let’s add the i18n attribute to all of the text that we want to translate

<main>
  <section>
    <h1 i18n>Why is Internationalization so important?</h1>
    <p i18n>
      These days, with so many websites to choose from, making applications
      available and user-friendly to a worldwide audience is important. It's the
      move to make a better user experience.
    </p>
    <small i18n
      >Find the full article
      <a
        href="https://github.com/ThPadelis/ng-internationalization"
        target="_blank"
        >here</a
      ></small
    >
  </section>
</main>


i18n is a custom attribute, recognized by Angular tools and compilers. After translation, the compiler removes it. It is not an Angular directive.


Now, we need a script that uses the Angular CLI to extract this into a messages.xlf file. This file contains all of our marked items. Head over to packages.json and add this script

"scripts": {
    "i18n:extract": "ng xi18n --output-path src/locales"
}

After adding this script, go ahead and run npm run i18n:extract. Then, open up scr/locales/messages.xlf and you will see something like this

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="en" datatype="plaintext" original="ng2.template">
    <body>
      <trans-unit id="4bcef995bebcf205074f9fd756b822a488b452cc" datatype="html">
        <source>Why is Internationalization so important?</source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">3</context>
        </context-group>
      </trans-unit>
      <trans-unit id="e8db4c58a5fc95a2a8d80183e4b527f4480fa06e" datatype="html">
        <source>
      These days, with so many websites to choose from, making applications
      available and user-friendly to a worldwide audience is important. It's the
      move to make a better user experience.
    </source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">4</context>
        </context-group>
      </trans-unit>
      <trans-unit id="0f16c7aaa76d2f52dbabcd329ebf11a39a26918d" datatype="html">
        <source>Find the full article
      <x id="START_LINK" ctype="x-a" equiv-text="<a>"/>here<x id="CLOSE_LINK" ctype="x-a" equiv-text="</a>"/></source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">10</context>
        </context-group>
      </trans-unit>
    </body>
  </file>
</xliff>

For each html element marked with the i18n directive, a trans-unit will be created.

<trans-unit id="4bcef995bebcf205074f9fd756b822a488b452cc" datatype="html">
    <source>Why is Internationalization so important?</source>
    <context-group purpose="location">
        <context context-type="sourcefile">src/app/app.component.html</context>
        <context context-type="linenumber">3</context>
    </context-group>
</trans-unit>

We can provide more information about the translations using this structure by adding a description. Inside of app.component.hmtl, update the i18n items with a description.

Additionally, we can help the translator with a description and a meaning .

We can also set a custom id for persistence and maintenance. aber all these are optional.

<!-- i18n="<meanin>|<description>@@customId" -->
<h1 i18n="Article Heading|Title for the article@@articleHeading">
    Why is Internationalization so important?
</h1>

We can finally generate our translations.


npm run i18n:extract

Translations

At this point, we have a messages.xlf file that contains all of the items that we want to translate. Let’s create a copy of messages.xlf for each language we want to translate the application.

cp src\locales\messages.xlf src\locales\messages.fr.xlf
cp src\locales\messages.xlf src\locales\messages.el.xlf

Let’s start with messages.fr.xlf. We will translate the messages by using the target and  source. The target attribute is the translation in that language.


<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="en" datatype="plaintext" original="ng2.template">
    <body>
      <trans-unit id="articleHeading" datatype="html">
        <source>Why is Internationalization so important?</source>
        <target>Pourquoi l'internationalisation est-elle si importante?</target>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">3</context>
        </context-group>
        <note priority="1" from="description">Title for the article</note>
        <note priority="1" from="meaning">Article Heading</note>
      </trans-unit>
      <trans-unit id="articleDescription" datatype="html">
        <source>These days, with so many websites to choose from, making applications available and user-friendly to a worldwide audience is important. It's the move to make a better user experience.</source>
        <target>Ces jours-ci, avec autant de sites Web à choisir, il est important de rendre les applications disponibles et conviviales pour un public mondial. C'est le geste d'améliorer l'expérience utilisateur.</target>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">8</context>
        </context-group>
        <note priority="1" from="description">Description for the article</note>
        <note priority="1" from="meaning">Article Description</note>
      </trans-unit>
      <trans-unit id="fullArticle" datatype="html">
        <source>Find the full article <x id="START_LINK" ctype="x-a" equiv-text="<a>"/>here<x id="CLOSE_LINK" ctype="x-a" equiv-text="</a>"/></source>
        <target>Retrouvez l'article complet <x id="START_LINK" ctype="x-a" equiv-text="<a>"/>ici<x id="CLOSE_LINK" ctype="x-a" equiv-text="</a>"/></target>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">14</context>
        </context-group>
        <note priority="1" from="description">Read the whole article</note>
        <note priority="1" from="meaning">Full Article</note>
      </trans-unit>
    </body>
  </file>
</xliff>

Locale Build Configuration

Now, we have different versions of our application. A good practice is to have a script that builds the application for each locale we want to support.

Head over to angular.json and add the below configurations.

{
  "projects": {
    "ng-internationalization": {
      "architect": {
        "build": {
          "configurations": {
            "fr-FR": {
              "aot": true,
              "outputPath": "dist/fr-FR",
              "i18nFile": "src/locales/messages.fr.xlf",
              "i18nFormat": "xlf",
              "i18nLocale": "fr",
              "i18nMissingTranslation": "error"
            },
            "el-GR": {
              "aot": true,
              "outputPath": "dist/el-GR",
              "i18nFile": "src/locales/messages.el.xlf",
              "i18nFormat": "xlf",
              "i18nLocale": "el-GR",
              "i18nMissingTranslation": "error"
            }
          }
        },
        "serve": {
          "configurations": {
            "production": {
              "browserTarget": "ng-internationalization:build:production"
            },
            "fr-FR": {
              "browserTarget": "ng-internationalization:build:fr-FR"
            },
            "el-GR": {
              "browserTarget": "ng-internationalization:build:el-GR"
            }
          }
        }
      }
    }
  }
}

Let’s create some more scripts inside the package.json file to be able to build and serve our new locales.

"scripts": {
    "start": "ng serve",
    "start:fr": "ng serve --configuration=fr-FR",
    "start:gr": "ng serve --configuration=el-GR",
    "build": "ng build",
    "build:fr": "ng build --configuration=fr-FR",
    "build:gr": "ng build --configuration=el-GR",
}

It’s time to see what we have created.


npm run start
npm run start:fr -- --port 4201
npm run start:gr -- --port 4202

Conclusion

Internationalization and localization are important parts of an application. We can use angular-cli to support it or install an external library to save some time.

reference

https://dzone.com/articles/internationalization-i18n-with-angular-1

related / usefull Links

MissingTranslationStrategy

By Shabazz

Software Engineer, MCSD, Web developer & Angular specialist

Leave a Reply

Your email address will not be published. Required fields are marked *