Kogito Tooling i18n

We’re happy to announce that Kogito Tooling is ready to be internationalized! This means that it will be possible to change the locale and access translations of the Kogito Tooling Channels.

To enable this new feature, we developed an i18n type-safe library with React usability in mind, which allows simple and easy integration with an already existing project. This article will explain our choices and go through all the minimal settings required to use it.

Integration

As mentioned, this is a library to be used on a React TypeScript project, so first of all, it’s necessary to create a dictionary type that is going to be used by our default locale. This is important, so our application doesn’t have any missing strings. The reference dictionary interface should extend the ReferenceDictionary<D> type.

interface MyDictionary extends ReferenceDictionary<MyDictionary> {
inputName: string;
welcome: (name: string) => string;
home: {
title: string;
body: string;
};
currentLocale: (locale: string) => string;
}
view raw myDictionary.ts hosted with ❤ by GitHub

Notice how we can only have string or functions receiving and returning strings. This makes the dictionaries implementations clean without any conversations to strings, or even worse, dangerous concatenations of non-string objects.

With our reference dictionary interface ready, we need to create our reference dictionary object which implements its interface.

const english: MyDictionary = {
inputName: "Please, enter your name",
welcome: (name) => `Welcome ${name.bold()}`,
home: {
title: "This is a React i18n library!",
body: "Use i18n on your TypeScript projects!"
},
currentLocale: (locale) => `My current locale is: ${locale}`
};
view raw english.ts hosted with ❤ by GitHub

The bold() function is a native JS feature, and will wrap the ‘name’ string in <b> HTML tags.

The application must have only one ReferenceDictionary object. All other dictionaries are going to be a translated version of the reference dictionary. With that in mind, the translated dictionaries should implement the TranslatedDictionary<D> type. The TranslatedDictionary<D> is a type with the same keys and types of the ReferenceDictionary<D>, but they’re all optional.

const portuguese: TranslatedDictionary<MyDictionary> = {
inputName: "Por favor, coloque o seu nome",
home: {
title: "Está é uma biblioteca i18n para React",
body: "Use i18n em seus projetos TypeScript!"
},
currentLocale: (locale) => `Meu local atual é: ${locale}`
};
view raw portuguese.ts hosted with ❤ by GitHub

In this example, the ‘welcome’ key isn’t provided. When the user eventually selects the Portuguese dictionary, the ‘welcome’ key will fall back to the English dictionary because it is our reference dictionary.

Having optional keys is important for partial translations. It can be very difficult to translate an application to a whole other language. More than that, programmers won’t speak every language supported by the application, so upon creation of new keys, it’s important that the programmer is not required to translate them, leaving it for a translator to do later.

Now, it’s necessary to give the application access to these dictionaries. For that, we have the I18nDictionariesProvider React component, and it’s necessary to initialize it with a few props at the top level of our app.

// The Context typed with your Dictionary, which will be used by your components
export const myI18nCtx React.createContext<I18nContextType<MyDictionary>>({} as any);
export function App(props: Props) {
// Fallback locale and respective dictionary
const myI18nDefaults = { locale: "en", dictionary: english };
// All your dictionaries. The key of the Map object should follow the browser pattern
const myI18nDictionaries = new Map([
["en", english],
["pt", portuguese]
]);
return (
<I18nDictionariesProvider defaults={myI18nDefaults} dictionaries={myI18nDictionaries} ctx={myI18nCtx}>
<MyComponent />
</I18nDictionariesProvider>
);
}
view raw MyApp.tsx hosted with ❤ by GitHub

The I18nDictionariesProvider component will add the dictionaries to the application context. When a dictionary is selected, it will be merged with the reference dictionary, creating a new dictionary object. In this process, all existing keys on the translated dictionary will override the reference keys, and this way, a new dictionary will be formed without any missing key. To illustrate this behavior, if the Portuguese dictionary is selected, the resultant dictionary object would be:

{
inputName: "Por favor, coloque o seu nome",
welcome: (name) => `Welcome ${name.bold()}`,
home: {
title: "Está é uma biblioteca i18n para React",
body: "Use i18n em seus projetos TypeScript!"
},
currentLocale: (locale) => `Meu local atual é: ${locale}`
}
view raw mergedDictionary.ts hosted with ❤ by GitHub

After the I18nDictionariesProvider component is ready, it’s possible to use the dictionaries on the children components with the useContext hook (useContext(myI18nCtx)) or the context provider (myI18nCtx.Provider), which gives access to the current locale, a function to change the locale (setLocale), and the object (i18n) with the current actual dictionary.

function MyComponent() {
const { locale, setLocale, i18n } = useContext(myI18nCtx);
const [name, setName] = useState("");
return (
<div>
<p>{i18n.home.title} 🙂</p>
<p>{i18n.home.body}</p>
<input type={"text"} value={name} onChange={e => setName(e.target.value)} />
{/* a couple of <br /> tags, just to give a better look to the example. */}
<br />
{/* `welcome` will always fallback on the 'en' dictionary because the ‘pt’ dictionary doesn't provide it. */}
<I18nHtml>{i18n.welcome(name)}</I18nHtml>
<br />
<a onClick={() => setLocale("pt")}>pt</a>
<br />
<a onClick={() => setLocale("en")}>en</a>
<p>{i18n.myCurrentLocale(locale)}</p>
</div>
);
}
view raw MyComponent.tsx hosted with ❤ by GitHub

In this example we use an I18nHtml component. Remember the ‘welcome’ string with <b> tags that were added by the bold() function? We utilize this component because it can render a string with HTML tags using the dangerouslySetInnerHTML prop. It’s not recommended to use that with interpolated translation keys.

Wrapping up

This library solved the i18n problem for our needs at the moment, and if you think you have a similar use-case, you can use our i18n library too! All you have to do is install it using npm or yarn, and just follow the above steps to integrate it!

Installation:

npm install @kogito-tooling/i18n or yarn add @kogito-tooling/i18n

Stay tuned for more updates on Kogito Tooling! Don’t forget to try our VS Code and Chrome extensions. An online version of the editors is available at https://kiegroup.github.io/kogito-online/#/ . You can also download our Desktop app on our GitHub release page.

This post was original published on here.
0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments