๐ŸŒŽInternationalization and Translations

Or i18n for short

Internationalization and Translation, referred as i18n is the set of feature that enables you to make your pages available in multiple languages.

Base principles

When in your components you see instructions like:

src/login/Register.tsx
export default function Register(props: RegisterProps) {
    const { i18n } = props;
    
    const { msg, msgStr, advancedMsg, advancedMsgStr } = i18n;

    return (
        //...
        <a href={url.loginUrl}>
            {msg("backToLogin")}
        </a>
        // ...
    );
}

Overriding the base message or adding custom ones

In the theme

If you want to see the base message translations you can navigate to the node_modules/keycloakify/src/login/i18n/messages_defaultSet/ directory:

As you can see, the translation message for the key backToLogin in English (en.ts) is:

We are <strong>sorry</strong> ...

As a result:

msg(
<div data-kc-msg="backToLogin">We are <strong>sorry</strong> ...</div>

The data-kc-msg attribute is only here to help you find the source code that generates this node when inspecting with the browser dev tools. Note also that the text that is going to be rendered is:

We are sorry ... (with sorry in bold)

msgStr(
"We are <strong>sorry</strong> ...";

Keycloakify let's you overwrite the values of the translations messages and define new ones. This is how to do it:

src/login/i18n.tsx
import { createUseI18n } from "keycloakify/login";

export const { useI18n, ofTypeI18n } = createUseI18n({
  en: {
    backToLogin: "โช Back to <strong>Login page</strong>",
    myCustomKey: "My custom message",
  },
  fr: {
    backToLogin: "โช Retour ร  la <strong>page de Login</strong>",
    myCustomKey: "Mon message personalisรฉ",
  },
});

export type I18n = typeof ofTypeI18n;

The messageBundle that you provide as argument of the createUseI18n function must be statically valuable. You can't import from external files. All the translations must be declared inline. This is because Keycloakify will analyze your code at build time to make Keycloak aware of your modifications of the base messages so that server side generated feedback messages can use your translations.

If you don't provide translation for all the language that are enabled in the realm configuration it will fallback to english (or your first translation declared).

In the Keycloak Realm configuration

Some relevant messages, namely termsText and all the messages used in the User Profile Attributes like for example the Display name, the helper text or the select option labels can be defined at the realm level and it will work as you would expect:

Note that if you try to use:

msg("profile.attributes.favourite_pet");

It will work at runtime, you'll get Favourite Pet but typescript will complain because "profile.attributes.favourite_pet" or string isn't a known i18n message key, it makes sense as it's only defined on the server.

This is why you'll see in some place in the code the usage of advancedMsg(attribute.displayName), advancedMsg() is basically equivalent to msg() except that TypeScript won't complain if the key isn't part of the statically defined set. More details. See also:

๐Ÿ“„Terms and conditions

Stories in different languages

Changing the language directly using the dropdown select in Storybook isn't supported. To preview your component in different languages, create separate stories for each language. Example:

pages/***.stories.tsx
export const Default: Story = {
  render: () => <KcPageStory />,
};

export const French: Story = {
  render: () => (
    <KcPageStory
      kcContext={{
        locale: {
          currentLanguageTag: "fr",
        },
      }}
    />
  ),
};

export const Spanish: Story = {
  render: () => (
    <KcPageStory
      kcContext={{
        locale: {
          currentLanguageTag: "es",
        },
      }}
    />
  ),
};

If you want all your story to by by default in an other language you can edit:

src/login/KcPageStory.tsx
export const { getKcContextMock } = createGetKcContextMock({
  kcContextExtension,
  kcContextExtensionPerPage,
  overrides: {
    locale: {
      currentLanguageTag: "de",
    },
  },
  overridesPerPage: {},
});

What do do if my language is not in the default set

Support for adding extra language will be added soon. In the meantime see https://github.com/keycloakify/keycloakify/issues/599

As of writing theses line Keycloak support 27 languages.

What to do is your language isn't one of them? Like Hebrew for example.

Unfortunately, Keycloak doesn't provide a way to easily add a new language however there's a workaround with Keycloakify. You can overrides the translation of an other language to add your translations. Here is an example:

Last updated