15

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?

Bogac
  • 3,596
  • 6
  • 35
  • 58
  • 1
    See https://github.com/Greentube/localize-router and https://github.com/ngx-i18n-router/core , as suggested here https://github.com/ngx-translate/core/issues/178 . – Estus Flask May 15 '17 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. – Bogac May 16 '17 at 08:58
  • Do you build a dedicated app for each language or how do you support multiple locales? – PeterFromCologne Jun 10 '17 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](https://github.com/martinroob/ngx-i18nsupport/wiki/Tutorial-for-using-xliffmerge-with-angular-cli). 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. – Bogac Jun 11 '17 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. – Bogac Jun 11 '17 at 11:52

3 Answers3

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.

Miroslav Jonas
  • 5,407
  • 1
  • 27
  • 41
Bogac
  • 3,596
  • 6
  • 35
  • 58
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.

PeterFromCologne
  • 10,213
  • 9
  • 36
  • 46
  • 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. – Bogac Jun 12 '17 at 07:33
  • Ahh. now I see. Thanks for commenting. – PeterFromCologne Jun 12 '17 at 10:43
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 {}
Jason Glez
  • 1,254
  • 1
  • 16
  • 16