Skip to content

M3 Internationalization (i18n)

Camille Villa edited this page Jun 16, 2021 · 3 revisions

Mirador's user facing text is internationalized using react-18next. There are translation.json files for each supported locale in the locales directory.

Overriding i18n keys

An implementer may override text in an existing, configured language via the config. For example, the menu option text, "Download / export settings", can be replaced with the text "gimme".

translations: {
    en: { downloadExportWorkspace: 'gimme' }
  },

Adding a new language

  1. Create a directory with the locale code for the language you're adding in the locales directory.
  2. Create a translation.json file in the newly created directory.
  3. Translate all the keys found in an existing language's translation.json file.
  4. Import your translation.json file in the i18n.js file and add it to the resources object under the appropriate locale.

Internationalizing a component

There are several different ways to internationalize a component (Hook, HOC, Render Prop, etc) that you can choose to best fit your needs and the kind of component you're working with. The react-18next documentation has detailed information on all of these scenarios, but we'll document some of our most common cases here.

withTranslation HOC

If you're working with a class component, using the withTranslation HOC may be the easiest way to i18n your component. If there is already a container for your presentational component you'll want to implement withTranslation there.

import { compose } from 'redux';
+ import { withNamespaces } from 'react-i18next';
import miradorWithPlugins from '../lib/miradorWithPlugins';
import MyComponent from '../components/MyComponent';

const enhance = compose(
+   withNamespaces(), 
  miradorWithPlugins,
);
export default enhance(MyComponent);

Note that it is withNamespaces() not withNamespaces

Now, you'll have a t prop passed to your component.

import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class MyComponent extends Component {
  render() {
+    const { t } = this.props;
    return (
-      <div>My Key</div>
+      <div>{t('myKey')}</div>
    );
  };
};

MyComponent.propTypes = {
+  t: PropTypes.func, // See below about required vs. default t prop
};

MyComponent.defaultProps = {
+  t: key => key, // See below about required vs. default t prop
};
{
  "translation": {
    "aKey": "A Key",
    "closeWindow": "Close window",
+   "myKey": "My Key"
  }
}

Required vs. default t prop

As of writing this, the pattern we're using here is fluid. It'll be best to look at what the established pattern in the code is and try to use that.

Guiding principles for i18n keys and user facing strings

  • All user facing text must be internationalized (screen-reader only text, relevant aria attributes, etc. included)
  • Keys should be camelCase
  • Keys should be alphabetized in the translation.json file