From 6c4219e034f7cb56b5fdf24b61bb19ad94705347 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 30 Oct 2024 21:01:19 -0600 Subject: [PATCH 1/6] :green_heart: Don't copy locale files to dist --- bin/postbuildClass.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bin/postbuildClass.js b/bin/postbuildClass.js index ca86c9d1..67731340 100644 --- a/bin/postbuildClass.js +++ b/bin/postbuildClass.js @@ -14,7 +14,6 @@ export default class Postbuild { commonBuild() { this.handleManifest(); - this.localeFiles(); } edgeLegacyBuild() { @@ -33,10 +32,6 @@ export default class Postbuild { fse.copyFileSync('./store/edge/src/contentScriptsAPIBridge.js', './dist/contentScriptsAPIBridge.js'); } - localeFiles() { - fse.copySync('./locales', './dist/locales'); - } - updateManifestVersion() { if (this.manifest.version != this.buildData.version) this.manifest.version = this.buildData.version; } From f4f6246c6cc0db2db739b8355cc245e110b3f52d Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 30 Oct 2024 21:01:24 -0600 Subject: [PATCH 2/6] :globe_with_meridians: Fix broken strings --- locales/en/options.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en/options.json b/locales/en/options.json index 4cbec4de..22cb04d9 100644 --- a/locales/en/options.json +++ b/locales/en/options.json @@ -241,7 +241,7 @@ "censorPreserveLast": "Preserve the last letter", "defaultSubstitution": "Default Substitution", "defaultWordMatchMethod": "$t(options:headers.matchMethod)", - "defaultWordMatchRepeated": "$t(common:labels.matchRepeatedCharacters)", + "defaultWordMatchRepeated": "$t(options:labels.matchRepeatedCharacters)", "defaultWordMatchSeparators": "Match separator characters", "showContextMenu": "Show context menu", "showCounter": "Show number of filtered words", @@ -318,7 +318,7 @@ }, "tableHeaders": { "summaryTotal": "Total", - "summaryWords": "$t(common:names.word)" + "summaryWord": "$t(common:names.word)" }, "validations": { "lessUsedWordsInvalid": "Enter a positive whole number." From e49137f0e8fd2de47c9523144d0c07551703457a Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 30 Oct 2024 21:01:29 -0600 Subject: [PATCH 3/6] :bug: Add namespaces to Options page translation --- src/script/optionPage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/optionPage.ts b/src/script/optionPage.ts index 795e50a3..c9752a33 100644 --- a/src/script/optionPage.ts +++ b/src/script/optionPage.ts @@ -69,7 +69,7 @@ export default class OptionPage { this.prefersDarkScheme = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)').matches : false; this.setHelpVersion(); this.filter = new this.Class.Filter; - this.translation = new this.Class.Translation; + this.translation = new this.Class.Translation(['common', 'options']); this.t = this.translation.t; this.applyTranslation(); } From ae8e47caac2d589abd1baf0f00651c2d2f3ed8cd Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 30 Oct 2024 21:01:35 -0600 Subject: [PATCH 4/6] :sparkles: Add WebConfig.language configuration --- src/script/webConfig.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/script/webConfig.ts b/src/script/webConfig.ts index a5d5ec04..5f9c73be 100644 --- a/src/script/webConfig.ts +++ b/src/script/webConfig.ts @@ -18,6 +18,7 @@ export default class WebConfig extends Config { domains: { [site: string]: DomainCfg }; enabledDomainsOnly: boolean; enabledFramesOnly: boolean; + language: string; password: string; showUpdateNotification: boolean; syncLargeKeys: boolean; @@ -35,6 +36,7 @@ export default class WebConfig extends Config { domains: {}, enabledDomainsOnly: false, enabledFramesOnly: false, + language: 'en', password: null, showUpdateNotification: false, syncLargeKeys: true, From 56a4442fd30add772fb372704d5985726e700dc6 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 30 Oct 2024 21:01:41 -0600 Subject: [PATCH 5/6] :sparkles: Allow config to specify language --- src/script/background.ts | 3 ++- src/script/optionPage.ts | 10 +++++++--- src/script/popup.ts | 5 +++-- src/script/webConfig.ts | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/script/background.ts b/src/script/background.ts index 912f7a85..1e600b6b 100644 --- a/src/script/background.ts +++ b/src/script/background.ts @@ -45,13 +45,14 @@ export default class Background { static async contextMenuSetup() { await this.contextMenuRemoveAll(); - const translation = new this.Translation(['common', 'background']); const requiredConfig = { contextMenu: this.Config._defaults.contextMenu, + language: this.Config._defaults.language, password: this.Config._defaults.password, }; const config = await this.Config.getSyncStorage(requiredConfig) as Partial; + const translation = new this.Translation(['common', 'background'], config.language); if (config.contextMenu) { if (!config.password) { diff --git a/src/script/optionPage.ts b/src/script/optionPage.ts index c9752a33..78eecf4a 100644 --- a/src/script/optionPage.ts +++ b/src/script/optionPage.ts @@ -69,9 +69,6 @@ export default class OptionPage { this.prefersDarkScheme = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)').matches : false; this.setHelpVersion(); this.filter = new this.Class.Filter; - this.translation = new this.Class.Translation(['common', 'options']); - this.t = this.translation.t; - this.applyTranslation(); } applyDarkTheme(allElements = true) { @@ -952,6 +949,8 @@ export default class OptionPage { async init(refreshTheme = false) { await this.initializeCfg(); + this.initializeTranslations(); + this.applyTranslation(); logger.setLevel(this.cfg.loggingLevel); this.applyTheme(refreshTheme); if (!this.auth) this.auth = new this.Class.OptionAuth(this, this.cfg.password); @@ -981,6 +980,11 @@ export default class OptionPage { this.cfg = await this.Class.Config.load(); } + initializeTranslations() { + this.translation = new this.Class.Translation(['common', 'options'], this.cfg.language); + this.t = this.translation.t; + } + isStorageError(error: Error): boolean { if (error.message) { const chromeQuotaError = '[QUOTA_BYTES quota exceeded]'; diff --git a/src/script/popup.ts b/src/script/popup.ts index 323c103d..1c45b479 100644 --- a/src/script/popup.ts +++ b/src/script/popup.ts @@ -36,6 +36,7 @@ export default class Popup { 'domains', 'enabledDomainsOnly', 'filterMethod', + 'language', 'loggingLevel', 'password', 'wordlistId', @@ -281,10 +282,10 @@ export default class Popup { } async initializePopup() { - this.translation = new this.Class.Translation(['common', 'popup']); - this.applyTranslation(); await this.Class.load(this); this.applyTheme(); + this.translation = new this.Class.Translation(['common', 'popup'], this.cfg.language); + this.applyTranslation(); this.populateOptions(true); } diff --git a/src/script/webConfig.ts b/src/script/webConfig.ts index 5f9c73be..c162effc 100644 --- a/src/script/webConfig.ts +++ b/src/script/webConfig.ts @@ -352,7 +352,7 @@ export default class WebConfig extends Config { localizeDefaults() { if (!this._defaultsLoaded || !this._defaultsLoaded.length) return; - const translation = new Translation('common'); + const translation = new Translation('common', this.language); if (this._defaultsLoaded.includes('defaultSubstitution')) { const options = { defaultValue: this.Class._defaults.defaultSubstitution }; From 49e27a984c888e908e95473bf565417813516d61 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 30 Oct 2024 21:01:45 -0600 Subject: [PATCH 6/6] :memo: Add localization to development doc --- development.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/development.md b/development.md index 4164c9f9..4cd4c3b6 100644 --- a/development.md +++ b/development.md @@ -74,6 +74,8 @@ For all scripts, please see `package.json`. - npm run prebuild - npm run clean:build - node bin/clean.js --build + - npm run build:translations + - node bin/buildTranslations.js - node bin/prebuild.js --$npm_config_target - NOTE: $npm_config_target will be blank (`--`) - webpack --config bin/webpack.dev.js @@ -89,6 +91,8 @@ For all scripts, please see `package.json`. - npm run prebuild - npm run clean:build - node bin/clean.js --build + - npm run build:translations + - node bin/buildTranslations.js - node bin/prebuild.js --$npm_config_target - npm run build - webpack --config bin/webpack.dev.js @@ -104,6 +108,8 @@ For all scripts, please see `package.json`. - npm run prerelease:build - npm run clean:build - node bin/clean.js --build + - npm run build:translations + - node bin/buildTranslations.js - node bin/prebuild.js --release --$npm_config_target - webpack --config bin/webpack.prod.js - npm run build:static @@ -120,6 +126,8 @@ For all scripts, please see `package.json`. - npm run prerelease:build - npm run clean:build - node bin/clean.js --build + - npm run build:translations + - node bin/buildTranslations.js - node bin/prebuild.js --release --$npm_config_target - webpack --config bin/webpack.prod.js - npm run build:static @@ -128,3 +136,18 @@ For all scripts, please see `package.json`. - node bin/postbuild.js - npm run package - npx addons-linter ./dist + +## Localization + +Adding support for a new language can be done by creating a new locale folder (`locales/{lang}`) with a file for each namespace. To update an existing translation, modify the existing file in the same location. + +Translations will automatically be compiled at build time (part of the `prebuild` script), but can be run manually as well with `npm run build:translations`. The compiled translations are stored in `src/script/translations.js`. + +To use the translations, use the `Translation` class (`src/script/translation.ts`). When creating a new instance, pass in the desired namespace(s) (you should almost always include the `'common'` namespace). Once you have the translation instance you can simply call `translation.t()` with the desired key, such as `common:app.name`. + +### Namespaces + +- **Background**: Tranlations for context menu entries and the update notification +- **Common**: Common translations shared across the app +- **Options**: Translations for the extension's Option page +- **Popup**: Translations for the extension's Popup page