Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Theme translation messages support #17

Closed
markodvornik opened this issue Jul 5, 2021 · 9 comments
Closed

Theme translation messages support #17

markodvornik opened this issue Jul 5, 2021 · 9 comments

Comments

@markodvornik
Copy link

markodvornik commented Jul 5, 2021

I would like to add translation files to the theme.

Expected behaviour

Keycloak documentation on internationalization states that in order to support a custom language two steps are neccessary:

  1. create a messages* file inside the theme folder
  2. modify theme.properties by adding the locales= ... entry

Actual state

(1) Messages

I was investigating if translations are already supported. AFAIK the build theme script generateKeycloakThemeResources.js only copies the resources folder to the theme folder. The messages folder is not mentioned in the script.

To be clear what I was looking for: Keycloak expects the messages folder next to the resources folder.

    META-INF/keycloak-themes.json
    theme/mytheme/login/theme.properties
    theme/mytheme/login/login.ftl
    theme/mytheme/login/resources/css/styles.css
    theme/mytheme/login/resources/img/image.png
    theme/mytheme/login/messages/messages_en.properties
    theme/mytheme/email/messages/messages_en.properties

Maybe I am missing something here, so any help regarding adding translation files would be much appreciated.

A workaround would be to add the messages folder to the theme by updating a jar package once it is compiled, but that is not a permanent solution.

(2) Modify theme.properties

I think this pull-request solves it: #18

@garronej
Copy link
Collaborator

garronej commented Jul 6, 2021

Hi @markodvornik,
I am sorry I didn't implement any mechanism to update the default message.
I made the assumption (wrong obviously) that pepoles would want to use their own translation engine.
I currently don't have time to update Keycloakify however you can use the langage hook to tell what language is currently selected.

import {  useKcLanguageTag  } from "keycloakify";

const { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag(); 

For example if language selected is slovenian you will get kcLanguageTak === "sk", if it's english kcLanguageTak === "en" after that you are free to display you string it whatever way you see fit.
With setKcLanguageTag("sk") for example you can switch the language but be mindful that you should reload the page to tell Keycloak about it otherwise the keycloak user profile (and the JWT won't reflect the correct language once the user is logged in, example).

Now, if you don't care about type safety and don't want to implement your own translation engine you can update at runtime this object.

Example:

index.tsx

import { kcMessages } from "keycloakify/lib/i18n/generated_kcMessages/login";

kcMessages["sk"]["my new message"] = "foo bar in slovanian";
kcMessages["en"]["my new message"] = "foo bar in english";

MyComponent.tsx

import { useKcMessage } from "keycloakify";

export funct MyComponent(){

     const { msgStr } =useKcMessage();

     return <h1>{msgStr("my new message" as any)}</h1>;

}

This will work... I hope this helps.

@markodvornik
Copy link
Author

Thank you for the response, much appreciated.

Just a quick correction before I continue, i18n code for slovenian is si (not sk).

I didn't plan to implement my own translation engine. I am using const { msg, msgStr } = useKcMessage() to display strings.

However, I was refering to something else. How can I get a custom language (not present in the generated_kcMessages, like si) to the theme in the first place? Or is there some other way to install a custom language?

So if I understand correctly, I could define my own kcMessages["si"] dictionary somewhere in the project and then import it in all of my template files in render local translations of strings at runtime.

The second part: (2) Modify theme.properties still needs to be updated otherwise theme language is not available in the Keycloak admin. But as a workaround I can do this in a post-build process, so this is not a big issue.

@garronej
Copy link
Collaborator

garronej commented Jul 8, 2021

Hi,

So if I understand correctly, I could define my own kcMessages["si"] dictionary somewhere in the project and then import it in all of my template files in render local translations of strings at runtime.

You just need to overwrite extend kcMessages once. You could do that for example:
src/kcMessagesExtention.ts

import { kcMessages } from "keycloakify/lib/i18n/generated_kcMessages/login";

(kcMessages as any)["si"]= {
    "doLogIn": "start a session in si",
    "doRegister": "register in si",
    //...implement only the default identifier that you use,
    //  if ever an identifier is not implemented you'll falbacl to english
    "myCustomIdentifier": "my custom identifier in si",
    "myCustomIdentifier2": "my custom identifier 2 in si"
};

Object.assign(
    kcMessages["en"],
    {
        "myCustomIdentifier": "my custom identifier in english",
        "myCustomIdentifier2": "my custom identifier 2 in english"
    }
);

index.tsx

import "./kcMessagesExtention";

MyComponent.tsx

import { useKcMessage } from "keycloakify";

export funct MyComponent(){

     const { msgStr } =useKcMessage();

     return <h1>{msgStr("my new message" as any)} {msgStr("doLogin")}</h1>;

}

The second part: (2) Modify theme.properties still needs to be updated otherwise theme language is not available in the Keycloak admin. But as a workaround I can do this in a post-build process, so this is not a big issue.

Ok, for that the PR of asashey #18 make sense.

You could do:
package.json:

{
    "keycloakify": {
        "extraThemeProperties": ["locales=en,si"]
    }
}

I will merge he's pr and release a new version.

@markodvornik
Copy link
Author

This works for updatingtheme.properties.

However, partial hack is still needed: insert a translation file messages/messages_LANG.properties to the jar package. Custome language is then recoginised inside the admin panel.

A solution would be some sort of CI routine that copies resource files to the jar.

@garronej
Copy link
Collaborator

I feel that I should reopen this because it has never been really addressed.

@garronej garronej reopened this Oct 11, 2021
@ilkou
Copy link

ilkou commented Nov 8, 2021

@markodvornik @garronej

My work around this is to generate the files from KcMessages

import * as fs from "fs";
import { kcMessages } from "./login";

Object.keys(kcMessages).map((lang) => {
  let obj = kcMessages[lang];

  Object.entries(obj).map(([key, value]) => {
    fs.appendFile(
      `./messages/messages_${lang}.properties`,
      `${key}=${value}\n`,
      (err) => {
        if (err) throw err;
      }
    );
  });
});

then copy the messages folder to the appropriate destination

cp -r messages build_keycloak/src/main/resources/theme/demo1/login

or by injecting this command in our project's scripts

    "keycloak": "yarn build && build-keycloak-theme && cp -r messages build_keycloak/src/main/resources/theme/demo1/login"

gitbook-com bot pushed a commit that referenced this issue Apr 23, 2022
@loki344
Copy link

loki344 commented Aug 5, 2022

@markodvornik @garronej

My work around this is to generate the files from KcMessages

import * as fs from "fs";
import { kcMessages } from "./login";

Object.keys(kcMessages).map((lang) => {
  let obj = kcMessages[lang];

  Object.entries(obj).map(([key, value]) => {
    fs.appendFile(
      `./messages/messages_${lang}.properties`,
      `${key}=${value}\n`,
      (err) => {
        if (err) throw err;
      }
    );
  });
});

then copy the messages folder to the appropriate destination

cp -r messages build_keycloak/src/main/resources/theme/demo1/login

or by injecting this command in our project's scripts

    "keycloak": "yarn build && build-keycloak-theme && cp -r messages build_keycloak/src/main/resources/theme/demo1/login"

thanks @ilkou, I ended up with this order of the command because if you call build-keycloak-theme and copy it afterwards it's not included in the jar (i guess)

"keycloak": "npm run build && cp -r messages messages build_keycloak/src/main/resources/theme/demo/login && build-keycloak-theme"

@garronej
Copy link
Collaborator

garronej commented Aug 5, 2022

Hi @loki344,
Keycloak v6 is just around the corner (actually it's even released in beta) and features an actual support for i18n customisation along side with significant optimisations on the bundle size.

It's not fully documented yet but
https://github.com/garronej/keycloakify-demo-app-css-only
https://docs.keycloakify.dev/v/v6/

gitbook-com bot pushed a commit that referenced this issue Aug 22, 2022
@garronej
Copy link
Collaborator

garronej commented Sep 5, 2022

There is now a proper i18n API in Keycloakify v6 ( 6.0.0-beta.13) 🥳

https://docs.keycloakify.dev/v/v6/i18n

@garronej garronej closed this as completed Sep 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants