mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-01-10 04:25:08 +00:00
File based translations - multi language
+ Example in the Mail app + Component/doc page for translations
This commit is contained in:
parent
98e2ff0e1e
commit
9ecd921722
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -268,6 +268,11 @@
|
|||
"integrity": "sha1-w6DFRNYjkqzCgTpCyKDcb1j4aSI=",
|
||||
"dev": true
|
||||
},
|
||||
"@ngx-translate/core": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-8.0.0.tgz",
|
||||
"integrity": "sha1-dR/WtRLYDzp0jS3o38lt/vopr+A="
|
||||
},
|
||||
"@schematics/angular": {
|
||||
"version": "0.0.45",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.0.45.tgz",
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
"@angular/platform-browser": "4.4.6",
|
||||
"@angular/platform-browser-dynamic": "4.4.6",
|
||||
"@angular/router": "4.4.6",
|
||||
"@ngx-translate/core": "8.0.0",
|
||||
"@swimlane/ngx-charts": "6.0.2",
|
||||
"@swimlane/ngx-datatable": "9.3.1",
|
||||
"@swimlane/ngx-dnd": "3.0.0",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { FuseSplashScreenService } from './core/services/splash-screen.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-root',
|
||||
|
@ -8,7 +9,18 @@ import { FuseSplashScreenService } from './core/services/splash-screen.service';
|
|||
})
|
||||
export class AppComponent
|
||||
{
|
||||
constructor(private fuseSplashScreen: FuseSplashScreenService)
|
||||
constructor(
|
||||
private fuseSplashScreen: FuseSplashScreenService,
|
||||
private translate: TranslateService
|
||||
)
|
||||
{
|
||||
// Add languages
|
||||
this.translate.addLangs(['en', 'tr']);
|
||||
|
||||
// Set the default language
|
||||
this.translate.setDefaultLang('en');
|
||||
|
||||
// Use a language
|
||||
this.translate.use('en');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import { ComponentsThirdPartyModule } from './main/content/components-third-part
|
|||
import { ServicesModule } from './main/content/services/services.module';
|
||||
import { FuseAngularMaterialModule } from './main/content/components/angular-material/angular-material.module';
|
||||
import { MarkdownModule } from 'angular2-markdown';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
const appRoutes: Routes = [
|
||||
{
|
||||
|
@ -69,6 +70,7 @@ const appRoutes: Routes = [
|
|||
RouterModule.forRoot(appRoutes),
|
||||
SharedModule,
|
||||
MarkdownModule.forRoot(),
|
||||
TranslateModule.forRoot(),
|
||||
|
||||
InMemoryWebApiModule.forRoot(FuseFakeDbService, {
|
||||
delay : 0,
|
||||
|
|
|
@ -19,8 +19,10 @@ import { FuseHljsComponent } from '../components/hljs/hljs.component';
|
|||
import { FusePerfectScrollbarDirective } from '../directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
|
||||
import { FuseIfOnDomDirective } from '../directives/fuse-if-on-dom/fuse-if-on-dom.directive';
|
||||
import { FuseMaterialColorPickerComponent } from '../components/material-color-picker/material-color-picker.component';
|
||||
import { FuseTranslationLoaderService } from '../services/translation-loader.service';
|
||||
import { CookieService } from 'ngx-cookie-service';
|
||||
import { MarkdownModule } from 'angular2-markdown';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
@NgModule({
|
||||
declarations : [
|
||||
|
@ -62,7 +64,8 @@ import { MarkdownModule } from 'angular2-markdown';
|
|||
NgxDatatableModule,
|
||||
FuseIfOnDomDirective,
|
||||
FuseMaterialColorPickerComponent,
|
||||
MarkdownModule
|
||||
MarkdownModule,
|
||||
TranslateModule
|
||||
],
|
||||
entryComponents: [
|
||||
FuseConfirmDialogComponent
|
||||
|
@ -71,7 +74,8 @@ import { MarkdownModule } from 'angular2-markdown';
|
|||
CookieService,
|
||||
FuseMatchMedia,
|
||||
FuseNavbarVerticalService,
|
||||
FuseMatSidenavHelperService
|
||||
FuseMatSidenavHelperService,
|
||||
FuseTranslationLoaderService
|
||||
]
|
||||
})
|
||||
|
||||
|
|
27
src/app/core/services/translation-loader.service.ts
Normal file
27
src/app/core/services/translation-loader.service.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
export interface Locale
|
||||
{
|
||||
lang: string;
|
||||
data: Object;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class FuseTranslationLoaderService
|
||||
{
|
||||
constructor(private translate: TranslateService)
|
||||
{
|
||||
}
|
||||
|
||||
public loadTranslations(...args: Locale[]): void
|
||||
{
|
||||
const locales = [...args];
|
||||
|
||||
locales.forEach((locale) => {
|
||||
// use setTranslation() with the third argument set to true
|
||||
// to append translations instead of replacing them
|
||||
this.translate.setTranslation(locale.lang, locale.data, true);
|
||||
});
|
||||
}
|
||||
}
|
14
src/app/main/content/apps/mail/i18n/en.ts
Normal file
14
src/app/main/content/apps/mail/i18n/en.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
export const locale = {
|
||||
lang: 'en',
|
||||
data: {
|
||||
'MAIL': {
|
||||
'COMPOSE' : 'COMPOSE',
|
||||
'FOLDERS' : 'FOLDERS',
|
||||
'FILTERS' : 'FILTERS',
|
||||
'LABELS' : 'LABELS',
|
||||
'NO_MESSAGES' : 'There are no messages!',
|
||||
'SELECT_A_MESSAGE_TO_READ': 'Select a message to read',
|
||||
'SEARCH_PLACEHOLDER': 'Search for an e-mail or contact'
|
||||
}
|
||||
}
|
||||
};
|
14
src/app/main/content/apps/mail/i18n/tr.ts
Normal file
14
src/app/main/content/apps/mail/i18n/tr.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
export const locale = {
|
||||
lang: 'tr',
|
||||
data: {
|
||||
'MAIL': {
|
||||
'COMPOSE' : 'YENİ E-POSTA',
|
||||
'FOLDERS' : 'KLASÖRLER',
|
||||
'FILTERS' : 'FİLTRELER',
|
||||
'LABELS' : 'ETİKETLER',
|
||||
'NO_MESSAGES' : 'Mesajiniz bulunmamakta!',
|
||||
'SELECT_A_MESSAGE_TO_READ': 'Okumak için bir mesaj seçin',
|
||||
'SEARCH_PLACEHOLDER' : 'E-mail yada bir kişi arayın'
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,6 +1,10 @@
|
|||
<div *ngIf="!mail" fxLayout="column" fxLayoutAlign="center center" fxFlex>
|
||||
<mat-icon class="s-128 mb-16 select-message-icon" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'300ms',scale:'0.2'}}">email</mat-icon>
|
||||
<span class="select-message-text hint-text" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'400ms'}}">Select a message to read</span>
|
||||
<mat-icon class="s-128 mb-16 select-message-icon" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'300ms',scale:'0.2'}}">
|
||||
email
|
||||
</mat-icon>
|
||||
<span class="select-message-text hint-text" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'400ms'}}">
|
||||
<span>{{ 'MAIL.SELECT_A_MESSAGE_TO_READ' | translate }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="mail">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div *ngIf="mails.length === 0" fxLayout="column" fxLayoutAlign="center center" fxFlexFill>
|
||||
<span class="no-messages-text hint-text">There are no messages!</span>
|
||||
<span class="no-messages-text hint-text">{{ 'MAIL.NO_MESSAGES' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="mail-list" *fuseIfOnDom [@animateStagger]="{value:'50'}">
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<div class="search mat-white-bg" flex fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon>search</mat-icon>
|
||||
<input [formControl]="searchInput" placeholder="Search for an e-mail or contact" fxFlex>
|
||||
<input [formControl]="searchInput" [placeholder]="'MAIL.SEARCH_PLACEHOLDER' | translate" fxFlex>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ import { MailService } from './mail.service';
|
|||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { Mail } from './mail.model';
|
||||
import { FuseTranslationLoaderService } from '../../../../core/services/translation-loader.service';
|
||||
import { locale as english } from './i18n/en';
|
||||
import { locale as turkish } from './i18n/tr';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-mail',
|
||||
|
@ -25,9 +28,13 @@ export class FuseMailComponent implements OnInit, OnDestroy
|
|||
onLabelsChanged: Subscription;
|
||||
onCurrentMailChanged: Subscription;
|
||||
|
||||
constructor(private mailService: MailService)
|
||||
constructor(
|
||||
private mailService: MailService,
|
||||
private translationLoader: FuseTranslationLoaderService
|
||||
)
|
||||
{
|
||||
this.searchInput = new FormControl('');
|
||||
this.translationLoader.loadTranslations(english, turkish);
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
|
|
|
@ -30,13 +30,13 @@
|
|||
class="mat-accent compose-dialog-button"
|
||||
(click)="composeDialog()"
|
||||
aria-label="Compose">
|
||||
COMPOSE
|
||||
{{ 'MAIL.COMPOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="nav">
|
||||
|
||||
<div class="nav-subheader">FOLDERS</div>
|
||||
<div class="nav-subheader">{{ 'MAIL.FOLDERS' | translate }}</div>
|
||||
|
||||
<div class="nav-item" *ngFor="let folder of folders">
|
||||
<a class="nav-link" matRipple [routerLink]="'/apps/mail/' + folder.handle" routerLinkActive="active">
|
||||
|
@ -45,7 +45,7 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-subheader">FILTERS</div>
|
||||
<div class="nav-subheader">{{ 'MAIL.FILTERS' | translate }}</div>
|
||||
|
||||
<div class="nav-item" *ngFor="let filter of filters">
|
||||
<a class="nav-link" matRipple [routerLink]="'/apps/mail/filter/' + filter.handle" routerLinkActive="active">
|
||||
|
@ -54,7 +54,7 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-subheader">LABELS</div>
|
||||
<div class="nav-subheader">{{ 'MAIL.LABELS' | translate }}</div>
|
||||
|
||||
<div class="nav-item" *ngFor="let label of labels">
|
||||
<a class="nav-link" matRipple [routerLink]="'/apps/mail/label/' + label.handle" routerLinkActive="active">
|
||||
|
|
|
@ -4,6 +4,7 @@ import { RouterModule } from '@angular/router';
|
|||
import { FuseCountdownDocsComponent } from './countdown/countdown.component';
|
||||
import { FuseHljsDocsComponent } from './hljs/hljs.component';
|
||||
import { FuseMaterialColorPickerDocsComponent } from './material-color-picker/material-color-picker.component';
|
||||
import { FuseMultiLanguageDocsComponent } from './multi-language/multi-language.component';
|
||||
import { FuseNavigationDocsComponent } from './navigation/navigation.component';
|
||||
import { FuseShortcutsDocsComponent } from './shortcuts/shortcuts.component';
|
||||
import { FuseSearchBarDocsComponent } from 'app/main/content/components/search-bar/search-bar.component';
|
||||
|
@ -23,6 +24,10 @@ const routes = [
|
|||
path : 'components/material-color-picker',
|
||||
component: FuseMaterialColorPickerDocsComponent
|
||||
},
|
||||
{
|
||||
path : 'components/multi-language',
|
||||
component: FuseMultiLanguageDocsComponent
|
||||
},
|
||||
{
|
||||
path : 'components/navigation',
|
||||
component: FuseNavigationDocsComponent
|
||||
|
@ -51,6 +56,7 @@ const routes = [
|
|||
FuseCountdownDocsComponent,
|
||||
FuseHljsDocsComponent,
|
||||
FuseMaterialColorPickerDocsComponent,
|
||||
FuseMultiLanguageDocsComponent,
|
||||
FuseNavigationDocsComponent,
|
||||
FuseSearchBarDocsComponent,
|
||||
FuseShortcutsDocsComponent,
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
<div id="multi-language" class="page-layout simple fullwidth" fusePerfectScrollbar>
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header mat-accent-bg p-24 h-160" fxLayout="row" fxLayoutAlign="start center">
|
||||
<div fxLayout="column" fxLayoutAlign="center start">
|
||||
<div class="black-fg" fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="secondary-text s-16">home</mat-icon>
|
||||
<mat-icon class="secondary-text s-16">chevron_right</mat-icon>
|
||||
<span class="secondary-text">Components</span>
|
||||
</div>
|
||||
<div class="h2 mt-16">Multi Language</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="content p-24">
|
||||
|
||||
<p>
|
||||
Fuse uses <a class="link" href="https://github.com/ngx-translate/core" target="_blank">ngx-translate</a>
|
||||
module and supports multiple languages and translations.
|
||||
</p>
|
||||
|
||||
<p class="warning-box">
|
||||
Since not everybody need multi-language setup for their apps, we decided NOT to put translations everywhere.
|
||||
If you want to see the translations in action, visit <a class="link" [routerLink]="'/apps/mail'">
|
||||
Mail</a> app and then change the language from the <b>Toolbar.</b>
|
||||
<br><br>
|
||||
Mail app is the only app that has translations for demonstration purposes. You can look at its source code
|
||||
to see the usage.
|
||||
</p>
|
||||
|
||||
<div class="my-48">
|
||||
<h2>Usage</h2>
|
||||
<p>In order to use the translations, create your translation file within the module you want to use
|
||||
the translations. For example, for the Mail app, create <code>i18n/en.ts</code> file inside the
|
||||
<code>apps/mail</code> folder.
|
||||
</p>
|
||||
<p>
|
||||
The structure of the translation file is important and it must define the language id along with the
|
||||
translation data:
|
||||
</p>
|
||||
|
||||
<p class="mat-grey-200-bg py-8">
|
||||
<fuse-hljs lang="ts" class="source-code">
|
||||
<textarea #source hidden="hidden">
|
||||
// i18n/en.ts
|
||||
export const locale = {
|
||||
lang: 'en',
|
||||
data: {
|
||||
'MAIL': {
|
||||
'COMPOSE': 'COMPOSE'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// i18n/tr.ts
|
||||
export const locale = {
|
||||
lang: 'en',
|
||||
data: {
|
||||
'MAIL': {
|
||||
'COMPOSE': 'YENİ E-POSTA'
|
||||
}
|
||||
}
|
||||
};
|
||||
</textarea>
|
||||
</fuse-hljs>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="my-48">
|
||||
<p>
|
||||
After you create your translation files, open the <code>*.component.ts</code> file for the module you
|
||||
want to have translations, and register your translation file. For this example, we will use the
|
||||
<code>mail.component.ts</code> file:
|
||||
</p>
|
||||
|
||||
<p class="mat-grey-200-bg py-8">
|
||||
<fuse-hljs lang="ts" class="source-code">
|
||||
<textarea #source hidden="hidden">
|
||||
// Your imports
|
||||
import { ... } from '..';
|
||||
|
||||
// Import the locale files
|
||||
import { locale as english } from './i18n/en';
|
||||
import { locale as turkish } from './i18n/tr';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-mail',
|
||||
templateUrl: './mail.component.html',
|
||||
styleUrls : ['./mail.component.scss']
|
||||
})
|
||||
export class FuseMailComponent
|
||||
{
|
||||
constructor(private translationLoader: FuseTranslationLoaderService)
|
||||
{
|
||||
this.translationLoader.loadTranslations(english, turkish);
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
</textarea>
|
||||
</fuse-hljs>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="my-48">
|
||||
<h2>Changing the language</h2>
|
||||
<p class="py-8">
|
||||
Changing the current language can happen instantly. Simply call the <code>use</code> method from the
|
||||
translate service:
|
||||
</p>
|
||||
<p class="mat-grey-200-bg py-8">
|
||||
<fuse-hljs lang="ts" class="source-code">
|
||||
<textarea #source hidden="hidden">
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
constructor(private translate: TranslateService) {}
|
||||
|
||||
setLanguage()
|
||||
{
|
||||
// Use the selected language for translations
|
||||
this.translate.use('tr');
|
||||
}
|
||||
</textarea>
|
||||
</fuse-hljs>
|
||||
</p>
|
||||
<p>
|
||||
More detailed usage of the translation service can be found in the <code>toolbar.component.ts</code>
|
||||
file.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
:host {
|
||||
|
||||
.content{
|
||||
max-width: 1100px;
|
||||
|
||||
.warning-box{
|
||||
background: #FFFDE7;
|
||||
border: 1px solid #FFC107;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-multi-language-docs',
|
||||
templateUrl: './multi-language.component.html',
|
||||
styleUrls : ['./multi-language.component.scss']
|
||||
})
|
||||
export class FuseMultiLanguageDocsComponent
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -71,7 +71,7 @@
|
|||
</button>
|
||||
|
||||
<mat-menu #languageMenu="matMenu">
|
||||
<button mat-menu-item *ngFor="let lang of languages" (click)="selectedLanguage = lang">
|
||||
<button mat-menu-item *ngFor="let lang of languages" (click)="setLanguage(lang)">
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
<img class="flag mr-16" [src]="'assets/images/flags/'+lang.flag+'.png'">
|
||||
<span class="iso">{{lang.title}}</span>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { NavigationEnd, NavigationStart, Router } from '@angular/router';
|
||||
import { FuseConfigService } from '../../core/services/config.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-toolbar',
|
||||
|
@ -18,7 +19,8 @@ export class FuseToolbarComponent
|
|||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private fuseConfig: FuseConfigService
|
||||
private fuseConfig: FuseConfigService,
|
||||
private translate: TranslateService
|
||||
)
|
||||
{
|
||||
this.userStatusOptions = [
|
||||
|
@ -55,11 +57,6 @@ export class FuseToolbarComponent
|
|||
'title': 'English',
|
||||
'flag' : 'us'
|
||||
},
|
||||
{
|
||||
'id' : 'es',
|
||||
'title': 'Spanish',
|
||||
'flag' : 'es'
|
||||
},
|
||||
{
|
||||
'id' : 'tr',
|
||||
'title': 'Turkish',
|
||||
|
@ -92,4 +89,13 @@ export class FuseToolbarComponent
|
|||
// Do your search here...
|
||||
console.log(value);
|
||||
}
|
||||
|
||||
setLanguage(lang)
|
||||
{
|
||||
// Set the selected language for toolbar
|
||||
this.selectedLanguage = lang;
|
||||
|
||||
// Use the selected language for translations
|
||||
this.translate.use(lang.id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -725,6 +725,13 @@ export class NavigationModel
|
|||
'icon' : 'settings_input_component',
|
||||
'url' : '/components/material-color-picker'
|
||||
},
|
||||
{
|
||||
'id' : 'multi-language',
|
||||
'title': 'Multi Language',
|
||||
'type' : 'item',
|
||||
'icon' : 'settings_input_component',
|
||||
'url' : '/components/multi-language'
|
||||
},
|
||||
{
|
||||
'id' : 'navigation',
|
||||
'title': 'Navigation',
|
||||
|
|
Loading…
Reference in New Issue
Block a user