diff --git a/package.json b/package.json index 4d2ad44..88aa9df 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "start": "rm -rf dist/ && webpack-dev-server --progress --colors", "lint": "eslint ./src", "i18n": "cd ./scripts && ../node_modules/.bin/babel-node i18n-collect.js", - "build": "rm -rf dist/ && NODE_ENV=production webpack --progress --colors" + "build": "rm -rf dist/ && NODE_ENV=production webpack --progress --colors", + "i18n:pull": "cd ./scripts && ../node_modules/.bin/babel-node --presets es2015,stage-0 i18n-onesky.js pull" }, "dependencies": { "babel-polyfill": "^6.3.14", @@ -32,6 +33,7 @@ "react-intl": "^2.0.0" }, "devDependencies": { + "babel-cli": "^6.18.0", "babel-core": "^6.0.0", "babel-eslint": "^6.0.0", "babel-loader": "^6.0.0", diff --git a/scripts/.babelrc b/scripts/.babelrc deleted file mode 100644 index 0522a89..0000000 --- a/scripts/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "breakConfig": true -} diff --git a/scripts/i18n-onesky.js b/scripts/i18n-onesky.js new file mode 100644 index 0000000..f978a00 --- /dev/null +++ b/scripts/i18n-onesky.js @@ -0,0 +1,149 @@ +/* eslint-env node */ +/* eslint-disable no-console */ + +import onesky from 'onesky-utils'; +import fs from 'fs'; +import ch from 'chalk'; + +const LANG_DIR = `${__dirname}/../src/i18n`; +const SOURCE_LANG = 'en'; // Базовый язык, относительно которого будут формироваться все остальные переводы +const SOURCE_FILE_NAME = 'i18n.json'; // Название файла с исходными строками внутри OneSky +const INDEX_FILE_NAME = 'index.json'; // Название файла с информацией о переводах +const MIN_RELEASE_PROGRESS = 80; // Какой процент локали перевода должен быть выполнен, чтобы локаль была опубликована + +/** + * Массив локалей для соответствия каноничному виду в OneSky и нашему представлению + * о том, каким должны быть имена локалей + */ +const LOCALES_MAP = { + ru: 'ru-RU', + en: 'en-GB', + sl: 'sl-SI', + fr: 'fr-FR', + el: 'el-GR', + de: 'de-DE', + sr: 'sr-RS', +}; + +// https://ely-translates.oneskyapp.com/admin/site/settings +const defaultOptions = { + apiKey: '5MaW9TYp0S3qdJgkZ5QLgEIDeabkFDzB', + secret: 'qd075hUNpop4DItD6KOXKQnbqWPLZilf', + projectId: 202784, +}; + +/** + * Переводит из кода языка в OneSky в наше представление + * + * @param {string} code + * @return {string} + */ +function code2locale(code) { + for (const locale in LOCALES_MAP) { + if (code === LOCALES_MAP[locale]) { + return locale; + } + } + + return code; +} + +/** + * Переводит из нашего формата локалей в ожидаемое значение OneSky + * + * @param {string} locale + * @return {string} + */ +function locale2code(locale) { + return LOCALES_MAP[locale] || locale; +} + +/** + * Форматирует входящий объект с переводами в итоговую строку в том формате, в каком они + * хранятся в самом приложении + * + * @param {object} translates + * @return {string} + */ +function formatTranslates(translates) { + return JSON.stringify(sortByKeys(translates), null, 4) + '\n'; // eslint-disable-line prefer-template +} + +/** + * http://stackoverflow.com/a/29622653/5184751 + * + * @param {object} object + * @return {object} + */ +function sortByKeys(object) { + return Object.keys(object).sort().reduce((result, key) => { + result[key] = object[key]; + return result; + }, {}); +} + +async function pullReadyLanguages() { + const languages = JSON.parse(await onesky.getLanguages({...defaultOptions})); + return languages.data + .filter((elem) => elem.is_ready_to_publish || parseFloat(elem.translation_progress) > MIN_RELEASE_PROGRESS); +} + +async function pullTranslate(language) { + const rawResponse = await onesky.getFile({...defaultOptions, language, fileName: SOURCE_FILE_NAME}); + const response = JSON.parse(rawResponse); + fs.writeFileSync(`${LANG_DIR}/${code2locale(language)}.json`, formatTranslates(response)); +} + +async function pull() { + console.log('Pulling locales list...'); + const langs = await pullReadyLanguages(); + const langsList = langs.map((elem) => elem.custom_locale || elem.code); + + console.log(ch.green('Pulled locales: ') + langsList.map((lang) => code2locale(lang)).join(', ')); + + console.log('Pulling translates...'); + await Promise.all(langsList.map(async (lang) => { + await pullTranslate(lang); + console.log(ch.green('Locale ') + ch.white.bold(code2locale(lang)) + ch.green(' successfully pulled')); + })); + + console.log('Writing an index file...'); + const mapFileContent = {}; + langs.map((elem) => { + mapFileContent[elem.locale] = { + name: elem.local_name.match(/^([^\(]+)/)[0].trim(), // Обрезаем значения в скобках + progress: parseFloat(elem.translation_progress), + }; + }); + fs.writeFileSync(`${LANG_DIR}/${INDEX_FILE_NAME}`, formatTranslates(mapFileContent)); + console.log(ch.green('The index file was successfully written')); +} + +async function publish() { + console.log(`Publishing ${ch.bold(SOURCE_LANG)} translates file...`); + await onesky.postFile({ + ...defaultOptions, + format: 'HIERARCHICAL_JSON', + content: fs.readFileSync(`${LANG_DIR}/${SOURCE_LANG}.json`, 'utf8'), + keepStrings: false, + language: locale2code(SOURCE_LANG), + fileName: SOURCE_FILE_NAME, + }); + console.log(ch.green('Success')); +} + +try { + const action = process.argv[2]; + switch (action) { + case 'pull': + pull(); + break; + case 'publish': + publish(); + break; + default: + throw new Error(`Unknown action ${action}`); + } +} catch (exception) { + console.error(exception); +} diff --git a/scripts/package.json b/scripts/package.json index 25bea1e..8919fb4 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -12,6 +12,7 @@ "dependencies": { "chalk": "^1.1.3", "node-babel": "^0.1.2", - "prompt": "^1.0.0" + "prompt": "^1.0.0", + "onesky-utils": "erickskrauch/nodejs-onesky-utils#locales_list" } } diff --git a/src/constants.js b/src/constants.js index fa02904..0c452b9 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,2 +1,4 @@ -export const SUPPORTED_LANGUAGES = ['be', 'en', 'ru', 'pt', 'uk']; +import LOCALES from 'i18n/index.json'; + +export const SUPPORTED_LANGUAGES = Object.keys(LOCALES); export const DEFAULT_LANGUAGE = 'en'; diff --git a/src/i18n/index.json b/src/i18n/index.json new file mode 100644 index 0000000..7ffc4ef --- /dev/null +++ b/src/i18n/index.json @@ -0,0 +1,22 @@ +{ + "be": { + "name": "Беларуская", + "progress": 100 + }, + "en": { + "name": "English", + "progress": 100 + }, + "pt": { + "name": "Português", + "progress": 100 + }, + "ru": { + "name": "Русский", + "progress": 100 + }, + "uk": { + "name": "Українська", + "progress": 100 + } +}