Skip to content

Commit 8d73f1b

Browse files
author
Brian Vaughn
committed
Added config validation and fixed language <> locale mapping
1 parent 5f2ef48 commit 8d73f1b

File tree

4 files changed

+49
-22
lines changed

4 files changed

+49
-22
lines changed

crowdin/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
__translations/
2+
translations/

crowdin/config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module.exports = {
22
key: process.env.CROWDIN_API_KEY,
33
url: 'https://api.crowdin.com/api/project/react',
4-
translation_threshold: 50,
4+
threshold: 50,
5+
downloadedRootDirectory: 'test-17',
56
};

crowdin/download.js

+43-18
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,43 @@ const {symlink, lstatSync, readdirSync} = require('fs');
55

66
const SYMLINKED_TRANSLATIONS_PATH = path.resolve(__dirname, 'translations');
77
const DOWNLOADED_TRANSLATIONS_PATH = path.resolve(__dirname, '__translations');
8-
const DOWNLOADED_TRANSLATIONS_DOCS_PATH = path.resolve(
8+
9+
const getDownloadedDocsPath = ({ downloadedRootDirectory }) => path.resolve(
910
__dirname,
1011
'__translations',
12+
downloadedRootDirectory,
1113
'docs',
1214
);
1315

16+
const validateConfig = ({ key, downloadedRootDirectory, threshold, url }) => {
17+
const errors = [];
18+
if (!key) {
19+
errors.push('key: No process.env.CROWDIN_API_KEY value defined.');
20+
}
21+
if (!Number.isInteger(threshold)) {
22+
errors.push(`threshold: Invalid translation threshold defined.`);
23+
}
24+
if (!downloadedRootDirectory) {
25+
errors.push('downloadedRootDirectory: No root directory defined for the downloaded translations bundle.');
26+
}
27+
if (!url) {
28+
errors.push('url: No Crowdin project URL defined.');
29+
}
30+
if (errors.length > 0) {
31+
console.error('Invalid Crowdin config values for:\n• ' + errors.join('\n• '));
32+
throw Error('Invalid Crowdin config');
33+
}
34+
};
35+
1436
function main() {
37+
validateConfig(config);
38+
1539
const crowdin = new Crowdin({apiKey: config.key, endpointUrl: config.url});
40+
1641
process.chdir(SYMLINKED_TRANSLATIONS_PATH);
1742

43+
const downloadedDocsPath = getDownloadedDocsPath(config);
44+
1845
crowdin
1946
// .export() // Not sure if this should be called in the script since it could be very slow
2047
// .then(() => crowdin.downloadToPath(DOWNLOADED_TRANSLATIONS_PATH))
@@ -23,34 +50,30 @@ function main() {
2350
.then(locales => {
2451
const usableLocales = locales
2552
.filter(
26-
locale => locale.translated_progress > config.translation_threshold,
53+
locale => locale.translated_progress > config.threshold,
2754
)
2855
.map(local => local.code);
2956

30-
const localeDirectories = getDirectories(
31-
DOWNLOADED_TRANSLATIONS_DOCS_PATH,
32-
);
33-
57+
const localeDirectories = getDirectories(downloadedDocsPath);
3458
const localeToFolderMap = createLocaleToFolderMap(localeDirectories);
3559

3660
usableLocales.forEach(locale => {
37-
createSymLink(localeToFolderMap.get(locale));
61+
createSymLink(downloadedDocsPath, localeToFolderMap.get(locale));
3862
});
3963
});
4064
}
4165

4266
// Creates a relative symlink from a downloaded translation in the current working directory
4367
// Note that the current working directory of this node process should be where the symlink is created
4468
// or else the relative paths would be incorrect
45-
function createSymLink(folder) {
46-
symlink(`../__translations/docs/${folder}`, folder, err => {
69+
function createSymLink(downloadedDocsPath, folder) {
70+
symlink(path.resolve(downloadedDocsPath, folder), folder, err => {
4771
if (!err) {
48-
console.log(`Created symlink for ${folder}.`);
4972
return;
5073
}
5174

5275
if (err.code === 'EEXIST') {
53-
console.log(
76+
console.info(
5477
`Skipped creating symlink for ${folder}. A symlink already exists.`,
5578
);
5679
} else {
@@ -60,19 +83,21 @@ function createSymLink(folder) {
6083
});
6184
}
6285

63-
// When we run getTranslationStatus(), it gives us 2-ALPHA locale codes unless necessary
64-
// However, the folder structure of downloaded translations always has 4-ALPHA locale codes
65-
// This function creates a map from a locale code to its corresponding folder name
86+
// When we run getTranslationStatus(), it typically gives us ISO 639-1 (e.g. "fr" for French) or 639-3 (e.g. "fil" for Filipino) language codes,
87+
// But the folder structure of downloaded translations uses locale codes (e.g. "fr-FR" for French, "fil-PH" for the Philippines).
88+
// This function creates a map between language and locale code.
6689
function createLocaleToFolderMap(directories) {
67-
const twoAlphaLocale = locale => locale.substring(0, 2);
90+
const localeToLanguageCode = locale => locale.includes('-') ? locale.substr(0, locale.indexOf('-')) : locale;
6891
const localeToFolders = new Map();
6992
const localeToFolder = new Map();
7093

7194
for (let locale of directories) {
95+
const languageCode = localeToLanguageCode(locale);
96+
7297
localeToFolders.set(
73-
twoAlphaLocale(locale),
74-
localeToFolders.has(twoAlphaLocale(locale))
75-
? localeToFolders.get(twoAlphaLocale(locale)).concat(locale)
98+
languageCode,
99+
localeToFolders.has(languageCode)
100+
? localeToFolders.get(languageCode).concat(locale)
76101
: [locale],
77102
);
78103
}

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,20 @@
7979
"build": "gatsby build",
8080
"check-all": "npm-run-all prettier --parallel lint flow",
8181
"ci-check": "npm-run-all prettier:diff --parallel lint flow",
82+
"crowdin:download": "node ./crowdin/download",
8283
"dev": "gatsby develop -H 0.0.0.0",
8384
"flow": "flow",
8485
"format:source": "prettier --config .prettierrc --write \"{gatsby-*.js,{flow-typed,plugins,src}/**/*.js}\"",
8586
"format:examples": "prettier --config .prettierrc.examples --write \"examples/**/*.js\"",
8687
"lint": "eslint .",
87-
"netlify": "yarn install && yarn translations && yarn build",
88+
"netlify": "yarn install && yarn crowdin:download && yarn build",
8889
"nit:source": "prettier --config .prettierrc --list-different \"{gatsby-*.js,{flow-typed,plugins,src}/**/*.js}\"",
8990
"nit:examples": "prettier --config .prettierrc.examples --list-different \"examples/**/*.js\"",
9091
"prettier": "yarn format:source && yarn format:examples",
9192
"prettier:diff": "yarn nit:source && yarn nit:examples",
9293
"reset": "yarn reset:cache && yarn reset:translations",
9394
"reset:cache": "rimraf ./.cache",
94-
"reset:translations": "rimraf ./crowdin/__translations && find crowdin/translations -type l -not -name '*en-US' -delete",
95-
"translations": "node ./crowdin/download"
95+
"reset:translations": "rimraf ./crowdin/__translations && find crowdin/translations -type l -not -name '*en-US' -delete"
9696
},
9797
"devDependencies": {
9898
"eslint-config-prettier": "^2.6.0",

0 commit comments

Comments
 (0)