From 2d4848bdeecf4127aba69917d3aa54497f93fbf8 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 27 Sep 2023 11:34:44 +0200 Subject: [PATCH] Added locale sync --- .github/workflows/release-beta.yml | 9 ++- .github/workflows/release.yml | 9 ++- .gitignore | 3 +- package-lock.json | 19 +++++ package.json | 1 + scripts/sync-localization.js | 122 +++++++++++++++++++++++++++-- 6 files changed, 155 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release-beta.yml b/.github/workflows/release-beta.yml index 1daf9235..08afa9ae 100644 --- a/.github/workflows/release-beta.yml +++ b/.github/workflows/release-beta.yml @@ -20,11 +20,18 @@ jobs: registry-url: https://registry.npmjs.org/ - name: Install the dependencies - run: npm i + run: npm ci - name: Prepare BETA run: node scripts/beta-release.js $GITHUB_RUN_ID + - name: Run localization sync + run: npm run localization:sync + env: + TRANSLATION_API_KEY: ${{ secrets.TRANSLATION_API_KEY }} + TRANSLATION_API_LOCATION: ${{ secrets.TRANSLATION_API_LOCATION }} + TRANSLATION_API_URL: ${{ secrets.TRANSLATION_API_URL }} + - name: Publish run: npx @vscode/vsce publish -p ${{ secrets.VSCE_PAT }} --baseImagesUrl https://raw.githubusercontent.com/estruyf/vscode-front-matter/dev diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 29c2beef..27861b5f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,11 +20,18 @@ jobs: registry-url: https://registry.npmjs.org/ - name: Install the dependencies - run: npm i + run: npm ci - name: Prepare MAIN release run: node scripts/main-release.js + - name: Run localization sync + run: npm run localization:sync + env: + TRANSLATION_API_KEY: ${{ secrets.TRANSLATION_API_KEY }} + TRANSLATION_API_LOCATION: ${{ secrets.TRANSLATION_API_LOCATION }} + TRANSLATION_API_URL: ${{ secrets.TRANSLATION_API_URL }} + - name: Publish run: npx @vscode/vsce publish -p ${{ secrets.VSCE_PAT }} diff --git a/.gitignore b/.gitignore index f850006d..94035d25 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ e2e/extensions e2e/sample localization.log -localization.md \ No newline at end of file +localization.md +.env diff --git a/package-lock.json b/package-lock.json index a6f24a89..b0f7cd22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,6 +51,7 @@ "cheerio": "1.0.0-rc.12", "css-loader": "5.2.7", "date-fns": "2.23.0", + "dotenv": "^16.3.1", "downshift": "6.0.6", "eslint": "^8.33.0", "fuse.js": "6.5.3", @@ -3817,6 +3818,18 @@ "tslib": "^1.10.0" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/downshift": { "version": "6.0.6", "dev": true, @@ -15855,6 +15868,12 @@ "tslib": "^1.10.0" } }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true + }, "downshift": { "version": "6.0.6", "dev": true, diff --git a/package.json b/package.json index 900ea6cf..47720fef 100644 --- a/package.json +++ b/package.json @@ -2558,6 +2558,7 @@ "cheerio": "1.0.0-rc.12", "css-loader": "5.2.7", "date-fns": "2.23.0", + "dotenv": "^16.3.1", "downshift": "6.0.6", "eslint": "^8.33.0", "fuse.js": "6.5.3", diff --git a/scripts/sync-localization.js b/scripts/sync-localization.js index 04c043c9..636ccebb 100644 --- a/scripts/sync-localization.js +++ b/scripts/sync-localization.js @@ -1,6 +1,42 @@ const fs = require('fs'); const path = require('path'); const glob = require('glob'); +const { v4: uuidv4 } = require('uuid'); +require('dotenv').config() + +const transKey = process.env.TRANSLATION_API_KEY || ""; +const apiUrl = process.env.TRANSLATION_API_URL || ""; +const location = process.env.TRANSLATION_API_LOCATION || ""; + +const getTranslation = (translation) => { + let value = undefined; + + if (translation && translation.translations && translation.translations.length > 0) { + value = translation.translations[0].text; + } + + return value; +} + +const callTranslationService = async (body, locale) => { + const response = await fetch(`${apiUrl}/translate?api-version=3.0&from=en&to=${locale}`, { + method: 'POST', + headers: { + 'Ocp-Apim-Subscription-Key': transKey, + 'Ocp-Apim-Subscription-Region': location, + 'Content-type': 'application/json', + 'Accept': 'application/json', + 'X-ClientTraceId': uuidv4().toString(), + }, + body + }); + + if (!response.ok) { + return undefined; + } + + return await response.json(); +} (async () => { // Get all the files from the l10n directory @@ -11,6 +47,7 @@ const glob = require('glob'); const enContent = JSON.parse(enFile); const enKeys = Object.keys(enContent); + console.log(`Starting l10n bundles`); for (const file of files) { if (file.endsWith(`bundle.l10n.json`)) { continue; @@ -20,17 +57,53 @@ const glob = require('glob'); const fileContent = fs.readFileSync(path.join(__dirname, `../l10n/${file}`), 'utf8'); let content = {}; + // Get the locale + const fileName = path.basename(file); + const fileSplit = fileName.split('.'); + const locale = fileSplit[fileSplit.length - 2]; + if (!locale) { + continue; + } + console.log(`- Processing: ${locale}`); + try { content = JSON.parse(fileContent); } catch (e) { // Ignore the error } + const keysToTranslate = []; + // Loop through the EN keys for (const key of enKeys) { // If the key does not exist in the file, add it - if (!content[key]) { - content[key] = `${enContent[key]}`; + if (!content[key] || content[key].startsWith(`🚧: `)) { + keysToTranslate.push({ + name: key, + value: enContent[key], + }); + + if (!apiUrl || !transKey || !location) { + content[key] = `${enContent[key]}`; + } + } + } + + if (apiUrl && transKey && location) { + if (keysToTranslate.length > 0) { + const body = JSON.stringify(keysToTranslate.map(key => ({ text: key.value }))); + const data = await callTranslationService(body, locale); + + for (let i = 0; i < keysToTranslate.length; i++) { + const keyToTranslate = keysToTranslate[i]; + const translation = getTranslation(data[i]); + + if (keyToTranslate.name && translation) { + content[keyToTranslate.name] = translation; + } else { + content[keyToTranslate.name] = `${keyToTranslate.value}`; + } + } } } @@ -46,21 +119,60 @@ const glob = require('glob'); const pkgFiles = glob.sync(path.join(__dirname, '../package.nls.*.json')); + + console.log(``); + console.log(`Starting nls bundles`); for (const file of pkgFiles) { const fileContent = fs.readFileSync(file, 'utf8'); let content = {}; + // Get the locale + const fileName = path.basename(file); + const fileSplit = fileName.split('.'); + const locale = fileSplit[fileSplit.length - 2]; + if (!locale) { + continue; + } + console.log(`- Processing: ${locale}`); + try { content = JSON.parse(fileContent); } catch (e) { // Ignore the error } + const keysToTranslate = []; + // Loop through the EN keys for (const key of enPkgKeys) { - // If the key does not exist in the file, add it - if (!content[key]) { - content[key] = `🚧: ${enPkgContent[key]}`; + const contentValue = content[key]; + if (!contentValue || contentValue.startsWith(`🚧: `)) { + keysToTranslate.push({ + name: key, + value: enPkgContent[key], + }); + + if (!apiUrl || !transKey || !location) { + content[key] = `🚧: ${enPkgContent[key]}`; + } + } + } + + if (apiUrl && transKey && location) { + if (keysToTranslate.length > 0) { + const body = JSON.stringify(keysToTranslate.map(key => ({ text: key.value }))); + const data = await callTranslationService(body, locale); + + for (let i = 0; i < keysToTranslate.length; i++) { + const keyToTranslate = keysToTranslate[i]; + const translation = getTranslation(data[i]); + + if (keyToTranslate.name && translation) { + content[keyToTranslate.name] = translation; + } else { + content[keyToTranslate.name] = `${keyToTranslate.value}`; + } + } } }