Adding New Translation Messages Or Changing The Default Ones

Let's see firs how you can overwrite the default translation messages to best fit your usecases.

At theme level

See, for example, by default the login page shows "Sign in to your account":

Let's say we want to change that with a message more specific to you usecase.

First setp is to identify the message key. You can usually found it just by inspecting the HTML of your page:

Here we can see that the "Sign in to your account" translation message corespond to the message key loginAccountTitle.

Let's change the English and French translations:

src/login/i18n.ts
import { i18nBuilder } from "keycloakify/login";
import type { ThemeName } from "../kc.gen";

/** @see: https://docs.keycloakify.dev/i18n */
const { useI18n, ofTypeI18n } = i18nBuilder
    .withThemeName<ThemeName>()
    .withExtraLanguages({ /* ... */ })
    .withCustomTranslations({
        en: {
            loginAccountTitle: "Log in to your ACME account"
        },
        // cspell: disable
        fr: {
            loginAccountTitle: "Connectez-vous a votre compte ACME"
        }
        // cspell: enable
    })
    .build();

type I18n = typeof ofTypeI18n;

export { useI18n, type I18n };

Here is the result that you should get:

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 have opted for a configuration at the component level it can come handy to define you own custom message keys:

src/login/i18n.ts
import { i18nBuilder } from "keycloakify/login";
import type { ThemeName } from "../kc.gen";

/** @see: https://docs.keycloakify.dev/i18n */
const { useI18n, ofTypeI18n } = i18nBuilder
    .withThemeName<ThemeName>()
    .withExtraLanguages({ /* ... */ })
    .withCustomTranslations({
        en: {
            loginAccountTitle: "Log in to your ACME account",
            myCustomMessage: "This is a custom message"
        },
        // cspell: disable
        fr: {
            loginAccountTitle: "Connectez-vous a votre compte ACME",
            myCustomMessage: "Ceci est un message personnalisรฉ"
        }
        // cspell: enable
    })
    .build();

type I18n = typeof ofTypeI18n;

export { useI18n, type I18n };

You'll then be able to use the message key "myCustomMessage" in your components:

If you are implementing theme variants you can provides translations on a per-theme variant basis. See how.

Now this is perfect for defining generale purpose text. But some other translations messages are more specific to a specific Keycloak configuration and are best configured via the Keycloak Account Console. I'm thinking in particular as translations related to custom user attribues (favourite pet for example) or terms and conditions.

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

Adding registration form fields.

Last updated