@ngx-i18n-router/core v5.0.0
@ngx-i18n-router/core

Route internationalization utility for Angular
Please support this project by simply putting a Github star. Share this library with friends on Twitter and everywhere else you can.
@ngx-i18n-router/core translates each path and redirectTo property of routes, during Angular app initialization
and also during runtime - when the working language gets changed.
NOTICE
This 5.x.x branch is intented to work with
@angular v5.x.x. If you're developing on a later release of Angular thanv5.x.x, then you should probably choose the appropriate version of this library by visiting the master branch.Also, please check the Workaround for '@ngtools/webpack' section if your app depends on @angular/cli or
@ngtools/webpackfor AoT compilation.
Table of contents:
- Prerequisites
- Getting started
- Settings
- Setting up
I18NRouterModuleto useI18NRouterStaticLoader- Setting upI18NRouterModuleto useI18NRouterHttpLoader- Setting upI18NRouterModuleto useI18NRouterConfigLoader- Translations object - Change language (runtime)
- Pipe
- Workaround for '@ngtools/webpack'
- Credits
- License
Prerequisites
This library depends on Angular v4.0.0. Older versions contain outdated dependencies, might produce errors.
Also, please ensure that you are using Typescript v2.5.3 or higher.
Getting started
Installation
You can install @ngx-i18n-router/core using npm
npm install @ngx-i18n-router/core --saveExamples
- ng-seed/universal and fulls1z3/example-app are officially maintained projects, showcasing common patterns and best
practices for
@ngx-i18n-router/core.
Related packages
The following packages may be used in conjunction with @ngx-i18n-router/core
Recommended packages
The following package(s) have no dependency for @ngx-i18n-router/core, however may provide supplementary/shorthand
functionality:
- @ngx-config/core: provides route translations from the application settings loaded during application initialization
- @ngx-cache/core: provides caching features to retrieve the route translations using
non-static loaders(http,fs, etc.)
Adding @ngx-i18n-router/core to your project (SystemJS)
Add map for @ngx-i18n-router/core in your systemjs.config
'@ngx-i18n-router/core': 'node_modules/@ngx-i18n-router/core/bundles/core.umd.min.js'### Route configuration
In order to use @ngx-i18n-router/core properly, you should have more or less a similar route structure as follows:
app.routes.ts
export const routes: Routes = [
{
path: '',
children: [
{
path: '',
loadChildren: './+home/home.module#HomeModule'
},
{
path: 'about',
loadChildren: './+about/about.module#AboutModule'
},
...
],
data: {
i18n: {
isRoot: true
}
}
},
{
path: 'change-language/:languageCode',
component: ChangeLanguageComponent
},
...
{
path: '**',
redirectTo: '',
pathMatch: 'full'
}
];I18N-ROOT
The route configuration above shows that, one of the routes contains i18n property inside the data property.
When its value is set to true, @ngx-i18n-router/core will prepend descendants of this route with the 2-letter
language code (ex: en/fr/de/nl/tr).
We call this route, with
dataproperty containingi18n\isRootset totrue,I18N-ROOTof Angular application.
(English)
http://mysite.com/about -> http://mysite.com/en/aboutNote: There must be a maximum of one i18n\isRoot in the route configuration, and (if exists) this must be placed
inside the data property of any of the first-level routes.
Note: It is always a good practice to have exactly one route (and component) in the Home feature module, with
a path set to '' (see home.routes.ts in this readme).
Non-prefixed routes
Routes outside I18N-ROOT scope will NOT have this 2-letter language code prefix. It allows the Angular
application to support both prefixed and non-prefixed routes.
(English)
http://mysite.com/about -> http://mysite.com/en/about
http://mysite.com/sitemap
http://mysite.com/adminCatchall route
There must be a catchall route in the route configuration, redirecting to the I18N-ROOT of the app (here, redirects
to ''). The redirectTo property will be reset to the 2-letter language code by @ngx-i18n-router/core.
app.module configuration
Import I18NRouterModule using the mapping '@ngx-i18n-router/core' and append I18NRouterModule.forRoot(routes, {...})
within the imports property of app.module (considering the app.module is the core module in Angular application).
Also, don't forget to provide I18N_ROUTER_PROVIDERS within the providers property of app.module.
Note: I18N_ROUTER_PROVIDERS must be imported in the app.module (instead of in I18NRouterModule), to resolve
the I18NRouterService dependency at the uppermost level (otherwise child modules will have different instances of
I18NRouterService).
app.module.ts
...
import { I18NRouterModule, I18N_ROUTER_PROVIDERS } from '@ngx-i18n-router/core';
...
@NgModule({
declarations: [
AppComponent,
...
],
...
imports: [
RouterModule.forRoot(routes),
I18NRouterModule.forRoot(routes),
...
],
...
providers: [
I18N_ROUTER_PROVIDERS,
...
],
...
bootstrap: [AppComponent]
})Feature modules configuration
Import I18NRouterModule using the mapping '@ngx-i18n-router/core' and append I18NRouterModule.forChild(routes, moduleKey)
within the imports property of the feature module. The moduleKey parameter for the forChild method obviously refers
to the module's root path (in kebab-case).
home.routes.ts
export const routes: Routes = [
{
path: '',
component: HomeComponent
}
];home.module.ts
...
import { I18NRouterModule } from '@ngx-i18n-router/core';
...
@NgModule({
...
imports: [
//RouterModule.forChild(routes),
I18NRouterModule.forChild(routes, 'home'),
...
],
...
})about.routes.ts
export const routes: Routes = [
{
path: '',
component: AboutComponent
},
{
path: 'us/:topicId',
component: AboutUsComponent
},
{
path: 'banana',
component: AboutBananaComponent
},
{
path: 'apple/:fruitId/pear',
component: AboutApplePearComponent
}
];about.module.ts
...
import { I18NRouterModule } from '@ngx-i18n-router/core';
...
@NgModule({
...
imports: [
//RouterModule.forChild(routes),
I18NRouterModule.forChild(routes, 'about'),
...
],
...
})Note: You must comment (or better delete) the line with RouterModule.forChild(routes), in order to get @ngx-i18n-router/core
working. forChild method of I18NRouterModule provides routes for feature modules itself (if imports both RouterModule
and I18NRouterModule, it will cause @ngx-i18n-router/core to malfunction, even crash).
app.component configuration
Import I18NRouterService using the mapping '@ngx-i18n-router/core' and inject it in the constructor of app.component
(considering the app.component is the bootstrap component in Angular application).
Then, invoke the init method to fetch route translations loaded during application initialization and allow the use
of @ngx-i18n-router/core by the Angular app.
Lastly, you need to invoke the changeLanguage method by supplying the 2-letter language code, which translates routes
to the specified language.
app.component.ts
...
import { I18NRouterService } from '@ngx-i18n-router/core';
...
@Component({
...
})
export class AppComponent implements OnInit {
...
constructor(private readonly i18nRouter: I18NRouterService) {
// invoking the `init` method with false won't allow the use of i18n-router,
// would be handy in the case you need to use i18n-router programmatically
i18nRouter.init();
}
...
ngOnInit(): void {
this.i18nRouter.changeLanguage('en');
}
...
}Settings
You can call the forRoot static method using I18NRouterStaticLoader. By default, it is configured to pass the routes
to @ngx-i18n-router/core and have no translations.
You can customize this behavior (and ofc other settings) by supplying route translations to
I18NRouterStaticLoader.
If you provide route translations using a JSON file or an API, you can call the forRoot static method using the I18NRouterHttpLoader.
By default, it is configured to retrieve route translations from the path /routes.json (if not specified).
You can customize this behavior (and ofc other settings) by supplying a file path/api endpoint to I18NRouterHttpLoader.
You can also use the @ngx-i18n-router/config-loader, to reduce the amount of HTTP requests during application
initialization, by including route translations within the application settings - if @ngx-config/core is already
used to retrieve settings by the Angular app.
The following examples show the use of an exported function (instead of an inline function) for AoT compilation.
Setting up I18NRouterModule to use I18NRouterStaticLoader
app.module.ts
...
import { I18NRouterModule, I18NRouterLoader, I18NRouterStaticLoader, I18N_ROUTER_PROVIDERS, RAW_ROUTES } from '@ngx-i18n-router/core';
...
export function i18nRouterFactory(rawRoutes: Routes): I18NRouterLoader {
return new I18NRouterStaticLoader({
routes: rawRoutes,
translations: {
"en": {
"ROOT.ABOUT": "about",
"ROOT.ABOUT.US": "us",
"ROOT.ABOUT.BANANA": "banana",
"ROOT.ABOUT.APPLE": "apple",
"ROOT.ABOUT.APPLE.PEAR": "pear",
"CHANGE_LANGUAGE": "change-language"
},
"tr": {
"ROOT.ABOUT": "hakkinda",
"ROOT.ABOUT.US": "biz",
"ROOT.ABOUT.BANANA": "muz",
"ROOT.ABOUT.APPLE": "elma",
"ROOT.ABOUT.APPLE.PEAR": "armut",
"CHANGE_LANGUAGE": "dil-secimi"
}
}
});
}
...
@NgModule({
declarations: [
AppComponent,
...
],
...
imports: [
RouterModule.forRoot(routes),
I18NRouterModule.forRoot(routes, [
{
provide: I18NRouterLoader,
useFactory: (i18nRouterFactory),
deps: [RAW_ROUTES]
}
]),
...
],
...
providers: [
I18N_ROUTER_PROVIDERS,
...
],
...
bootstrap: [AppComponent]
})I18NRouterStaticLoader has one parameter:
- providedSettings:
I18NRouterSettings: i18n-router settings- routes:
Routes: raw routes - translations:
any: route translations
- routes:
Setting up I18NRouterModule to use I18NRouterHttpLoader
If you provide route translations using a JSON file or an API, you can call the forRoot static method using the I18NRouterHttpLoader.
By default, it is configured to retrieve route translations from the endpoint /routes.json (if not specified).
You can customize this behavior (and ofc other settings) by supplying a api endpoint to
I18NRouterHttpLoader.
You can find detailed information about the usage guidelines for the ConfigHttpLoader here.
Setting up I18NRouterModule to use I18NRouterConfigLoader
I18NRouterConfigLoader provides route translations to @ngx-i18n-router/core using @ngx-config/core.
You can find detailed information about the usage guidelines for the I18NRouterConfigLoader here.
Translations object
The translations object is designed to contain route translations in every language supported by Angular application, in JSON format.
When the changeLanguage method of @ngx-i18n-router/core is invoked, route configuration is reset based on
the supplied translations.
You should use the following data structure while working with the translation object:
- Assume that there're a number of {N} supported languages. The object contains {N} times first-level children, keyed with its 2-letter language code and valued by translations specific to that language.
- Language keys are in lowercase.
ex: Angular app supports en, fr and tr
{
"en": { ... },
"fr": { ... },
"tr": { ... }
}- Routes within the
I18N-ROOTscope must be keyed with theROOTprefix, followed by a dot char., and then the moduleKey (module's root path in kebab-case). - Route keys are followed (if any, after prefixes) by the
pathattribute of routes. - Route keys are in UPPERCASE.
- Dot char
.is used as a separator between prefixes/parts (ex: ROOT.ABOUT).
ex: Angular app supports en and tr
modules:
AboutModule (path: 'about')
components:
AboutComponent (path: '')
routes:
http://mysite.com/about -> http://mysite.com/en/about, http://mysite.com/tr/hakkinda
{
"en": {
"ROOT.ABOUT": "about"
},
"tr": {
"ROOT.ABOUT": "iletisim"
}
}- Routes outside the
I18N-ROOTscope must be keyed with the moduleKey (module's root path in kebab-case).
ex: Angular app supports en and tr
modules:
AboutModule (path: 'about')
SitemapModule (path: 'sitemap')
components:
AboutComponent (path: '')
SitemapComponent (path: '')
routes:
http://mysite.com/about -> http://mysite.com/en/about, http://mysite.com/tr/hakkinda
http://mysite.com/sitemap -> http://mysite.com/sitemap
{
"en": {
"ROOT.ABOUT": "about"
},
"tr": {
"ROOT.ABOUT": "iletisim"
}
}- Underscores
_must be used instead of dashes-in the route keys (using dashes in keys causes errors). They're automatically replaced with dashes-whileI18nRouterServiceis translating the routes.
ex: Angular app supports en and tr
modules:
AboutModule (path: 'about')
SitemapModule (path: 'site-map')
components:
AboutComponent (path: '')
SitemapComponent (path: '')
routes:
http://mysite.com/about -> http://mysite.com/en/about, http://mysite.com/tr/hakkinda
http://mysite.com/site-map -> http://mysite.com/site-map, http://mysite.com/site-haritasi
{
"en": {
"ROOT.ABOUT": "about",
"SITE_MAP": "site-map"
},
"tr": {
"ROOT.ABOUT": "iletisim",
"SITE_MAP": "site-haritasi"
}
}- Route paths are split by slashes
/into string parts. When keying and they're separated by dots.(ex: path: 'goes/to/your-page' -> 'GOES.TO.YOUR_PAGE'). - Route params (followed by colon) are not needed to be included in the translations object (ex: path: goes/to/:id/page -> 'GOES.TO.PAGE')
ex: Angular app supports en and tr
modules:
AboutModule (path: 'about'), ContactModule (path: 'contact'), ProfileComponent (path: 'profile')
SitemapModule (path: 'site-map')
components:
AboutComponent (path: ''), ContactComponent (path: ''), ContactMapComponent (path: 'map'), ProfileComponent (path: 'profile'), ProfileEditComponent (path: 'profile/:id/edit')
SitemapComponent (path: '')
routes:
http://mysite.com/about -> http://mysite.com/en/about, http://mysite.com/tr/hakkinda
http://mysite.com/contact -> http://mysite.com/en/contact, http://mysite.com/tr/iletisim
http://mysite.com/contact/map -> http://mysite.com/en/contact/map, http://mysite.com/tr/iletisim/harita
http://mysite.com/profile -> http://mysite.com/en/profile, http://mysite.com/tr/profil
http://mysite.com/profile/:id/edit -> http://mysite.com/en/profile/:id/edit, http://mysite.com/tr/profil/:id/duzenle
{
"en": {
"ROOT.ABOUT": "about",
"ROOT.CONTACT": "contact",
"ROOT.PROFILE": "profile",
"ROOT.PROFILE.EDIT": "edit",
"SITE_MAP": "site-map"
},
"tr": {
"ROOT.ABOUT": "iletisim",
"ROOT.CONTACT": "hakkimizda",
"ROOT.PROFILE": "profil",
"ROOT.PROFILE.EDIT": "duzenle",
"SITE_MAP": "site-haritasi"
}
}:+1: Hooyah! It was quite a long story, but
@ngx-i18n-router/corewill now translate eachpathandredirectToproperty of routes.
Change language (runtime)
Import I18NRouterService using the mapping '@ngx-i18n-router/core' and inject it in the constructor of change-language.component
(considering the change-language.component changes the language in Angular application).
Then, invoke the changeLanguage method by supplying the 2-letter language code, which translates routes to the destination
language.
...
import { I18NRouterService } from '@ngx-i18n-router/core';
...
@Component({
...
})
export class ChangeLanguageComponent implements OnInit {
...
constructor(private readonly route: ActivatedRoute,
private readonly i18nRouter: I18NRouterService,
private readonly router: Router) { }
...
ngOnInit(): void {
this.route.params.subscribe(params => {
var languageCode = params['languageCode'];
if (languageCode)
// change language
this.i18nRouter.changeLanguage(languageCode);
this.router.navigate(['/']);
});
}
...
}Pipe
I18nRouterPipe is used to prefix and translate routerLink directive's content. Pipe can be appended ONLY
to a single empty string in the routerLink's definition or to an entire array element:
<a [routerLink]="['' | i18nRouter]">Home</a>
<a [routerLink]="['about'] | i18nRouter">About</a>
<a [routerLink]="['about', 'us', 22] | i18nRouter">About us</a>
<a [routerLink]="['about', 'banana'] | i18nRouter">Banana Republic</a>
<a [routerLink]="['about', 'apple', 6, 'pear'] | i18nRouter">(apple || pear)</a>Example for Turkish language and link to 'about':
['about'] | i18nRouter -> '/tr/hakkinda'Workaround for '@ngtools/webpack'
@ngx-i18n-router/core does not work with angular-cli, and giving the following error during AoT compilation:
ERROR in Cannot read property 'loadChildren' of undefined
@ngx-i18n-router/core injects routes with the ROUTES DI token using the useFactory property. However @ngtools/webpack
forces routes to be static, and prevents code splitting (for lazy-loaded modules) by third parties.
This issue is caused by the ngtools_impl located in the package @angular/compiler-cli.
You can track the actual status of this issue at the following URLs:
On the other hand, the ng-router-loader (together with awesome-typescipt-loader) is safe to go with - it compiles without a problem. There's an overhead: you need to manually configure build tools (dev/prod sever, task runners, webpack, etc).
If you really need to stick to angular-cli, you can use the following workaround, by changing the contents of /node_modules/@angular/compiler-cli/src/ngtools_impl.js
as described below:
- Method name:
_collectRoutes - Line number: 139
- Replacement: comment the line containing
return routeList.concat(p.useValue);, and replace with:
if (p.useFactory != null) {
return routeList.concat(p.useFactory);
} else {
return routeList.concat(p.useValue);
}ngtools_impl.js
function _collectRoutes(providers, reflector, ROUTES) {
return providers.reduce(function (routeList, p) {
if (p.provide === ROUTES) {
// return routeList.concat(p.useValue);
if (p.useFactory != null) {
return routeList.concat(p.useFactory);
} else {
return routeList.concat(p.useValue);
}
}
else if (Array.isArray(p)) {
return routeList.concat(_collectRoutes(p, reflector, ROUTES));
}
else {
return routeList;
}
}, []);
}Credits
- localize-router: An implementation of routes localization for Angular 2
License
The MIT License (MIT)
Copyright (c) 2018 Burak Tasci
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago