This repository has been archived by the owner on Mar 1, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
intl+babel makes translation easier by collecting translatable pieces…
… in the code
- Loading branch information
Showing
8 changed files
with
278 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
{ | ||
"presets": [ "es2015" ] | ||
"presets": [ | ||
"es2015", | ||
"stage-0", | ||
"react" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* eslint-disable */ | ||
/** | ||
* This script will extract the internationalization messages from all components | ||
and package them in the transalation json files in the translations file. | ||
*/ | ||
const fs = require('fs'); | ||
const nodeGlob = require('glob'); | ||
const transform = require('babel-core').transform; | ||
|
||
const animateProgress = require('./helpers/progress'); | ||
const addCheckmark = require('./helpers/checkmark'); | ||
|
||
const pkg = require('../package.json'); | ||
const i18n = require('../imports/i18n.js'); | ||
|
||
require('shelljs/global'); | ||
|
||
// Glob to match all js files except test files | ||
const FILES_TO_PARSE = 'imports/**/*.jsx' | ||
// 'imports/client/**/*.jsx!(*.test).js!(*.spec).js!imports/client/helpers'; | ||
const DEST_FOLDER = 'i18n' | ||
const locales = i18n.appLocales; | ||
|
||
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, (error, value) => (error ? reject(error) : resolve(value))); | ||
}); | ||
|
||
const writeFile = (fileName, data) => new Promise((resolve, reject) => { | ||
fs.writeFile(fileName, data, (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 locales) { | ||
oldLocaleMappings[locale] = {}; | ||
localeMappings[locale] = {}; | ||
// File to store translation messages into | ||
const translationFileName = `${DEST_FOLDER}/${locale}.json`; | ||
try { | ||
// Parse the old translation message JSON files | ||
const messages = JSON.parse(fs.readFileSync(translationFileName)); | ||
for (const message of messages) { | ||
oldLocaleMappings[locale][message.id] = message; | ||
} | ||
} 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); | ||
// Use babel plugin to extract instances where react-intl is used | ||
const { metadata: result } = await transform(code, { | ||
presets: pkg.babel.presets, | ||
plugins: [ | ||
['react-intl'], | ||
], | ||
}); | ||
|
||
|
||
for (const message of result['react-intl'].messages) { | ||
for (const locale of locales) { | ||
const oldLocaleMapping = oldLocaleMappings[locale][message.id]; | ||
// Merge old translations into the babel extracted instances where react-intl is used | ||
localeMappings[locale][message.id] = { | ||
id: message.id, | ||
description: message.description, | ||
defaultMessage: message.defaultMessage, | ||
message: (oldLocaleMapping && oldLocaleMapping.message) | ||
? oldLocaleMapping.message | ||
: '', | ||
}; | ||
} | ||
} | ||
} catch (error) { | ||
process.stderr.write(`Error transforming file: ${fileName}\n${error}`); | ||
} | ||
}; | ||
|
||
(async function main() { | ||
const memoryTaskDone = task('Storing language files in memory'); | ||
const files = await glob(FILES_TO_PARSE); | ||
memoryTaskDone() | ||
|
||
const extractTaskDone = task('Run extraction on all files') | ||
// Run extraction on all files that match the glob on line 16 | ||
await Promise.all(files.map((fileName) => extractFromFile(fileName))); | ||
extractTaskDone() | ||
|
||
// Make the directory if it doesn't exist, especially for first run | ||
mkdir('-p', DEST_FOLDER); | ||
for (const locale of locales) { | ||
const translationFileName = `${DEST_FOLDER}/${locale}.json`; | ||
try { | ||
const 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 | ||
let messages = Object.values(localeMappings[locale]).sort((a, b) => { | ||
a = a.id.toUpperCase(); | ||
b = b.id.toUpperCase(); | ||
return do { | ||
if (a < b) -1; | ||
else if (a > b) 1; | ||
else 0; | ||
}; | ||
}); | ||
|
||
// Write to file the JSON representation of the translation messages | ||
const prettified = `${JSON.stringify(messages, null, 2)}\n`; | ||
|
||
await writeFile(translationFileName, prettified); | ||
|
||
localeTaskDone(); | ||
} catch (error) { | ||
localeTaskDone( | ||
`There was an error saving this translation file: ${translationFileName} | ||
\n${error}` | ||
); | ||
} | ||
} | ||
|
||
process.exit() | ||
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
var chalk = require('chalk'); | ||
|
||
/** | ||
* Adds mark check symbol | ||
*/ | ||
function addCheckMark(callback) { | ||
process.stdout.write(chalk.green(' ✓')); | ||
callback(); | ||
} | ||
|
||
module.exports = addCheckMark; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
var readline = require('readline'); | ||
|
||
/** | ||
* Adds an animated progress indicator | ||
* | ||
* @param {string} message The message to write next to the indicator | ||
* @param {number} amountOfDots The amount of dots you want to animate | ||
*/ | ||
function animateProgress(message, amountOfDots) { | ||
if (typeof amountOfDots !== 'number') { | ||
amountOfDots = 3; | ||
} | ||
|
||
var i = 0; | ||
return setInterval(function () { | ||
readline.cursorTo(process.stdout, 0); | ||
i = (i + 1) % (amountOfDots + 1); | ||
var dots = new Array(i + 1).join('.'); | ||
process.stdout.write(message + dots); | ||
}, 500); | ||
} | ||
|
||
module.exports = animateProgress; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
[ | ||
{ | ||
"id": "home.browseTopograms", | ||
"defaultMessage": "Browse publics topograms", | ||
"message": "Consulter les topograms publics" | ||
}, | ||
{ | ||
"id": "home.subtitle", | ||
"defaultMessage": "An open-source toolkit to process, visualize and analyze networks.", | ||
"message": "Un outil open-source pour créer,visualiser et analyser des réseaux." | ||
}, | ||
{ | ||
"id": "home.tagline", | ||
"defaultMessage": "Social Network Analysis for humans.", | ||
"message": "L'analyse de réseaux sociaux enfin à la portée des humains." | ||
}, | ||
{ | ||
"id": "topogram.addForm.hint", | ||
"defaultMessage": "Input a name", | ||
"message": "Entrer un nom" | ||
}, | ||
{ | ||
"id": "topogram.addForm.label", | ||
"defaultMessage": "Create a new Topogram", | ||
"message": "Créer un nouveau topogram" | ||
}, | ||
{ | ||
"id": "topogram.deleteDialog.button.cancel", | ||
"defaultMessage": "Cancel", | ||
"message": "Annuler" | ||
}, | ||
{ | ||
"id": "topogram.deleteDialog.button.delete", | ||
"defaultMessage": "Delete", | ||
"message": "Supprimer" | ||
}, | ||
{ | ||
"id": "topogram.index.card.button.browse", | ||
"defaultMessage": "Browse", | ||
"message": "Voir" | ||
}, | ||
{ | ||
"id": "topogram.index.card.button.data", | ||
"defaultMessage": "Data", | ||
"message": "Données" | ||
}, | ||
{ | ||
"id": "topogram.index.card.deleteDialog.confirmQuestion", | ||
"defaultMessage": "Are you sure you want to delete this topogram ?", | ||
"message": "Êtes-vous sûr de vouloir supprimer ce topogram ?" | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters