{ "content": "\n

Keycloak is an open-source IAM solution that provides user federation, strong authentication, user management, and much more. As a single sign-on provider, it allows users to authenticate with Keycloak rather than individual applications via dedicated login forms. Such forms are often internationalized and require different layouts and language bundles to render properly, and Keycloak allows one to customize the locale selection and resolution rules as necessary.

\n\n
\n \n \n \n
\n\n

In this post, we will look at options provided by Keycloak that allow a server developer to customize the locale resolution rules for various freemarker templates and HTML forms. Our starting position is as follows:

\n\n\n\n

Locale Selection Rules

\n\n

Keycloak documentation indicates that the default locale is English with the internationalization setting disabled. When this option is enabled, the locale is resolved according to the following logic:

\n\n\n
\n \n \n \n
\n\n\n

If none of the above, fall back to English.

\n\n

If the above selection does not immediately meet your needs, Keycloak also allows one to provide their locale selection logic via a dedicated implementation of the LocaleSelectorProvider interface. These implementations can extend the DefaultLocaleSelectorProvider to reuse, ignore or enhance parts of the default behavior.

\n\n

Custom Locale Selection

\n\n

To extend parts of Keycloak, one has to register custom implementations of Keycloak Service Provider Interfaces (SPIs). In our case, we will need to implement the org.keycloak.locale.LocaleSelectorProviderFactory and register it with the Java Service Loader API. This factory is then tasked to supply an implementation of the LocaleSelectorProvider that selects and delivers the final locale to Keycloak.

\n\n

So, let’s start with our factory implementation:

\n
\n \n \n \n
\n
package org.example.keycloak;\n\npublic class MyLocaleSelectorProviderFactory \n  extends DefaultLocaleSelectorProviderFactory {\n\n  @Override    \n  public LocaleSelectorProvider create(KeycloakSession session) {\n    return new MyLocaleSelectorProvider(session);    \n  }\n\n  @Override    \n  public String getId() {\n    return \"MyLocale\";\n  }\n}\n
\n\n

…and then, our own MyLocaleSelectorProvider implementation:

\n
\n \n \n \n
\n
public class MyLocaleSelectorProvider extends DefaultLocaleSelectorProvider {\n  @Override\n  public Locale resolveLocale(RealmModel realm, UserModel user) {\n    // Stuff happens...\n    return ...;\n  }\n}\n
\n\n

Next, we need to register our factory implementation inside the file META-INF/services/org.keycloak.locale.LocaleSelectorProviderFactory:

\n
\n \n \n \n
\n
org.example.keycloak.MyLocaleSelectorProviderFactory\n
\n\n

At this point, Keycloak has access to multiple options for selecting and loading locales. Ours, and what ships by default. So, we will need to instruct Keycloak to use our version of the locale selection rules and skip the default:

\n
\n \n \n \n
\n
/path/to/keycloak/bin/kc.sh --build --spi-locale-selector-provider=MyLocale\n
\n\n

The SPI identifier, MyLocale, represents the identifier of the factory implementation as stated by the getId() method.

\n\n

Need Help?

\n\n

If you have questions about the contents and the topic of this blog post, or if you need additional guidance and support, feel free to send us a note and ask about consulting and support services.

\n\n

So…

\n\n

I hope the content here was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. If you have suggestions or ideas on how to improve this post, please feel free to reach out to us.

\n\n

Misagh Moayyed

\n\n" }