123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- /**
- * This script will extract the internationalization messages from all components
- and package them in the translation json files in the translations file.
- */
- require('shelljs/global')
- const fs = require('fs')
- const nodeGlob = require('glob')
- const { transform } = require('@babel/core')
- const get = require('lodash/get')
- const animateProgress = require('./helpers/progress')
- const addCheckmark = require('./helpers/checkmark')
- const { appLocales, DEFAULT_LOCALE } = require('../../app/i18n')
- const babel = require('../../babel.config.js')
- const { presets } = babel
- let plugins = babel.plugins || []
- plugins.push('react-intl')
- // Glob to match all js files except test files
- const FILES_TO_PARSE = 'app/**/!(*.test).js'
- const newLine = () => process.stdout.write('\n')
- // Progress Logger
- let progress
- const task = (message) => {
- progress = animateProgress(message)
- process.stdout.write(message)
- return (error) => {
- if (error) {
- process.stderr.write(error)
- }
- clearTimeout(progress)
- return addCheckmark(() => newLine())
- }
- }
- // Wrap async functions below into a promise
- const glob = (pattern) =>
- new Promise((resolve, reject) => {
- nodeGlob(
- pattern,
- (error, value) => (error ? reject(error) : resolve(value))
- )
- })
- const readFile = (fileName) =>
- new Promise((resolve, reject) => {
- fs.readFile(
- fileName,
- 'utf8',
- (error, value) => (error ? reject(error) : resolve(value))
- )
- })
- // Store existing translations into memory
- const oldLocaleMappings = []
- const localeMappings = []
- // Loop to run once per locale
- for (const locale of appLocales) {
- oldLocaleMappings[locale] = {}
- localeMappings[locale] = {}
- // File to store translation messages into
- const translationFileName = `app/translations/${locale}.json`
- try {
- // Parse the old translation message JSON files
- const messages = JSON.parse(fs.readFileSync(translationFileName))
- const messageKeys = Object.keys(messages)
- for (const messageKey of messageKeys) {
- oldLocaleMappings[locale][messageKey] = messages[messageKey]
- }
- } catch (error) {
- if (error.code !== 'ENOENT') {
- process.stderr.write(
- `There was an error loading this translation file: ${translationFileName}
- \n${error}`
- )
- }
- }
- }
- const extractFromFile = async filename => {
- try {
- const code = await readFile(filename)
- const output = await transform(code, { filename, presets, plugins })
- const messages = get(output, 'metadata.react-intl.messages', [])
- for (const message of messages) {
- for (const locale of appLocales) {
- const oldLocaleMapping = oldLocaleMappings[locale][message.id]
- // Merge old translations into the babel extracted instances where react-intl is used
- const newMsg = locale === DEFAULT_LOCALE ? message.defaultMessage : ''
- localeMappings[locale][message.id] = oldLocaleMapping || newMsg
- }
- }
- } catch (error) {
- process.stderr.write(`\nError transforming file: ${filename}\n${error}\n`)
- }
- }
- const memoryTask = glob(FILES_TO_PARSE)
- const memoryTaskDone = task('Storing language files in memory')
- memoryTask.then(files => {
- memoryTaskDone()
- const extractTask = Promise.all(
- files.map(fileName => extractFromFile(fileName)),
- )
- const extractTaskDone = task('Run extraction on all files')
- // Run extraction on all files that match the glob on line 16
- extractTask.then(result => {
- extractTaskDone()
- // Make the directory if it doesn't exist, especially for first run
- mkdir('-p', 'app/translations')
- let localeTaskDone
- let translationFileName
- for (const locale of appLocales) {
- translationFileName = `app/translations/${locale}.json`
- localeTaskDone = task(
- `Writing translation messages for ${locale} to: ${translationFileName}`
- )
- // Sort the translation JSON file so that git diffing is easier
- // Otherwise the translation messages will jump around every time we extract
- const messages = {}
- Object.keys(localeMappings[locale])
- .sort()
- .forEach((key) => {
- messages[key] = localeMappings[locale][key]
- })
- // Write to file the JSON representation of the translation messages
- const prettified = `${JSON.stringify(messages, null, 2)}\n`
- try {
- fs.writeFileSync(translationFileName, prettified)
- localeTaskDone()
- } catch (error) {
- localeTaskDone(
- `There was an error saving this translation file: ${translationFileName}
- \n${error}`,
- )
- }
- }
- process.exit()
- })
- })
|