From 5be8e16c2d7956daef8755057dbc6caca887e6e6 Mon Sep 17 00:00:00 2001 From: Christian Rackerseder Date: Wed, 22 Jul 2026 13:39:53 +0200 Subject: [PATCH] Revert "Block unapproved and invalid Crowdin translation placeholders [WPB-22420] (#486)" This reverts commit 19beb69823ac12391c96610904ecf7239fc69742. --- .github/workflows/test_build_deploy.yml | 6 -- bin/validate-translations.js | 96 ------------------------- bin/validate-translations.test.js | 72 ------------------- package.json | 8 +-- 4 files changed, 3 insertions(+), 179 deletions(-) delete mode 100644 bin/validate-translations.js delete mode 100644 bin/validate-translations.test.js diff --git a/.github/workflows/test_build_deploy.yml b/.github/workflows/test_build_deploy.yml index d5cbac39..f41930c0 100644 --- a/.github/workflows/test_build_deploy.yml +++ b/.github/workflows/test_build_deploy.yml @@ -76,7 +76,6 @@ jobs: upload_sources: true upload_translations: false download_translations: true - export_only_approved: true skip_untranslated_files: true push_translations: false create_pull_request: false @@ -95,17 +94,12 @@ jobs: upload_sources: false upload_translations: false download_translations: true - export_only_approved: true skip_untranslated_files: false push_translations: false create_pull_request: false token: ${{secrets.WEB_CROWDIN_TOKEN}} config: ${{env.CROWDIN_CONFIG_PATH}} - - name: Validate downloaded translations - if: (github.event_name == 'pull_request' && (github.actor != 'dependabot[bot]' && github.actor != 'otto-the-bot')) || env.BRANCH_NAME == 'master' - run: yarn translate:validate - - name: Build if: env.BRANCH_NAME == 'master' # We need to execute `yarn translate:process` with sudo in order to delete and modify files diff --git a/bin/validate-translations.js b/bin/validate-translations.js deleted file mode 100644 index 9c3cfeff..00000000 --- a/bin/validate-translations.js +++ /dev/null @@ -1,96 +0,0 @@ -const fileSystem = require('node:fs'); -const path = require('node:path'); - -const numericHtmlTagPattern = /<\/?[0-9]+(?=\s|\/?>)[^>]*>/g; - -function findInvalidPlaceholderTags(htmlContent) { - return htmlContent.match(numericHtmlTagPattern) || []; -} - -function collectHtmlFiles(directoryPath) { - const directoryEntries = fileSystem - .readdirSync(directoryPath, {withFileTypes: true}) - .sort((firstEntry, secondEntry) => firstEntry.name.localeCompare(secondEntry.name)); - const htmlFilePaths = []; - - for (const directoryEntry of directoryEntries) { - const entryPath = path.join(directoryPath, directoryEntry.name); - - if (directoryEntry.isDirectory()) { - htmlFilePaths.push(...collectHtmlFiles(entryPath)); - continue; - } - - if (directoryEntry.isFile() && path.extname(directoryEntry.name).toLowerCase() === '.html') { - htmlFilePaths.push(entryPath); - } - } - - return htmlFilePaths; -} - -function findInvalidTranslations(translationDirectories) { - const invalidTranslations = []; - - for (const translationDirectory of translationDirectories) { - const htmlFilePaths = collectHtmlFiles(translationDirectory); - - for (const htmlFilePath of htmlFilePaths) { - const htmlContent = fileSystem.readFileSync(htmlFilePath, 'utf8'); - const invalidPlaceholderTags = findInvalidPlaceholderTags(htmlContent); - - if (invalidPlaceholderTags.length > 0) { - invalidTranslations.push({ - filePath: htmlFilePath, - invalidPlaceholderTags, - }); - } - } - } - - return invalidTranslations; -} - -function formatValidationErrors(invalidTranslations, rootDirectory) { - return invalidTranslations - .flatMap(invalidTranslation => - invalidTranslation.invalidPlaceholderTags.map( - invalidPlaceholderTag => - `${path.relative(rootDirectory, invalidTranslation.filePath)}: invalid numeric Crowdin placeholder ${invalidPlaceholderTag}`, - ), - ) - .join('\n'); -} - -function main() { - const rootDirectory = path.resolve(__dirname, '..'); - const translationDirectories = ['src/pages', 'src/partials'].map(translationDirectory => - path.join(rootDirectory, translationDirectory), - ); - - try { - const invalidTranslations = findInvalidTranslations(translationDirectories); - - if (invalidTranslations.length > 0) { - console.error('Invalid numeric Crowdin placeholder tags found:'); - console.error(formatValidationErrors(invalidTranslations, rootDirectory)); - process.exitCode = 1; - return; - } - - console.log('Translation HTML validation passed.'); - } catch (error) { - console.error(`Unable to validate translations: ${error.message}`); - process.exitCode = 1; - } -} - -if (require.main === module) { - main(); -} - -module.exports = { - findInvalidPlaceholderTags, - findInvalidTranslations, - formatValidationErrors, -}; diff --git a/bin/validate-translations.test.js b/bin/validate-translations.test.js deleted file mode 100644 index 39b8d495..00000000 --- a/bin/validate-translations.test.js +++ /dev/null @@ -1,72 +0,0 @@ -const assert = require('node:assert'); -const fileSystem = require('node:fs'); -const operatingSystem = require('node:os'); -const path = require('node:path'); -const {test} = require('node:test'); - -const { - findInvalidPlaceholderTags, - findInvalidTranslations, - formatValidationErrors, -} = require('./validate-translations'); - -function createTemporaryTranslationDirectory() { - return fileSystem.mkdtempSync(path.join(operatingSystem.tmpdir(), 'wire-emails-translations-')); -} - -function removeTemporaryTranslationDirectory(directoryPath) { - fileSystem.rmSync(directoryPath, {force: true, recursive: true}); -} - -test('accepts ordinary HTML', () => { - const actualInvalidTags = findInvalidPlaceholderTags('

Hello world.

'); - - assert.deepStrictEqual(actualInvalidTags, []); -}); - -test('accepts project variables', () => { - const actualInvalidTags = findInvalidPlaceholderTags('

Welcome to ${brand}, ${email}.

'); - - assert.deepStrictEqual(actualInvalidTags, []); -}); - -test('detects an opening numeric placeholder tag', () => { - const actualInvalidTags = findInvalidPlaceholderTags('

<0>Translated text

'); - - assert.strictEqual(actualInvalidTags[0], '<0>'); -}); - -test('detects a closing numeric placeholder tag', () => { - const actualInvalidTags = findInvalidPlaceholderTags('

Translated text'); - - assert.deepStrictEqual(actualInvalidTags, ['']); -}); - -test('reports filenames and multiple invalid placeholders recursively', () => { - const temporaryDirectory = createTemporaryTranslationDirectory(); - const pagesDirectory = path.join(temporaryDirectory, 'src', 'pages'); - const partialsDirectory = path.join(temporaryDirectory, 'src', 'partials'); - const invalidPagePath = path.join(pagesDirectory, 'ru', 'email.html'); - const invalidPartialPath = path.join(partialsDirectory, 'fr', 'footer.html'); - - try { - fileSystem.mkdirSync(path.dirname(invalidPagePath), {recursive: true}); - fileSystem.mkdirSync(path.dirname(invalidPartialPath), {recursive: true}); - fileSystem.writeFileSync(invalidPagePath, '

<0>Russian text

'); - fileSystem.writeFileSync(invalidPartialPath, '

French text <2>

'); - - const actualInvalidTranslations = findInvalidTranslations([pagesDirectory, partialsDirectory]); - const actualErrorOutput = formatValidationErrors(actualInvalidTranslations, temporaryDirectory); - - assert.strictEqual(actualInvalidTranslations.length, 2); - assert.strictEqual(actualInvalidTranslations[0].invalidPlaceholderTags.length, 2); - assert.strictEqual(actualInvalidTranslations[1].invalidPlaceholderTags.length, 1); - assert.strictEqual(actualErrorOutput.includes(path.join('src', 'pages', 'ru', 'email.html')), true); - assert.strictEqual(actualErrorOutput.includes(path.join('src', 'partials', 'fr', 'footer.html')), true); - assert.strictEqual(actualErrorOutput.includes('<0>'), true); - assert.strictEqual(actualErrorOutput.includes(''), true); - assert.strictEqual(actualErrorOutput.includes('<2>'), true); - } finally { - removeTemporaryTranslationDirectory(temporaryDirectory); - } -}); diff --git a/package.json b/package.json index aea5d11e..9f1c71e2 100644 --- a/package.json +++ b/package.json @@ -56,18 +56,16 @@ "name": "wire-emails", "private": true, "scripts": { - "build": "yarn translate:validate && yarn translate:process && gulp build --production && yarn text", + "build": "yarn translate:process && gulp build --production && yarn text", "text": "node bin/generate-text-emails.js", "deploy": "npm version patch", "postversion": "git push && git push --tags", "prettier": "prettier --ignore-path .gitignore --write \"**/*.{js,scss,md,yml,yaml}\"", "start": "gulp", - "test": "yarn test:unit && yarn build", + "test": "yarn build", "translate": "yarn translate:upload && yarn translate:download", - "translate:download": "crowdin download && yarn translate:validate && yarn translate:process", + "translate:download": "crowdin download && yarn translate:process", "translate:process": "node bin/translate.js", - "translate:validate": "node bin/validate-translations.js", - "test:unit": "node --test bin/validate-translations.test.js", "translate:upload": "crowdin upload sources", "prepare": "husky install" },