16

I'm doing an i18n Angular app, so far it works great.

However I have same route strings for different languages, which isn't best for SEO.

Is it possible to have 'path' properties of Routes array be different for each language?

Ex:

const appRoutesEN: Routes = [
  { path: 'crisis-center', component: CrisisListComponent },
  { path: 'hero/:id',      component: HeroDetailComponent },
  {
    path: 'heroes',
    component: HeroListComponent,
    data: { title: 'Heroes List' }
  },
  { path: '**', component: PageNotFoundComponent }
];

Is it possible to define also a appRoutesFR: Routes if yes how I can use it? Shall I inject LOCALE_ID to routing module? If so how?

5
  • 1
    See github.com/Greentube/localize-router and github.com/ngx-i18n-router/core , as suggested here github.com/ngx-translate/core/issues/178 . Commented May 15, 2017 at 15:06
  • @estus while they look nice, I'm using Angular's default i18n, not ngx-translate and I'd like to see some solution there instead of having yet another dependency. Commented May 16, 2017 at 8:58
  • Do you build a dedicated app for each language or how do you support multiple locales? Commented Jun 10, 2017 at 16:14
  • Hi @PeterFromCologne App was already crated from ground up thinking i18n in mind, from creation of database objects etc, using i18n tools/directives provided by Angular team. ngx-i18nsupport package is big help to streamline the process. More on this here. Only thing those tools can't help is route strings. Route variables are not a problem, if you've been creating your app i18n way, route variables can be translated versions but not route strings. Commented Jun 11, 2017 at 11:41
  • @PeterFromCologne as you'll see in that link, you have one code base, but several npm scripts to extract strings to be translated and then build/serve in a selected language. Since route strings are only part that can't be in this streamline process, I've created all route definitions in all available languages and before I build in desired language, I comment out that those needed and comment ones not to be used. This is the ugly part and that is because I have lazy loaded modules with child routes. If I didn't I could use @estus' recommended package. If you need more info contact me. Commented Jun 11, 2017 at 11:52

4 Answers 4

4

If you need different routing per language as you describe in your comment you could have a dedicated routing module for each individual language. Then define in the angular-cli.json for each language a dedicated app with it's own main.ts and it's own AppModule, pulling in only the routing module required for the particular language.

  "apps": [
   {
      "root": "src",
      "name": "yourapp_FR",
...
      "main": "./app/yourapp_FR/main.ts",
...   
    },
   {
      "root": "src",
      "name": "yourapp_DE",
...
      "main": "./app/yourapp_DE/main.ts",
...   
    }
    ]

You then build for each language the app like this:

ng build --app yourapp_FR --i18n-file src/i18n/messages.fr.xlf --locale fr --i18n-format xlf --aot

This way you set it up once and can build each time without commenting out anything. I do not have the full context. You say having routes per language is better for SEO. I do not understand this, but if you say so, OK. However I would not like dedicated routing for each language. This means a lot of redundancy and more maintenance.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow, seems very doable and logical. Will test it soon. I can bring for example product name (or news title, whatever) as a route variable in selected language, which is better for SEO but in front you see products or news..etc. Which is not ideal. Not sure "how much" that affects SEO, I'd rather prefer it in selected language.
Ahh. now I see. Thanks for commenting.
4

For the moment there seems to be no easy solution for this. I'll update if I find one.

Angular i18n people are working to integrate code level internationalization, maybe then.

Best solution I can come up with is to change routing module(s) in your code and routerLink attributes in templates and all links in other parts of your code for each language, then build your app for each language separately.

Not ideal at all.

UPDATE

As recommended by @estus, I've tried out Greentube/localize-router.

I wasn't happy to install dependencies like @ngx-translate/core and @ngx-translate/http-loader since I'm using Angular i18n implementation/tools and not ngx-translate.

It works till it hits a lazy-loaded module with child routes.

So if you don't have any lazy loaded module with children, localize-router is the way to go.

UPDATE

Lazy loaded modules are now supported in the latest version of localize-router.

Angular i18n will be supported once the programatic translations arrive.

Comments

2

You can use @angular/localize by setting it up following the official documentation. If you have the proper setup, you can use $localize in your routes definition (no other routes definition needed):

const appRoutes: Routes = [
  { path: $localize`crisis-center`, component: CrisisListComponent },
  { path: $localize`hero/:id`,      component: HeroDetailComponent },
  {
    path: $localize`heroes`,
    component: HeroListComponent,
    data: { title: $localize`Heroes List` }
  },
  { path: '**', component: PageNotFoundComponent }
];

By generating a translation file, you will get the an XLF formatted file with your original texts as sources.

ng extract-i18n --output-file messages.fr.xlf

Adding targets to them will inject translations on changing your locale.

<trans-unit id="****" datatype="html">
    <source>crisis-center</source>
    <target>centre-de-crise</target>
    ...
</trans-unit>

You can change your locale on build level in angular.json to test if it works as expected.

"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:application",
    "options": {
      "localize": ["fr-FR"],
      ...
    }
  }
}

Comments

0

If you are already using something like @ngx-translate/core then you can create your own mapping instead of adding more external libraries.

Example:

function generateI18nRoutes(
    elements: Array<{ i18nPaths: string[]; component: any; data: object; canActivate?: 
[] }>
): Routes {
    return elements.reduce(
        (accumulator, currentValue) => [
            ...accumulator,
            ...currentValue.i18nPaths.map((path: string) => ({
                path,
                component: currentValue.component,
                data: currentValue.data,
                canActivate: currentValue.canActivate
            }))
        ],
        []
    );
}

And then use it like:

const routes: Routes = [
    {
        path: "admin",
        component: AdminLayoutComponent,
        canActivate: [AdminAuthGuard],
        children: generateI18nRoutes([{ i18nPaths: [""], component: HomeComponent, data: { title: "ADMIN" } }])
    },
    {
        path: "",
        component: GeneralLayoutComponent,
        children: generateI18nRoutes([
            { i18nPaths: [""], component: HomeComponent, data: { title: "HOME" } },
            {
                i18nPaths: ["sign-in", "iniciar-sesión", "iniciar-sessão"],
                component: SignInComponent,
                data: { title: "SIGN_IN" }
            }
        ])
    },
    {
        path: "**",
        component: PageNotFoundComponent,
        data: { title: "PAGE_NOT_FOUND" }
    }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule {}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.