# Internationalization Service

Main class to be used by user is**I18NService**. I18N is the standard acronym for the word Internationalization. It's implemented as a Decorator for other classes that implement particular logic.

**I18NService**should be included in the project root class, and then it's accessible as a singleton everywhere in the application.

## **Localization** <a href="#localization" id="localization"></a>

By default, the service takes browser language and sets default locale accordingly. User can always change locale by using**setLocale(locale: string)**&#x6D;ethod. This method takes standard locales as a string, like**en-US, fr-FR, fr-CA**etc. First part is language, second is country.

```
  /**
     * <p> Sets new locale and returns Promise when new dictionary is uploaded to memory.</p>
     * <p> Locale format examples: en-US, fr-FR, fr-CA, de-DE etc.</p>
     */
    setLocale(locale: string): Promise<any>
```

## Dates Formatting <a href="#dates-formatting" id="dates-formatting"></a>

Use this method to format date with current locale and pass component name if you want to use date format from component dictionary:

```
  /**
     * <p> Format date according to the current locale.</p>
     * <p> Date format is taken from dictionary.</p>
     */
    formatDate(value: any, componentName?: string): string
```

Service wraps**moment.js**to provide date formatting and, therefore, can take its acronyms as date formats:

```
 /**
     * <p> Format date according to the current locale.</p>
     * <p> Date format corresponds to the moment.js tokens:</p>
     * <p> LT - Time</p>
     * <p> LTS - Time with seconds</p>
     * <p> L - Month numeral, day of month, year</p>
     * <p> l - Month numeral, day of month, year - shortcut</p>
     * <p> LL - Month name, day of month, year</p>
     * <p> ll - Month name, day of month, year - shortcut</p>
     * <p> LLL - Month name, day of month, year, time</p>
     * <p> lll - Month name, day of month, year, time - shortcut</p>
     * <p> LLLL - Month name, day of month, day of week, year, time</p>
     * <p> llll - Month name, day of month, day of week, year, time - shortcut</p>
     */
    formatDateWithTokens(value: any, format: string): string {
        return this.dateFormat.formatDateWithTokens(value, format);
    }
```

By convention, date format should be under "dateFormat" path, for example:

```
{
    "dateFormat": "MM/DD/YYYY"
}
```

## Currency Formatting <a href="#currency-formatting" id="currency-formatting"></a>

Service uses standard JavaScript possibilities to format currency. Method to format it is:

```
   /**
     * <p> Format currency according to the current locale.</p>
     */
    formatCurrency(value: number, componentName?: string): string {
        return this.currencyFormat.formatCurrency(value, this.locale);
    }
```

As for other methods, you can pass component name to take currency format from component dictionary. By convention, currency format should be under "currency" path, for example:

```
{
    "currency": {
        "symbol" : "$",
        "decimal" : ".",
        "thousand": ".",
        "precision": 2,
        "format": "%s%v"
    },
    "dateFormat": "MM/DD/YYYY"
}
```

## Messages Formatting - Dictionary <a href="#messages-formatting---dictionary" id="messages-formatting---dictionary"></a>

Dictionary is an interface to translate messages. These messages are placed in the JSON files named by language, ex: en.json for English language and fr.json for French language. There is a default dictionary placed under**assets/i18n**folder. User can create its own default dictionary and set its URL:

```
  /**
     * <p> Sets new dictionary URL.</p>
     * <p> Dictionary files must be named according to the locales, ex: en.json, fr.json etc.</p>
     * <p> Therefore, if the URL is "http://my_site/my_dictionary", the system will try to find
     * new dictionaries under "http://my_site/my_dictionary/en.json", "http://my_site/my_dictionary/fr.json" etc.</p>
     */
    setDictionaryURL(path: string): Promise<any> {
        return this.dictionary.setDictionaryURL(path);
    }
```

Every component can use its own dictionary by setting its URL in:

```
 /**
     * <p> Sets new dictionary URL for the particular component.</p>
     * <p> Dictionary files must be named according to the locales, ex: en.json, fr.json etc.</p>
     * <p> Therefore, if the URL is "http://my_site/my_dictionary", the system will try to find
     * new dictionaries under "http://my_site/my_dictionary/en.json", "http://my_site/my_dictionary/fr.json" etc.</p>
     * <p> NOTE: If dictionary for this path and locale is already in memory, then it will NOT be reset.</p>
     */
    setComponentDictionaryURL(path: string, componentName: string): Promise<any> {
        return this.dictionary.setComponentDictionaryURL(path, componentName);
    }
```

User can get translated messages by using this method:

```
 /**
     * <p> Looks for the translated value from the current dictionary.</p>
     */
    lookup(path: string, componentName?: string): any {
        return this.dictionary.lookup(path, this.getLanguageId());
    }
```

When using the particular component dictionary, you should pass component name as a parameter.

## Example <a href="#example" id="example"></a>

The complete example code can be found under Examples/Internationalization of the Cedrus/CodeFusion project.

Important note is that when user changes locale, another dictionary should be put in memory. Therefore, setLocale() method, as well as setDictionaryURL() and setComponentDictionaryURL() methods returns promises to let system wait until new dictionary is downloaded.

### Internationalize Button Component Label <a href="#internationalize-button-component-label" id="internationalize-button-component-label"></a>

This is HTML used to render CfButton component.

```
<cf-button md-raised-button [tooltip]="myTooltip" [settings]="button1"></cf-button>
```

This is the component model and simple label internationalization using the default dictionary:

```
    button1: ButtonModel = {
       label: "",
       color: {
           foreground: "black",
           background: "accent"
       },
       icon: null,
       icon_position:"right"
    };

    ngOnInit() {
        // get localized messages from current dictionary
        this.button1.label = this.i18nService.lookup('customer.form.validate');
    }
```

If user changes locale, for example, by choosing country in drop down list, then in the listener, the messages should be reset from new dictionary:

```
    setLocale(): void {
    this.i18nService.setLocale(this.localeName)
        .then(() => {
            // after resetting locale, we have to reset localized messages from new current dictionary
            this.button1.label = this.i18nService.lookup('customer.form.validate');
        });
    }
```

### Internationalize Business Component <a href="#internationalize-business-component" id="internationalize-business-component"></a>

Lets internationalize the part of the CfWeatherComponent. First, we have to import i18n service and a Subscription class:

```
import { I18NService } from '../../services/i18n-service/i18n.service';
import { Subscription } from 'rxjs/Subscription';
```

Then, we should create a method where we put all our internationalization code. Note, that if we want to use a separate dictionary for this component, we can do it with setComponentDictionaryURL() method:

```
     /**
     * <p> This method internationalizes the component.</p>
     */
    internationalize(locale: string): void {
        if (this.enabledI18N) { // verify if internationalization is enabled
            this.i18nService.setComponentDictionaryURL('/assets/i18n/weather', 'weather')
            .then(() => {
                this.title = this.i18nService.lookupByComponent('weather.title', 'weather');
                this.input.placeholder = this.i18nService.lookupByComponent('weather.placeholder', 'weather');
            });
        }
    }
```

Then, we should call internationalize() method and, if we want the component to change its messages when user changes locale, we should subscribe on the locale changes:

```
onLangChangeSubscription: Subscription;

ngOnInit() {
    // other init code here...

    // internationalize component
    this.internationalize( this.i18nService.getLocale() );

    // re-internationalize component in case of locale change
    this.onLangChangeSubscription = this.i18nService.onLangChange.subscribe(locale => {
        this.internationalize(locale);
    });
}
```

Also, do not forget to unsubscribe when component is destroyed to avoid memory leaks:

```
ngOnDestroy() {
        // prevent memory leak when component destroyed
        this.onLangChangeSubscription.unsubscribe();
}
```

This is CfWeatherComponent component HTML to be rendered:

```
<cf-weather [themeClass]="themeName" [settings]="demoWeather" [enabledI18N]="enabledI18N"></cf-weather>
```

This is the code to use:

```
enabledI18N = true; // this is property to enable component internationalization, comes from CfWeatherComponent

demoWeather = new WeatherComponentModel ({
    defaultCities: [ "Paris", "Beirut", "London", "Dubai" ],
    mode: "card",
    onItemClick: null
});
```

That's it, you should do nothing more, when user changes locale, the component will change its messages accordingly.

## Angular 2 Internationalization Tools <a href="#angular-2-internationalization-tools" id="angular-2-internationalization-tools"></a>

User can always use standard Angular 2 tools, like:

*   DatePipe:

    [https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html](https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html)
*   CurrencyPipe:

    [https://angular.io/docs/ts/latest/api/common/index/CurrencyPipe-pipe.html](https://angular.io/docs/ts/latest/api/common/index/CurrencyPipe-pipe.html)

But they will not react on the fact that user changes the localization dynamically, for example in drop-down list and passes it to i18n service. They will react only on browser settings changes.

But, all methods provided by i18n service will react on dynamic locale changes.
