The Flask-Babel tool we are using does not supply any native way to access translations via JavaScript, so would require hacky solutions like adding data attributes or hidden elements to the HTML.
We have several areas of the application where we must use text in JavaScript. The DataTables plugin for example allows you to provide strings to use for the buttons it generates, but they must be defined in JS.
===Outline===
==== String extraction from JavaScript files ====
The main [[https://www.gnu.org/software/gettext/|GNU gettext library]] allows extraction from JavaScript (and all other main languages). This can be merged into the existing messages.pot file, before continuing with the usual compiling process to reach a .mo file.
NOTE: The API does **not** extract from HTML, or any HTML template format. Hence it's best to leave the existing Flask-Babel extraction to deal with the Python and HTML, and //only// use GNU gettext API for JavaScript.
==== Displaying language content in JavaScript files ====
Use the [[https://webpack.js.org/plugins/i18n-webpack-plugin/ | i18n Webpack Plugin]] to compile different language versions of each JavaScript file automatically.
So instead of outputting the file to `/static/js`, we output to `/static/js/<lang code>/` instead.
There will be 1 copy of each output JavaScript file per language (initially, that means one full set in `/static/js/en` and one full set in `/static/js/fr`
In the source JavaScript files (`src` folder), we can mark a translatable string using the format ` __('some translatable text')`.
The i18n-webpack-plugin then replaces this this text with actual strings for each language. This happens when webpack compiles the the output files (during `npm run build` or `npm run dev`).
i18n-webpack-plugin needs a .json file to find the translations, so we use [[https://www.npmjs.com/package/po2json | po2json]] to create a json conversion of each language's .po file.
Finally, the <script> tag used on each page loading our JavaScript files needs to be updated to use the session language to determine which /static/js/<lang code> folder to load from. I.e. we only load from the js file for the current language
==== Extraction Instructions ====
These are the steps that need to be taken in addition to the existing extracting/compiling:
//For all steps you should be in the `isa` subfolder within the main project folder//
1. Make sure you're messages.pot file is ready and up to date using Flask-Babel. At this stage you have all translation strings extracted from Python and HTML template files
2. Generate list of JavaScript files in the .src folder. The list is stored in a file, so you do not need to repeat next time unless the list of JS files changes.
```find src/*.js -type f -print > js-file-list```
3. Invoke the xgettext command using the generated list as input, using `--join-existing` to add extracted translation to the **existing** .pot file
```xgettext --files-from=js-file-list --output=messages.pot --language=JavaScript --from-code=UTF-8 --join-existing --omit-header```
//Now the messages.pot file contains all original strings, **plus the new JavaScript strings** that have been merged in//
4. Continue with the normal workflow with Flask-Babel and generate the .po files for each language (or //update// the .po files if they already exist). The .po files will then need the actual translations added for the new JavaScript strings
5. Convert each .po file to JSON using po2json and save it as messages.json (in same folder as the .po and .mo file)
This has been setup as an npm script to build French json file (the only one we need initially).
```npm run build-fr-json```
==== Usage Instructions ====
1. In any of the source js files, use the format ` __('some translatable text')`
This can then be extracted to the .pot file in the process described above.
It will be then be automatically replaced with the relevant translation for each language version of the js file
IMPORTANT: i18n-webpack plugin does not have built in support for plural strings, or sprintf expressions. For the next improvement, we can use [[https://www.npmjs.com/package/sprintf-js| sprintf-js]] for inserting variables into strings, but this would need a different .po to .json conversion - the current po2json does not preserve the required format %{variable name}.
Alternatively, a solution like jed-webpack-plugin would allow everything in one package, including parsing .mo files directly. Unfortunately this does not seem to work with latest webpack version.