Bug 1638822 - convert openpgp strings to Fluent - part 5 - jsm files continue. r=mkmelin
authorKhushil Mistry <khushil324@gmail.com>
Mon, 29 Jun 2020 18:09:13 +0300
changeset 38879 97ca0281509e4a0f24066b8fa0b876c5a6f2a9a8
parent 38878 376d4a7f56f68beed993e202b2cec4a0e9a7857c
child 38880 abe41c82065282417721bf3dbac9ec7a7cc7ceaa
push id2646
push userclokep@gmail.com
push dateMon, 29 Jun 2020 21:33:35 +0000
treeherdercomm-beta@b1e911288dbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmkmelin
bugs1638822
Bug 1638822 - convert openpgp strings to Fluent - part 5 - jsm files continue. r=mkmelin
mail/components/compose/content/MsgComposeCommands.js
mail/extensions/openpgp/content/modules/cryptoAPI/GnuPGCryptoAPI.jsm
mail/extensions/openpgp/content/modules/decryption.jsm
mail/extensions/openpgp/content/modules/encryption.jsm
mail/extensions/openpgp/content/modules/errorHandling.jsm
mail/extensions/openpgp/content/modules/keyLookupHelper.jsm
mail/extensions/openpgp/content/modules/keyRing.jsm
mail/extensions/openpgp/content/modules/trust.jsm
mail/extensions/openpgp/content/modules/windows.jsm
mail/extensions/openpgp/content/strings/enigmail.ftl
mail/extensions/openpgp/content/strings/enigmail.properties
mail/extensions/openpgp/content/ui/commonWorkflows.js
mail/extensions/openpgp/content/ui/enigmailKeyManager.js
mail/extensions/openpgp/content/ui/enigmailMessengerOverlay.js
mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
mail/extensions/openpgp/content/ui/enigmailMsgHdrViewOverlay.js
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -51,17 +51,17 @@ var { AppConstants } = ChromeUtils.impor
 );
 var { MailConstants } = ChromeUtils.import(
   "resource:///modules/MailConstants.jsm"
 );
 var { ExtensionParent } = ChromeUtils.import(
   "resource://gre/modules/ExtensionParent.jsm"
 );
 
-var l10n = new Localization(
+var l10nCompose = new Localization(
   ["messenger/messengercompose/messengercompose.ftl"],
   true
 );
 
 ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
 ChromeUtils.defineModuleGetter(
   this,
   "ShortcutUtils",
@@ -4123,26 +4123,26 @@ function updateStringsOfAddressingFields
 function udpateAddressingInputAriaLabel(row) {
   let type = row.querySelector(".address-label-container > label").value;
   let pills = row.querySelectorAll("mail-address-pill");
   let input = row.querySelector(
     `input[is="autocomplete-input"][recipienttype]`
   );
   input.setAttribute(
     "aria-label",
-    l10n.formatValueSync("address-input-type-aria-label", {
+    l10nCompose.formatValueSync("address-input-type-aria-label", {
       type,
       count: pills.length,
     })
   );
 
   for (let pill of pills) {
     pill.setAttribute(
       "aria-label",
-      l10n.formatValueSync("pill-aria-label", {
+      l10nCompose.formatValueSync("pill-aria-label", {
         email: pill.fullAddress,
         count: pills.length,
       })
     );
   }
 }
 
 /**
--- a/mail/extensions/openpgp/content/modules/cryptoAPI/GnuPGCryptoAPI.jsm
+++ b/mail/extensions/openpgp/content/modules/cryptoAPI/GnuPGCryptoAPI.jsm
@@ -18,17 +18,17 @@ Services.scriptloader.loadSubScript(
 
 const { EnigmailLog } = ChromeUtils.import(
   "chrome://openpgp/content/modules/log.jsm"
 );
 const { EnigmailConstants } = ChromeUtils.import(
   "chrome://openpgp/content/modules/constants.jsm"
 );
 
-const l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
+var l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
 
 const {
   obtainKeyList,
   getPhotoFileFromGnuPG,
   getGpgKeyData,
 } = ChromeUtils.import(
   "chrome://openpgp/content/modules/cryptoAPI/gnupg-keylist.jsm"
 );
--- a/mail/extensions/openpgp/content/modules/decryption.jsm
+++ b/mail/extensions/openpgp/content/modules/decryption.jsm
@@ -248,17 +248,17 @@ var EnigmailDecryption = {
     var tail = cipherText.substr(
       endIndexObj.value + 1,
       cipherText.length - endIndexObj.value - 1
     );
 
     if (publicKey) {
       // TODO: import key into our scratch area for new, unknown keys
       if (!allowImport) {
-        errorMsgObj.value = EnigmailLocale.getString("keyInMessageBody");
+        errorMsgObj.value = l10n.formatValueSync("key-in-message-body");
         statusFlagsObj.value |= EnigmailConstants.DISPLAY_MESSAGE;
         statusFlagsObj.value |= EnigmailConstants.INLINE_KEY;
 
         return "";
       }
 
       // Import public key
       exitCodeObj.value = EnigmailKeyRing.importKey(
@@ -283,17 +283,17 @@ var EnigmailDecryption = {
         EnigmailConstants.SIGNATURE_ARMOR
       );
       if (oldSignature && newSignature != oldSignature) {
         EnigmailLog.ERROR(
           "enigmail.js: Enigmail.decryptMessage: Error - signature mismatch " +
             newSignature +
             "\n"
         );
-        errorMsgObj.value = EnigmailLocale.getString("sigMismatch");
+        errorMsgObj.value = l10n.formatValueSync("sig-mismatch");
         statusFlagsObj.value |= EnigmailConstants.DISPLAY_MESSAGE;
 
         return "";
       }
     }
 
     if (!EnigmailCore.getService(parent)) {
       statusFlagsObj.value |= EnigmailConstants.DISPLAY_MESSAGE;
@@ -395,19 +395,17 @@ var EnigmailDecryption = {
     }
 
     var pubKeyId = keyIdObj.value;
 
     if (statusFlagsObj.value & EnigmailConstants.BAD_SIGNATURE) {
       if (verifyOnly && indentStrObj.value) {
         // Probably replied message that could not be verified
         errorMsgObj.value =
-          EnigmailLocale.getString("unverifiedReply") +
-          "\n\n" +
-          errorMsgObj.value;
+          l10n.formatValueSync("unverified-reply") + "\n\n" + errorMsgObj.value;
         return "";
       }
 
       // Return bad signature (for checking later)
       signatureObj.value = newSignature;
     } else if (
       pubKeyId &&
       statusFlagsObj.value & EnigmailConstants.UNCERTAIN_SIGNATURE
@@ -451,20 +449,22 @@ var EnigmailDecryption = {
           false,
           pubKeyId,
           importErrorMsgObj
         );
 
         importedKey = exitStatus === 0;
 
         if (exitStatus > 0) {
-          EnigmailDialog.alert(
-            parent,
-            EnigmailLocale.getString("cantImport") + importErrorMsgObj.value
-          );
+          l10n.formatValue("cant-import").then(value => {
+            EnigmailDialog.alert(
+              parent,
+              value + importErrorMsgObj.value
+            );
+          });
         }
       }
 
       if (importedKey) {
         // Recursive call; note that EnigmailConstants.UI_ALLOW_KEY_IMPORT is unset
         // to break the recursion
         var uiFlagsDeep = interactive ? EnigmailConstants.UI_INTERACTIVE : 0;
         signatureObj.value = "";
@@ -570,31 +570,31 @@ var EnigmailDecryption = {
         exitCodeObj.keyList = preview;
         let exitStatus = 0;
 
         if (preview && errorMsgObj.value === "") {
           if (preview.length > 0) {
             if (preview.length == 1) {
               exitStatus = EnigmailDialog.confirmDlg(
                 parent,
-                EnigmailLocale.getString("doImportOne", [
-                  preview[0].name,
-                  preview[0].id,
-                ])
+                l10n.formatValueSync("do-import-one", {
+                  name: preview[0].name,
+                  id: preview[0].id,
+                })
               );
             } else {
               exitStatus = EnigmailDialog.confirmDlg(
                 parent,
-                EnigmailLocale.getString("doImportMultiple", [
-                  preview
+                l10n.formatValueSync("do-import-multiple", {
+                  key: preview
                     .map(function(a) {
                       return "\t" + a.name + " (" + a.id + ")";
                     })
                     .join("\n"),
-                ])
+                })
               );
             }
 
             if (exitStatus) {
               exitCodeObj.value = EnigmailKeyRing.importKey(
                 parent,
                 false,
                 byteData,
--- a/mail/extensions/openpgp/content/modules/encryption.jsm
+++ b/mail/extensions/openpgp/content/modules/encryption.jsm
@@ -18,19 +18,16 @@ const { EnigmailLog } = ChromeUtils.impo
   "chrome://openpgp/content/modules/log.jsm"
 );
 const { EnigmailPrefs } = ChromeUtils.import(
   "chrome://openpgp/content/modules/prefs.jsm"
 );
 const { EnigmailApp } = ChromeUtils.import(
   "chrome://openpgp/content/modules/app.jsm"
 );
-const { EnigmailLocale } = ChromeUtils.import(
-  "chrome://openpgp/content/modules/locale.jsm"
-);
 const { EnigmailDialog } = ChromeUtils.import(
   "chrome://openpgp/content/modules/dialog.jsm"
 );
 const { EnigmailGpg } = ChromeUtils.import(
   "chrome://openpgp/content/modules/gpg.jsm"
 );
 const { EnigmailErrorHandling } = ChromeUtils.import(
   "chrome://openpgp/content/modules/errorHandling.jsm"
@@ -48,16 +45,17 @@ const { EnigmailConstants } = ChromeUtil
   "chrome://openpgp/content/modules/constants.jsm"
 );
 const { EnigmailCryptoAPI } = ChromeUtils.import(
   "chrome://openpgp/content/modules/cryptoAPI.jsm"
 );
 var { PgpSqliteDb2 } = ChromeUtils.import(
   "chrome://openpgp/content/modules/sqliteDb.jsm"
 );
+var l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
 
 const gMimeHashAlgorithms = [
   null,
   "sha1",
   "ripemd160",
   "sha256",
   "sha384",
   "sha512",
@@ -87,17 +85,17 @@ var EnigmailEncryption = {
       "encryption.jsm: getEncryptCommand: hashAlgorithm=" + hashAlgorithm + "\n"
     );
 
     try {
       fromMailAddr = EnigmailFuncs.stripEmail(fromMailAddr);
       toMailAddr = EnigmailFuncs.stripEmail(toMailAddr);
       bccMailAddr = EnigmailFuncs.stripEmail(bccMailAddr);
     } catch (ex) {
-      errorMsgObj.value = EnigmailLocale.getString("invalidEmail");
+      errorMsgObj.value = l10n.formatValueSync("invalid-email");
       return null;
     }
 
     var signMsg = sendFlags & EnigmailConstants.SEND_SIGNED;
     var encryptMsg = sendFlags & EnigmailConstants.SEND_ENCRYPTED;
     var usePgpMime = sendFlags & EnigmailConstants.SEND_PGP_MIME;
 
     var useDefaultComment = false;
@@ -251,17 +249,17 @@ var EnigmailEncryption = {
       logFileObj
     );
 
     try {
       fromMailAddr = EnigmailFuncs.stripEmail(fromMailAddr);
       toMailAddr = EnigmailFuncs.stripEmail(toMailAddr);
       bccMailAddr = EnigmailFuncs.stripEmail(bccMailAddr);
     } catch (ex) {
-      errorMsgObj.value = EnigmailLocale.getString("invalidEmail");
+      errorMsgObj.value = l10n.formatValueSync("invalid-email");
       return null;
     }
 
     var signMsg = sendFlags & EnigmailConstants.SEND_SIGNED;
     var encryptMsg = sendFlags & EnigmailConstants.SEND_ENCRYPTED;
     var usePgpMime = sendFlags & EnigmailConstants.SEND_PGP_MIME;
 
     var detachedSig =
@@ -448,17 +446,17 @@ var EnigmailEncryption = {
     }
 
     errorMsgObj.value = "";
 
     if (!sendFlags) {
       EnigmailLog.DEBUG(
         "encryption.jsm: encryptMessageStart: NO ENCRYPTION!\n"
       );
-      errorMsgObj.value = EnigmailLocale.getString("notRequired");
+      errorMsgObj.value = l10n.formatValueSync("not-required");
       return null;
     }
 
     if (!EnigmailCore.getService(win)) {
       throw new Error(
         "encryption.jsm: encryptMessageStart: not yet initialized"
       );
     }
--- a/mail/extensions/openpgp/content/modules/errorHandling.jsm
+++ b/mail/extensions/openpgp/content/modules/errorHandling.jsm
@@ -20,17 +20,17 @@ const getEnigmailKeyRing = EnigmailLazy.
   "EnigmailKeyRing"
 );
 const getEnigmailFiles = EnigmailLazy.loader(
   "enigmail/files.jsm",
   "EnigmailFiles"
 );
 const getEnigmailRNG = EnigmailLazy.loader("enigmail/rng.jsm", "EnigmailRNG");
 
-const l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
+var l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
 
 var EnigmailErrorHandling = {
   /**
    * Determin why a given key or userID cannot be used for signing
    *
    * @param keySpec String - key ID or user ID
    *
    * @return String - the reason(s) as message to display to the user
--- a/mail/extensions/openpgp/content/modules/keyLookupHelper.jsm
+++ b/mail/extensions/openpgp/content/modules/keyLookupHelper.jsm
@@ -18,24 +18,21 @@ var EnigmailKeyRing = ChromeUtils.import
   "chrome://openpgp/content/modules/keyRing.jsm"
 ).EnigmailKeyRing;
 var EnigmailKeyServer = ChromeUtils.import(
   "chrome://openpgp/content/modules/keyserver.jsm"
 ).EnigmailKeyServer;
 var { EnigmailKeyserverURIs } = ChromeUtils.import(
   "chrome://openpgp/content/modules/keyserverUris.jsm"
 );
-var EnigmailLocale = ChromeUtils.import(
-  "chrome://openpgp/content/modules/locale.jsm"
-).EnigmailLocale;
 var EnigmailWkdLookup = ChromeUtils.import(
   "chrome://openpgp/content/modules/wkdLookup.jsm"
 ).EnigmailWkdLookup;
 
-const l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
+var l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
 
 var KeyLookupHelper = {
   async lookupAndImportOnKeyserver(
     window,
     identifier,
     giveFeedbackToUser,
     whenDoneCB
   ) {
@@ -57,17 +54,17 @@ var KeyLookupHelper = {
       if (keyList) {
         somethingWasImported = EnigmailKeyRing.importKeyDataWithConfirmation(
           window,
           keyList,
           vks.keyData,
           true
         );
       } else {
-        EnigmailDialog.alert(window, EnigmailLocale.getString("previewFailed"));
+        EnigmailDialog.alert(window, await l10n.formatValue("preview-failed"));
       }
     } else {
       console.debug("searchKeysOnInternet no data in keys.openpgp.org");
     }
 
     return somethingWasImported;
   },
 
@@ -89,17 +86,17 @@ var KeyLookupHelper = {
       let keyList = EnigmailKey.getKeyListFromKeyBlock(
         wkdKeys.keyData,
         {},
         false,
         true,
         false
       );
       if (!keyList) {
-        EnigmailDialog.alert(window, EnigmailLocale.getString("previewFailed"));
+        EnigmailDialog.alert(window, await l10n.formatValue("preview-failed"));
       } else {
         somethingWasImported = EnigmailKeyRing.importKeyDataWithConfirmation(
           window,
           keyList,
           wkdKeys.keyData,
           true
         );
         if (somethingWasImported && whenDoneCB) {
--- a/mail/extensions/openpgp/content/modules/keyRing.jsm
+++ b/mail/extensions/openpgp/content/modules/keyRing.jsm
@@ -580,17 +580,17 @@ var EnigmailKeyRing = {
         keyBlock,
         0,
         "",
         beginIndexObj,
         endIndexObj,
         {}
       );
       if (!blockType) {
-        errorMsgObj.value = EnigmailLocale.getString("noPGPblock");
+        errorMsgObj.value = l10n.formatValueSync("no-pgp-block");
         return 1;
       }
 
       if (blockType.search(/^(PUBLIC|PRIVATE) KEY BLOCK$/) !== 0) {
         errorMsgObj.value = l10n.formatValueSync("not-first-block");
         return 1;
       }
 
@@ -663,31 +663,31 @@ var EnigmailKeyRing = {
 
   importKeyDataWithConfirmation(window, preview, keyData, isBinary) {
     let somethingWasImported = false;
     if (preview.length > 0) {
       let exitStatus;
       if (preview.length == 1) {
         exitStatus = getDialog().confirmDlg(
           window,
-          EnigmailLocale.getString("doImportOne", [
-            preview[0].name,
-            preview[0].id,
-          ])
+          l10n.formatValueSync("do-import-one", {
+            name: preview[0].name,
+            id: preview[0].id,
+          })
         );
       } else {
         exitStatus = getDialog().confirmDlg(
           window,
-          EnigmailLocale.getString("doImportMultiple", [
-            preview
+          l10n.formatValueSync("do-import-multiple", {
+            key: preview
               .map(function(a) {
                 return "\t" + a.name + " (" + a.id + ")";
               })
               .join("\n"),
-          ])
+          })
         );
       }
 
       if (exitStatus) {
         let errorMsgObj = {};
         try {
           exitStatus = EnigmailKeyRing.importKey(
             window,
--- a/mail/extensions/openpgp/content/modules/trust.jsm
+++ b/mail/extensions/openpgp/content/modules/trust.jsm
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["EnigmailTrust"];
 
-const l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
+var l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
 
 // trust flags according to GPG documentation:
 // - https://www.gnupg.org/documentation/manuals/gnupg.pdf
 // - sources: doc/DETAILS
 // In the order of trustworthy:
 //  ---------------------------------------------------------
 //  i = The key is invalid (e.g. due to a missing self-signature)
 //  n = The key is not valid / Never trust this key
--- a/mail/extensions/openpgp/content/modules/windows.jsm
+++ b/mail/extensions/openpgp/content/modules/windows.jsm
@@ -21,17 +21,17 @@ const { EnigmailLocale } = ChromeUtils.i
 );
 const { EnigmailKeyRing } = ChromeUtils.import(
   "chrome://openpgp/content/modules/keyRing.jsm"
 );
 const { EnigmailStdlib } = ChromeUtils.import(
   "chrome://openpgp/content/modules/stdlib.jsm"
 );
 
-const l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
+var l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
 
 var EnigmailWindows = {
   /**
    * Open a window, or focus it if it is already open
    *
    * @winName   : String - name of the window; used to identify if it is already open
    * @spec      : String - window URL (e.g. chrome://openpgp/content/ui/test.xhtml)
    * @winOptions: String - window options as defined in nsIWindow.open
--- a/mail/extensions/openpgp/content/strings/enigmail.ftl
+++ b/mail/extensions/openpgp/content/strings/enigmail.ftl
@@ -347,16 +347,17 @@ no-key-selected = You should select at l
 export-to-file = Export Public Key To File
 export-keypair-to-file = Export Secret and Public Key To File
 export-secret-key = Do you want to include the secret key in the saved OpenPGP key file?
 save-keys-ok = The keys were successfully saved
 save-keys-failed = Saving the keys failed
 default-pub-key-filename = Exported-public-keys
 default-pub-sec-key-filename = Exported-public-and-secret-keys
 refresh-key-warn = Warning: depending on the number of keys and the connection speed, refreshing all keys could be quite a lengthy process!
+preview-failed = Can't read public key file.
 
 # Strings in keyObj.jsm
 key-ring-pub-key-revoked = The key { $userId } (key ID { $keyId }) is revoked.
 key-ring-pub-key-expired = The key { $userId } (key ID { $keyId }) has expired.
 key-ring-key-disabled = The key { $userId } (key ID { $keyId }) is disabled; it cannot be used.
 key-ring-key-invalid = The key { $userId } (key ID { $keyId }) is not valid. Please consider verifying it correctly.
 key-ring-key-not-trusted=The key { $userId } (key ID { $keyId }) is not trusted enough. Please set the trust level of your key to "ultimate" to use it for signing.
 key-ring-no-secret-key = You do not seem to have the secret key for { $userId } (key ID { $keyId }) on your keyring; you cannot use the key for signing.
@@ -402,16 +403,17 @@ no-key-found = We could not find any key
 fail-key-extract = Error - key extraction command failed
 
 # Strings used in keyRing.jsm
 fail-cancel = Error - Key receive cancelled by user
 not-first-block = Error - First OpenPGP block not public key block
 import-key-confirm = Import public key(s) embedded in message?
 fail-key-import = Error - key importing failed
 file-write-failed = Failed to write to file { $output }
+no-pgp-block = Error - No valid armored OpenPGP data block found
 
 # Strings used in trust.jsm
 key-valid-unknown = unknown
 key-valid-invalid = invalid
 key-valid-disabled = disabled
 key-valid-revoked = revoked
 key-valid-expired = expired
 key-trust-untrusted = untrusted
@@ -419,13 +421,54 @@ key-trust-marginal = marginal
 key-trust-full = trusted
 key-trust-ultimate = ultimate
 key-trust-group = (group)
 
 # Strings used in commonWorkflows.js
 import-key-file = Import OpenPGP Key File
 gnupg-file = GnuPG Files
 import-keys-failed=Importing the keys failed
+passphrase-prompt = Please enter the passphrase that unlocks the following key: { $key }
 
 # Strings used in enigmailKeygen.js
 save-revoke-cert-as = Create & Save Revocation Certificate
 revoke-cert-ok = The revocation certificate has been successfully created. You can use it to invalidate your public key, e.g. in case you would lose your secret key.
 revoke-cert-failed = The revocation certificate could not be created.
+
+# Strings used in enigmailMessengerOverlay.js
+failed-decrypt = Error - decryption failed
+
+# Strings used in enigmailMsgComposeOverlay.js
+msg-compose-button-send = &Send Message
+msg-compose-details-button-label = Details…
+msg-compose-details-button-access-key = D
+send-aborted = Send operation aborted.\n\n
+key-not-trusted = Not enough trust for key '{ $key }'
+key-not-found = Key '{ $key }' not found
+key-revoked = Key '{ $key }' revoked
+key-expired = Key '{ $key }' expired
+msg-compose-internal-error = An internal error has occurred.
+keys-to-export = Select OpenPGP Keys to Insert
+msg-compose-partially-encrypted-inlinePGP = The message you are replying to contained both unencrypted and encrypted parts. If the sender was not able to decrypt some message parts originally, you may be leaking confidential information that the sender was not able to originally decrypt themselves.\n\nPlease consider removing all quoted text from your reply to this sender.
+msg-compose-cannot-save-draft = Error while saving draft
+msg-compose-partially-encrypted-short = Beware of leaking sensitive information - partially encrypted email.
+quoted-printable-warn = You have enabled 'quoted-printable' encoding for sending messages. This may result in incorrect decryption and/or verification of your message.\nDo you wish to turn off sending 'quoted-printable' messages now?
+minimal-line-wrapping = You have set line wrapping to { $width } characters. For correct encryption and/or signing, this value needs to be at least 68.\nDo you wish to change line wrapping to 68 characters now?
+sending-hidden-rcpt = This message has BCC (blind copy) recipients. If this message is encrypted, it is possible to hide the BCC recipients but users of some products (e.g. PGP Corp.) will not be able to decrypt the message. Given this, we recommend to avoid BCC-emails with encrypted messages.
+send-with-hidden-bcc = Hide BCC recipients
+send-with-shown-bcc = Encrypt normally
+sending-news = Encrypted send operation aborted.\n\nThis message cannot be encrypted because there are newsgroup recipients. Please re-send the message without encryption.
+send-to-news-warning = Warning: you are about to send an encrypted email to a newsgroup.\n\nThis is discouraged because it only makes sense if all members of the group can decrypt the message, i.e. the message needs to be encrypted with the keys of all group participants. Please send this message only if you know exactly what you are doing.\n\nContinue?
+
+# Strings used in decryption.jsm
+do-import-multiple = Import the following keys?\n\n{ $key }
+do-import-one = Import { $name } ({ $id })?
+cant-import = Error importing public key\n\n
+unverified-reply = Indented message part (reply) was probably modified
+key-in-message-body = A key was found in the message body. Click 'Import Key' to import the key
+sig-mismatch = Error - Signature mismatch
+invalid-email = Error - invalid email address(es)
+
+# Strings used in enigmailMsgHdrViewOverlay.js
+decrypted-msg-with-format-error = Decrypted message (restored broken PGP email format probably caused by an old Exchange server, so that the result might not be perfect to read)
+
+# Strings used in encryption.jsm
+not-required = Error - no encryption required
--- a/mail/extensions/openpgp/content/strings/enigmail.properties
+++ b/mail/extensions/openpgp/content/strings/enigmail.properties
@@ -89,69 +89,45 @@ noteCutMessage2=*Multiple message blocks
 decryptOkNoSig=Warning\n\nDecryption was successful, but the signature could not be verified correctly
 msgOvl.button.contAnyway=&Continue Anyway
 signature.verifiedOK=The signature for attachment %S was successfully verified
 signature.verifyFailed=The signature for attachment %S could not be verified
 attachment.noMatchToSignature=Could not match attachment '%S' to a signature file
 attachment.noMatchFromSignature=Could not match signature file '%S' to an attachment
 fixBrokenExchangeMsg.failed=Did not succeed to repair message.
 ### detailsDlg.importKey=Import key
-wksNoIdentity=This key is not linked to any of your email accounts. Please add an account for at least one of the following email addresse(s):\n\n%S
-wksConfirmSuccess=Confirmation email sent.
-wksConfirmFailure=Sending the confirmation email failed.
+### wksNoIdentity=This key is not linked to any of your email accounts. Please add an account for at least one of the following email addresse(s):\n\n%S
+### wksConfirmSuccess=Confirmation email sent.
+### wksConfirmFailure=Sending the confirmation email failed.
 
 #####################################################################
 # Strings in enigmailMsgComposeOverlay.js
 #####################################################################
 
-keysToExport=Select OpenPGP Keys to Insert
 ### keysToUse=Select OpenPGP Key(s) to use for %S
 ### pubKey=Public key for %S\n
 
 ### windowLocked=Compose window is locked; send cancelled
 ### composeSpecifyEmail=Please specify your primary email address, which will be used to choose the signing key for outgoing messages.\n If you leave it blank, the FROM address of the message will be used to choose the signing key.
-sendingHiddenRcpt=This message has BCC (blind copy) recipients. If this message is encrypted, it is possible to hide the BCC recipients but users of some products (e.g. PGP Corp.) will not be able to decrypt the message. Given this, we recommend to avoid BCC-emails with encrypted messages.
-sendWithHiddenBcc=Hide BCC recipients
-sendWithShownBcc=Encrypt normally
-sendingNews=Encrypted send operation aborted.\n\nThis message cannot be encrypted because there are newsgroup recipients. Please re-send the message without encryption.
-sendToNewsWarning=Warning: you are about to send an encrypted email to a newsgroup.\n\nThis is discouraged because it only makes sense if all members of the group can decrypt the message, i.e. the message needs to be encrypted with the keys of all group participants. Please send this message only if you know exactly what you are doing.\n\nContinue?
-hasHTML=HTML email warning:\nThis message may contain HTML, which could cause signing/encryption to fail. To avoid this in the future, you should press the SHIFT key when clicking on the Compose/Reply button to send signed email.\nIf you sign email by default, you should uncheck the 'Compose Messages in HTML' preference box to permanently disable HTML email for this email account.
-strippingHTML=Message contains HTML formatting information that will be lost when converting to plain text for signing/encryption. Do you wish to proceed?
-msgCompose.button.sendAnyway=&Send Message Anyway
 ### attachWarning=Attachments to this message are not local, they cannot be encrypted. In order to encrypt the attachments, store them as local files first and attach these files. Do you wish to send the message anyway?
-quotedPrintableWarn=You have enabled 'quoted-printable' encoding for sending messages. This may result in incorrect decryption and/or verification of your message.\nDo you wish to turn off sending 'quoted-printable' messages now?
-minimalLineWrapping=You have set line wrapping to %S characters. For correct encryption and/or signing, this value needs to be at least 68.\nDo you wish to change line wrapping to 68 characters now?
 ### warning=Warning
 ### signIconClicked=You have manually modified signing. Therefore, while you are composing this message, (de)activating signing does not depend anymore on (de)activating encryption.
-errorOwnKeyUnusable=The key ID '%S' configured for the current identity does not yield a usable OpenPGP key.\n\nPlease ensure that you have a valid, not expired OpenPGP key and that your account settings point to that key.\nIf your key is not expired, then check if you did set Owner trust to "full" or "ultimate".
-msgCompose.cannotSaveDraft=Error while saving draft
-msgCompose.partiallyEncrypted.short=Beware of leaking sensitive information - partially encrypted email.
-msgCompose.partiallyEncrypted.inlinePGP=The message you are replying to contained both unencrypted and encrypted parts. If the sender was not able to decrypt some message parts originally, you may be leaking confidential information that the sender was not able to originally decrypt themselves.\n\nPlease consider removing all quoted text from your reply to this sender.
 
 ### msgCompose.internalEncryptionError=Internal Error: promised encryption disabled
-msgCompose.internalError=An internal error has occurred.
 
 ### msgCompose.protectSubject.tooltip=Protect the message subject
 ### msgCompose.noSubjectProtection.tooltip=Do not protect the message subject
 ### msgCompose.protectSubject.dialogTitle=Enable Protection of Subject?
 ### msgCompose.protectSubject.question=Regular encrypted emails contain the unredacted subject.\n\nWe have established a standard to hide the original subject in the encrypted message\nand replace it with a dummy text, such that the subject is only visible after the email is decrypted.\n\nDo you want to protect the subject in encrypted messages?
 ### msgCompose.protectSubject.yesButton=&Protect subject
 ### msgCompose.protectSubject.noButton=&Leave subject unprotected
 
-msgCompose.detailsButton.label=Details ...
-msgCompose.detailsButton.accessKey=D
-
 # note: should end with double newline:
-sendAborted=Send operation aborted.\n\n
 
 # details:
-keyNotTrusted=Not enough trust for key '%S'
-keyNotFound=Key '%S' not found
-keyRevoked=Key '%S' revoked
-keyExpired=Key '%S' expired
 
 ### statPGPMIME=PGP/MIME
 ### statSMIME=S/MIME
 ### statSigned=SIGNED
 ### statEncrypted=ENCRYPTED
 ### statPlain=UNSIGNED and UNENCRYPTED
 
 ### offlineSave=Save %1$S message to %2$S in Unsent Messages folder?
@@ -181,116 +157,100 @@ keyExpired=Key '%S' expired
 ### reasonManuallyForced=manually forced
 ### reasonByRecipientRules=forced by per-recipient rules
 ### reasonByAutoEncryption=forced by auto encryption
 ### reasonByConflict=due to conflict in per-recipient rules
 ### reasonByEncryptionMode=due to encryption mode
 
 # should not be used anymore:
 ### encryptYes=Message will be encrypted
-encryptNo=Message will not be encrypted
 
 # should not be used anymore:
 ### signYes=Message will be signed
-signNo=Message will not be signed
 
 
 # PGP/MIME status:
-pgpmimeNormal=Protocol: PGP/MIME
-inlinePGPNormal=Protocol: Inline PGP
-smimeNormal=Protocol: S/MIME
+### pgpmimeNormal=Protocol: PGP/MIME
+### inlinePGPNormal=Protocol: Inline PGP
+### smimeNormal=Protocol: S/MIME
 ### pgpmimeAuto=Protocol: PGP/MIME (auto)
 ### inlinePGPAuto=Protocol: Inline PGP (auto)
 ### smimeAuto=Protocol: S/MIME (auto)
 
 # should not be used anymore
 ### pgpmimeYes=PGP/MIME will be used
 ### pgpmimeNo=Inline PGP will be used
 
 # Attach own key status (tooltip strings):
-attachOwnKeyNo=Your own public key will not be attached
-attachOwnKeyYes=Your own public key will be attached
-attachOwnKeyDisabled=Your own public key cannot be attached. You have to select a specific key\nin the OpenPGP section of the Account Settings to enable this feature.
+### attachOwnKeyYes=Your own public key will be attached
+### attachOwnKeyDisabled=Your own public key cannot be attached. You have to select a specific key\nin the OpenPGP section of the Account Settings to enable this feature.
 
 ### rulesConflict=Conflicting per-recipient rules detected\n%S\n\nSend message with these settings?
 ### msgCompose.button.configure=&Configure
-msgCompose.button.send=&Send Message
 ### msgCompose.button.save=&Save Message
 
 # Strings in enigmailMsgHdrViewOverlay.js
 ### signatureFrom=Signature from public key %S
 ### clickDecrypt=; use 'Decrypt/Verify' function
 ### clickDecryptRetry=; use 'Decrypt/Verify' function to retry
 ### clickDetailsButton=; click on 'Details' button for more information
 ### clickImportButton=; click on the 'Import Key' button to import the key
 ### keyTypeUnsupported=; the key type is not supported by your version of GnuPG
-decryptManually=; click on the 'Decrypt' button to decrypt the message
-verifyManually=; click on the 'Verify' button to verify the signature
-headerView.button.verify=Verify
-headerView.button.decrypt=Decrypt
-msgPart=Part of the message %S
-msgSigned=signed
+### decryptManually=; click on the 'Decrypt' button to decrypt the message
+### verifyManually=; click on the 'Verify' button to verify the signature
+### headerView.button.verify=Verify
+### headerView.button.decrypt=Decrypt
+### msgPart=Part of the message %S
+### msgSigned=signed
 ### msgSignedUnkownKey=signed with unknown key
-msgEncrypted=encrypted
+### msgEncrypted=encrypted
 ### msgSignedAndEnc=signed and encrypted
 
 ### goodSig=Good signature
 ### uncertainSig=Uncertain signature
 ### badSig=Bad signature
 ### incompleteDecrypt=Decryption incomplete
 ### needKey=Error - no matching secret key found to decrypt message
-failedDecrypt=Error - decryption failed
 ### badPhrase=Error - bad passphrase
 ### missingMdcError=Error - missing or broken integrity protection (MDC)
 ### failedDecryptVerify=Error - decryption/verification failed
 ### viewInfo=; View > Message security info for details
 ### brokenExchangeMessage=Broken PGP/MIME message from MS-Exchange.
 
 ### decryptedMsg=Decrypted message
-decryptedMsgWithFormatError=Decrypted message (restored broken PGP email format probably caused by an old Exchange server, so that the result might not be perfect to read)
 
 ### usedAlgorithms=Used Algorithms: %1$S and %2$S
 
-wksConfirmationReq=Web Key Directory Confirmation Request
-wksConfirmationReq.message=This message has been sent by your email provider to confirm deployment of your OpenPGP public key\nin their Web Key Directory.\nProviding your public key helps others to discover your key and thus being able to encrypt messages to you.\n\nIf you want to deploy your key in the Web Key Directory now, please click on the button "Confirm Request" in the status bar.\nOtherwise, simply ignore this message.
-wksConfirmationReq.button.label=Confirm Request
+### wksConfirmationReq=Web Key Directory Confirmation Request
+### wksConfirmationReq.message=This message has been sent by your email provider to confirm deployment of your OpenPGP public key\nin their Web Key Directory.\nProviding your public key helps others to discover your key and thus being able to encrypt messages to you.\n\nIf you want to deploy your key in the Web Key Directory now, please click on the button "Confirm Request" in the status bar.\nOtherwise, simply ignore this message.
+### wksConfirmationReq.button.label=Confirm Request
 
-autocryptSetupReq.setupMsg.desc=This message contains all information to transfer your Autocrypt settings along with your secret key securely from your original device.
-autocryptSetupReq.setupMsg.backup=You can keep this message and use it as a backup for your secret key. If you want to do this, you should write down the password and store it securely.
+### autocryptSetupReq.setupMsg.desc=This message contains all information to transfer your Autocrypt settings along with your secret key securely from your original device.
+### autocryptSetupReq.setupMsg.backup=You can keep this message and use it as a backup for your secret key. If you want to do this, you should write down the password and store it securely.
 ### autocryptSetupReq.message.sent=Please click on the message on your new device and follow the instuctions to import the settings.
 
 # strings in pref-enigmail.js
 ### locateGpg=Locate GnuPG program
 ### warningsAreReset=All warnings have been reset.
 ### prefs.gpgFound=GnuPG was found in %S
 ### prefs.gpgNotFound=Could not find GnuPG
 ### prefEnigmail.oneKeyserverOnly=Error - you can only specify one keyserver for automatic downloading of missing OpenPGP keys.
 ### acSetupMessage.desc=Transfer your key to another Autocrypt-enabled device. (<html:span class='enigmailLink' href='https://autocrypt.org'>What is Autocrypt</html:span>)
 
 # Strings used in core.jsm
 # (said file also re-uses some strings from above)
 
 ### enterAdminPin=Please type in the ADMIN PIN of your SmartCard
 ### enterCardPin=Please type your SmartCard PIN
 
-badCommand=Error - encryption command failed
-cmdLine=command line and output:
-notRequired=Error - no encryption required
-notComplete=Error - key generation not yet completed
-invalidEmail=Error - invalid email address(es)
+### badCommand=Error - encryption command failed
+### cmdLine=command line and output:
+### notComplete=Error - key generation not yet completed
+
 ### noPassphrase=Error - no passphrase supplied
-noPGPblock=Error - No valid armored OpenPGP data block found
-unverifiedReply=Indented message part (reply) was probably modified
-keyInMessageBody=A key was found in the message body. Click 'Import Key' to import the key
-sigMismatch=Error - Signature mismatch
-cantImport=Error importing public key\n\n
-doImportOne=Import %1$S (%2$S)?
-doImportMultiple=Import the following keys?\n\n%S
-previewFailed=Can't read public key file.
-passphrasePrompt=Please enter the passphrase that unlocks the following key: %S
 
 # Strings used in errorHandling.jsm
 ### sc.wrongCardAvailable=The SmartCard %1$S found in your reader cannot be used to process the message.\nPlease insert your SmartCard %2$S and repeat the operation.
 ### sc.insertCard=The operation requires your SmartCard %S.\nPlease insert the required SmartCard and repeat the operation.
 ### sc.removeCard=The operation requires no SmartCard to be in the reader.\nPlease remove your SmartCard and repeat the operation.
 ### sc.noCardAvailable=No SmartCard could be found in your reader\nPlease insert your SmartCard and repeat the operation.
 ### sc.noReaderAvailable=Your SmartCard reader could not be accessed\nPlease attach your SmartCard reader, insert your card, and repeat the operation.
 ### keyError.resolutionAction=Please select a valid key in the OpenPGP section of your Account Settings.
--- a/mail/extensions/openpgp/content/ui/commonWorkflows.js
+++ b/mail/extensions/openpgp/content/ui/commonWorkflows.js
@@ -30,17 +30,19 @@ var l10n = new Localization(["messenger/
 function passphrasePromptCallback(win, keyId, resultFlags) {
   let p = {};
   p.value = "";
   let dummy = {};
   if (
     !Services.prompt.promptPassword(
       win,
       "",
-      EnigmailLocale.getString("passphrasePrompt", [keyId]),
+      l10n.formatValueSync("passphrase-prompt", {
+        key: keyId,
+      }),
       p,
       null,
       dummy
     )
   ) {
     resultFlags.canceled = true;
     return "";
   }
@@ -88,31 +90,31 @@ function EnigmailCommon_importKeysFromFi
     return false;
   }
   let exitStatus = -1;
 
   if (preview.length > 0) {
     if (preview.length == 1) {
       exitStatus = EnigmailDialog.confirmDlg(
         window,
-        EnigmailLocale.getString("doImportOne", [
-          preview[0].name,
-          preview[0].id,
-        ])
+        l10n.formatValueSync("do-import-one", {
+          name: preview[0].name,
+          id: preview[0].id,
+        })
       );
     } else {
       exitStatus = EnigmailDialog.confirmDlg(
         window,
-        EnigmailLocale.getString("doImportMultiple", [
-          preview
+        l10n.formatValueSync("do-import-multiple", {
+          key: preview
             .map(function(a) {
               return "\t" + a.name + " (" + a.id + ")";
             })
             .join("\n"),
-        ])
+        })
       );
     }
 
     if (exitStatus) {
       // import
       let resultKeys = {};
       let exitCode = EnigmailKeyRing.importKeyFromFile(
         window,
--- a/mail/extensions/openpgp/content/ui/enigmailKeyManager.js
+++ b/mail/extensions/openpgp/content/ui/enigmailKeyManager.js
@@ -766,31 +766,31 @@ function enigmailImportFromClipbrd() {
   );
   // should we allow importing secret keys?
   var exitStatus = -1;
 
   if (preview && preview.length > 0) {
     if (preview.length == 1) {
       exitStatus = EnigmailDialog.confirmDlg(
         window,
-        EnigmailLocale.getString("doImportOne", [
-          preview[0].name,
-          preview[0].id,
-        ])
+        l10n.formatValueSync("do-import-one", {
+          name: preview[0].name,
+          id: preview[0].id,
+        })
       );
     } else {
       exitStatus = EnigmailDialog.confirmDlg(
         window,
-        EnigmailLocale.getString("doImportMultiple", [
-          preview
+        l10n.formatValueSync("do-import-multiple", {
+          key: preview
             .map(function(a) {
               return "\t" + a.name + " (" + a.id + ")";
             })
             .join("\n"),
-        ])
+        })
       );
     }
 
     if (exitStatus) {
       // import
       EnigmailKeyRing.importKey(
         window,
         false,
@@ -801,17 +801,19 @@ function enigmailImportFromClipbrd() {
       );
       var keyList = preview.map(function(a) {
         return a.id;
       });
       EnigmailDialog.keyImportDlg(window, keyList);
       refreshKeys();
     }
   } else {
-    EnigmailDialog.alert(window, EnigmailLocale.getString("previewFailed"));
+    document.l10n.formatValue("preview-failed").then(value => {
+      EnigmailDialog.alert(window, value);
+    });
   }
 }
 
 function enigmailCopyToClipbrd() {
   var enigmailSvc = GetEnigmailSvc();
   if (!enigmailSvc) {
     return;
   }
@@ -1108,51 +1110,50 @@ function enigmailImportKeysFromUrl() {
         );
         // should we allow importing secret keys?
         var exitStatus = -1;
 
         if (preview && preview.length > 0) {
           if (preview.length == 1) {
             exitStatus = EnigmailDialog.confirmDlg(
               window,
-              EnigmailLocale.getString("doImportOne", [
-                preview[0].name,
-                preview[0].id,
-              ])
+              l10n.formatValueSync("do-import-one", {
+                name: preview[0].name,
+                id: preview[0].id,
+              })
             );
           } else {
             exitStatus = EnigmailDialog.confirmDlg(
               window,
-              EnigmailLocale.getString("doImportMultiple", [
-                preview
+              l10n.formatValueSync("do-import-multiple", {
+                key: preview
                   .map(function(a) {
                     return "\t" + a.name + " (" + a.id + ")";
                   })
                   .join("\n"),
-              ])
+              })
             );
           }
 
           if (exitStatus) {
             EnigmailKeyRing.importKey(
               window,
               false,
               data,
               false,
               "",
               errorMsgObj
             );
             errorMsgObj.preview = preview;
             resolve(errorMsgObj);
           }
         } else {
-          EnigmailDialog.alert(
-            window,
-            EnigmailLocale.getString("previewFailed")
-          );
+          document.l10n.formatValue("preview-failed").then(value => {
+            EnigmailDialog.alert(window, value);
+          });
         }
       };
 
       try {
         var bufferListener = EnigmailStreams.newStringStreamListener(cbFunc);
         var ioServ = Services.io;
         var msgUri = ioServ.newURI(value.value);
 
--- a/mail/extensions/openpgp/content/ui/enigmailMessengerOverlay.js
+++ b/mail/extensions/openpgp/content/ui/enigmailMessengerOverlay.js
@@ -1787,20 +1787,19 @@ Enigmail.msg = {
     if (preview && errorMsgObj.value === "") {
       EnigmailKeyRing.importKeyDataWithConfirmation(
         window,
         preview,
         keyData,
         true
       );
     } else {
-      EnigmailDialog.alert(
-        window,
-        EnigmailLocale.getString("previewFailed") + "\n" + errorMsgObj.value
-      );
+      document.l10n.formatValue("preview-failed").then(value => {
+        EnigmailDialog.alert(window, value + "\n" + errorMsgObj.value);
+      });
     }
   },
 
   async searchSignatureKey() {
     let keyId = document
       .getElementById("signatureKeyBox")
       .getAttribute("keyid");
     if (!keyId) {
@@ -1838,20 +1837,19 @@ Enigmail.msg = {
     if (preview && errorMsgObj.value === "") {
       EnigmailKeyRing.importKeyDataWithConfirmation(
         window,
         preview,
         keyData,
         false
       );
     } else {
-      EnigmailDialog.alert(
-        window,
-        EnigmailLocale.getString("previewFailed") + "\n" + errorMsgObj.value
-      );
+      document.l10n.formatValue("preview-failed").then(value => {
+        EnigmailDialog.alert(window, value + "\n" + errorMsgObj.value);
+      });
     }
   },
 
   /**
    * Extract the subject from the 1st content line and move it to the subject line
    */
   movePEPsubject() {
     EnigmailLog.DEBUG("enigmailMessengerOverlay.js: movePEPsubject:\n");
@@ -2714,17 +2712,17 @@ Enigmail.msg = {
       attachment.displayName = newLabel;
     }
 
     if (index && index.length > 0) {
       this.revealAttachments(parseInt(index, 10) + 1);
     }
   },
 
-  decryptAttachmentCallback(cbArray) {
+  async decryptAttachmentCallback(cbArray) {
     EnigmailLog.DEBUG(
       "enigmailMessengerOverlay.js: decryptAttachmentCallback:\n"
     );
 
     var callbackArg = cbArray[0];
 
     var exitCodeObj = {};
     var statusFlagsObj = {};
@@ -2821,20 +2819,19 @@ Enigmail.msg = {
       if (preview && errorMsgObj.value === "") {
         EnigmailKeyRing.importKeyDataWithConfirmation(
           window,
           preview,
           callbackArg.data,
           false
         );
       } else {
-        EnigmailDialog.alert(
-          window,
-          EnigmailLocale.getString("previewFailed") + "\n" + errorMsgObj.value
-        );
+        document.l10n.formatValue("preview-failed").then(value => {
+          EnigmailDialog.alert(window, value + "\n" + errorMsgObj.value);
+        });
       }
       outFile.remove(true);
       return;
     }
 
     exitStatus = EnigmailDecryption.decryptAttachment(
       window,
       outFile,
@@ -2861,17 +2858,19 @@ Enigmail.msg = {
           EnigmailDialog.info(
             window,
             EnigmailLocale.getString("decryptOkNoSig")
           );
         }
       } else {
         EnigmailDialog.info(
           window,
-          EnigmailLocale.getString("failedDecrypt") + "\n\n" + errorMsgObj.value
+          (await document.l10n.formatValue("failed-decrypt")) +
+            "\n\n" +
+            errorMsgObj.value
         );
         exitStatus = false;
       }
     }
     if (exitStatus) {
       if (statusFlagsObj.value & EnigmailConstants.IMPORTED_KEY) {
         if (exitCodeObj.keyList) {
           let importKeyList = exitCodeObj.keyList.map(function(a) {
--- a/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
+++ b/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
@@ -95,16 +95,18 @@ var EnigmailMsgRead = ChromeUtils.import
 var EnigmailMimeEncrypt = ChromeUtils.import(
   "chrome://openpgp/content/modules/mimeEncrypt.jsm"
 ).EnigmailMimeEncrypt;
 const { EnigmailCryptoAPI } = ChromeUtils.import(
   "chrome://openpgp/content/modules/cryptoAPI.jsm"
 );
 var { jsmime } = ChromeUtils.import("resource:///modules/jsmime.jsm");
 
+var l10n = new Localization(["messenger/openpgp/enigmail.ftl"], true);
+
 // Account encryption policy values:
 // const kEncryptionPolicy_Never = 0;
 // 'IfPossible' was used by ns4.
 // const kEncryptionPolicy_IfPossible = 1;
 var kEncryptionPolicy_Always = 2;
 
 if (!Enigmail) {
   var Enigmail = {};
@@ -955,24 +957,24 @@ Enigmail.msg = {
       );
       if (attachedObj) {
         this.attachOwnKeyObj.attachedObj = attachedObj;
         this.attachOwnKeyObj.attachedKey = hex;
       }
     }
   },
 
-  attachKey() {
+  async attachKey() {
     EnigmailLog.DEBUG(
       "enigmailMsgComposeOverlay.js: Enigmail.msg.attachKey: \n"
     );
 
     var resultObj = {};
     var inputObj = {};
-    inputObj.dialogHeader = EnigmailLocale.getString("keysToExport");
+    inputObj.dialogHeader = await document.l10n.formatValue("keys-to-export");
     inputObj.options = "multisel,allowexpired,nosending";
     if (this.trustAllKeys) {
       inputObj.options += ",trustallkeys";
     }
     window.openDialog(
       "chrome://openpgp/content/ui/enigmailKeySelection.xhtml",
       "",
       "dialog,modal,centerscreen,resizable",
@@ -1578,17 +1580,19 @@ Enigmail.msg = {
       var editor = gMsgCompose.editor.QueryInterface(Ci.nsIEditorMailSupport);
       var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak;
 
       var wrapWidth = this.getMailPref("mailnews.wraplength");
       if (wrapWidth > 0 && wrapWidth < 68 && editor.wrapWidth > 0) {
         if (
           EnigmailDialog.confirmDlg(
             window,
-            EnigmailLocale.getString("minimalLineWrapping", [wrapWidth])
+            l10n.formatValueSync("minimal-line-wrapping", {
+              width: wrapWidth,
+            })
           )
         ) {
           wrapWidth = 68;
           EnigmailPrefs.getPrefRoot().setIntPref(
             "mailnews.wraplength",
             wrapWidth
           );
         }
@@ -1757,22 +1761,26 @@ Enigmail.msg = {
     if (
       testStatusFlagsObj.value &
       (EnigmailConstants.INVALID_RECIPIENT | EnigmailConstants.NO_SECKEY)
     ) {
       // check if own key is invalid
       if (testErrorMsgObj.value && testErrorMsgObj.value.length > 0) {
         ++this.saveDraftError;
         if (this.saveDraftError === 1) {
-          this.notifyUser(
-            3,
-            EnigmailLocale.getString("msgCompose.cannotSaveDraft"),
-            "saveDraftFailed",
-            testErrorMsgObj.value
-          );
+          document.l10n
+            .formatValue("msg-compose-cannot-save-draft")
+            .then(value => {
+              this.notifyUser(
+                3,
+                value,
+                "saveDraftFailed",
+                testErrorMsgObj.value
+              );
+            });
         }
         return false;
       }
     }
 
     let secInfo;
 
     let param = Enigmail.msg.getSecurityParams();
@@ -2037,23 +2045,23 @@ Enigmail.msg = {
 
         var dummy = {
           value: null,
         };
 
         var hideBccUsers = promptSvc.confirmEx(
           window,
           EnigmailLocale.getString("enigConfirm2"),
-          EnigmailLocale.getString("sendingHiddenRcpt"),
+          l10n.formatValueSync("sending-hidden-rcpt"),
           promptSvc.BUTTON_TITLE_IS_STRING * promptSvc.BUTTON_POS_0 +
             promptSvc.BUTTON_TITLE_CANCEL * promptSvc.BUTTON_POS_1 +
             promptSvc.BUTTON_TITLE_IS_STRING * promptSvc.BUTTON_POS_2,
-          EnigmailLocale.getString("sendWithShownBcc"),
+          l10n.formatValueSync("send-with-shown-bcc"),
           null,
-          EnigmailLocale.getString("sendWithHiddenBcc"),
+          l10n.formatValueSync("send-with-hidden-bcc"),
           null,
           dummy
         );
         switch (hideBccUsers) {
           case 2:
             this.addRecipients(bccAddrList, recList);
             this.addRecipients(toAddrList, recList);
             break;
@@ -2066,24 +2074,26 @@ Enigmail.msg = {
       }
     }
 
     if (newsgroups) {
       toAddrList.push(newsgroups);
 
       if (sendFlags & EnigmailConstants.SEND_ENCRYPTED) {
         if (!EnigmailPrefs.getPref("encryptToNews")) {
-          EnigmailDialog.alert(window, EnigmailLocale.getString("sendingNews"));
+          document.l10n.formatValue("sending-news").then(value => {
+            EnigmailDialog.alert(window, value);
+          });
           return false;
         } else if (
           !EnigmailDialog.confirmPref(
             window,
-            EnigmailLocale.getString("sendToNewsWarning"),
+            l10n.formatValueSync("send-to-news-warning"),
             "warnOnSendingNewsgroups",
-            EnigmailLocale.getString("msgCompose.button.send")
+            l10n.formatValueSync("msg-compose-button-send")
           )
         ) {
           return false;
         }
       }
     }
 
     return {
@@ -2497,17 +2507,17 @@ Enigmail.msg = {
       return false;
     }
 
     try {
       if (this.getMailPref("mail.strictly_mime")) {
         if (
           EnigmailDialog.confirmPref(
             window,
-            EnigmailLocale.getString("quotedPrintableWarn"),
+            l10n.formatValueSync("quoted-printable-warn"),
             "quotedPrintableWarn"
           )
         ) {
           EnigmailPrefs.getPrefRoot().setBoolPref("mail.strictly_mime", false);
         }
       }
     } catch (ex) {}
 
@@ -2623,55 +2633,61 @@ Enigmail.msg = {
           return false;
         }
       }
     }
 
     return true;
   },
 
-  sendAborted(window, errorMsgObj) {
+  async sendAborted(window, errorMsgObj) {
     if (errorMsgObj && errorMsgObj.value) {
       var txt = errorMsgObj.value;
       var txtLines = txt.split(/\r?\n/);
       var errorMsg = "";
       for (var i = 0; i < txtLines.length; ++i) {
         var line = txtLines[i];
         var tokens = line.split(/ /);
         // process most important business reasons for invalid recipient (and sender) errors:
         if (
           tokens.length == 3 &&
           (tokens[0] == "INV_RECP" || tokens[0] == "INV_SGNR")
         ) {
           var reason = tokens[1];
           var key = tokens[2];
           if (reason == "10") {
-            errorMsg += EnigmailLocale.getString("keyNotTrusted", [key]) + "\n";
+            errorMsg +=
+              (await document.l10n.formatValue("key-not-trusted", { key })) +
+              "\n";
           } else if (reason == "1") {
-            errorMsg += EnigmailLocale.getString("keyNotFound", [key]) + "\n";
+            errorMsg +=
+              (await document.l10n.formatValue("key-not-found", { key })) +
+              "\n";
           } else if (reason == "4") {
-            errorMsg += EnigmailLocale.getString("keyRevoked", [key]) + "\n";
+            errorMsg +=
+              (await document.l10n.formatValue("key-revoked", { key })) + "\n";
           } else if (reason == "5") {
-            errorMsg += EnigmailLocale.getString("keyExpired", [key]) + "\n";
+            errorMsg +=
+              (await document.l10n.formatValue("key-expired", { key })) + "\n";
           }
         }
       }
       if (errorMsg !== "") {
         txt = errorMsg + "\n" + txt;
       }
       EnigmailDialog.info(
         window,
-        EnigmailLocale.getString("sendAborted") + txt
+        (await document.l10n.formatValue("send-aborted")) + txt
       );
     } else {
       EnigmailDialog.info(
         window,
-        EnigmailLocale.getString("sendAborted") +
+        (await document.l10n.formatValue("send-aborted")) +
           "\n" +
-          EnigmailLocale.getString("msgCompose.internalError")
+          (await document.l10n.formatValue("msg-compose-internal-error"))
       );
     }
   },
 
   getMailPref(prefName) {
     let prefRoot = EnigmailPrefs.getPrefRoot();
 
     var prefValue = null;
@@ -3308,17 +3324,17 @@ Enigmail.msg = {
    * Display a notification to the user at the bottom of the window
    *
    * @param priority: Number    - Priority of the message [1 = high (error) ... 3 = low (info)]
    * @param msgText: String     - Text to be displayed in notification bar
    * @param messageId: String   - Unique message type identification
    * @param detailsText: String - optional text to be displayed by clicking on "Details" button.
    *                              if null or "", then the Detail button will no be displayed.
    */
-  notifyUser(priority, msgText, messageId, detailsText) {
+  async notifyUser(priority, msgText, messageId, detailsText) {
     let notif = document.getElementById("attachmentNotificationBox");
     if (!notif) {
       notif = gNotification.notificationbox;
     }
     let prio;
 
     switch (priority) {
       case 1:
@@ -3330,40 +3346,42 @@ Enigmail.msg = {
       default:
         prio = notif.PRIORITY_WARNING_MEDIUM;
     }
 
     let buttonArr = [];
 
     if (detailsText && detailsText.length > 0) {
       buttonArr.push({
-        accessKey: EnigmailLocale.getString(
-          "msgCompose.detailsButton.accessKey"
+        accessKey: await document.l10n.formatValue(
+          "msg-compose-details-button-access-key"
         ),
-        label: EnigmailLocale.getString("msgCompose.detailsButton.label"),
+        label: await document.l10n.formatValue(
+          "msg-compose-details-button-label"
+        ),
         callback(aNotificationBar, aButton) {
           EnigmailDialog.info(window, detailsText);
         },
       });
     }
     notif.appendNotification(msgText, messageId, null, prio, buttonArr);
   },
 
   /**
    * Display a warning message if we are replying to or forwarding
    * a partially decrypted inline-PGP email
    */
-  displayPartialEncryptedWarning() {
-    let msgLong = EnigmailLocale.getString(
-      "msgCompose.partiallyEncrypted.inlinePGP"
+  async displayPartialEncryptedWarning() {
+    let msgLong = await document.l10n.formatValue(
+      "msg-compose-partially-encrypted-inlinePGP"
     );
 
     this.notifyUser(
       1,
-      EnigmailLocale.getString("msgCompose.partiallyEncrypted.short"),
+      await document.l10n.formatValue("msg-compose-partially-encrypted-short"),
       "notifyPartialDecrypt",
       msgLong
     );
   },
 
   editorSelectAll() {
     if (this.editor) {
       this.editor.selectAll();
--- a/mail/extensions/openpgp/content/ui/enigmailMsgHdrViewOverlay.js
+++ b/mail/extensions/openpgp/content/ui/enigmailMsgHdrViewOverlay.js
@@ -514,17 +514,17 @@ Enigmail.hdrView = {
         if (k) {
           gDBView.reloadMessageWithAllParts();
         }
       }
     });
   },
   */
 
-  displayStatusBar() {
+  async displayStatusBar() {
     let secInfo = Enigmail.msg.securityInfo;
     let statusFlags = secInfo.statusFlags;
     let extStatusFlags =
       "extStatusFlags" in secInfo ? secInfo.extStatusFlags : 0;
     let cryptoContainer, encryptedUINode, signedUINode;
 
     cryptoContainer = gCryptoContainer;
     signedUINode = gSignedUINode;
@@ -547,17 +547,19 @@ Enigmail.hdrView = {
         this.msgEncryptionState = EnigmailConstants.MSG_ENC_FAILURE;
       }
       this.msgSignatureState = EnigmailConstants.MSG_SIG_NONE;
     } else if (statusFlags & EnigmailConstants.DECRYPTION_OKAY) {
       EnigmailURIs.rememberEncryptedUri(this.lastEncryptedMsgKey);
       encryptedUINode.setAttribute("encrypted", "ok");
       this.msgEncryptionState = EnigmailConstants.MSG_ENC_OK;
       if (secInfo.xtraStatus && secInfo.xtraStatus == "buggyMailFormat") {
-        console.log(EnigmailLocale.getString("decryptedMsgWithFormatError"));
+        console.log(
+          await document.l10n.formatValue("decrypted-msg-with-format-error")
+        );
       }
     }
 
     if (
       statusFlags &
       (EnigmailConstants.BAD_SIGNATURE |
         EnigmailConstants.REVOKED_KEY |
         EnigmailConstants.EXPIRED_KEY_SIGNATURE |