mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-13 21:02:08 +08:00
chore: remove crowdin scripts (#49374)
This commit is contained in:
parent
b5fcc389f0
commit
26367a17c7
1
.github/labeler.yml
vendored
1
.github/labeler.yml
vendored
@ -23,4 +23,3 @@
|
||||
- client/i18n/**/*
|
||||
- config/crowdin/**/*
|
||||
- config/i18n/**/*
|
||||
- tools/crowdin/**/*
|
||||
|
||||
388
package-lock.json
generated
388
package-lock.json
generated
@ -19,7 +19,6 @@
|
||||
"tools/challenge-editor/client",
|
||||
"tools/challenge-helper-scripts",
|
||||
"tools/challenge-parser",
|
||||
"tools/crowdin",
|
||||
"tools/scripts/build",
|
||||
"tools/scripts/seed",
|
||||
"tools/ui-components"
|
||||
@ -702,38 +701,6 @@
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.10.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/github": {
|
||||
"version": "5.1.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@octokit/core": "^3.6.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
"version": "4.0.1",
|
||||
"license": "MIT"
|
||||
@ -3272,10 +3239,6 @@
|
||||
"resolved": "client",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@freecodecamp/crowdin": {
|
||||
"resolved": "tools/crowdin",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@freecodecamp/curriculum": {
|
||||
"resolved": "curriculum",
|
||||
"link": true
|
||||
@ -4946,111 +4909,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "3.6.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.3",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint/node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "11.2.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "2.17.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.34.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=2"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.13.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.34.0",
|
||||
"deprecation": "^2.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "5.6.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request/node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "6.34.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^11.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
|
||||
"version": "0.4.3",
|
||||
"license": "MIT",
|
||||
@ -17982,10 +17840,6 @@
|
||||
"version": "2.4.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/better-opn": {
|
||||
"version": "2.1.1",
|
||||
"license": "MIT",
|
||||
@ -22030,10 +21884,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/deps-sort": {
|
||||
"version": "2.0.1",
|
||||
"license": "MIT",
|
||||
@ -38651,13 +38501,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-opencc": {
|
||||
"version": "2.0.1",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 7.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.6",
|
||||
"license": "MIT"
|
||||
@ -40516,14 +40359,6 @@
|
||||
"which": "bin/which"
|
||||
}
|
||||
},
|
||||
"node_modules/path": {
|
||||
"version": "0.12.7",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"process": "^0.11.1",
|
||||
"util": "^0.10.3"
|
||||
}
|
||||
},
|
||||
"node_modules/path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"license": "MIT"
|
||||
@ -40581,17 +40416,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path/node_modules/inherits": {
|
||||
"version": "2.0.3",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/path/node_modules/util": {
|
||||
"version": "0.10.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/pathval": {
|
||||
"version": "1.1.1",
|
||||
"license": "MIT",
|
||||
@ -50289,13 +50113,6 @@
|
||||
"integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"license": "Apache-2.0",
|
||||
@ -50841,10 +50658,6 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
@ -54282,38 +54095,6 @@
|
||||
"unist-util-stringify-position": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"tools/crowdin": {
|
||||
"name": "@freecodecamp/crowdin",
|
||||
"version": "0.0.1",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@actions/core": "1.10.0",
|
||||
"@actions/github": "5.1.1",
|
||||
"dotenv": "16.0.3",
|
||||
"fs-extra": "10.0.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"node-fetch": "2.6.9",
|
||||
"node-opencc": "2.0.1",
|
||||
"path": "0.12.7",
|
||||
"readdirp": "3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16",
|
||||
"npm": ">=8"
|
||||
}
|
||||
},
|
||||
"tools/crowdin/node_modules/fs-extra": {
|
||||
"version": "10.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"tools/scripts/build": {
|
||||
"name": "@freecodecamp/scripts-build",
|
||||
"version": "0.0.1",
|
||||
@ -54447,33 +54228,6 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": {
|
||||
"version": "1.10.0",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "8.3.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@actions/github": {
|
||||
"version": "5.1.1",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@octokit/core": "^3.6.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
||||
}
|
||||
},
|
||||
"@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"@adobe/css-tools": {
|
||||
"version": "4.0.1"
|
||||
},
|
||||
@ -56515,30 +56269,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@freecodecamp/crowdin": {
|
||||
"version": "file:tools/crowdin",
|
||||
"requires": {
|
||||
"@actions/core": "1.10.0",
|
||||
"@actions/github": "5.1.1",
|
||||
"dotenv": "16.0.3",
|
||||
"fs-extra": "10.0.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"node-fetch": "2.6.9",
|
||||
"node-opencc": "2.0.1",
|
||||
"path": "0.12.7",
|
||||
"readdirp": "3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": {
|
||||
"version": "10.0.0",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@freecodecamp/curriculum": {
|
||||
"version": "file:curriculum",
|
||||
"requires": {
|
||||
@ -57801,91 +57531,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "3.6.0",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.3",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"requires": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "11.2.0"
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.17.0",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.34.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.13.0",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.34.0",
|
||||
"deprecation": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "5.6.3",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "6.34.0",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^11.2.0"
|
||||
}
|
||||
},
|
||||
"@pmmmwh/react-refresh-webpack-plugin": {
|
||||
"version": "0.4.3",
|
||||
"requires": {
|
||||
@ -67305,9 +66950,6 @@
|
||||
"bcryptjs": {
|
||||
"version": "2.4.3"
|
||||
},
|
||||
"before-after-hook": {
|
||||
"version": "2.2.2"
|
||||
},
|
||||
"better-opn": {
|
||||
"version": "2.1.1",
|
||||
"requires": {
|
||||
@ -70066,9 +69708,6 @@
|
||||
"depd": {
|
||||
"version": "1.1.2"
|
||||
},
|
||||
"deprecation": {
|
||||
"version": "2.3.1"
|
||||
},
|
||||
"deps-sort": {
|
||||
"version": "2.0.1",
|
||||
"requires": {
|
||||
@ -81047,9 +80686,6 @@
|
||||
"node-object-hash": {
|
||||
"version": "2.3.10"
|
||||
},
|
||||
"node-opencc": {
|
||||
"version": "2.0.1"
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.6"
|
||||
},
|
||||
@ -82247,24 +81883,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": {
|
||||
"version": "0.12.7",
|
||||
"requires": {
|
||||
"process": "^0.11.1",
|
||||
"util": "^0.10.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "2.0.3"
|
||||
},
|
||||
"util": {
|
||||
"version": "0.10.4",
|
||||
"requires": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"path-browserify": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
@ -88378,9 +87996,6 @@
|
||||
"integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
|
||||
"dev": true
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6"
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"requires": {
|
||||
@ -88719,9 +88334,6 @@
|
||||
"unist-util-is": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.0"
|
||||
},
|
||||
"universalify": {
|
||||
"version": "2.0.0"
|
||||
},
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
"tools/challenge-editor/client",
|
||||
"tools/challenge-helper-scripts",
|
||||
"tools/challenge-parser",
|
||||
"tools/crowdin",
|
||||
"tools/scripts/build",
|
||||
"tools/scripts/seed",
|
||||
"tools/ui-components"
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
name: 'Translate Simplified Chinese to Traditional'
|
||||
description: 'Converts Simplified Chinese characters to Traditional Chinese Characters'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: './index.js'
|
||||
@ -1,41 +0,0 @@
|
||||
/* eslint-disable import/no-unresolved */
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
const opencc = require('node-opencc');
|
||||
|
||||
const getFiles = async (directory, fileList = []) => {
|
||||
const files = await fs.readdir(directory);
|
||||
for (const file of files) {
|
||||
const fileStat = await fs.stat(path.join(directory, file));
|
||||
if (fileStat.isDirectory()) {
|
||||
fileList = await getFiles(path.join(directory, file), fileList);
|
||||
} else {
|
||||
fileList.push(path.join(directory, file));
|
||||
}
|
||||
}
|
||||
return fileList;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
console.info('Getting file list...');
|
||||
const fileList = [];
|
||||
const curriculum = await getFiles(
|
||||
path.join(__dirname, '/../../../../curriculum/challenges/chinese')
|
||||
);
|
||||
fileList.push(...curriculum);
|
||||
|
||||
const client = await getFiles(
|
||||
path.join(__dirname, '/../../../../client/i18n/locales/chinese')
|
||||
);
|
||||
fileList.push(...client);
|
||||
|
||||
for (const file of fileList) {
|
||||
console.info(`Translating ${file}`);
|
||||
const fileText = await fs.readFile(file, 'utf-8');
|
||||
const translatedText = await opencc.simplifiedToTraditional(fileText);
|
||||
await fs.outputFile(
|
||||
file.replace('chinese', 'chinese-traditional'),
|
||||
translatedText
|
||||
);
|
||||
}
|
||||
})();
|
||||
@ -1,5 +0,0 @@
|
||||
name: 'Hide Non-Translated Strings'
|
||||
description: "Updates each file's non-translatable string to Hidden"
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: './index.js'
|
||||
@ -1,62 +0,0 @@
|
||||
require('dotenv').config({ path: `${__dirname}/../../.env` });
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const matter = require('gray-matter');
|
||||
const { getFiles } = require('../../utils/files');
|
||||
const { getStrings, updateFileString } = require('../../utils/strings');
|
||||
|
||||
const createChallengeTitleLookup = (
|
||||
lookup,
|
||||
{ fileId, path: crowdinFilePath }
|
||||
) => {
|
||||
const challengeFilePath = path.join(
|
||||
__dirname,
|
||||
'/../../../../',
|
||||
crowdinFilePath
|
||||
);
|
||||
try {
|
||||
const challengeContent = fs.readFileSync(challengeFilePath);
|
||||
const {
|
||||
data: { title: challengeTitle }
|
||||
} = matter(challengeContent);
|
||||
return {
|
||||
...lookup,
|
||||
[fileId]: {
|
||||
crowdinFilePath,
|
||||
challengeTitle
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
console.log(err.name);
|
||||
console.log(err.message);
|
||||
}
|
||||
return lookup;
|
||||
};
|
||||
|
||||
const hideNonTranslatedStrings = async projectId => {
|
||||
console.log('hide non-translated strings...');
|
||||
const crowdinFiles = await getFiles(projectId);
|
||||
if (crowdinFiles && crowdinFiles.length) {
|
||||
const challengeTitleLookup = crowdinFiles.reduce(
|
||||
createChallengeTitleLookup,
|
||||
{}
|
||||
);
|
||||
const crowdinStrings = await getStrings({ projectId });
|
||||
if (crowdinStrings && crowdinStrings.length) {
|
||||
for (let string of crowdinStrings) {
|
||||
const { crowdinFilePath, challengeTitle } =
|
||||
challengeTitleLookup[string.data.fileId];
|
||||
await updateFileString({
|
||||
projectId,
|
||||
string,
|
||||
challengeTitle,
|
||||
crowdinFilePath
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('complete');
|
||||
};
|
||||
|
||||
const projectId = process.env.CROWDIN_PROJECT_ID;
|
||||
hideNonTranslatedStrings(projectId);
|
||||
@ -1,12 +0,0 @@
|
||||
name: 'Hide Specific String'
|
||||
description: 'Updates a specific string to be hidden'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: './index.js'
|
||||
inputs:
|
||||
filename:
|
||||
description: 'name of file with specific string to hide'
|
||||
required: true
|
||||
string-content:
|
||||
description: 'text content of string to hide'
|
||||
required: true
|
||||
@ -1,34 +0,0 @@
|
||||
require('dotenv').config({ path: `${__dirname}/../../.env` });
|
||||
const core = require('@actions/core');
|
||||
const { getFiles } = require('../../utils/files');
|
||||
const { getStrings, changeHiddenStatus } = require('../../utils/strings');
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
|
||||
const filename = core.getInput('filename');
|
||||
const stringContent = core.getInput('string-content');
|
||||
|
||||
const hideString = async (projectId, fileName, string) => {
|
||||
const fileResponse = await getFiles(projectId);
|
||||
const targetFile = fileResponse.find(el => el.path.endsWith(filename));
|
||||
if (!targetFile) {
|
||||
core.setFailed(`${fileName} was not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const stringResponse = await getStrings({
|
||||
projectId,
|
||||
fileId: targetFile.fileId
|
||||
});
|
||||
|
||||
const targetString = stringResponse.find(el => el.data.text === string);
|
||||
if (!targetString) {
|
||||
core.setFailed(`${string} was not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
await changeHiddenStatus(projectId, targetString.data.id, true);
|
||||
console.log('string hidden!');
|
||||
};
|
||||
|
||||
const projectId = process.env.CROWDIN_PROJECT_ID;
|
||||
hideString(projectId, filename, stringContent);
|
||||
@ -1,37 +0,0 @@
|
||||
name: 'Create Crowdin PRs'
|
||||
description: 'Creates a PR by camperbot for Crowdin translation downloads'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: './index.js'
|
||||
inputs:
|
||||
github-token:
|
||||
description: 'PAT with write access to create PRs'
|
||||
required: true
|
||||
branch:
|
||||
description: 'Branch name to which commits are made'
|
||||
required: true
|
||||
owner-repo:
|
||||
description: 'owner and repo name specified as ownerName/repoName'
|
||||
required: true
|
||||
base:
|
||||
description: 'base branch name'
|
||||
default: 'main'
|
||||
required: true
|
||||
title:
|
||||
description: 'PR title'
|
||||
required: true
|
||||
body:
|
||||
description: 'PR body text'
|
||||
required: true
|
||||
labels:
|
||||
description: 'PR labels'
|
||||
required: false
|
||||
reviewers:
|
||||
description: 'Requested PR reviewers'
|
||||
required: false
|
||||
team_reviewers:
|
||||
# Note that this should be a slug, not a full tag
|
||||
# So a requested review from @freeCodeCamp/dev-team
|
||||
# Should be passed only as 'dev-team'
|
||||
description: 'Requested organization team PR reviewers'
|
||||
required: false
|
||||
@ -1,101 +0,0 @@
|
||||
/* eslint-disable import/no-unresolved */
|
||||
/* eslint-disable camelcase */
|
||||
const core = require('@actions/core');
|
||||
const githubRoot = require('@actions/github');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const token = core.getInput('github-token');
|
||||
const branch = core.getInput('branch');
|
||||
const [owner, repo] = core.getInput('owner-repo').split('/');
|
||||
if (!owner || !repo) {
|
||||
core.setFailed('Must specify a valid ownerName/repoName');
|
||||
}
|
||||
const base = core.getInput('base');
|
||||
const title = core.getInput('title');
|
||||
const body = core.getInput('body');
|
||||
const labelsStr = core.getInput('labels');
|
||||
const labels = labelsStr.trim().split(/,\s+/);
|
||||
const reviewersStr = core.getInput('reviewers');
|
||||
const reviewers = reviewersStr.trim().split(/,\s+/);
|
||||
const teamStr = core.getInput('team_reviewers');
|
||||
const team_reviewers = teamStr.trim().split(/,\s+/);
|
||||
|
||||
const github = githubRoot.getOctokit(token);
|
||||
|
||||
const branchExists = await github.rest.repos
|
||||
.getBranch({
|
||||
owner,
|
||||
repo,
|
||||
branch
|
||||
})
|
||||
.catch(() => {
|
||||
console.info('Branch does not exist. Likely no changes in download?');
|
||||
});
|
||||
if (!branchExists || branchExists.status !== 200) {
|
||||
return;
|
||||
}
|
||||
const pullRequestExists = await github.rest.pulls.list({
|
||||
owner,
|
||||
repo,
|
||||
head: `${owner}:${branch}`
|
||||
});
|
||||
if (pullRequestExists.data.length) {
|
||||
console.info(
|
||||
'It looks like a pull request already exists for this branch.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
const PR = await github.rest.pulls
|
||||
.create({
|
||||
owner,
|
||||
repo,
|
||||
head: branch,
|
||||
base,
|
||||
title,
|
||||
body
|
||||
})
|
||||
.catch(err => {
|
||||
console.info(
|
||||
'Unpredicted error occurred when trying to create the PR.'
|
||||
);
|
||||
console.error(err);
|
||||
});
|
||||
if (!PR || PR.status !== 201) {
|
||||
return;
|
||||
}
|
||||
const prNumber = PR.data.number;
|
||||
console.log(
|
||||
`https://github.com/freeCodeCamp/freeCodeCamp/pull/${prNumber} created`
|
||||
);
|
||||
if (labels && labels.length) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: prNumber,
|
||||
labels
|
||||
});
|
||||
console.log(`Labels ${labels} added to PR`);
|
||||
}
|
||||
if (reviewers && reviewers.length) {
|
||||
await github.rest.pulls.requestReviewers({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
reviewers
|
||||
});
|
||||
console.log(`Requested Reviewers ${reviewers} added to PR`);
|
||||
}
|
||||
if (team_reviewers && team_reviewers.length) {
|
||||
await github.rest.pulls.requestReviewers({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
team_reviewers
|
||||
});
|
||||
console.log(`Requested Team Reviewers ${team_reviewers} added to PR`);
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
})();
|
||||
@ -1,5 +0,0 @@
|
||||
name: 'Remove Deleted English Files From Crowdin'
|
||||
description: 'Deletes files from Crowdin that are no longer in the English curriculum folder'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: './index.js'
|
||||
@ -1,55 +0,0 @@
|
||||
require('dotenv').config({ path: `${__dirname}/../../.env` });
|
||||
// const core = require('@actions/core');
|
||||
const util = require('util');
|
||||
const exec = util.promisify(require('child_process').exec);
|
||||
|
||||
const { getFiles, deleteFile } = require('../../utils/files');
|
||||
|
||||
const getOutputFromCommand = async command => {
|
||||
try {
|
||||
const { stdout } = await exec(command);
|
||||
return stdout;
|
||||
} catch (err) {
|
||||
console.log('Error');
|
||||
console.log('command');
|
||||
console.log(command + '\n');
|
||||
console.log(err.message);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const removeDeletedFiles = async projectId => {
|
||||
console.log('start deleting source files no longer in English curriculum...');
|
||||
const crowdinFiles = await getFiles(projectId);
|
||||
|
||||
if (crowdinFiles && crowdinFiles.length) {
|
||||
const challengeCommand = 'find curriculum/challenges/english -name \\*.*';
|
||||
const listOfEnglishFiles = await getOutputFromCommand(challengeCommand);
|
||||
const dictionaryCommand =
|
||||
'find curriculum/dictionaries/english -name \\*.*';
|
||||
const listOfDictFiles = await getOutputFromCommand(dictionaryCommand);
|
||||
let curriculumFilesArr = listOfEnglishFiles.split('\n');
|
||||
curriculumFilesArr = curriculumFilesArr.concat(listOfDictFiles.split('\n'));
|
||||
if (curriculumFilesArr.length) {
|
||||
const curriculumLookup = curriculumFilesArr.reduce((obj, filename) => {
|
||||
return { ...obj, [filename]: 1 };
|
||||
}, {});
|
||||
for (let { fileId, path: crowdinFilePath } of crowdinFiles) {
|
||||
if (
|
||||
!Object.prototype.hasOwnProperty.call(
|
||||
curriculumLookup,
|
||||
crowdinFilePath
|
||||
)
|
||||
) {
|
||||
await deleteFile(projectId, fileId, crowdinFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(`WARNING! No Crowdin files found for projectId ${projectId}`);
|
||||
}
|
||||
console.log('deleting source non-existent source files complete');
|
||||
};
|
||||
|
||||
const projectId = process.env.CROWDIN_PROJECT_ID;
|
||||
removeDeletedFiles(projectId);
|
||||
@ -1,12 +0,0 @@
|
||||
name: 'Unhide Specific String'
|
||||
description: 'Updates a specific string to be not hidden'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: './index.js'
|
||||
inputs:
|
||||
filename:
|
||||
description: 'name of file with specific string to hide'
|
||||
required: true
|
||||
string-content:
|
||||
description: 'text content of string to unhide'
|
||||
required: true
|
||||
@ -1,33 +0,0 @@
|
||||
require('dotenv').config({ path: `${__dirname}/../../.env` });
|
||||
const core = require('@actions/core');
|
||||
const { getFiles } = require('../../utils/files');
|
||||
const { getStrings, changeHiddenStatus } = require('../../utils/strings');
|
||||
|
||||
const filename = core.getInput('filename');
|
||||
const stringContent = core.getInput('string-content');
|
||||
|
||||
const hideString = async (projectId, fileName, string) => {
|
||||
const fileResponse = await getFiles(projectId);
|
||||
const targetFile = fileResponse.find(el => el.path.endsWith(filename));
|
||||
if (!targetFile) {
|
||||
core.setFailed(`${fileName} was not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const stringResponse = await getStrings({
|
||||
projectId,
|
||||
fileId: targetFile.fileId
|
||||
});
|
||||
|
||||
const targetString = stringResponse.find(el => el.data.text === string);
|
||||
if (!targetString) {
|
||||
core.setFailed(`${string} was not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
await changeHiddenStatus(projectId, targetString.data.id, false);
|
||||
console.log('string unhidden!');
|
||||
};
|
||||
|
||||
const projectId = process.env.CROWDIN_PROJECT_ID;
|
||||
hideString(projectId, filename, stringContent);
|
||||
@ -1,30 +0,0 @@
|
||||
/*
|
||||
This one-off script can be used to delete all existing translations for a specified language on Crowdin.
|
||||
|
||||
Specifying a projectId and lanaguageId in the .env file allows the script to accomplish this task.
|
||||
*/
|
||||
|
||||
require('dotenv').config({ path: `${__dirname}/../.env` });
|
||||
|
||||
const {
|
||||
getLanguageTranslations,
|
||||
deleteLanguageTranslations
|
||||
} = require('../utils/strings');
|
||||
|
||||
const projectId = process.env.CROWDIN_PROJECT_ID;
|
||||
const languageId = process.env.CROWDIN_LANGUAGE_ID;
|
||||
|
||||
(async (projectId, languageId) => {
|
||||
console.log('starting script...');
|
||||
const translations = await getLanguageTranslations({
|
||||
projectId,
|
||||
languageId
|
||||
});
|
||||
if (translations && translations.length) {
|
||||
for (let translation of translations) {
|
||||
const { stringId } = translation.data;
|
||||
await deleteLanguageTranslations(projectId, languageId, stringId);
|
||||
}
|
||||
}
|
||||
console.log('complete');
|
||||
})(projectId, languageId);
|
||||
@ -1,54 +0,0 @@
|
||||
/*
|
||||
This one-off script can be used to make any string in a Crowdin project to be marked as "Done" in case a workflow
|
||||
change inadvertently causes strings, which already have translations (and even an approved translation), to be
|
||||
reverted to "To Do".
|
||||
|
||||
Specifying a projectId in the .env file allows the script to find any string with at least one translation,
|
||||
adds a new temporary translation to it, and then delete the newly added translation. It is the addition of a
|
||||
new translation that switches the status back to "Done" in the Crowdsourcing view on Crowdin.
|
||||
|
||||
*/
|
||||
|
||||
require('dotenv').config({ path: `${__dirname}/../.env` });
|
||||
|
||||
const getLanguages = require('../utils/get-languages');
|
||||
|
||||
const {
|
||||
addTranslation,
|
||||
deleteTranslation,
|
||||
getLanguageTranslations
|
||||
} = require('../utils/strings');
|
||||
|
||||
const markTranslatedStringsAsDone = async projectId => {
|
||||
console.log('starting script...');
|
||||
const languageIds = await getLanguages(projectId);
|
||||
for (let languageId of languageIds) {
|
||||
const translations = await getLanguageTranslations({
|
||||
projectId,
|
||||
languageId
|
||||
});
|
||||
if (translations && translations.length) {
|
||||
console.log(
|
||||
`${languageId} has ${translations.length} strings with at least one translation`
|
||||
);
|
||||
for (let translation of translations) {
|
||||
const { stringId } = translation.data;
|
||||
const newTranslation = await addTranslation(
|
||||
projectId,
|
||||
stringId,
|
||||
languageId,
|
||||
'this is a camperbot test translation'
|
||||
);
|
||||
if (newTranslation && newTranslation.id);
|
||||
console.log(
|
||||
`added new translation (translationId: ${newTranslation.id}) for stringId: ${stringId}`
|
||||
);
|
||||
await deleteTranslation(projectId, newTranslation.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('complete');
|
||||
};
|
||||
|
||||
const projectId = process.env.CROWDIN_PROJECT_ID;
|
||||
markTranslatedStringsAsDone(projectId);
|
||||
@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "@freecodecamp/crowdin",
|
||||
"version": "0.0.1",
|
||||
"description": "The freeCodeCamp.org open-source codebase and curriculum",
|
||||
"license": "BSD-3-Clause",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=16",
|
||||
"npm": ">=8"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/freeCodeCamp/freeCodeCamp.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/freeCodeCamp/freeCodeCamp/issues"
|
||||
},
|
||||
"homepage": "https://github.com/freeCodeCamp/freeCodeCamp#readme",
|
||||
"author": "freeCodeCamp <team@freecodecamp.org>",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "1.10.0",
|
||||
"@actions/github": "5.1.1",
|
||||
"dotenv": "16.0.3",
|
||||
"fs-extra": "10.0.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"node-fetch": "2.6.9",
|
||||
"node-opencc": "2.0.1",
|
||||
"path": "0.12.7",
|
||||
"readdirp": "3.6.0"
|
||||
}
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
CROWDIN_PROJECT_ID=
|
||||
CROWDIN_PERSONAL_TOKEN=
|
||||
CROWDIN_API_URL='https://freecodecamp.crowdin.com/api/v2/'
|
||||
CROWDIN_LANGUAGE_ID=
|
||||
@ -1,7 +0,0 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const authHeader = {
|
||||
Authorization: `Bearer ${process.env.CROWDIN_PERSONAL_TOKEN}`
|
||||
};
|
||||
|
||||
module.exports = authHeader;
|
||||
@ -1,5 +0,0 @@
|
||||
const delay = (time = 2000) => {
|
||||
return new Promise(resolve => setTimeout(() => resolve(true), time));
|
||||
};
|
||||
|
||||
module.exports = delay;
|
||||
@ -1,86 +0,0 @@
|
||||
const authHeader = require('./auth-header');
|
||||
const delay = require('./delay');
|
||||
const makeRequest = require('./make-request');
|
||||
|
||||
const getDirs = async projectId => {
|
||||
let headers = { ...authHeader };
|
||||
let done = false;
|
||||
let offset = 0;
|
||||
let files = [];
|
||||
while (!done) {
|
||||
const endPoint = `projects/${projectId}/directories?limit=500&offset=${offset}`;
|
||||
await delay(1000);
|
||||
const response = await makeRequest({
|
||||
method: 'get',
|
||||
endPoint,
|
||||
headers
|
||||
});
|
||||
if (response.data) {
|
||||
if (response.data.length) {
|
||||
files = [...files, ...response.data];
|
||||
offset += 500;
|
||||
} else {
|
||||
done = true;
|
||||
return files;
|
||||
}
|
||||
} else {
|
||||
const { error } = response;
|
||||
console.log(error.errorcode);
|
||||
console.log(error.messsage);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const addDir = async (projectId, dirName, parentDirId) => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `projects/${projectId}/directories`;
|
||||
let body = {
|
||||
name: dirName
|
||||
};
|
||||
if (parentDirId) {
|
||||
body = { ...body, directoryId: parentDirId };
|
||||
}
|
||||
|
||||
const response = await makeRequest({
|
||||
method: 'post',
|
||||
endPoint,
|
||||
headers,
|
||||
body
|
||||
});
|
||||
return response;
|
||||
};
|
||||
|
||||
const createDirs = async (crowdinDirs, dirPath) => {
|
||||
// superParent is the top level directory on crowdin
|
||||
const superParent = crowdinDirs.find(dir => !dir.data.directoryId);
|
||||
let lastParentId = superParent.data.id;
|
||||
|
||||
const splitDirPath = dirPath.split('/');
|
||||
splitDirPath.shift();
|
||||
|
||||
// we are assuming that the first directory in 'newFile' is the same as the superParent
|
||||
// maybe throw a check in here to verify that's true
|
||||
const findCurrDir = (directory, crowdinDirs) => {
|
||||
return crowdinDirs.find(({ data: { name, directoryId } }) => {
|
||||
return name === directory && directoryId === lastParentId;
|
||||
});
|
||||
};
|
||||
|
||||
for (let directory of splitDirPath) {
|
||||
const currentDirectory = findCurrDir(directory, crowdinDirs);
|
||||
if (!currentDirectory) {
|
||||
const response = await addDir(10, directory, lastParentId);
|
||||
lastParentId = response.data.id;
|
||||
} else {
|
||||
lastParentId = currentDirectory.data.id;
|
||||
}
|
||||
}
|
||||
return lastParentId;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addDir,
|
||||
getDirs,
|
||||
createDirs
|
||||
};
|
||||
@ -1,122 +0,0 @@
|
||||
const authHeader = require('./auth-header');
|
||||
const makeRequest = require('./make-request');
|
||||
|
||||
const addFile = async (projectId, filename, fileContent, directoryId) => {
|
||||
let headers = { ...authHeader };
|
||||
headers['Crowdin-API-FileName'] = filename;
|
||||
const endPoint = `storages`;
|
||||
const contentType = 'application/text';
|
||||
const body = fileContent;
|
||||
const storageResponse = await makeRequest({
|
||||
method: 'post',
|
||||
contentType,
|
||||
endPoint,
|
||||
headers,
|
||||
body
|
||||
});
|
||||
if (storageResponse.data) {
|
||||
const fileBody = {
|
||||
storageId: storageResponse.data.id,
|
||||
name: filename,
|
||||
directoryId
|
||||
};
|
||||
const fileResponse = await makeRequest({
|
||||
method: 'post',
|
||||
endPoint: `projects/${projectId}/files`,
|
||||
headers,
|
||||
body: fileBody
|
||||
});
|
||||
if (fileResponse.data) {
|
||||
return fileResponse.data;
|
||||
} else {
|
||||
console.log('error');
|
||||
console.dir(fileResponse, { depth: null, colors: true });
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const updateFile = async (projectId, fileId, fileContent) => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `storages`;
|
||||
const contentType = 'application/text';
|
||||
const body = fileContent;
|
||||
const storageResponse = await makeRequest({
|
||||
method: 'post',
|
||||
contentType,
|
||||
endPoint,
|
||||
headers,
|
||||
body
|
||||
});
|
||||
if (storageResponse.data) {
|
||||
const fileBody = {
|
||||
storageId: storageResponse.data.id
|
||||
};
|
||||
const fileResponse = await makeRequest({
|
||||
method: 'put',
|
||||
endPoint: `projects/${projectId}/files${fileId}`,
|
||||
headers,
|
||||
body: fileBody
|
||||
});
|
||||
if (fileResponse.data) {
|
||||
return fileResponse.data;
|
||||
} else {
|
||||
console.log('error');
|
||||
console.dir(fileResponse, { depth: null, colors: true });
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const deleteFile = async (projectId, fileId, filePath) => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `projects/${projectId}/files/${fileId}`;
|
||||
await makeRequest({
|
||||
method: 'delete',
|
||||
endPoint,
|
||||
headers
|
||||
});
|
||||
console.log(`Deleted ${filePath} from Crowdin project`);
|
||||
return null;
|
||||
};
|
||||
|
||||
const getFiles = async projectId => {
|
||||
let headers = { ...authHeader };
|
||||
let done = false;
|
||||
let offset = 0;
|
||||
let files = [];
|
||||
while (!done) {
|
||||
const endPoint = `projects/${projectId}/files?limit=500&offset=${offset}`;
|
||||
const response = await makeRequest({
|
||||
method: 'get',
|
||||
endPoint,
|
||||
headers
|
||||
});
|
||||
if (response.data) {
|
||||
if (response.data.length) {
|
||||
files = [...files, ...response.data];
|
||||
offset += 500;
|
||||
} else {
|
||||
done = true;
|
||||
files = files.map(({ data: { directoryId, id: fileId, path } }) => {
|
||||
// remove leading forwardslash
|
||||
path = path.slice(1);
|
||||
return { directoryId, fileId, path };
|
||||
});
|
||||
return files;
|
||||
}
|
||||
} else {
|
||||
const { error } = response;
|
||||
console.log(error.errorcode);
|
||||
console.log(error.messsage);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addFile,
|
||||
updateFile,
|
||||
deleteFile,
|
||||
getFiles
|
||||
};
|
||||
@ -1,17 +0,0 @@
|
||||
const authHeader = require('./auth-header');
|
||||
const makeRequest = require('./make-request');
|
||||
|
||||
const getLanguages = async projectId => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `projects/${projectId}?limit=500`;
|
||||
const response = await makeRequest({ method: 'get', endPoint, headers });
|
||||
if (response.data && response.data.targetLanguageIds.length) {
|
||||
return response.data.targetLanguageIds;
|
||||
} else {
|
||||
const { error, errors } = response;
|
||||
console.error(error ? error : errors);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = getLanguages;
|
||||
@ -1,34 +0,0 @@
|
||||
require('dotenv').config();
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
const makeRequest = async ({
|
||||
method,
|
||||
endPoint,
|
||||
contentType = 'application/json',
|
||||
accept = 'application/json',
|
||||
headers,
|
||||
body
|
||||
}) => {
|
||||
headers = { ...headers, 'Content-Type': contentType, Accept: accept };
|
||||
const apiUrl = process.env.CROWDIN_API_URL + endPoint;
|
||||
|
||||
if (contentType === 'application/x-www-form-urlencoded') {
|
||||
body = Object.entries(body)
|
||||
.reduce((formDataArr, [key, value]) => {
|
||||
return formDataArr.concat(`${key}=${value}`);
|
||||
}, [])
|
||||
.join('&');
|
||||
} else if (contentType === 'application/json') {
|
||||
body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const response = await fetch(apiUrl, { headers, method, body });
|
||||
if (method !== 'delete') {
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = makeRequest;
|
||||
@ -1,239 +0,0 @@
|
||||
const authHeader = require('./auth-header');
|
||||
const makeRequest = require('./make-request');
|
||||
|
||||
const isReservedHeading = (context, str) => {
|
||||
const reservedHeadings = [
|
||||
'after-user-code',
|
||||
'answers',
|
||||
'before-user-code',
|
||||
'description',
|
||||
'fcc-editable-region',
|
||||
'hints',
|
||||
'instructions',
|
||||
'question',
|
||||
'assignments',
|
||||
'seed',
|
||||
'seed-contents',
|
||||
'solutions',
|
||||
'text',
|
||||
'video-solution'
|
||||
];
|
||||
const captureGroupStr = `(${reservedHeadings.join('|')})`;
|
||||
const regex = new RegExp(`--${captureGroupStr}--`);
|
||||
return !!(context.match(/^Headline/) && str.match(regex));
|
||||
};
|
||||
|
||||
const isCode = str => /^\/pre\/code|\/code$/.test(str);
|
||||
|
||||
const isTitle = str => str.endsWith('title');
|
||||
|
||||
const shouldHide = (text, context, challengeTitle, crowdinFilePath) => {
|
||||
if (crowdinFilePath.endsWith('.yml')) {
|
||||
return !isTitle(context);
|
||||
}
|
||||
if (isReservedHeading(context, text) || isCode(context)) {
|
||||
return true;
|
||||
}
|
||||
return text !== challengeTitle && context.includes('id=front-matter');
|
||||
};
|
||||
|
||||
const getStrings = async ({ projectId, fileId }) => {
|
||||
let headers = { ...authHeader };
|
||||
let done = false;
|
||||
let offset = 0;
|
||||
let strings = [];
|
||||
while (!done) {
|
||||
let endPoint = `projects/${projectId}/strings?limit=500&offset=${offset}`;
|
||||
if (fileId) {
|
||||
endPoint += `&fileId=${fileId}`;
|
||||
}
|
||||
const response = await makeRequest({ method: 'get', endPoint, headers });
|
||||
if (response.data) {
|
||||
if (response.data.length) {
|
||||
strings = [...strings, ...response.data];
|
||||
offset += 500;
|
||||
} else {
|
||||
done = true;
|
||||
return strings;
|
||||
}
|
||||
} else {
|
||||
const { error, errors } = response;
|
||||
console.error(error ? error : errors);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const updateString = async ({ projectId, stringId, propsToUpdate }) => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `projects/${projectId}/strings/${stringId}`;
|
||||
const body = propsToUpdate.map(({ path, value }) => ({
|
||||
op: 'replace',
|
||||
path,
|
||||
value
|
||||
}));
|
||||
await makeRequest({
|
||||
method: 'patch',
|
||||
endPoint,
|
||||
headers,
|
||||
body
|
||||
});
|
||||
};
|
||||
|
||||
const changeHiddenStatus = async (projectId, stringId, newStatus) => {
|
||||
await updateString({
|
||||
projectId,
|
||||
stringId,
|
||||
propsToUpdate: [{ path: '/isHidden', value: newStatus }]
|
||||
});
|
||||
};
|
||||
|
||||
const updateFileStrings = async ({ projectId, fileId, challengeTitle }) => {
|
||||
const fileStrings = await getStrings({
|
||||
projectId,
|
||||
fileId
|
||||
});
|
||||
|
||||
for (let {
|
||||
data: { id: stringId, text, isHidden, context }
|
||||
} of fileStrings) {
|
||||
const hideString = shouldHide(text, context, challengeTitle);
|
||||
if (!isHidden && hideString) {
|
||||
changeHiddenStatus(projectId, stringId, true);
|
||||
} else if (isHidden && !hideString) {
|
||||
changeHiddenStatus(projectId, stringId, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const updateFileString = async ({
|
||||
projectId,
|
||||
string,
|
||||
challengeTitle,
|
||||
crowdinFilePath
|
||||
}) => {
|
||||
const {
|
||||
data: { id: stringId, text, isHidden, context }
|
||||
} = string;
|
||||
const hideString = shouldHide(text, context, challengeTitle, crowdinFilePath);
|
||||
if (!isHidden && hideString) {
|
||||
await changeHiddenStatus(projectId, stringId, true);
|
||||
console.log(
|
||||
`${challengeTitle} - stringId: ${stringId} - changed isHidden to true`
|
||||
);
|
||||
} else if (isHidden && !hideString) {
|
||||
await changeHiddenStatus(projectId, stringId, false);
|
||||
console.log(
|
||||
`${challengeTitle} - stringId: ${stringId} - changed isHidden to false`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getStringTranslations = async ({ projectId, stringId, languageId }) => {
|
||||
let headers = { ...authHeader };
|
||||
let done = false;
|
||||
let offset = 0;
|
||||
let translations = [];
|
||||
while (!done) {
|
||||
let endPoint = `projects/${projectId}/translations?stringId=${stringId}&languageId=${languageId}&limit=500&offset=${offset}`;
|
||||
const response = await makeRequest({ method: 'get', endPoint, headers });
|
||||
if (response.data) {
|
||||
if (response.data.length) {
|
||||
translations = [...translations, ...response.data];
|
||||
offset += 500;
|
||||
} else {
|
||||
done = true;
|
||||
return translations;
|
||||
}
|
||||
} else {
|
||||
const { error, errors } = response;
|
||||
console.error(
|
||||
error ? JSON.stringify(error, null, 2) : JSON.stringify(errors, null, 2)
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const deleteTranslation = async (projectId, translationId) => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `projects/${projectId}/translations/${translationId}`;
|
||||
await makeRequest({
|
||||
method: 'delete',
|
||||
endPoint,
|
||||
headers
|
||||
});
|
||||
console.log(`Deleted translationId ${translationId} from Crowdin project`);
|
||||
return null;
|
||||
};
|
||||
|
||||
const addTranslation = async (projectId, stringId, languageId, text) => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `projects/${projectId}/translations`;
|
||||
const body = {
|
||||
stringId,
|
||||
languageId,
|
||||
text
|
||||
};
|
||||
const response = await makeRequest({
|
||||
method: 'post',
|
||||
endPoint,
|
||||
headers,
|
||||
body
|
||||
});
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const getLanguageTranslations = async ({ projectId, languageId }) => {
|
||||
let headers = { ...authHeader };
|
||||
let done = false;
|
||||
let offset = 0;
|
||||
let translations = [];
|
||||
while (!done) {
|
||||
let endPoint = `projects/${projectId}/languages/${languageId}/translations?limit=500&offset=${offset}`;
|
||||
const response = await makeRequest({ method: 'get', endPoint, headers });
|
||||
if (response.data) {
|
||||
if (response.data.length) {
|
||||
translations = [...translations, ...response.data];
|
||||
offset += 500;
|
||||
} else {
|
||||
done = true;
|
||||
return translations;
|
||||
}
|
||||
} else {
|
||||
const { error, errors } = response;
|
||||
console.error(
|
||||
error ? JSON.stringify(error, null, 2) : JSON.stringify(errors, null, 2)
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const deleteLanguageTranslations = async (projectId, languageId, stringId) => {
|
||||
let headers = { ...authHeader };
|
||||
const endPoint = `projects/${projectId}/translations?languageId=${languageId}&stringId=${stringId}`;
|
||||
console.log(`deleting ${stringId}...`);
|
||||
await makeRequest({
|
||||
method: 'delete',
|
||||
endPoint,
|
||||
headers
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getStrings,
|
||||
updateString,
|
||||
updateFileStrings,
|
||||
updateFileString,
|
||||
getStringTranslations,
|
||||
addTranslation,
|
||||
deleteTranslation,
|
||||
getLanguageTranslations,
|
||||
deleteLanguageTranslations,
|
||||
changeHiddenStatus
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user