translations-loader.js 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. /*
  2. * Custom webpack loader for i18next locale JSON files.
  3. *
  4. * It extracts translations used in the frontend (based on the list of keys in
  5. * extracted-locales.json), and merges them with the fallback language (English)
  6. *
  7. * This means that we only load minimal translations data used in the frontend.
  8. */
  9. const fs = require('fs').promises
  10. const Path = require('path')
  11. const SOURCE_PATH = Path.join(__dirname, '../locales')
  12. const EXTRACTED_TRANSLATIONS_PATH = Path.join(
  13. __dirname,
  14. 'extracted-translations.json'
  15. )
  16. module.exports = function translationsLoader() {
  17. // Mark the loader as asynchronous, and get the done callback function
  18. const callback = this.async()
  19. // Mark the extracted keys file and English translations as a "dependency", so
  20. // that it gets watched for changes in dev
  21. this.addDependency(EXTRACTED_TRANSLATIONS_PATH)
  22. this.addDependency(`${SOURCE_PATH}/en.json`)
  23. const [, locale] = this.resourcePath.match(/(\w{2}(-\w{2})?)\.json$/)
  24. run(locale)
  25. .then(translations => {
  26. callback(null, JSON.stringify(translations))
  27. })
  28. .catch(err => callback(err))
  29. }
  30. async function run(locale) {
  31. const json = await fs.readFile(EXTRACTED_TRANSLATIONS_PATH)
  32. const keys = Object.keys(JSON.parse(json))
  33. const fallbackTranslations = await extract('en', keys)
  34. return extract(locale, keys, fallbackTranslations)
  35. }
  36. async function extract(locale, keys, fallbackTranslations = null) {
  37. const allTranslations = await getAllTranslations(locale)
  38. const extractedTranslations = extractByKeys(keys, allTranslations)
  39. return Object.assign({}, fallbackTranslations, extractedTranslations)
  40. }
  41. async function getAllTranslations(locale) {
  42. const content = await fs.readFile(Path.join(SOURCE_PATH, `${locale}.json`))
  43. return JSON.parse(content)
  44. }
  45. function extractByKeys(keys, translations) {
  46. return keys.reduce((acc, key) => {
  47. const foundString = translations[key]
  48. if (foundString) {
  49. acc[key] = foundString
  50. }
  51. return acc
  52. }, {})
  53. }