Internationalization (I18n)

Files for internationalization are located at:

  • frontend/src/i18n

  • backend/src/i18n



The first thing you need to do when adding a new language to ScaffoldHub is to create a dictionary file.

You may want to copy the frontend/src/i18n/en.ts file and translate each value.

Then you must declare this file on thefrontend/src/i18n/index.ts file.

The index object will need:

  • id: The locale code.

  • label: The label that is displayed on the i18n select box.

  • flag: The path to the flag that is displayed on the sign-in page. Download more flags at

  • dictionary: The dictionary file content. It is lazy-loaded, that's why on the image it starts as null.

Each frontend has its specific framework related i18n files.

React Ant Design

  • antd: Path to the Ant Design language provider: antd/lib/locale-provider/<locale-id>.

  • moment: Path to the Moment language file: moment/locale/<locale-id>.

React Bootstrap and React Material UI

  • dateFns: Path to the DateFns locale: date-fns/locale/<locale-id>.

Vue Element UI

  • elementUI: The path to the Element UI locale file: element-ui/lib/locale/lang/<locale-id>.

  • moment: Path to the Moment language file: moment/locale/<locale-id>.

Angular Material

  • materialLocale: The Material locale code.

  • owlDateTimeLocale: The owl date-time locale code.


Typescript and JSX Files (React)

On typescript and JSX files you can use the dictionary by importing this helper function:

import { i18n } from 'src/i18n';

The helper function accepts a key and arguments.

export function i18n(key, ...args) {
  if (!getLanguage()) {
    return key;

  const message = _get(getLanguage().dictionary, key);

  if (!message) {
    return key;

  return format(message, args);

For example, if we call this key, passing two arguments:

just: {
    an: {
        example: 'with the keys {0} and {1}'
i18n('', 'A', 'B')

The result will be:

with the keys A and B

JSX files can also use the i18nHtml function, which allows you to use HTML on the dictionary.

message: `Please confirm your email at <strong>{0}</strong> to continue.`,
import { i18nHtml } from 'src/i18n';
    {i18nHtml('auth.emailUnverified.message', email)}

Angular Templates

Angular templates have this <app-i18n> with the key property to handle the internationalization.

<app-i18n key="user.title"></app-i18n>

Vue Templates

Vue templates have this <app-i18n> with the code property to handle the internationalization.

<app-i18n code=""></app-i18n>


The backend receives the current language via the accept-language parameter.

req.language = req.headers['accept-language'] || 'en';


The backend configuration is very simple, you just have to declare the dictionary file.


The usage is the same as the typescript from the frontend.


The internationalization for the backend is most used on error handling, and it uses the i18n methods on its constructor.

Errors constructors receive the language, key, and arguments.

import { i18n, i18nExists } from '../i18n';

 * Error with code 400
export default class Error400 extends Error {
  code: Number;

  constructor(language?, messageCode?, ...args) {
    let message;

    if (messageCode && i18nExists(language, messageCode)) {
      message = i18n(language, messageCode, ...args);

    message =
      message ||
      i18n(language, 'errors.validation.message');

    this.code = 400;

Error400 usage:

throw new Error400(

Last updated