Keycloakify
HomeGitHubStorybookAlternative to keycloak-js
v11
  • Documentation
  • Release Notes & Upgrade Instructions
  • FAQ
v11
  • Quick Start
  • CSS Customization
  • Testing your Theme
    • Outside of Keycloak
    • Inside of Keycloak
  • Deploying Your Theme
  • Integrating Keycloakify in your Codebase
    • Vite
    • Create-React-App / Webpack
    • yarn/npm/pnpm/bun Workspaces
    • Turborepo
    • Nx
    • Angular Workspace
  • Common Use Case Examples
    • Using a Component Library
    • Custom Fonts
    • Changing the background image
    • Adding your Logo
    • Using Tailwind
    • Dark Mode Persistence
  • Features
    • Internationalization and Translations
      • Basic principles
      • Previewing Your Pages in Different Languages
      • Adding New Translation Messages or Changing the Default Ones
      • Adding Support for Extra Languages
    • Theme Variants
    • Environment Variables
    • Styling a Custom Page Not Included in Base Keycloak
    • Integrating an Existing Theme into Your Keycloakify Project
    • Compiler Options
      • --project
      • keycloakVersionTargets
      • environmentVariables
      • themeName
      • startKeycloakOptions
      • themeVersion
      • accountThemeImplementation
      • postBuild
      • XDG_CACHE_HOME
      • kcContextExclusionsFtl
      • keycloakifyBuildDirPath
      • groupId
      • artifactId
      • Webpack specific options
        • projectBuildDirPath
        • staticDirPathInProjectBuildDirPath
        • publicDirPath
  • Page-Specific Guides
    • Registration Page
    • Terms and Conditions Page
  • Theme types
    • Differences Between Login Themes and Other Types of Themes
    • Account Theme
      • Single-Page
      • Multi-Page
    • Email Theme
    • Admin Theme
Powered by GitBook
On this page
  • At theme level
  • In the Keycloak Realm configuration
  • My Realm Overrides Translation aren't applied

Was this helpful?

Edit on GitHub
  1. Features
  2. Internationalization and Translations

Adding New Translation Messages or Changing the Default Ones

Last updated 3 months ago

Was this helpful?

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 or keycloakify/accont";
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 translations that you provide to the i18nBuilder 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.

src/login/i18n.ts
import { i18nBuilder } from "keycloakify/login or keycloakify/account";
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:

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

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.

My Realm Overrides Translation aren't applied

There is a limitation in the current version of Keycloakify: Not all translations defined at the Keycloak realm level are pulled by the theme.

It will be addressed in future version but as of now, here is a workarond that you can use.

Let's say you want to make sure that the message key "doRegister" and "invalidUserMessage" can be overriten at the ream level, you can edit your vite.config.ts like so:

vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { keycloakify } from "keycloakify/vite-plugin";

// https://vitejs.dev/config/
export default defineConfig({
    plugins: [
        react(),
        keycloakify({
            // ...
            kcContextExclusionsFtl: `
                <@addToXKeycloakifyMessagesIfMessageKey str="doRegister" />
                <@addToXKeycloakifyMessagesIfMessageKey str="invalidUserMessage" />
            `
        })
    ]
});

If you have opted for a configuration it can come handy to define you own custom message keys:

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

Some relevant messages, namely 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:

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. .

at the component level
See how
termsText
More details
TypeScript knows that "myCustomMessage" is a valid key
The custom user attribute favourite_pet has for Display Name the message key "profile.attributes.favourite_pet"
A translation for the message key "profile.attributes.favourite_pet" has been defined for the English language: "Favourite Pet"
"Favourite Pet" is correctly used as Display Name for the input field in the register page