diff --git a/lib/chromiumRebaseL10n.js b/lib/chromiumRebaseL10n.js index af848ee9af..85d1acf700 100644 --- a/lib/chromiumRebaseL10n.js +++ b/lib/chromiumRebaseL10n.js @@ -5,7 +5,7 @@ const path = require('path') const config = require('../lib/config') const util = require('../lib/util') -const {rebaseBraveStringFilesOnChromiumL10nFiles, braveAutoGeneratedPaths, logRemovedGRDParts} = require('./l10nUtil') +const l10nUtil = require('./l10nUtil') const resetChromeStringFiles = () => { // Revert to originals before string replacement because original grd(p)s are @@ -19,13 +19,13 @@ const resetChromeStringFiles = () => { const chromiumRebaseL10n = async (options) => { resetChromeStringFiles() - const removed = await rebaseBraveStringFilesOnChromiumL10nFiles() - braveAutoGeneratedPaths.forEach((sourceStringPath) => { + const removed = await l10nUtil.rebaseBraveStringFilesOnChromiumL10nFiles() + l10nUtil.getBraveAutoGeneratedPaths().forEach((sourceStringPath) => { const cmdOptions = config.defaultOptions cmdOptions.cwd = config.projects['brave-core'].dir util.run('python', ['script/chromium-rebase-l10n.py', '--source_string_path', sourceStringPath], cmdOptions) }) - logRemovedGRDParts(removed) + l10nUtil.logRemovedGRDParts(removed) } module.exports = chromiumRebaseL10n diff --git a/lib/l10nUtil.js b/lib/l10nUtil.js index a635f51314..11e56ecb7a 100644 --- a/lib/l10nUtil.js +++ b/lib/l10nUtil.js @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ - /** * This file manages the following: * - Lists of files needed to be translated (Which is all top level GRD and JSON files) @@ -17,6 +16,7 @@ const { JSDOM } = require("jsdom") // Change to `true` for verbose console log output of GRD traversal const verboseLogFindGrd = false + const srcDir = path.resolve(path.join(__dirname, '..', 'src')) // chromium_strings.grd and any of its parts files that we track localization for in transifex @@ -58,8 +58,6 @@ const braveExtensionMessagesPath = path.resolve(path.join(srcDir, 'brave', 'comp const braveRewardsExtensionMessagesPath = path.resolve(path.join(srcDir, 'brave', 'components', 'brave_rewards', 'resources', 'extension', 'brave_rewards', '_locales', 'en_US', 'messages.json')) const braveAndroidBraveStringsPath = path.resolve(path.join(srcDir, 'brave', 'browser', 'ui', 'android', 'strings', 'android_brave_strings.grd')) -const srcGit = path.resolve(path.join(srcDir, '.git')) - // Helper function to find all grdp parts in a grd. function getGrdPartsFromGrd(path) { const grd = new JSDOM(fs.readFileSync(path, 'utf8')) @@ -72,20 +70,16 @@ function getGrdPartsFromGrd(path) { } // Helper function to create a mapping for grd and all of its grdp parts. -function AddGrd(chromiumPath, bravePath, exclude = new Set()) { - if (!fs.existsSync(srcGit)) { - // Chromium repository has not been initialized yet. - return - } +function addGrd(chromiumPath, bravePath, exclude = new Set()) { if (verboseLogFindGrd) console.log("Adding mappings for GRD: " + chromiumPath) - let mapping = { - [chromiumPath]: bravePath - } if (!fs.existsSync(chromiumPath)) { - const err = new Error(`AddGrd: Error. File not found at path "${chromiumPath}"`) + const err = new Error(`addGrd: Error. File not found at path "${chromiumPath}"`) console.error(err) - return + throw err + } + let mapping = { + [chromiumPath]: bravePath } const grdps = getGrdPartsFromGrd(chromiumPath) if (grdps.length) { @@ -103,58 +97,6 @@ function AddGrd(chromiumPath, bravePath, exclude = new Set()) { return mapping } -// Add all GRD mappings here. -// Brave specific only grd and grdp files should NOT be added. -// Using AddGrd will add GRD and all of its GRDPs. -// TODO(petemill): Do not do this file processing in the module root, do it behind a function. -console.log(chalk.italic('Recursing through GRD to find GRDP files...')) -const grdsWithAutoAddedGrdps = { - ...AddGrd(chromiumComponentsStringsPath, braveComponentsStringsPath), - ...AddGrd(chromiumGeneratedResourcesPath, braveGeneratedResourcesPath, chromiumGeneratedResourcesExcludes), - ...AddGrd(androidChromeStringsPath, braveAndroidChromeStringsPath) -} -console.log(chalk.italic('Done recursing through GRD to find GRDP files.')) - -// When adding new grd or grdp files, never add a grdp part path without a parent grd path. -// Group them with a leading and trailing newline to keep this file organized. -// The first 3 are added explicitly because we change the file names. -const chromiumToAutoGeneratedBraveMapping = { - [chromiumStringsPath]: braveStringsPath, - [chromiumSettingsPartPath]: braveSettingsPartPath, - - [chromiumComponentsChromiumStringsPath]: braveComponentsBraveStringsPath, - - ...grdsWithAutoAddedGrdps -} - -// Same as with chromiumToAutoGeneratedBraveMapping but maps in the opposite direction -module.exports.autoGeneratedBraveToChromiumMapping = Object.keys(chromiumToAutoGeneratedBraveMapping) - .reduce((obj, key) => ({ ...obj, [chromiumToAutoGeneratedBraveMapping[key]]: key }), {}) - -// All paths which are not generated -module.exports.braveNonGeneratedPaths = [ - braveSpecificGeneratedResourcesPath, braveResourcesComponentsStringsPath, braveExtensionMessagesPath, braveRewardsExtensionMessagesPath, braveAndroidBraveStringsPath -] - -// All paths which are generated -module.exports.braveAutoGeneratedPaths = Object.values(chromiumToAutoGeneratedBraveMapping) - -// Brave specific strings and Chromium mapped Brave strings will be here. -// But you only need to add the Brave specific strings manually here. -module.exports.allBravePaths = module.exports.braveNonGeneratedPaths.concat(module.exports.braveAutoGeneratedPaths) - -// Get all GRD and JSON paths whether they are generatd or not -// Push and pull scripts for l10n use this. -// Transifex manages files per grd and not per grd or grdp. -// This is because only 1 xtb is created per grd per locale even if it has multiple grdp files. -module.exports.braveTopLevelPaths = module.exports.allBravePaths.filter((x) => ['grd', 'json'].includes(x.split('.').pop())) - -// ethereum-remote-client path relative to the Brave paths -module.exports.ethereumRemoteClientPaths = [ - '../../../ethereum-remote-client/app/_locales/en/messages.json', - '../../../ethereum-remote-client/brave/app/_locales/en/messages.json' -] - // Helper functions that's, for a given pair of chromium to brave GRD mapping // from the supplied map, determines which GRDP parts are no longer present in // the chromium GRD file. @@ -178,40 +120,129 @@ function getRemovedGRDParts(mapping) { return removedMap } -// Helper function to pretty print removed GRDP file names. -module.exports.logRemovedGRDParts = function (mapping) { - if (mapping.size) { - console.log("\n**************************************************************************") - console.log("The following GRDP files are no longer in the corresponding Chromium GRDs:\n") - for (const [grd, grdps] of mapping.entries()) { - console.log(" From " + grd + ":") - for (const grdp of grdps) { - console.log(" - " + grdp) - } +// Add all GRD mappings here. +function getAutoGeneratedGrdMappings() { + if (typeof(getAutoGeneratedGrdMappings.mappings) === 'undefined') { + console.log(chalk.italic('Recursing through GRD to find GRDP files...')) + // Brave specific only grd and grdp files should NOT be added. + // Using AddGrd will add GRD and all of its GRDPs. + getAutoGeneratedGrdMappings.mappings = { + ...addGrd(chromiumComponentsStringsPath, braveComponentsStringsPath), + ...addGrd(chromiumGeneratedResourcesPath, braveGeneratedResourcesPath, chromiumGeneratedResourcesExcludes), + ...addGrd(androidChromeStringsPath, braveAndroidChromeStringsPath) } + console.log(chalk.italic('Done recursing through GRD to find GRDP files.')) } + return getAutoGeneratedGrdMappings.mappings } -// This simply reads Chromium files that are passed to it and replaces branding strings -// with Brave specific branding strings. -// Do not use this for filtering XML, instead use chromium-rebase-l10n.py. -// Only add idempotent replacements here (i.e. don't append replace A with AX here) -module.exports.rebaseBraveStringFilesOnChromiumL10nFiles = async function (path) { - const removedMap = getRemovedGRDParts(grdsWithAutoAddedGrdps) - const ops = Object.entries(chromiumToAutoGeneratedBraveMapping).map(async ([sourcePath, destPath]) => { - let contents = await new Promise(resolve => fs.readFile(sourcePath, 'utf8', (err, data) => resolve(data))) - for (const replacement of defaultReplacements) { - contents = contents.replace(replacement[0], replacement[1]) - } - for (const replacement of fixupReplacements) { - contents = contents.replace(replacement[0], replacement[1]) +function getChromiumToAutoGeneratedBraveMapping() { + if (typeof(getChromiumToAutoGeneratedBraveMapping.mapping) === 'undefined') { + // When adding new grd or grdp files, never add a grdp part path without a parent grd path. + // Group them with a leading and trailing newline to keep this file organized. + // The first 3 are added explicitly because we change the file names. + getChromiumToAutoGeneratedBraveMapping.mapping = { + [chromiumStringsPath]: braveStringsPath, + [chromiumSettingsPartPath]: braveSettingsPartPath, + + [chromiumComponentsChromiumStringsPath]: braveComponentsBraveStringsPath, + + ...getAutoGeneratedGrdMappings() } - await new Promise(resolve => fs.writeFile(destPath, contents, 'utf8', resolve)) - }) - await Promise.all(ops) - return removedMap + } + return getChromiumToAutoGeneratedBraveMapping.mapping } +const l10nUtil = { + // Same as with GetChromiumToAutoGeneratedBraveMapping but maps in the opposite direction + getAutoGeneratedBraveToChromiumMapping: () => { + if (typeof(l10nUtil.getAutoGeneratedBraveToChromiumMapping.mapping) === 'undefined') { + const chromiumToAutoGeneratedBraveMapping = getChromiumToAutoGeneratedBraveMapping() + l10nUtil.getAutoGeneratedBraveToChromiumMapping.mapping = Object.keys( + chromiumToAutoGeneratedBraveMapping).reduce((obj, key) => ( + { ...obj, [chromiumToAutoGeneratedBraveMapping[key]]: key }), {}) + } + return l10nUtil.getAutoGeneratedBraveToChromiumMapping.mapping + }, + + // All paths which are generated + getBraveAutoGeneratedPaths: () => { + return Object.values(getChromiumToAutoGeneratedBraveMapping()) + }, + + // All paths which are not generated + getBraveNonGeneratedPaths: () => { + if (typeof(l10nUtil.getBraveNonGeneratedPaths.paths) === 'undefined') { + l10nUtil.getBraveNonGeneratedPaths.paths = [ + braveSpecificGeneratedResourcesPath, + raveResourcesComponentsStringsPath, + raveExtensionMessagesPath, + raveRewardsExtensionMessagesPath, + raveAndroidBraveStringsPath + ] + } + return l10nUtil.getBraveNonGeneratedPaths.paths + }, + + // Brave specific strings and Chromium mapped Brave strings will be here. + // But you only need to add the Brave specific strings manually here. + getAllBravePaths: () => { + return getBraveNonGeneratedPaths.concat(getBraveAutoGeneratedPaths()) + }, + + // Get all GRD and JSON paths whether they are generatd or not + // Push and pull scripts for l10n use this. + // Transifex manages files per grd and not per grd or grdp. + // This is because only 1 xtb is created per grd per locale even if it has multiple grdp files. + getBraveTopLevelPaths: () => { + return getAllBravePaths().filter((x) => ['grd', 'json'].includes(x.split('.').pop())) + }, + + // ethereum-remote-client path relative to the Brave paths + getEthereumRemoteClientPaths: () => { + return [ + '../../../ethereum-remote-client/app/_locales/en/messages.json', + '../../../ethereum-remote-client/brave/app/_locales/en/messages.json' + ] + }, + + // Helper function to pretty print removed GRDP file names. + logRemovedGRDParts: (mapping) => { + if (mapping.size) { + console.log("\n**************************************************************************") + console.log("The following GRDP files are no longer in the corresponding Chromium GRDs:\n") + for (const [grd, grdps] of mapping.entries()) { + console.log(" From " + grd + ":") + for (const grdp of grdps) { + console.log(" - " + grdp) + } + } + } + }, + + // This simply reads Chromium files that are passed to it and replaces branding strings + // with Brave specific branding strings. + // Do not use this for filtering XML, instead use chromium-rebase-l10n.py. + // Only add idempotent replacements here (i.e. don't append replace A with AX here) + rebaseBraveStringFilesOnChromiumL10nFiles: async (path) => { + const removedMap = getRemovedGRDParts(getAutoGeneratedGrdMappings()) + const ops = Object.entries(getChromiumToAutoGeneratedBraveMapping()).map(async ([sourcePath, destPath]) => { + let contents = await new Promise(resolve => fs.readFile(sourcePath, 'utf8', (err, data) => resolve(data))) + for (const replacement of defaultReplacements) { + contents = contents.replace(replacement[0], replacement[1]) + } + for (const replacement of fixupReplacements) { + contents = contents.replace(replacement[0], replacement[1]) + } + await new Promise(resolve => fs.writeFile(destPath, contents, 'utf8', resolve)) + }) + await Promise.all(ops) + return removedMap + }, +} // const l10nUtil + +module.exports = l10nUtil + // Straight-forward string replacement list. // Consider mapping chromium resource ID to a new brave resource ID // for whole-message replacements, instead of adding to this list. diff --git a/lib/pullL10n.js b/lib/pullL10n.js index f6b8c81957..258d1d0b17 100644 --- a/lib/pullL10n.js +++ b/lib/pullL10n.js @@ -1,13 +1,13 @@ const config = require('../lib/config') const util = require('../lib/util') -const {braveTopLevelPaths, ethereumRemoteClientPaths} = require('./l10nUtil') +const l10nUtil = require('./l10nUtil') const pullL10n = (options) => { const cmdOptions = config.defaultOptions cmdOptions.cwd = config.projects['brave-core'].dir if (options.extension) { if (options.extension === 'ethereum-remote-client') { - ethereumRemoteClientPaths.forEach((sourceStringPath) => { + l10nUtil.getEthereumRemoteClientPaths().forEach((sourceStringPath) => { util.run('python', ['script/pull-l10n.py', '--source_string_path', sourceStringPath], cmdOptions) }) return @@ -16,7 +16,7 @@ const pullL10n = (options) => { process.exit(1) } - braveTopLevelPaths.forEach((sourceStringPath) => { + l10nUtil.getBraveTopLevelPaths().forEach((sourceStringPath) => { if (!options.grd_path || sourceStringPath.endsWith(`/${options.grd_path}`)) util.run('python', ['script/pull-l10n.py', '--source_string_path', sourceStringPath], cmdOptions) }) diff --git a/lib/pushL10n.js b/lib/pushL10n.js index 81b57cd54f..531017b087 100644 --- a/lib/pushL10n.js +++ b/lib/pushL10n.js @@ -1,6 +1,6 @@ const config = require('../lib/config') const util = require('../lib/util') -const {braveTopLevelPaths, ethereumRemoteClientPaths} = require('./l10nUtil') +const l10nUtil = require('./l10nUtil') const pushL10n = (options) => { const runOptions = { cwd: config.projects.chrome.dir } @@ -8,7 +8,7 @@ const pushL10n = (options) => { cmdOptions.cwd = config.projects['brave-core'].dir if (options.extension) { if (options.extension === 'ethereum-remote-client') { - ethereumRemoteClientPaths.forEach((sourceStringPath) => { + l10nUtil.getEthereumRemoteClientPaths().forEach((sourceStringPath) => { util.run('python', ['script/push-l10n.py', '--source_string_path', sourceStringPath], cmdOptions) }) return @@ -21,7 +21,7 @@ const pushL10n = (options) => { util.run('git', args, runOptions) args = ['checkout', '--', '*.grd*'] util.run('git', args, runOptions) - braveTopLevelPaths.forEach((sourceStringPath) => { + l10nUtil.getBraveTopLevelPaths().forEach((sourceStringPath) => { util.run('python', ['script/push-l10n.py', '--source_string_path', sourceStringPath], cmdOptions) }) } diff --git a/lib/util.js b/lib/util.js index 8d16c47c27..9d376b4a24 100755 --- a/lib/util.js +++ b/lib/util.js @@ -3,7 +3,7 @@ const { spawn, spawnSync } = require('child_process') const config = require('./config') const fs = require('fs-extra') const crypto = require('crypto') -const autoGeneratedBraveToChromiumMapping = Object.assign({}, require('./l10nUtil').autoGeneratedBraveToChromiumMapping) +const l10nUtil = require('./l10nUtil') const os = require('os') const fixPywin32 = (options = {}) => { @@ -160,6 +160,7 @@ const util = { const braveAndroidJavaStringsTranslationsDir = path.join(config.projects['brave-core'].dir, 'browser', 'ui', 'android', 'strings', 'translations') let fileMap = new Set(); + const autoGeneratedBraveToChromiumMapping = Object.assign({}, l10nUtil.getAutoGeneratedBraveToChromiumMapping()) // The following 3 entries we map to the same name, not the chromium equivalent name for copying back autoGeneratedBraveToChromiumMapping[path.join(braveAppDir, 'brave_strings.grd')] = path.join(chromeAppDir, 'brave_strings.grd') autoGeneratedBraveToChromiumMapping[path.join(braveAppDir, 'settings_brave_strings.grdp')] = path.join(chromeAppDir, 'settings_brave_strings.grdp')