Angular Internationalization

Overview

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.

Prerequisites

to prepare your project for translations, you should have a basic understanding of the following subjects.

Setting Up the Project

To facilitate the implementation of a translation project, I want to create a simple Angular project that does not include routing, CSS compatibility, and testing features. Open a command prompt or terminal window and run the following command to create a new Angular project:

npx @angular/cli new angular-i18n-example --style=css --routing=false --skip-tests 

This will configure a new Angular project with styles set to “CSS” (as opposed to “Sass”, Less”, or “Stylus”), no routing, and skipping tests.

Navigate to the newly created project directory:

cd angular-i18n-example 

Add the localize package

To take advantage of the localization features of Angular, use the Angular CLI to add the @angular/localize package to your project.

To add the @angular/localize package, use the following command to update the package.json and TypeScript configuration files in your project.

ng add @angular/localize

It adds types: [“@angular/localize”] in the TypeScript configuration files as well as the reference to the type definition of @angular/localize at the top of the main.ts file.

Mark text in component template

In a component template, the i18n metadata is the value of the i18n attribute. Use the i18n attribute to mark a static text message in your component templates for translation. Place it on every element tag that contains fixed text you want to translate.

The following <h1> tag displays a simple English language greeting, “Hello i18n!”. open app.component.html in your code editor and replace the code with the following lines:

<h1 i18n="User welcome | An introduction header for this sample@introductionHeader"><br>Hello i18n!<br></h1>

In above code, the <h1> element has an i18n attribute, which tells Angular that this element and its text should be translated when the application is localized for different languages.

The i18n attribute has two parts separated by a vertical bar |. The first part “User welcome” is the message to be translated. This message will be replaced by a translated version of the message in the target language.

The second part @@introductionHeader is a unique identifier for this message. It is used to link the original text with its translation in the language files. When you run the localization tool to generate language files, the tool scans your application for i18n attributes and extracts the original text and its identifier into a .xlf file. You can then provide translations for the text in the .xlf file for each supported language.

The text “Hello i18n!” inside the <h1> element is the default text that will be displayed if no translation is available for the target language. This is useful for development purposes, as it allows you to see the layout of your application while you’re working on translations.

Extract the source language file

To extract the source language file, run the following CLI command:

ng extract-i18n --output-path src/locale 

The extract-i18n command creates a source language file named messages.xlf in the root directory of your project. For more information about the XML Localization Interchange File Format (XLIFF, version 1.2), see XLIFF.

In the command ng extract-i18n –output-path src/locale, the –output-path option specifies the location where the translation template file should be saved, which is src/locale in this case. The src/locale folder is typically used to store the language files for your application, including the translation template file.

After running this command, Angular will scan the project’s source files for any elements and attributes marked for translation with the i18n attribute and generate a translation template file in the src/locale folder. The translation template file will contain all the translatable messages extracted from the project, along with their unique identifiers. You can then provide translations for these messages in the template file for each supported language.

In the src/locales folder, you will find a messages.xlf file. This is the base translation file with the following contents:

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en-US" datatype="plaintext" original="ng2.template">
        <body>
            <trans-unit id="introductionHeader" datatype="html">
                <source>Hello i18n!</source>
                <context-group purpose="location">
                    <context context-type="sourcefile">src/app/app.component.html</context>
                    <context context-type="linenumber">1,3</context>
                </context-group>
                <note priority="1" from="description">An introduction header for this sample</note>
                <note priority="1" from="meaning">User welcome</note>
            </trans-unit>
        </body>
    </file>
</xliff>
  • <trans-unit>:  is the tag containing a single translation. The id=”introductionHeader” is a custom ID, but without the @@ prefix required in the source HTML.
  • <source>: This is the original source string that needs to be translated.
  • <context-group>: This element provides additional context information for the translatable string. In this case, the purpose attribute is set to “location”, indicating that the context information is related to the location of the string in the source code.
  • <context-type=”sourcefile”> shows the file where the translation lives.
  • <context-type=”linenumber”> shows the actual line of code.
  • <note>: This element provides additional information about the translatable string that may be helpful for translators. In this case, there are two note elements: one with a from attribute of “description”, which provides a description of the string, and one with a from attribute of “meaning”, which provides the meaning of the string.

Translating the content

First, copy messages.xlf to messages.fr.xlf:

cp src/locale/messages.xlf src/locale/messages.fr.xlf 

Then, add a target for item with the French text:

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en-US" datatype="plaintext" original="ng2.template">
        <body>
            <trans-unit id="introductionHeader" datatype="html">
                <source>Hello i18n!</source>
                <target>Bonjour i18n!</target>
                <context-group purpose="location">
                    <context context-type="sourcefile">src/app/app.component.html</context>
                    <context context-type="linenumber">1,3</context>
                </context-group>
                <note priority="1" from="description">An introduction header for this sample</note>
                <note priority="1" from="meaning">User welcome</note>
            </trans-unit>
        </body>
    </file>
</xliff>

trans-unit now has a source message that is in English and a target message that is in French.

Merge translations into the application

Use the i18n project option in the angular.json workspace build configuration file of your project to define locales for a project.

For example, the following excerpt of an angular.json workspace build configuration file sets the source locale to en-US and provides the path to the French (fr) locale translation file.

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "angular-i18n-example": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "i18n": {
        "sourceLocale": "en-US",
        "locales": {
          "fr": {
            "translation": "src/locale/messages.fr.xlf"
          }
        }
      },
      "architect": {
        // This section should be filled with the relevant configuration.
      }
    }
  }
}

And create configuration settings for fr under build:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "angular-i18n-example": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "i18n": {
        "sourceLocale": "en-US",
        "locales": {
          "fr": {
            "translation": "src/locale/messages.fr.xlf"
          }
        }
      },
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            // Add your build options here
          },
          "configurations": {
            "fr": {
              "localize": ["fr"]
            },
            "production": {
              // Add production configuration here
            },
            "development": {
              // Add development configuration here
            }
          },
          "defaultConfiguration": "production"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "configurations": {
            "production": {
              // Add production serve configuration here
            }
          },
          "browserTarget": "angular-i18n-example:build:production"
        }
      }
    }
  }
}

You can also update the configuration settings under serve:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "angular-i18n-example": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "i18n": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            // Add build options here
          },
          "configurations": {
            "production": {
              // Add production build configurations here
            },
            "development": {
              // Add development build configurations here
            },
            "fr": {
              "localize": ["fr"]
            }
          },
          "defaultConfiguration": "production"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "configurations": {
            "fr": {
              "browserTarget": "angular-i18n-example:build:fr"
            },
            "production": {
              "browserTarget": "angular-i18n-example:build:production"
            },
            "development": {
              "browserTarget": "angular-i18n-example:build:development"
            }
          },
          "defaultConfiguration": "development"
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "angular-i18n-example:build"
          }
        }
      }
    }
  }
}

Create a script in your package.json file to start the application with the French localization. Open the package.json file in the root directory of your project and add the following script:

{
  "name": "angular-i18n-example",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "start:fr": "ng serve --configuration=fr"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^15.2.0",
    "@angular/common": "^15.2.0",
    "@angular/compiler": "^15.2.0",
    "@angular/core": "^15.2.0",
    "@angular/forms": "^15.2.0",
    "@angular/platform-browser": "^15.2.0",
    "@angular/platform-browser-dynamic": "^15.2.0",
    "@angular/router": "^15.2.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.12.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^15.2.3",
    "@angular/cli": "~15.2.3",
    "@angular/compiler-cli": "^15.2.0",
    "@angular/localize": "^15.2.9",
    "@types/jasmine": "~4.3.0",
    "jasmine-core": "~4.5.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.2.0"
  }
}

Start the application with the npm start and npm run start:fr command in your project directory.  See the results:

Hello i18n! 
Bonjour i18n ! 

Conclusion

Angular can be easily integrated into an Angular application using the Angular CLI. This makes it straightforward to add i18n support to an Angular application without having to install additional dependencies. i18n follows industry standards for internationalization and localization, making it easier to maintain and update translations for an application. But i18n is optimized for static content, so it may not be suitable for applications with a lot of dynamic content that is generated at runtime.

Overall, Angular i18n is a powerful tool for internationalizing and localizing Angular applications, but it may not be the best choice for every application, depending on its specific requirements and constraints.

Would you like to read more articles by Tekos’ Team? Everything’s here.

Author

Hieu Bui Avatar

Leave a comment

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

Comment
Name
Email
Website

Skip to content