graphdb-workbench

Internationalization (i18n)

How per-module translation files are merged into a single bundle per language, and how translations are added and validated.

Internationalization (i18n) Guide for the Application

How It Works

The system ensures that translations from different modules are merged into a single bundle per language, using the merge-i18n-plugin.js. After they are merged, all .json files from src/assets/i18n directories are transferred to the webpack output directory. That includes language-config.json, which contains the default language, the translation bundle version and the available languages for the application. The configuration file is read, upon starting the application inside ontotext-root-config.js#getLanguageConfig. The default language is loaded and the app starts listening for ontotext-root-config.js#onLanguageChange events. Once a language changes, the respective bundle is loaded and emitted via language-context.service.ts#updateLanguageBundle. Modules listen for bundle changes from language-context.service.ts#onLanguageBundleChanged and apply translation logic independently from each other.

Translation File Structure

Every module in the application must follow the convention of placing translation files under the src/assets/i18n directory. For example:

packages/ 
  module1/
    src/assets/i18n/en.json 
    src/assets/i18n/fr.json 
  module2/ 
    src/assets/i18n/en.json 
    src/assets/i18n/fr.json

Translation files should be JSON objects where the keys are the translation identifiers, and the values are the translated strings. For example:

src/assets/i18n/en.json:

{
  "greeting": "Hello",
  "farewell": {
    "label": "Goodbye"
  }
}

src/assets/i18n/fr.json:

{
  "greeting": "Bonjour",
  "farewell": {
    "label": "Au revoir"
  }
}

Bundling Translations

The merge-i18n-plugin.js aggregates these translation files across all modules and merges them into a single bundle for each language. For example:

packages/module1/src/assets/i18n/en.json and packages/module2/src/assets/i18n/en.json will be combined into a single en.json. The output will look like this:

dist/${outputDirectory}/en.json

Conflicts

The plugin resolves conflicts by throwing an error if multiple files define the same key for the same language. For example:
module1/src/assets/i18n/en.json

{
  "some-prop": "Hello",
  "menu.logo.link.title": {
    "label": "Goodbye"
  }
}

module2/src/assets/i18n/en.json:

{
  "another-prop": "Bonjour",
  "menu.logo.link.title": {
    "another-label": "Different Goodbye"
  }
}

Will result in an error, similar to this one:

Processing file: en.json
Error: Conflict detected for key 'menu.logo.link.title' in language 'en' in file: packages/workbench/src/assets/i18n/en.json

Key Features:

Automatic Directory Traversal: Scans all modules for src/assets/i18n folders.
Conflict Detection: Throws an error if there are duplicate keys in the same language.
JSON Merging: Combines all translations into one file per language.
Asset Emission: Writes the merged bundles to the specified output directory in the Webpack dist folder.

Plugin Options

startDirectory: The base directory where the plugin begins searching for modules.
outputDirectory: The directory inside the Webpack output folder where the merged translation bundles will be written.

Example Usage in Webpack Config

const { MergeI18nPlugin } = require('./plugins/MergeI18nPlugin');

module.exports = {
  // Other Webpack configurations...
  plugins: [
    new MergeI18nPlugin({
      startDirectory: 'packages',
      outputDirectory: 'assets/i18n',
    }),
  ],
};

How to Add new Translations

  1. Add your language in the availableLanguages array in language-config.json.
  2. Add translation files for the new language in every src/assets/i18n folder, where there are translations. The key in availableLanguages, should be the name of the new file translation, e.g. ${key}.json. Avoid conflicting keys in your new bundle, as it will cause an error.
  3. Build the application
  4. Check merged output: After building the application, check the ${webpack.outputFolder}/${mergeI18nPlugin.outputDirectory} (currently dist/assets/i18n) folder to verify that all translations are included and correctly merged.
  5. Listen for bundle changes in the new module, using language-context.service.ts#onLanguageBundleChanged
  6. Use the new bundle for module translation (may be different, depending on the module).

Translation Validation

To validate translations locally:

npm run validate

If the project structure differs or the script is placed elsewhere, provide the project root manually:

SCRIPT_ROOT=/absolute/path/to/repo-root npm run validate

The script will generate a file:

translation-report.json

If issues are found, the script will exit with code 1.


Running in Translation Vaidation CI

On Jenkins, the script runs automatically in the Validate stage.

If issues are found:

Look for this file under “Build Artifacts”:

translation-report.json

See also: Developers Guide