Skip to content

how to translate the breadcrumbs

Posted on:December 5, 2023

There is a section of the Remix docs explaining how to add breadcrumbs to youre site in a really smart way (check it out here).

Using this approach, each route can state only its own part of the breadcrumbs and they all get accumulated using useMatches.

However, as always, multi language support is nowhere to be found.

By following the guide you are left with a componenet you can render but not translate, and there is no way to use your translation hooks inside the handle export.

Thankfully, handle is much more flexible and powerful than.

Two ways to translate those breadcrums

There a two ways to translate the breadcrums this way. Either translate inside each route handle or outside, at the aggregator level.

changes are relative to example in the docs

Pass a trasnlation context to the breadcrumbs handler

First, pass the translation context to the breadcrumb handler

app/root.tsx
import {
Links,
Scripts,
useLoaderData,
useMatches,
} from "@remix-run/react";
import { useTranslation } from 'react-i18next' // or any other
export default function Root() {
const matches = useMatches();
const translationContext = useTranslation();
return (
<html lang="en">
<head>
<Links />
</head>
<body>
<header>
<ol>
{matches
.filter(
(match) =>
match.handle && match.handle.breadcrumb
)
.map((match, index) => (
<li key={index}>
{match.handle.breadcrumb({
...match,
...translationContext
})}
</li>
))}
</ol>
</header>
<Outlet />
</body>
</html>
);
}

Now it is available to use in order to translate inside handle

app/routes/some-route.ts
export const handle = {
breadcrumb: ({t}) => (
<Link to="/parent">
{t('some-route-translation-key')}
</Link>
),
};

Return only the translation keys from the breadcrumbs handler

In this approch we will not return a component from the breadcrumb handler but rather the data needed to render it.

First, return only the translation key and to

app/routes/some-route.ts
export const handle = {
breadcrumb: () => ({key: 'some-translation-key', to: '/some-route' })
};

And now trasnlate them in the component where the translation context is already available.

app/root.tsx
import {
Links,
Scripts,
useLoaderData,
useMatches,
} from "@remix-run/react";
import { useTranslation } from 'react-i18next';
export default function Root() {
const matches = useMatches();
const translationContext = useTranslation();
return (
<html lang="en">
<head>
<Links />
</head>
<body>
<header>
<ol>
{matches
.filter(
(match) =>
match.handle && match.handle.breadcrumb
)
.map((match, index) => {
const {key, to} = match.handle.breadcrumb(match)
return (
<li key={index}>
<Link to={to}>
{t(key)}
</Link>
</li>
)})}
</ol>
</header>
<Outlet />
</body>
</html>
);
}



Keep in mind
Both of these moethods can be used for other handle use cases just as well. In general, either:

  1. Pass more context to the handlers
  2. Return raw data that later can be manipulated



If you found it useful, I will be happy to hear about it :)