Skip to content

i18next

Preparation

Create an apps/i18n.ts file with this content and configure as needed:

import type { I18nConfig } from '@pit-shared/remix-runtime/i18n'

export const config = {
    supportedLngs: ['de', 'en'],
    fallbackLng: 'en',
    defaultNS: 'common',
    react: { useSuspense: false },
} satisfies I18nConfig

export const hash = 'xxx'

In the app/root.tsx add these parts:

  • Import statements
  • the handle export to provide a i18next namespace
  • Add the locale handling to the root loader
  • Add the lang, dir and base-path to the html tag
// ...

import { useTranslation } from "@pit-shared/remix-runtime/i18n";
import { getI18next } from "@pit-shared/remix-runtime/i18n.server.js";
import { config, hash } from "./i18n";

export let handle = {
  i18n: "common",
};

export async function loader({ request }: LoaderFunctionArgs) {
  let locale = await getI18next({ config, hash }).getLocale(request);
  return json({
    locale,
  });
}

// in your JSX

  // ...
  let { i18n } = useTranslation();
  // ...
  <html lang={locale} dir={i18n.dir()} data-base-path={basePath}>
    // ...
  </html>

Server Side

You have to configure server side i18n in your entry.server.tsx.

If that file is not yet in your project, run pnpm remix reveal in your project.

Add these parts to that file:

  • Import statements
  • The setup function call
  • The I18nProvider
// ...

import { I18nProvider } from "@pit-shared/remix-runtime/i18n";
import { setup } from "@pit-shared/remix-runtime/i18n.server.js";
import { config, hash } from "./i18n";

export default async function handleRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  remixContext: EntryContext,
  loadContext: AppLoadContext,
) {
  const i18n = await setup({ request, remixContext, config, hash });

  return new Promise((resolve, reject) => {
    // ...

    const { pipe, abort } = renderToPipeableStream(
      <I18nProvider i18n={i18n}>
        <RemixServer
          context={remixContext}
          url={request.url}
          abortDelay={ABORT_DELAY}
        />
      </I18nProvider>,
      {
       // :..
      },
    );

    // ...
  });
}

Client Side

You have to configure client side i18n in your entry.client.tsx.

If that file is not yet in your project, run pnpm remix reveal in your project.

Add these parts to that file:

  • Import statements
  • The setup function call
  • The I18nProvider
// ...

import { I18nProvider } from "@pit-shared/remix-runtime/i18n";
import { setup } from "@pit-shared/remix-runtime/i18n.client.js";
import { config, hash } from "./i18n";

async function hydrate() {
  const i18n = await setup({
    basePath: document.querySelector("html")?.dataset.basePath ?? "/",
    config,
    hash,
  });

  startTransition(() => {
    hydrateRoot(
      document,
      <I18nProvider i18n={i18n}>
        <StrictMode>
          <RemixBrowser />
        </StrictMode>
      </I18nProvider>,
    );
  });
}

if (window.requestIdleCallback) {
  window.requestIdleCallback(hydrate);
} else {
  // Safari doesn't support requestIdleCallback
  // https://caniuse.com/requestidlecallback
  window.setTimeout(hydrate, 1);
}

Usage

Default

import { useTranslation } from '@pit-shard/remix-runtime/i18n';

// ... somewhere in our component
export const Component = () => {
  const { t } = useTranslation();

  return <p>{t('YOUR_TRANSLATION_KEY')}</p>
}

Interpolation

In the monolith, interpolation keys are enclosed in single square brackets.

A translation from the monolith can look like this:

    <trans-unit id="YOUR_TRANSLATION_KEY">
          <source>YOUR_TRANSLATION_KEY</source>
          <target><![CDATA[{keyName} Statista]]></target>
    </trans-unit>

To use this translation, you can follow the structure below.

export const Component = () => {
  const { t } = useTranslation();

  return <p>{t('YOUR_TRANSLATION_KEY', {
    keyName: 'YOUR_TRANSLATION_VALUE'
  })}</p>
}

keyName will be transformed in to YOUR_TRANSLATION_VALUE.

Platform Overwrite

By default, the platform and language are detected from the request subdomain (e.g. de.statista.com → DE). A cookie-based override can be enabled to switch between platforms without changing domains (e.g. on local or PR deployments).

This feature must be explicitly enabled before the cookie override becomes active.

Setup

Enable the platform overwrite feature by starting the dev-server with the --enable-platform-overwrite flag:

pnpm remix-tools dev-server --enable-platform-overwrite

Or set the environment variable:

ENABLE_PLATFORM_OVERWRITE=true pnpm remix-tools dev-server

Usage

Once enabled, set the statista-platform cookie in your browser's DevTools console:

// Switch to DE platform
document.cookie = 'statista-platform=de; path=/'

// Switch back to EN platform
document.cookie = 'statista-platform=en; path=/'

// Remove override (fall back to subdomain detection)
document.cookie = 'statista-platform=; path=/; max-age=0'

The cookie value must be a supported language code (e.g. de or en). Invalid values are ignored and subdomain detection is used as fallback.

This affects both the platform() utility and the i18n language detection.