Reimplement the pull command of the crowdin script

This commit is contained in:
ErickSkrauch
2020-05-26 19:22:21 +03:00
parent b5d1cb01d4
commit e47eaf720f
9 changed files with 220 additions and 148 deletions

View File

@ -3,7 +3,10 @@
import fs from 'fs';
import path from 'path';
import axios from 'axios';
import JSON5 from 'json5';
import CrowdinApi, { LanguageStatusNode, LanguageStatusResponse, ProjectInfoResponse } from 'crowdin-api';
import { TranslationStatus, Translations, Credentials } from '@crowdin/crowdin-api-client';
import MultiProgress from 'multi-progress';
import ch from 'chalk';
import iso639 from 'iso-639-1';
@ -18,7 +21,9 @@ if (!config.crowdinApiKey) {
process.exit(126);
}
const PROJECT_ID = 'elyby';
const ORGANIZATION_ID = 'elyby';
const PROJECT_ID = 350687;
const FILE_ID = 6;
const PROJECT_KEY = config.crowdinApiKey;
const CROWDIN_FILE_PATH = 'accounts/site.json';
const SOURCE_LANG = 'en';
@ -26,16 +31,22 @@ const LANG_DIR = path.resolve(`${__dirname}/../app/i18n`);
const INDEX_FILE_NAME = 'index.js';
const MIN_RELEASE_PROGRESS = 80; // Minimal ready percent before translation can be published
const credentials: Credentials = {
token: config.crowdinApiKey,
};
const translationStatusApi = new TranslationStatus(credentials);
const translationsApi = new Translations(credentials);
const crowdin = new CrowdinApi({
apiKey: PROJECT_KEY,
projectName: PROJECT_ID,
projectName: ORGANIZATION_ID,
});
const progressBar = new MultiProgress();
/**
* Locales that has been verified by core team members
*/
const RELEASED_LOCALES: Array<string> = ['be', 'fr', 'id', 'pt', 'ru', 'uk', 'vi', 'zh'];
const releasedLocales: Array<string> = ['be', 'fr', 'id', 'pt', 'ru', 'uk', 'vi', 'zh'];
/**
* Array of Crowdin locales to our internal locales representation
@ -80,7 +91,7 @@ function toInternalLocale(code: string): string {
* хранятся в самом приложении
*/
function serializeToModule(translates: Record<string, any>): string {
const src = JSON.stringify(sortByKeys(translates), null, 2);
const src = JSON5.stringify(sortByKeys(translates), null, 4);
return `module.exports = ${src};\n`;
}
@ -129,6 +140,70 @@ interface IndexFileEntry {
isReleased: boolean;
}
async function pullNew(): Promise<void> {
console.log('Pulling translation progress...');
const { data: translationProgress } = await translationStatusApi.getFileProgress(PROJECT_ID, FILE_ID, 100);
const localesToPull: Array<string> = [];
const indexFileEntries: Record<string, IndexFileEntry> = {
en: {
code: 'en',
name: 'English',
englishName: 'English',
progress: 100,
isReleased: true,
},
};
translationProgress.forEach(({ data: { languageId, approvalProgress } }) => {
const locale = toInternalLocale(languageId);
if (releasedLocales.includes(locale) || approvalProgress >= MIN_RELEASE_PROGRESS) {
localesToPull.push(languageId);
indexFileEntries[locale] = {
code: locale,
name: NATIVE_NAMES_MAP[locale] || iso639.getNativeName(locale),
englishName: ENGLISH_NAMES_MAP[locale] || iso639.getName(locale),
progress: approvalProgress,
isReleased: releasedLocales.includes(locale),
};
}
});
// Add prefix 'c' to current and total to prevent filling thees placeholders with real values
const downloadingProgressBar = progressBar.newBar('Downloading translates :bar :percent | :cCurrent/:total', {
total: localesToPull.length,
incomplete: '\u2591',
complete: '\u2588',
width: Object.keys(indexFileEntries).length - 1,
});
let downloadingReady = 0;
const promises = localesToPull.map(async (languageId): Promise<void> => {
const { data: { url } } = await translationsApi.buildProjectFileTranslation(PROJECT_ID, FILE_ID, {
targetLanguageId: languageId,
exportApprovedOnly: true,
});
const fileResponse = await axios.get(url, {
// Disable response parsing
transformResponse: [],
});
fs.writeFileSync(path.join(LANG_DIR, `${toInternalLocale(languageId)}.json`), fileResponse.data);
downloadingProgressBar.update(++downloadingReady / localesToPull, {
cCurrent: downloadingReady,
});
});
await Promise.all(promises);
console.log('Writing an index file');
fs.writeFileSync(path.join(LANG_DIR, INDEX_FILE_NAME), serializeToModule(indexFileEntries));
console.log(ch.green('The index file was successfully written'));
}
async function pull() {
console.log('Pulling locales list...');
const locales = await pullLocales();
@ -169,7 +244,7 @@ async function pull() {
const progress = (fileInfo.words_approved / fileInfo.words) * 100;
if (!RELEASED_LOCALES.includes(toInternalLocale(locale.code)) && progress < MIN_RELEASE_PROGRESS) {
if (!releasedLocales.includes(toInternalLocale(locale.code)) && progress < MIN_RELEASE_PROGRESS) {
return null;
}
@ -196,7 +271,7 @@ async function pull() {
console.log('Locales are downloaded. Writing them to file system.');
const indexFileEntries: { [key: string]: IndexFileEntry } = {
const indexFileEntries: Record<string, IndexFileEntry> = {
en: {
code: 'en',
name: 'English',
@ -223,7 +298,7 @@ async function pull() {
name: NATIVE_NAMES_MAP[ourCode] || iso639.getNativeName(ourCode),
englishName: ENGLISH_NAMES_MAP[ourCode] || name,
progress: parseFloat(progress.toFixed(1)),
isReleased: RELEASED_LOCALES.includes(ourCode),
isReleased: releasedLocales.includes(ourCode),
};
fs.copyFile(translatesFilePath, path.join(LANG_DIR, `${ourCode}.json`), 0, (err) => {
@ -286,7 +361,7 @@ try {
switch (action) {
case 'pull':
pull();
pullNew();
break;
case 'push':
push();

View File

@ -11,15 +11,18 @@
"license": "ISC",
"dependencies": {
"@babel/node": "^7.8.3",
"@crowdin/crowdin-api-client": "^1.8.0",
"@types/mkdirp": "^1.0.0",
"@types/progress": "^2.0.3",
"axios": "^0.19.2",
"chalk": "^4.0.0",
"crowdin-api": "^4.0.0",
"glob": "^7.1.6",
"iso-639-1": "^2.1.3",
"json5": "^2.1.3",
"mkdirp": "^1.0.4",
"multi-progress": "^2.0.0",
"prompt": "^1.0.0",
"prompt": "https://github.com/flatiron/prompt.git#master",
"utility-types": "^3.10.0"
},
"devDependencies": {