Localization in Angular Application using Angular Locale

In this article, we will discuss related how to use the localization & internationalization functionalities in Angular 11 Applications. Angular provides the functionality to implement localization and activate those on basis of different types of language configuration. In this article, we are going to discuss the concept of Localization in Angular. So, with the help of the Internationalization or i18n process, we can design and develop our web-based application that is compatible with different locales or languages around the world. So, we can also say that through the Localization process, we can build different versions of our web application for different locales which includes extracting text for translation into different languages, and formatting data for any specific locales.
 

Overview in Localization in Angular

 
There are around more than 6,000 languages used around the world today, most of the languages are only used by very small groups of people. So, even if we only focus on the top five languages in different countries, then it is found as – English, Mandarin, Hindi, Spanish, and French – in all these languages, there will be significant differences in date formatting, grammatical structure, pluralization and number formatting. If we include the Sixth most widely used language – Arabic – we encounter another difference; Arabic is a right-to-left (RTL) script which means the UI will also have to be mirrored. So during localization, we have to consider grammar, layout, and formatting differences, and of course, we also have to change the text itself. Angular can help with much of this but you'll still need to manually translate the text. So, in a normal concept, a locale mainly identifies a region or a country in which people speak that particular language or language variant. With the help of locale, we can formatting and parsing of dates, times, numbers, currencies as well as different measuring units and can translate those names for time zone wise, language-wise, and country-wise.
 

Why need to use Localization or i18n?

 
 
We will need to localize for each locale we need to support. A locale refers to the general set of preferences for the considerations mentioned above that tend to be shared within a region of the world, typically a country. Each locale is represented by a Unicode locale identifier, which specifies the language code and the locale extension.
 
Angular's default locale is 'en-US', which is the language code 'en' (English) as spoken in the region ‘United States of America’. An app localized for 'en-US' will be subtly different from an app localized for 'en-GB' which is English as spoken in Great Britain. For example, in the US dates are (bafflingly) formatted mm/dd/yyyy, whereas here in the UK we use the more sensible dd/mm/yyyy approach. This minor difference can result in a major error incomprehension.
To make things interesting let's localize our demo app for Arabic as spoken in Iraq, aka 'ar-IQ' and English as spoken in the UK, aka 'en-GB'. We'll use English as the default this time.
 

Steps to Implement Angular Location in Application

 
So, if we want to implement the Localization in the Angular Application, then we need to perform the following steps –
 

Step 1

First of all, we need to create an Angular Application using the Angular CLI command. For that run the command 
         ng new localeDemo
 

Step 2

Now, we need to install the Angular Language package by using the below command –
  1. npm install @angular/localize  

Step 3

Now, open the polyfill.ts file and add the below line of code in that file –
  1. import 'zone.js/dist/zone';  // Included with Angular CLI.  
  2. import '@angular/localize/init'  

Step 4

Now, in the application open the app.component.html file and change the existing code with this one –
  1. <h1 style="color: red;">Static Locale Change</h1>  
  2.   
  3. <div class="container-fluid">  
  4.       
  5.     <div class="row">  
  6.         <h1 style="color: blue;" i18n>Hello i18n!</h1>  
  7.         <h1 style="color: blue;" i18n="header">An introduction header for this sample</h1>  
  8.         <h1 style="color: blue;" i18n="@@country">India</h1>  
  9.     </div>  
  10.       
  11. </div>  
In the above example, we can see that we use the i18n attribute in the <h1> tag. i18n is a custom attribute that can be recognized by the Angular Tools and compiler. After compilation, the compiler removes this attribute. It is not a directive. To translate the context properly, sometimes we need to mention a description or id against the i18n attribute. for that purpose, in the 2nd <h1> tag, we have used description text as “header” whereas in the next one we use the id value against the i18n attribute as “@@country”.
 

Step 5

Now, we need to create the translation file with the help of the Angular CLI command –
  1. ng xi18n --output-path src/locale  
This command will create messages.xlf file –
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">  
  3.   <file source-language="en-US" datatype="plaintext" original="ng2.template">  
  4.     <body>  
  5.       <trans-unit id="4150330030790364157" datatype="html">  
  6.         <source>Hello i18n!</source>  
  7.         <target>Hello i18n!!!!</target>  
  8.         <context-group purpose="location">  
  9.           <context context-type="sourcefile">src/app/static-locale/static.component.html</context>  
  10.           <context context-type="linenumber">6</context>  
  11.         </context-group>  
  12.       </trans-unit>  
  13.   
  14.       <trans-unit id="9207070150930908421" datatype="html">  
  15.         <source>An introduction header for this sample</source>  
  16.         <target>Translated by the Angular Locale</target>  
  17.         <context-group purpose="location">  
  18.           <context context-type="sourcefile">src/app/static-locale/static.component.html</context>  
  19.           <context context-type="linenumber">7</context>  
  20.         </context-group>  
  21.         <note priority="1" from="description">header</note>  
  22.       </trans-unit>  
  23.         
  24.       <trans-unit id="country" datatype="html">  
  25.         <source>India</source>  
  26.         <target>India</target>  
  27.         <context-group purpose="location">  
  28.           <context context-type="sourcefile">src/app/static-locale/static.component.html</context>  
  29.           <context context-type="linenumber">8</context>  
  30.         </context-group>  
  31.       </trans-unit>  
  32.     </body>  
  33.   </file>  
  34. </xliff>  
Now we can copy this file to create the other language translation file like – messages.fr.xlf
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">  
  3.   <file source-language="en-US" datatype="plaintext" original="ng2.template">  
  4.     <body>  
  5.       <trans-unit id="4150330030790364157" datatype="html">  
  6.         <source>Hello i18n!</source>  
  7.         <target>Bonjour i18n!!!!</target>  
  8.         <context-group purpose="location">  
  9.           <context context-type="sourcefile">src/app/static-locale/static.component.html</context>  
  10.           <context context-type="linenumber">6</context>  
  11.         </context-group>  
  12.       </trans-unit>  
  13.   
  14.       <trans-unit id="9207070150930908421" datatype="html">  
  15.         <source>An introduction header for this sample</source>  
  16.         <target>Traduit par Angular Locale</target>  
  17.         <context-group purpose="location">  
  18.           <context context-type="sourcefile">src/app/static-locale/static.component.html</context>  
  19.           <context context-type="linenumber">7</context>  
  20.         </context-group>  
  21.         <note priority="1" from="description">header</note>  
  22.       </trans-unit>  
  23.         
  24.       <trans-unit id="country" datatype="html">  
  25.         <source>India</source>  
  26.         <target>Inde</target>  
  27.         <context-group purpose="location">  
  28.           <context context-type="sourcefile">src/app/static-locale/static.component.html</context>  
  29.           <context context-type="linenumber">8</context>  
  30.         </context-group>  
  31.       </trans-unit>  
  32.     </body>  
  33.   </file>  
  34. </xliff>  
This file contains a list of multiple <trans-unit> tags. This tag will contain all the content which is marked for the translation or where we use the i18n attribute. We can also observe that each <trans-unit> tag has an id property associated with it. This unique id will be generated by default for each tag that was marked with the i18n attribute. We can also customize the id by providing a name prefixed with @@ as we have done in the 3rd <h1> tag in the HTML file. Hence, the id for <h1> tag is “country” as we defined it.
 

Step 6

Now, we already define the locale-related language translation file. Now, we need to update the build configuration related to the locale. For that, we need to perform the below changes in the angular.json file –
  1. {  
  2.   "$schema""./node_modules/@angular/cli/lib/config/schema.json",  
  3.   "cli": {  
  4.     "analytics"false  
  5.   },  
  6.   "version": 1,  
  7.   "newProjectRoot""projects",  
  8.   "projects": {  
  9.     "angular-language-demo": {  
  10.       "projectType""application",  
  11.       "schematics": {  
  12.         "@schematics/angular:application": {  
  13.           "strict"true  
  14.         }  
  15.       },  
  16.       "root""",  
  17.       "sourceRoot""src",  
  18.       "prefix""app",  
  19.       "i18n": {  
  20.         "sourceLocale""en-US",  
  21.         "locales": {  
  22.           "en": {  
  23.             "translation""src/locale/messages.xlf"  
  24.           },  
  25.           "es": {  
  26.             "translation""src/locale/messages.es.xlf"  
  27.           },  
  28.           "hi": {  
  29.             "translation""src/locale/messages.hi.xlf"  
  30.           },  
  31.           "fr": {  
  32.             "translation""src/locale/messages.fr.xlf"  
  33.           }  
  34.         }  
  35.       },   
  36.       "architect": {  
  37.         "build": {  
  38.           "builder""@angular-devkit/build-angular:browser",  
  39.           "options": {  
  40.             "outputPath""dist/angular-language-demo",  
  41.             "index""src/index.html",  
  42.             "main""src/main.ts",  
  43.             "polyfills""src/polyfills.ts",  
  44.             "tsConfig""tsconfig.app.json",  
  45.             "aot"true,  
  46.             "assets": [  
  47.               "src/favicon.ico",  
  48.               "src/assets"  
  49.             ],  
  50.             "styles": [  
  51.               "src/styles.css"  
  52.             ],  
  53.             "scripts": [],  
  54.             "localize":true  
  55.           },  
  56.           "configurations": {  
  57.             "production": {  
  58.               "fileReplacements": [  
  59.                 {  
  60.                   "replace""src/environments/environment.ts",  
  61.                   "with""src/environments/environment.prod.ts"  
  62.                 }  
  63.               ],  
  64.               "optimization"true,  
  65.               "outputHashing""all",  
  66.               "sourceMap"false,  
  67.               "namedChunks"false,  
  68.               "extractLicenses"true,  
  69.               "vendorChunk"false,  
  70.               "buildOptimizer"true,  
  71.               "budgets": [  
  72.                 {  
  73.                   "type""initial",  
  74.                   "maximumWarning""500kb",  
  75.                   "maximumError""1mb"  
  76.                 },  
  77.                 {  
  78.                   "type""anyComponentStyle",  
  79.                   "maximumWarning""2kb",  
  80.                   "maximumError""4kb"  
  81.                 }  
  82.               ]  
  83.             },  
  84.             "en": {  
  85.               "localize": ["en"]  
  86.             },  
  87.             "es": {  
  88.               "localize": ["es"]  
  89.             },  
  90.             "hi": {  
  91.               "localize": ["hi"]  
  92.             },  
  93.             "fr": {  
  94.               "localize": ["fr"]  
  95.             }  
  96.           }  
  97.         },  
  98.         "serve": {  
  99.           "builder""@angular-devkit/build-angular:dev-server",  
  100.           "options": {  
  101.             "browserTarget""angular-language-demo:build"  
  102.           },  
  103.           "configurations": {  
  104.             "production": {  
  105.               "browserTarget""angular-language-demo:build:production"  
  106.             },  
  107.             "en": {  
  108.               "browserTarget""angular-language-demo:build:en"  
  109.             },  
  110.             "es": {  
  111.               "browserTarget""angular-language-demo:build:es"  
  112.             },  
  113.             "hi": {  
  114.               "browserTarget""angular-language-demo:build:hi"  
  115.             },  
  116.             "fr": {  
  117.               "browserTarget""angular-language-demo:build:fr"  
  118.             }  
  119.           }  
  120.         },  
  121.         "extract-i18n": {  
  122.           "builder""@angular-devkit/build-angular:extract-i18n",  
  123.           "options": {  
  124.             "browserTarget""angular-language-demo:build"  
  125.           }  
  126.         },  
  127.         "test": {  
  128.           "builder""@angular-devkit/build-angular:karma",  
  129.           "options": {  
  130.             "main""src/test.ts",  
  131.             "polyfills""src/polyfills.ts",  
  132.             "tsConfig""tsconfig.spec.json",  
  133.             "karmaConfig""karma.conf.js",  
  134.             "assets": [  
  135.               "src/favicon.ico",  
  136.               "src/assets"  
  137.             ],  
  138.             "styles": [  
  139.               "src/styles.css"  
  140.             ],  
  141.             "scripts": []  
  142.           }  
  143.         },  
  144.         "lint": {  
  145.           "builder""@angular-devkit/build-angular:tslint",  
  146.           "options": {  
  147.             "tsConfig": [  
  148.               "tsconfig.app.json",  
  149.               "tsconfig.spec.json",  
  150.               "e2e/tsconfig.json"  
  151.             ],  
  152.             "exclude": [  
  153.               "**/node_modules/**"  
  154.             ]  
  155.           }  
  156.         },  
  157.         "e2e": {  
  158.           "builder""@angular-devkit/build-angular:protractor",  
  159.           "options": {  
  160.             "protractorConfig""e2e/protractor.conf.js",  
  161.             "devServerTarget""angular-language-demo:serve"  
  162.           },  
  163.           "configurations": {  
  164.             "production": {  
  165.               "devServerTarget""angular-language-demo:serve:production"  
  166.             }  
  167.           }  
  168.         }  
  169.       }  
  170.     }  
  171.   },  
  172.   "defaultProject""angular-language-demo"  
  173. }  
 

Step 7

Now, we need to update the package.json file as below –
  1. "scripts": {  
  2.     "ng""ng",  
  3.     "start""ng serve --configuration=production",  
  4.     "start:hi""ng serve --configuration=hi",  
  5.     "start:fr""ng serve --configuration=fr",  
  6.     "start:en""ng serve --configuration=en",  
  7.     "start:es""ng serve --configuration=es",  
  8.     "build""ng build",  
  9.     "build:prod""ng build --configuration=production",  
  10.     "test""ng test",  
  11.     "lint""ng lint",  
  12.     "e2e""ng e2e"  
  13.   },  
Step 8
Now, first, run the command to build the project for the production environment. When we build the project by using ng build –prod command, in the production environment, it will prepare separate files for each locale.
 
 
 
Now, if we want to start the application, we can run the application with a specific locale with the npm run start command –
  1. npm run start:en  
 
 Similarly, if we want to run the application using a french locale, then we need to run the below command - 
  1. npm run start:fr  
In that case, the output will be as below - 
 
 
 

Conclusion

 
In this article, we discussed how to implement the localization using the Angular Framework in any web application. Also, we discussed the basic concept of localization along with the sample example. I hope, this article will help you. Any feedback or query related to this article is most welcome.