import { Component, OnInit } from '@angular/core';
import { TranslateService } from './translate';

@Component({
    moduleId: module.id,
    selector: 'app-root',
    templateUrl: 'app.component.html',
})
export class AppComponent implements OnInit {
  
    public translatedText: string;
    public supportedLanguages: any[];
  
    constructor(private _translate: TranslateService) { }

    ngOnInit() {
      // standing data
      this.supportedLangs = [
        { display: 'English', value: 'en' },
        { display: 'Español', value: 'es' },
        { display: '华语', value: 'zh' },
      ];
      
      this.subscribeToLangChanged();
      
      // set language
      this._translate.setDefaultLang('en');
      this._translate.enableFallback(true);
      this.selectLang('es');
        
    }
    
    isCurrentLang(lang: string) {
      return lang === this._translate.currentLang;
    }
    
    selectLang(lang: string) {
      // set default;
      this._translate.use(lang);
      // this.refreshText(); // remove
    }
    
    refreshText() {
      this.translatedText = this._translate.instant('hello world');
    }
    
    subscribeToLangChanged() {
      return this._translate.onLangChanged.subscribe(x => this.refreshText());
    }
}
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }   from './app.component';
import { TRANSLATION_PROVIDERS, TranslatePipe, TranslateService }   from './translate';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, TranslatePipe ], // Inject Translate Pipe here
  bootstrap:    [ AppComponent ],
  providers:    [ TRANSLATION_PROVIDERS, TranslateService ]
})

export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

<!DOCTYPE html>
<html>
  <head>
    <title>Handle different form controls</title>
    <!--optional bootstrap for faster styling-->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- 1. Load libraries -->
     <!-- Polyfill(s) for older browsers -->
    <script src="https://unpkg.com/core-js/client/shim.min.js"></script>

    <script src="https://unpkg.com/zone.js@0.6.23?main=browser"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.3"></script>
    <script src="https://unpkg.com/systemjs@0.19.27/dist/system.src.js"></script>

    <!-- 2. Configure SystemJS -->
    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>

  <!-- 3. Display the application -->
  <body>
    <app-root>Loading...</app-root>
  </body>
</html>

/**
 * PLUNKER VERSION
 * (based on systemjs.config.js in angular.io)
 * System configuration for Angular 2 samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
    transpiler: 'ts',
    typescriptOptions: {
      tsconfig: true
    },
    meta: {
      'typescript': {
        "exports": "ts"
      }
    },
    paths: {
      // paths serve as alias
      'npm:': 'https://unpkg.com/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: 'app',

      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
      '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',

      // other libraries
      'rxjs':                       'npm:rxjs',
      'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
      'ts':                         'npm:plugin-typescript@4.0.10/lib/plugin.js',
      'typescript':                 'npm:typescript@2.0.2/lib/typescript.js',

    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.ts',
        defaultExtension: 'ts'
      },
      'app/translate': {
        main: 'index.ts', 
        defaultExtension: 'ts'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular2-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}
export * from './translate.service';
export * from './translations';
export * from './translate.pipe';
<div class="container">
  <h4>Translate: Hello World</h4>
  <div class="btn-group">
    <button *ngFor="let lang of supportedLangs"
      (click)="selectLang(lang.value)"
      class="btn btn-default" [class.btn-primary]="isCurrentLang(lang.value)">
      {{ lang.display }}
    </button>
  </div>
  <div style="margin-top: 20px">
    <p>
      Translate With Pipe: <strong>{{ 'hello world' | translate }}</strong>
    </p>
    <p>
      Translate with Service: <strong>{{ translatedText }}</strong>
    </p>
    <p>
      Translate <strong class="text-muted">Hello, %0 %1!</strong>:
      <br>
      <strong>{{ 'hello greet' | translate:['Jane', 'Doe'] }}</strong>
    </p>
    <p>
      Translate <strong class="text-muted">Well done %0</strong>: 
      <br>
      <strong>{{ 'well done' | translate:'John' }}</strong>
    </p>
    <p>
      Translate <strong class="text-muted">Good bye (fallback)</strong>: 
      <br>
      <strong>{{ 'good bye' | translate }}</strong>
    </p>
  </div>
</div>
// lang-en.ts

export const LANG_EN_NAME = 'en';

export const LANG_EN_TRANS = {
    'hello world': 'hello world',
    'hello greet': 'Hello, %0 %1!',
    'well done': 'Well done %0',
    'good bye': 'bye bye',
};
// lang-es.ts

export const LANG_ES_NAME = 'es';

export const LANG_ES_TRANS = {
    'hello world': 'hola mundo',
    'hello greet': 'Hola, %0 %1!',
    'well done': '%0 bien hecho',
};
// lang-zh.ts

export const LANG_ZH_NAME = 'zh';

export const LANG_ZH_TRANS = {
    'hello world': '你好,世界',
    'hello greet': '你好, %0 %1!',
    'well done': '干得好, %0',
};
// app/translate/translate.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '../translate'; // our translate service

@Pipe({
    name: 'translate',
    pure: false // impure pipe, update value when we change language
})

export class TranslatePipe implements PipeTransform {

	constructor(private _translate: TranslateService) { }

	transform(value: string, args: string | string[]): any {
		if (!value) return;
		
		return this._translate.instant(value, args);
	}
}
import { Injectable, Inject, EventEmitter } from '@angular/core';
import { TRANSLATIONS } from './translations'; // import our opaque token

@Injectable()
export class TranslateService {
	private _currentLang: string;
	private PLACEHOLDER = '%';
	private _defaultLang: string;
  private _currentLang: string;
  private _fallback: boolean;
	
	public onLangChanged: EventEmitter<string> = new EventEmitter<string>();
	
	public get currentLang() {
    return this._currentLang || this._defaultLang;
  }

  public setDefaultLang(lang: string) {
    this._defaultLang = lang;
  }

  public enableFallback(enable: boolean) {
    this._fallback = enable;
  }

  // inject our translations
	constructor(@Inject(TRANSLATIONS) private _translations: any) {
	}

	public use(lang: string): void {
		// set current language
		this._currentLang = lang;
		this.onLangChanged.emit(lang);
	}

	private translate(key: string): string {
    let translation = key;
    
    // found in current language
    if (this._translations[this.currentLang] && this._translations[this.currentLang][key]) {
      return this._translations[this.currentLang][key];
      }
      
    // fallback disabled
    if (!this._fallback) { 
      return translation;
    }
    
    // found in default language
    if (this._translations[this._defaultLang] && this._translations[this._defaultLang][key]) {
      return this._translations[this._defaultLang][key];
    }
    
    // not found
    return translation;
  }
	
  public replace(word: string = '', words: string | string[] = '') {
    let translation: string = word;

    const values: string[] = [].concat(words);
      values.forEach((e, i) => {
        translation = translation.replace(this.PLACEHOLDER.concat(<any>i), e);
      });

    return translation;
  }

	public instant(key: string, words?: string | string[]) {
		// public perform translation
		const translation: string = this.translate(key);

    if (!words) return translation;
    return this.replace(translation, words);
	}
}
// app/translate/translation.ts

import { OpaqueToken } from '@angular/core';

// import translations
import { LANG_EN_NAME, LANG_EN_TRANS } from './lang-en';
import { LANG_ES_NAME, LANG_ES_TRANS } from './lang-es';
import { LANG_ZH_NAME, LANG_ZH_TRANS } from './lang-zh';

// translation token
export const TRANSLATIONS = new OpaqueToken('translations');

// all traslations
const dictionary = {
	[LANG_EN_NAME]: LANG_EN_TRANS,
	[LANG_ES_NAME]: LANG_ES_TRANS,
	[LANG_ZH_NAME]: LANG_ZH_TRANS,
};

// providers
export const TRANSLATION_PROVIDERS = [
	{ provide: TRANSLATIONS, useValue: dictionary },
];