diff --git a/scripts/build.mjs b/scripts/build.mjs index 21d4554..7e7c6f8 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -18,6 +18,10 @@ import details from "../package.json" assert { type: "json" }; const { name, author, description, homepage, version, config } = details; +const t = new Date(); +const buildTime = dateFormat("YYYY-mm-dd HH:MM:SS", new Date()); +const buildDir = "build"; + function copyFileSync(source, target) { var targetFile = target; @@ -84,76 +88,7 @@ function dateFormat(fmt, date) { return fmt; } -async function main() { - const t = new Date(); - const buildTime = dateFormat("YYYY-mm-dd HH:MM:SS", t); - const buildDir = "build"; - - console.log( - `[Build] BUILD_DIR=${buildDir}, VERSION=${version}, BUILD_TIME=${buildTime}, ENV=${[ - env.NODE_ENV, - ]}` - ); - - clearFolder(buildDir); - - copyFolderRecursiveSync("addon", buildDir); - - copyFileSync("update-template.json", "update.json"); - - await build({ - entryPoints: ["src/index.ts"], - define: { - __env__: `"${env.NODE_ENV}"`, - }, - bundle: true, - outfile: join(buildDir, "addon/chrome/content/scripts/index.js"), - // Don't turn minify on - // minify: true, - }).catch(() => exit(1)); - - console.log("[Build] Run esbuild OK"); - - const replaceFrom = [ - /__author__/g, - /__description__/g, - /__homepage__/g, - /__buildVersion__/g, - /__buildTime__/g, - ]; - - const replaceTo = [author, description, homepage, version, buildTime]; - - replaceFrom.push( - ...Object.keys(config).map((k) => new RegExp(`__${k}__`, "g")) - ); - replaceTo.push(...Object.values(config)); - - const optionsAddon = { - files: [ - join(buildDir, "**/*.xhtml"), - join(buildDir, "**/*.json"), - join(buildDir, "addon/prefs.js"), - join(buildDir, "addon/manifest.json"), - join(buildDir, "addon/bootstrap.js"), - "update.json", - ], - from: replaceFrom, - to: replaceTo, - countMatches: true, - }; - - const replaceResult = sync(optionsAddon); - console.log( - "[Build] Run replace in ", - replaceResult - .filter((f) => f.hasChanged) - .map((f) => `${f.file} : ${f.numReplacements} / ${f.numMatches}`) - ); - - console.log("[Build] Replace OK"); - - // Walk the builds/addon/locale folder's sub folders and rename *.ftl to addonRef-*.ftl +function renameLocaleFiles() { const localeDir = join(buildDir, "addon/locale"); const localeFolders = readdirSync(localeDir, { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) @@ -176,6 +111,135 @@ async function main() { } } } +} + +function replaceString() { + const replaceFrom = [ + /__author__/g, + /__description__/g, + /__homepage__/g, + /__buildVersion__/g, + /__buildTime__/g, + ]; + const replaceTo = [author, description, homepage, version, buildTime]; + + replaceFrom.push( + ...Object.keys(config).map((k) => new RegExp(`__${k}__`, "g")) + ); + replaceTo.push(...Object.values(config)); + + const optionsAddon = { + files: [ + join(buildDir, "**/*.xhtml"), + join(buildDir, "**/*.json"), + join(buildDir, "addon/prefs.js"), + join(buildDir, "addon/manifest.json"), + join(buildDir, "addon/bootstrap.js"), + "update.json", + ], + from: replaceFrom, + to: replaceTo, + countMatches: true, + }; + + const replaceResult = sync(optionsAddon); + + const localeMessage = new Set(); + const localeMessageMiss = new Set(); + + const replaceResultFlt = sync({ + files: [join(buildDir, "addon/**/*.ftl")], + processor: (fltContent) => { + const lines = fltContent.split("\n"); + const prefixedLines = lines.map((line) => { + // https://regex101.com/r/lQ9x5p/1 + const match = line.match( + /^(?[a-zA-Z]\S*)([ ]*=[ ]*)(?.*)$/m + ); + if (match) { + localeMessage.add(match.groups.message); + return `${config.addonRef}-${line}`; + } else { + return line; + } + }); + return prefixedLines.join("\n"); + }, + }); + + const replaceResultXhtml = sync({ + files: [join(buildDir, "addon/**/*.xhtml")], + processor: (input) => { + const matchs = [...input.matchAll(/(data-l10n-id)="(\S*)"/g)]; + matchs.map((match) => { + if (localeMessage.has(match[2])) { + input = input.replace( + match[0], + `${match[1]}="${config.addonRef}-${match[2]}"` + ); + } else { + localeMessageMiss.add(match[2]); + } + }); + return input; + }, + }); + + console.log( + "[Build] Run replace in ", + replaceResult + .filter((f) => f.hasChanged) + .map((f) => `${f.file} : ${f.numReplacements} / ${f.numMatches}`), + replaceResultFlt.filter((f) => f.hasChanged).map((f) => `${f.file} : OK`), + replaceResultXhtml.filter((f) => f.hasChanged).map((f) => `${f.file} : OK`) + ); + + if (localeMessageMiss.size !== 0) { + console.warn( + `[Build] [Warn] Fluent message [${new Array( + ...localeMessageMiss + )}] do not exsit in addon's locale files.` + ); + } +} + +async function esbuild() { + await build({ + entryPoints: ["src/index.ts"], + define: { + __env__: `"${env.NODE_ENV}"`, + }, + bundle: true, + target: "firefox102", + outfile: join(buildDir, "addon/chrome/content/scripts/index.js"), + // Don't turn minify on + // minify: true, + }).catch(() => exit(1)); +} + +async function main() { + console.log( + `[Build] BUILD_DIR=${buildDir}, VERSION=${version}, BUILD_TIME=${buildTime}, ENV=${[ + env.NODE_ENV, + ]}` + ); + + clearFolder(buildDir); + + copyFolderRecursiveSync("addon", buildDir); + + copyFileSync("update-template.json", "update.json"); + + await esbuild(); + + console.log("[Build] Run esbuild OK"); + + replaceString(); + + console.log("[Build] Replace OK"); + + // Walk the builds/addon/locale folder's sub folders and rename *.ftl to addonRef-*.ftl + renameLocaleFiles(); console.log("[Build] Addon prepare OK"); diff --git a/src/utils/locale.ts b/src/utils/locale.ts index 516dec5..2642675 100644 --- a/src/utils/locale.ts +++ b/src/utils/locale.ts @@ -63,16 +63,17 @@ function _getString( localString: string, options: { branch?: string | undefined; args?: Record } = {} ): string { + const localStringWithPrefix = `${config.addonRef}-${localString}`; const { branch, args } = options; const pattern = addon.data.locale?.current.formatMessagesSync([ - { id: localString, args }, + { id: localStringWithPrefix, args }, ])[0]; if (!pattern) { - return localString; + return localStringWithPrefix; } if (branch && pattern.attributes) { - return pattern.attributes[branch] || localString; + return pattern.attributes[branch] || localStringWithPrefix; } else { - return pattern.value || localString; + return pattern.value || localStringWithPrefix; } }