Localized Routing

This module provides a plugin to handle localized routing linked to the i18n locale so the current route and locale are always in sync. Besides this, it also provides helper functions to generate a localized routing table and to navigate to a localized route.

Dependencies

Installation

createLocalizedRouting

Initialize the localizedRouting plugin using createLocalizedRouting function. Provide the router and i18n instance as parameters. This will setup the required watch and triggers to keep the i18n locale and router in sync.

import { createLocalizedRouting } from "@xerius/codey-core/modules/localized-routing";
import { localizedAppNames } from "./router/routes";

// router and i18 initialized here
// ...

const localizedRouting = createLocalizedRouting(router, i18n, localizedAppNames); // localizedAppNames only for front-office applications
// ...
app.use(localizedRouting);
//...

router setup

In order to have the localized routing working, you need to make some changes to your router setup.

router/routes.ts

Define Localized Application Names

As the application name is part of the url this can also change based on the selected localization. Therefore you need to define the localized application names for every local you support as following:

export const localizedAppNames = {
  "nl-be": "your-app-name-nl-be",
  "fr-be": "your-app-name-fr-be",
};

Define Routes

In the router/routes.ts file you should define your routes as you normally would. In this definition you do not need to take into account the prefix every front-office application has (/:locale/tool/:application-name). So if you have a home page, you can define it as /home instead of /fr-be/tool/my-app/home.

Every route should have a name and component property. The name property is used to generate the localized routes names. This is also internally used to redirect to the correct language.

Additionally you need to add a meta.i18n property to every route that should be localized. In this property you define the path for a specific language.

import type { I18nRouteRecordRaw } from "@xerius/codey-core/modules/localized-routing";

export const routes = [
  {
    path: "home",
    name: "Home",
    meta: {
      i18n: {
        "nl-be": "Thuis",
        "fr-be": "Accueil",
      },
    },
    component: HomeView,
  },
] satisfies I18nRouteRecordRaw[];

router/index.ts

To finish everything off we need to set the routes while creating the router instance. This is done by calling the createLocalizedRoutes function and passing the routes and default options.

import { createRouter, createWebHistory } from "vue-router";
import { generateLocalizedAppRoutes } from "@xerius/codey-core/modules/localized-routing";

import { routes } from "./routes"; // <- your route definition

const router = createRouter({
  history: createWebHistory(),
  routes: generateLocalizedAppRoutes(routes, {
    defaultRouteName: "Home",
    defaultLocale: "nl-be",
    defaultAppName: "starter-front-office",
  }),
});

export default router;

The available options:

PropertyOptionalDescription
defaultRouteNameYes*The route name used for redirection when the / is hit.
defaultLocaleNoThe default locale to use when no locale is provided in the url.
catchAllRouteNameYesThe default route name to use when an unknown url is hit. When not provided, the defaultRouteName will be used.
defaultAppNameYesThe default app name to use when no app is provided in the url. When not provided, the app name will not be included in the url and a url structure like /:locale instead of /:local/tool/:app will be used. This can parameter does not have to be set for backoffice applications.
landingViewComponentYes*The component shown when you hit the root route of your application e.g. /nl-be/tool/my-app.

* defaultRouteName or landingViewComponent is required to be set.

Usage

To navigate to a localized route you can use the XerLocalizedRouterLink component. This component is a wrapper around the RouterLink component from the vue-router package.

<script setup lang="ts">
import { XerLocalizedRouterLink } from "@xerius/codey-core/modules/localized-routing";
</script>

<template>
  <XerLocalizedRouterLink to-name="Home" locale="nl-be">Change to nl-be</XerLocalizedRouterLink>
</template>
Props
NameTypeDefaultRequiredDescription
toNamestringTheAppLandingView (landing route)falseThe base route name to navigate to (without any locale suffix)
localestringcurrent localefalseThe locale to navigate to, if not provided current locale is used

using pushLocalizedRoute

To programmatically navigate to a localized route you can use the pushLocalizedRoute function. This function is a wrapper around the router.push function from the vue-router package where we provide locale functionality.

Like the XerLocalizedRouterLink component, this function also accepts a locale parameter. If not provided the current locale is used.

import { useLocalizedRouter } from "@xerius/codey-core/modules/localized-routes";

const { pushLocalizedRoute } = useLocalizedRouter();
pushLocalizedRoute("Home");
pushLocalizedRoute("Home", "fr-be");

Underlying logic

The route generation works based upon having a route definition with the view component and metadata that holds i18n info for what the url needs to be in specific locales. This is used to generate a localized route table based on that meta.

Note

The path prefix for your application (/:locale/tool/:application-name for front-office or /:locale for backoffice) is omitted from below examples for clarity.

Flat route definition

The following example shows a flat rout definition and what the generated route table will be:

// definition
import type { I18nRouteRecordRaw } from "@xerius/codey-core/modules/localized-routing";

const routes = [
  {
    path: "home",
    name: "Home",
    meta: {
      i18n: {
        "nl-be": "Thuis",
        "fr-be": "Accueil",
      },
    },
    component: HomeView,
  },
] satisfies I18nRouteRecordRaw[];

// generated
import type { RouteRecordRaw } from "vue-router";

const generatedRoutes: RouteRecordRaw[] = [
  {
    path: "thuis",
    name: "Home-nl-be",
    meta: {},
    component: HomeView,
  },
  {
    path: "accueil",
    name: "Home-fr-be",
    meta: {},
    component: HomeView,
  },
];

The base route you define is absolved into the flat list above, only leaving the localized routes in place.

The LocalizedRouterLink component and pushLocalizedRoute function will create the correct router name based on the provided name and locale. You as developer can just use the defined route name in your code and the plugin will take care of the rest.

Nested route definition

We use the children property to have easy configuration of nested routes paths in our application. This prevents you from repeating a base part of the path in every route definition.

Note

Because we flatten this list, the vue-router nested routes definition is not supported.

The following example shows a nested route definition and what the generated route table will be:

// definition
import type { I18nRouteRecordRaw } from "@xerius/codey-core/modules/localized-routing";

const routes = [
  {
    path: "settings",
    name: "Settings",
    meta: {
      i18n: {
        "nl-be": "instellingen",
        "fr-be": "parametres",
      },
    },
    component: {},
    children: [
      {
        path: "documenten-delen",
        name: "SettingsDocumentenDelen",
        meta: {
          i18n: {
            "nl-be": "documenten-delen",
            "fr-be": "partager-des-documents",
          },
        },
        component: {},
      },
    ],
  },
] satisfies I18nRouteRecordRaw[];

// generated
import type { RouteRecordRaw } from "vue-router";

const generatedRoutes: RouteRecordRaw[] = [
  {
    path: "instellingen",
    name: "Settings-nl-be",
    meta: {},
    component: {},
  },
  {
    path: "parametres",
    name: "Settings-fr-be",
    meta: {},
    component: {},
  },
  {
    path: "instellingen/documenten-delen",
    name: "SettingsDocumentenDelen-nl-be",
    meta: {},
    component: {},
  },
  {
    path: "parametres/partager-des-documents",
    name: "SettingsDocumentenDelen-fr-be",
    meta: {},
    component: {},
  },
];