[tbb-commits] [Git][tpo/applications/tor-browser][tor-browser-115.10.0esr-13.5-1] 4 commits: fixup! Bug 40458: Implement .tor.onion aliases

richard (@richard) git at gitlab.torproject.org
Tue Apr 16 22:20:08 UTC 2024



richard pushed to branch tor-browser-115.10.0esr-13.5-1 at The Tor Project / Applications / Tor Browser


Commits:
5fd3baa6 by Henry Wilkes at 2024-04-16T21:57:16+00:00
fixup! Bug 40458: Implement .tor.onion aliases

Bug 42206: Migrate ruleset strings to Fluent.

- - - - -
7b790cf6 by Henry Wilkes at 2024-04-16T21:57:16+00:00
fixup! Tor Browser strings

Bug 42206: Migrate ruleset strings to Fluent.

- - - - -
caed3ae7 by Henry Wilkes at 2024-04-16T21:57:16+00:00
fixup! Add TorStrings module for localization

Bug 42206: Migrate ruleset strings to Fluent.

- - - - -
8c14330e by Henry Wilkes at 2024-04-16T21:57:16+00:00
fixup! Tor Browser localization migration scripts.

Bug 42206: Migrate ruleset strings to Fluent.

- - - - -


7 changed files:

- browser/components/rulesets/RulesetsParent.sys.mjs
- browser/components/rulesets/content/aboutRulesets.html
- browser/components/rulesets/content/aboutRulesets.js
- browser/locales/en-US/browser/tor-browser.ftl
- toolkit/modules/TorStrings.sys.mjs
- − toolkit/torbutton/chrome/locale/en-US/rulesets.properties
- + tools/torbrowser/l10n/migrations/bug-42206-rulesets.py


Changes:

=====================================
browser/components/rulesets/RulesetsParent.sys.mjs
=====================================
@@ -1,6 +1,5 @@
 // Copyright (c) 2022, The Tor Project, Inc.
 
-import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
 import {
   OnionAliasStore,
   OnionAliasStoreTopics,
@@ -8,8 +7,8 @@ import {
 
 const kShowWarningPref = "torbrowser.rulesets.show_warning";
 
-// This class allows about:rulesets to get TorStrings and to load/save the
-// preference for skipping the warning
+// This class allows about:rulesets to load/save the preference for skipping the
+// warning
 export class RulesetsParent extends JSWindowActorParent {
   constructor(...args) {
     super(...args);
@@ -53,7 +52,6 @@ export class RulesetsParent extends JSWindowActorParent {
         return OnionAliasStore.getChannels();
       case "rulesets:get-init-args":
         return {
-          TorStrings,
           showWarning: Services.prefs.getBoolPref(kShowWarningPref, true),
         };
       case "rulesets:set-channel":


=====================================
browser/components/rulesets/content/aboutRulesets.html
=====================================
@@ -11,13 +11,19 @@
       rel="stylesheet"
       href="chrome://browser/content/rulesets/aboutRulesets.css"
     />
+
+    <link rel="localization" href="branding/brand.ftl" />
+    <link rel="localization" href="browser/tor-browser.ftl" />
   </head>
   <body>
     <!-- Warning -->
     <div id="warning-wrapper">
       <div id="warning">
-        <h1 id="warning-title"></h1>
-        <p id="warning-description"></p>
+        <h1 id="warning-title" data-l10n-id="rulesets-warning-heading"></h1>
+        <p
+          id="warning-description"
+          data-l10n-id="rulesets-warning-description"
+        ></p>
         <p>
           <label>
             <input
@@ -25,11 +31,18 @@
               type="checkbox"
               checked="checked"
             />
-            <span id="warning-enable-label"></span>
+            <span
+              id="warning-enable-label"
+              data-l10n-id="rulesets-warning-checkbox"
+            ></span>
           </label>
         </p>
         <div id="warning-buttonbar">
-          <button id="warning-button" autofocus="autofocus"></button>
+          <button
+            id="warning-button"
+            autofocus="autofocus"
+            data-l10n-id="rulesets-warning-continue-button"
+          ></button>
         </div>
       </div>
     </div>
@@ -37,11 +50,20 @@
     <div id="main-content">
       <!-- Ruleset list -->
       <aside>
-        <div id="ruleset-heading"></div>
+        <div
+          id="ruleset-heading"
+          data-l10n-id="rulesets-side-panel-heading"
+        ></div>
         <div id="ruleset-list-container">
           <div id="ruleset-list-empty">
-            <p id="ruleset-list-empty-title"></p>
-            <p id="ruleset-list-empty-description"></p>
+            <p
+              id="ruleset-list-empty-title"
+              data-l10n-id="rulesets-side-panel-no-rules"
+            ></p>
+            <p
+              id="ruleset-list-empty-description"
+              data-l10n-id="rulesets-side-panel-no-rules-description"
+            ></p>
           </div>
           <ul id="ruleset-list">
             <li id="ruleset-template">
@@ -59,24 +81,40 @@
       <section id="ruleset-details">
         <div class="title">
           <h1 id="ruleset-title"></h1>
-          <button id="ruleset-edit" class="ghost-button"></button>
+          <button
+            id="ruleset-edit"
+            class="ghost-button"
+            data-l10n-id="rulesets-details-edit-button"
+          ></button>
         </div>
         <dl>
-          <dt id="ruleset-jwk-label"></dt>
+          <dt id="ruleset-jwk-label" data-l10n-id="rulesets-details-jwk"></dt>
           <dd id="ruleset-jwk-value"></dd>
-          <dt id="ruleset-path-prefix-label"></dt>
+          <dt
+            id="ruleset-path-prefix-label"
+            data-l10n-id="rulesets-details-path"
+          ></dt>
           <dd>
             <a id="ruleset-path-prefix-value" target="_blank"></a>
           </dd>
-          <dt id="ruleset-scope-label"></dt>
+          <dt
+            id="ruleset-scope-label"
+            data-l10n-id="rulesets-details-scope"
+          ></dt>
           <dd id="ruleset-scope-value"></dd>
         </dl>
         <label id="ruleset-enable">
           <input type="checkbox" id="ruleset-enable-checkbox" />
-          <span id="ruleset-enable-label"></span>
+          <span
+            id="ruleset-enable-label"
+            data-l10n-id="rulesets-details-enable-checkbox"
+          ></span>
         </label>
         <div id="ruleset-buttonbar">
-          <button id="ruleset-update-button"></button>
+          <button
+            id="ruleset-update-button"
+            data-l10n-id="rulesets-details-update-button"
+          ></button>
         </div>
         <hr />
         <p id="ruleset-updated"></p>
@@ -89,24 +127,52 @@
         </div>
         <form id="edit-ruleset-form">
           <label>
-            <div id="edit-jwk-label"></div>
-            <textarea id="edit-jwk-textarea" rows="10"></textarea>
+            <div id="edit-jwk-label" data-l10n-id="rulesets-details-jwk"></div>
+            <textarea
+              id="edit-jwk-textarea"
+              rows="10"
+              data-l10n-id="rulesets-details-jwk-input"
+            ></textarea>
           </label>
           <label>
-            <div id="edit-path-prefix-label"></div>
-            <input id="edit-path-prefix-input" type="text" />
+            <div
+              id="edit-path-prefix-label"
+              data-l10n-id="rulesets-details-path"
+            ></div>
+            <input
+              id="edit-path-prefix-input"
+              type="text"
+              data-l10n-id="rulesets-details-path-input"
+            />
           </label>
           <label>
-            <div id="edit-scope-label"></div>
-            <input id="edit-scope-input" type="text" />
+            <div
+              id="edit-scope-label"
+              data-l10n-id="rulesets-details-scope"
+            ></div>
+            <input
+              id="edit-scope-input"
+              type="text"
+              data-l10n-id="rulesets-details-scope-input"
+            />
           </label>
           <label id="edit-enable">
             <input type="checkbox" id="edit-enable-checkbox" />
-            <span id="edit-enable-label"></span>
+            <span
+              id="edit-enable-label"
+              data-l10n-id="rulesets-details-enable-checkbox"
+            ></span>
           </label>
           <div id="edit-buttonbar">
-            <button id="edit-save" class="primary"></button>
-            <button id="edit-cancel"></button>
+            <button
+              id="edit-save"
+              class="primary"
+              data-l10n-id="rulesets-details-save-button"
+            ></button>
+            <button
+              id="edit-cancel"
+              data-l10n-id="rulesets-details-cancel-button"
+            ></button>
           </div>
         </form>
       </section>


=====================================
browser/components/rulesets/content/aboutRulesets.js
=====================================
@@ -2,8 +2,6 @@
 
 /* globals RPMAddMessageListener, RPMSendQuery, RPMSendAsyncMessage */
 
-let TorStrings;
-
 const Orders = Object.freeze({
   Name: "name",
   NameDesc: "name-desc",
@@ -19,55 +17,35 @@ const States = Object.freeze({
 
 function setUpdateDate(ruleset, element) {
   if (!ruleset.enabled) {
-    element.textContent = TorStrings.rulesets.disabled;
+    document.l10n.setAttributes(element, "rulesets-update-rule-disabled");
     return;
   }
   if (!ruleset.currentTimestamp) {
-    element.textContent = TorStrings.rulesets.neverUpdated;
+    document.l10n.setAttributes(element, "rulesets-update-never");
     return;
   }
 
-  const formatter = new Intl.DateTimeFormat(navigator.languages, {
-    year: "numeric",
-    month: "long",
-    day: "numeric",
+  document.l10n.setAttributes(element, "rulesets-update-last", {
+    date: ruleset.currentTimestamp * 1000,
   });
-  element.textContent = TorStrings.rulesets.lastUpdated.replace(
-    "%S",
-    formatter.format(new Date(ruleset.currentTimestamp * 1000))
-  );
 }
 
 class WarningState {
-  selectors = Object.freeze({
-    wrapper: "#warning-wrapper",
-    title: "#warning-title",
-    description: "#warning-description",
-    enableCheckbox: "#warning-enable-checkbox",
-    enableLabel: "#warning-enable-label",
-    button: "#warning-button",
-  });
-
-  elements = Object.freeze({
-    wrapper: document.querySelector(this.selectors.wrapper),
-    title: document.querySelector(this.selectors.title),
-    description: document.querySelector(this.selectors.description),
-    enableCheckbox: document.querySelector(this.selectors.enableCheckbox),
-    enableLabel: document.querySelector(this.selectors.enableLabel),
-    button: document.querySelector(this.selectors.button),
-  });
+  elements = {
+    enableCheckbox: document.getElementById("warning-enable-checkbox"),
+    button: document.getElementById("warning-button"),
+  };
 
   constructor() {
-    const elements = this.elements;
-    elements.title.textContent = TorStrings.rulesets.warningTitle;
-    elements.description.textContent = TorStrings.rulesets.warningDescription;
-    elements.enableLabel.textContent = TorStrings.rulesets.warningEnable;
-    elements.button.textContent = TorStrings.rulesets.warningButton;
-    elements.enableCheckbox.addEventListener(
+    this.elements.enableCheckbox.addEventListener(
       "change",
       this.onEnableChange.bind(this)
     );
-    elements.button.addEventListener("click", this.onButtonClick.bind(this));
+
+    this.elements.button.addEventListener(
+      "click",
+      this.onButtonClick.bind(this)
+    );
   }
 
   show() {
@@ -89,50 +67,28 @@ class WarningState {
 }
 
 class DetailsState {
-  selectors = Object.freeze({
-    title: "#ruleset-title",
-    edit: "#ruleset-edit",
-    jwkLabel: "#ruleset-jwk-label",
-    jwkValue: "#ruleset-jwk-value",
-    pathPrefixLabel: "#ruleset-path-prefix-label",
-    pathPrefixValue: "#ruleset-path-prefix-value",
-    scopeLabel: "#ruleset-scope-label",
-    scopeValue: "#ruleset-scope-value",
-    enableCheckbox: "#ruleset-enable-checkbox",
-    enableLabel: "#ruleset-enable-label",
-    updateButton: "#ruleset-update-button",
-    updated: "#ruleset-updated",
-  });
-
-  elements = Object.freeze({
-    title: document.querySelector(this.selectors.title),
-    edit: document.querySelector(this.selectors.edit),
-    jwkLabel: document.querySelector(this.selectors.jwkLabel),
-    jwkValue: document.querySelector(this.selectors.jwkValue),
-    pathPrefixLabel: document.querySelector(this.selectors.pathPrefixLabel),
-    pathPrefixValue: document.querySelector(this.selectors.pathPrefixValue),
-    scopeLabel: document.querySelector(this.selectors.scopeLabel),
-    scopeValue: document.querySelector(this.selectors.scopeValue),
-    enableCheckbox: document.querySelector(this.selectors.enableCheckbox),
-    enableLabel: document.querySelector(this.selectors.enableLabel),
-    updateButton: document.querySelector(this.selectors.updateButton),
-    updated: document.querySelector(this.selectors.updated),
-  });
+  elements = {
+    title: document.getElementById("ruleset-title"),
+    jwkValue: document.getElementById("ruleset-jwk-value"),
+    pathPrefixValue: document.getElementById("ruleset-path-prefix-value"),
+    scopeValue: document.getElementById("ruleset-scope-value"),
+    enableCheckbox: document.getElementById("ruleset-enable-checkbox"),
+    updateButton: document.getElementById("ruleset-update-button"),
+    updated: document.getElementById("ruleset-updated"),
+  };
 
   constructor() {
-    const elements = this.elements;
-    elements.edit.textContent = TorStrings.rulesets.edit;
-    elements.edit.addEventListener("click", this.onEdit.bind(this));
-    elements.jwkLabel.textContent = TorStrings.rulesets.jwk;
-    elements.pathPrefixLabel.textContent = TorStrings.rulesets.pathPrefix;
-    elements.scopeLabel.textContent = TorStrings.rulesets.scope;
-    elements.enableCheckbox.addEventListener(
+    document
+      .getElementById("ruleset-edit")
+      .addEventListener("click", this.onEdit.bind(this));
+    this.elements.enableCheckbox.addEventListener(
       "change",
       this.onEnable.bind(this)
     );
-    elements.enableLabel.textContent = TorStrings.rulesets.enable;
-    elements.updateButton.textContent = TorStrings.rulesets.checkUpdates;
-    elements.updateButton.addEventListener("click", this.onUpdate.bind(this));
+    this.elements.updateButton.addEventListener(
+      "click",
+      this.onUpdate.bind(this)
+    );
   }
 
   show(ruleset) {
@@ -179,61 +135,22 @@ class DetailsState {
 }
 
 class EditState {
-  selectors = Object.freeze({
-    form: "#edit-ruleset-form",
-    title: "#edit-title",
-    nameGroup: "#edit-name-group",
-    nameLabel: "#edit-name-label",
-    nameInput: "#edit-name-input",
-    jwkLabel: "#edit-jwk-label",
-    jwkTextarea: "#edit-jwk-textarea",
-    pathPrefixLabel: "#edit-path-prefix-label",
-    pathPrefixInput: "#edit-path-prefix-input",
-    scopeLabel: "#edit-scope-label",
-    scopeInput: "#edit-scope-input",
-    enableCheckbox: "#edit-enable-checkbox",
-    enableLabel: "#edit-enable-label",
-    save: "#edit-save",
-    cancel: "#edit-cancel",
-  });
-
-  elements = Object.freeze({
-    form: document.querySelector(this.selectors.form),
-    title: document.querySelector(this.selectors.title),
-    jwkLabel: document.querySelector(this.selectors.jwkLabel),
-    jwkTextarea: document.querySelector(this.selectors.jwkTextarea),
-    pathPrefixLabel: document.querySelector(this.selectors.pathPrefixLabel),
-    pathPrefixInput: document.querySelector(this.selectors.pathPrefixInput),
-    scopeLabel: document.querySelector(this.selectors.scopeLabel),
-    scopeInput: document.querySelector(this.selectors.scopeInput),
-    enableCheckbox: document.querySelector(this.selectors.enableCheckbox),
-    enableLabel: document.querySelector(this.selectors.enableLabel),
-    save: document.querySelector(this.selectors.save),
-    cancel: document.querySelector(this.selectors.cancel),
-  });
+  elements = {
+    form: document.getElementById("edit-ruleset-form"),
+    title: document.getElementById("edit-title"),
+    jwkTextarea: document.getElementById("edit-jwk-textarea"),
+    pathPrefixInput: document.getElementById("edit-path-prefix-input"),
+    scopeInput: document.getElementById("edit-scope-input"),
+    enableCheckbox: document.getElementById("edit-enable-checkbox"),
+  };
 
   constructor() {
-    const elements = this.elements;
-    elements.jwkLabel.textContent = TorStrings.rulesets.jwk;
-    elements.jwkTextarea.setAttribute(
-      "placeholder",
-      TorStrings.rulesets.jwkPlaceholder
-    );
-    elements.pathPrefixLabel.textContent = TorStrings.rulesets.pathPrefix;
-    elements.pathPrefixInput.setAttribute(
-      "placeholder",
-      TorStrings.rulesets.pathPrefixPlaceholder
-    );
-    elements.scopeLabel.textContent = TorStrings.rulesets.scope;
-    elements.scopeInput.setAttribute(
-      "placeholder",
-      TorStrings.rulesets.scopePlaceholder
-    );
-    elements.enableLabel.textContent = TorStrings.rulesets.enable;
-    elements.save.textContent = TorStrings.rulesets.save;
-    elements.save.addEventListener("click", this.onSave.bind(this));
-    elements.cancel.textContent = TorStrings.rulesets.cancel;
-    elements.cancel.addEventListener("click", this.onCancel.bind(this));
+    document
+      .getElementById("edit-save")
+      .addEventListener("click", this.onSave.bind(this));
+    document
+      .getElementById("edit-cancel")
+      .addEventListener("click", this.onCancel.bind(this));
   }
 
   show(ruleset) {
@@ -276,7 +193,9 @@ class EditState {
       elements.jwkTextarea.setCustomValidity("");
     } catch (err) {
       console.error("Invalid JSON or invalid JWK", err);
-      elements.jwkTextarea.setCustomValidity(TorStrings.rulesets.jwkInvalid);
+      elements.jwkTextarea.setCustomValidity(
+        await document.l10n.formatValue("rulesets-details-jwk-input-invalid")
+      );
       valid = false;
     }
 
@@ -285,7 +204,7 @@ class EditState {
       const url = new URL(pathPrefix);
       if (url.protocol !== "http:" && url.protocol !== "https:") {
         elements.pathPrefixInput.setCustomValidity(
-          TorStrings.rulesets.pathPrefixInvalid
+          await document.l10n.formatValue("rulesets-details-path-input-invalid")
         );
         valid = false;
       } else {
@@ -294,7 +213,7 @@ class EditState {
     } catch (err) {
       console.error("The path prefix is not a valid URL", err);
       elements.pathPrefixInput.setCustomValidity(
-        TorStrings.rulesets.pathPrefixInvalid
+        await document.l10n.formatValue("rulesets-details-path-input-invalid")
       );
       valid = false;
     }
@@ -304,7 +223,9 @@ class EditState {
       scope = new RegExp(elements.scopeInput.value.trim());
       elements.scopeInput.setCustomValidity("");
     } catch (err) {
-      elements.scopeInput.setCustomValidity(TorStrings.rulesets.scopeInvalid);
+      elements.scopeInput.setCustomValidity(
+        await document.l10n.formatValue("rulesets-details-scope-input-invalid")
+      );
       valid = false;
     }
 
@@ -342,39 +263,17 @@ class NoRulesetsState {
 }
 
 class RulesetList {
-  selectors = Object.freeze({
-    heading: "#ruleset-heading",
-    list: "#ruleset-list",
-    emptyContainer: "#ruleset-list-empty",
-    emptyTitle: "#ruleset-list-empty-title",
-    emptyDescription: "#ruleset-list-empty-description",
-    itemTemplate: "#ruleset-template",
-    itemName: ".name",
-    itemDescr: ".description",
-  });
-
-  elements = Object.freeze({
-    heading: document.querySelector(this.selectors.heading),
-    list: document.querySelector(this.selectors.list),
-    emptyContainer: document.querySelector(this.selectors.emptyContainer),
-    emptyTitle: document.querySelector(this.selectors.emptyTitle),
-    emptyDescription: document.querySelector(this.selectors.emptyDescription),
-    itemTemplate: document.querySelector(this.selectors.itemTemplate),
-  });
+  elements = {
+    list: document.getElementById("ruleset-list"),
+    emptyContainer: document.getElementById("ruleset-list-empty"),
+    itemTemplate: document.getElementById("ruleset-template"),
+  };
 
   nameAttribute = "data-name";
 
   rulesets = [];
 
   constructor() {
-    const elements = this.elements;
-
-    // Header
-    elements.heading.textContent = TorStrings.rulesets.rulesets;
-    // Empty
-    elements.emptyTitle.textContent = TorStrings.rulesets.noRulesets;
-    elements.emptyDescription.textContent = TorStrings.rulesets.noRulesetsDescr;
-
     RPMAddMessageListener(
       "rulesets:channels-change",
       this.onRulesetsChanged.bind(this)
@@ -438,14 +337,10 @@ class RulesetList {
     const item = this.elements.itemTemplate.cloneNode(true);
     item.removeAttribute("id");
     item.classList.add("item");
-    item.querySelector(this.selectors.itemName).textContent = ruleset.name;
-    const descr = item.querySelector(this.selectors.itemDescr);
-    if (ruleset.enabled) {
-      setUpdateDate(ruleset, descr);
-    } else {
-      descr.textContent = TorStrings.rulesets.disabled;
-      item.classList.add("disabled");
-    }
+    item.querySelector(".name").textContent = ruleset.name;
+    const descr = item.querySelector(".description");
+    setUpdateDate(ruleset, descr);
+    item.classList.toggle("disabled", !ruleset.enabled);
     item.setAttribute(this.nameAttribute, ruleset.name);
     item.addEventListener("click", () => {
       this.onRulesetClick(ruleset);
@@ -478,7 +373,6 @@ class AboutRulesets {
 
   async init() {
     const args = await RPMSendQuery("rulesets:get-init-args");
-    TorStrings = args.TorStrings;
     const showWarning = args.showWarning;
 
     this.list = new RulesetList();


=====================================
browser/locales/en-US/browser/tor-browser.ftl
=====================================
@@ -557,3 +557,53 @@ downloads-tor-warning-title = Be careful opening downloads
 downloads-tor-warning-description = Some files may connect to the internet when opened without using Tor. To be safe, open the files while offline or use a portable operating system like <a data-l10n-name="tails-link">Tails</a>.
 # Button to dismiss the warning forever.
 downloads-tor-warning-dismiss-button = Got it
+
+## Initial warning page in about:rulesets. In Tor Browser, each ruleset is a set of rules for converting a ".tor.onion" address to a normal ".onion" address (used by SecureDrop). The feature is taken from the discontinued "HTTPS Everywhere".
+
+rulesets-warning-heading = Proceed with Caution
+rulesets-warning-description = Adding or modifying rulesets can cause attackers to hijack your browser. Proceed only if you know what you are doing.
+rulesets-warning-checkbox = Warn me when I attempt to access these preferences
+rulesets-warning-continue-button = Accept the Risk and Continue
+
+## Side panel in about:rulesets. In Tor Browser, each ruleset is a set of rules for converting a ".tor.onion" address to a normal ".onion" address (used by SecureDrop). The feature is taken from the discontinued "HTTPS Everywhere".
+
+rulesets-side-panel-heading = Rulesets
+rulesets-side-panel-no-rules = No rulesets found
+# -brand-short-name refers to 'Tor Browser', localized.
+rulesets-side-panel-no-rules-description = When you save a ruleset in { -brand-short-name }, it will show up here.
+
+## Ruleset update date in about:rulesets.
+
+# $date (Date) - The update date. The DATETIME function will format the $date according to the locale, using a "long" style. E.g. "January 1, 2000" for English (US), "١ يناير ٢٠٠٠" for Arabic, "2000년 1월 1일" in Korean, and "1 января 2000 г." in Russian.
+rulesets-update-last = Last updated { DATETIME($date, dateStyle: "long") }
+rulesets-update-never = Never updated, or last update failed
+# Shown when the ruleset is disabled.
+rulesets-update-rule-disabled = Disabled
+
+## Ruleset details in about:rulesets. In Tor Browser, each ruleset is a set of rules for converting a ".tor.onion" address to a normal ".onion" address (used by SecureDrop). The feature is taken from the discontinued "HTTPS Everywhere".
+
+rulesets-details-edit-button = Edit
+rulesets-details-enable-checkbox = Enable this ruleset
+rulesets-details-update-button = Check for Updates
+rulesets-details-save-button = Save
+rulesets-details-cancel-button = Cancel
+# "JWK" refers to "JSON Web Key" and likely should not be translated.
+rulesets-details-jwk = JWK
+# "JWK" refers to "JSON Web Key" and likely should not be translated.
+rulesets-details-jwk-input =
+    .placeholder = The key used to sign this ruleset in the JWK (JSON Web Key) format
+# "JWK" refers to "JSON Web Key" and likely should not be translated.
+rulesets-details-jwk-input-invalid = The JWK could not be parsed, or it is not a valid key
+# "Path" refers to the URL domain this rule applies to.
+rulesets-details-path = Path Prefix
+rulesets-details-path-input =
+    .placeholder = URL prefix that contains the files needed by the ruleset
+# "HTTP(S)" refers to "HTTP or HTTPS".
+rulesets-details-path-input-invalid = The path prefix is not a valid HTTP(S) URL
+# "Scope" refers to the breadth of URLs this rule applies to (as a regular expression).
+rulesets-details-scope = Scope
+# "Regular expression" refers to the computing term for a special pattern used for matching: https://en.wikipedia.org/wiki/Regular_expression.
+rulesets-details-scope-input =
+    .placeholder = Regular expression for the scope of the rules
+# "Regular expression" refers to the computing term for a special pattern used for matching: https://en.wikipedia.org/wiki/Regular_expression.
+rulesets-details-scope-input-invalid = The scope could not be parsed as a regular expression


=====================================
toolkit/modules/TorStrings.sys.mjs
=====================================
@@ -429,54 +429,6 @@ const Loader = {
       learnMoreURLNotification: `https://tb-manual.torproject.org/${getLocale()}/onion-services/`,
     };
   } /* OnionLocation */,
-
-  /*
-    Rulesets
-  */
-  rulesets() {
-    const strings = {
-      // Initial warning
-      warningTitle: "Proceed with Caution",
-      warningDescription:
-        "Adding or modifying rulesets can cause attackers to hijack your browser. Proceed only if you know what you are doing.",
-      warningEnable: "Warn me when I attempt to access these preferences",
-      warningButton: "Accept the Risk and Continue",
-      // Ruleset list
-      rulesets: "Rulesets",
-      noRulesets: "No rulesets found",
-      noRulesetsDescr:
-        "When you save a ruleset in Tor Browser, it will show up here.",
-      lastUpdated: "Last updated %S",
-      neverUpdated: "Never updated, or last update failed",
-      enabled: "Enabled",
-      disabled: "Disabled",
-      // Ruleset details
-      edit: "Edit",
-      name: "Name",
-      jwk: "JWK",
-      pathPrefix: "Path Prefix",
-      scope: "Scope",
-      enable: "Enable this ruleset",
-      checkUpdates: "Check for Updates",
-      // Add ruleset
-      jwkPlaceholder:
-        "The key used to sign this ruleset in the JWK (JSON Web Key) format",
-      jwkInvalid: "The JWK could not be parsed, or it is not a valid key",
-      pathPrefixPlaceholder:
-        "URL prefix that contains the files needed by the ruleset",
-      pathPrefixInvalid: "The path prefix is not a valid HTTP(S) URL",
-      scopePlaceholder: "Regular expression for the scope of the rules",
-      scopeInvalid: "The scope could not be parsed as a regular expression",
-      save: "Save",
-      cancel: "Cancel",
-    };
-
-    const tsb = new TorPropertyStringBundle(
-      ["chrome://torbutton/locale/rulesets.properties"],
-      "rulesets."
-    );
-    return tsb.getStrings(strings);
-  } /* Rulesets */,
 };
 
 export const TorStrings = {
@@ -507,11 +459,4 @@ export const TorStrings = {
     }
     return this._onionLocation;
   },
-
-  get rulesets() {
-    if (!this._rulesets) {
-      this._rulesets = Loader.rulesets();
-    }
-    return this._rulesets;
-  },
 };


=====================================
toolkit/torbutton/chrome/locale/en-US/rulesets.properties deleted
=====================================
@@ -1,35 +0,0 @@
-# Copyright (c) 2022, The Tor Project, Inc.
-# This Source Code Form is subject to the terms of the Mozilla Public
-# 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/.
-
-# about:rulesets strings.
-rulesets.warningTitle=Proceed with Caution
-rulesets.warningDescription=Adding or modifying rulesets can cause attackers to hijack your browser. Proceed only if you know what you are doing.
-rulesets.warningEnable=Warn me when I attempt to access these preferences
-rulesets.warningButton=Accept the Risk and Continue
-# Ruleset list
-rulesets.rulesets=Rulesets
-rulesets.noRulesets=No rulesets found
-rulesets.noRulesetsDescr=When you save a ruleset in Tor Browser, it will show up here.
-# LOCALIZATION NOTE: %S will be replaced by the update date (automatically formatted by Firefox's l10n component)
-rulesets.lastUpdated=Last updated %S
-rulesets.neverUpdated=Never updated, or last update failed
-rulesets.enabled=Enabled
-rulesets.disabled=Disabled
-# Ruleset details/edit ruleset
-rulesets.edit=Edit
-rulesets.name=Name
-rulesets.jwk=JWK
-rulesets.pathPrefix=Path Prefix
-rulesets.scope=Scope
-rulesets.enable=Enable this ruleset
-rulesets.checkUpdates=Check for Updates
-rulesets.jwkPlaceholder=The key used to sign this ruleset in the JWK (JSON Web Key) format
-rulesets.jwkInvalid=The JWK could not be parsed, or it is not a valid key
-rulesets.pathPrefixPlaceholder=URL prefix that contains the files needed by the ruleset
-rulesets.pathPrefixInvalid=The path prefix is not a valid HTTP(S) URL
-rulesets.scopePlaceholder=Regular expression for the scope of the rules
-rulesets.scopeInvalid=The scope could not be parsed as a regular expression
-rulesets.save=Save
-rulesets.cancel=Cancel


=====================================
tools/torbrowser/l10n/migrations/bug-42206-rulesets.py
=====================================
@@ -0,0 +1,70 @@
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import transforms_from
+from fluent.migrate.transforms import REPLACE
+
+
+def migrate(ctx):
+    legacy_path = "rulesets.properties"
+
+    ctx.add_transforms(
+        "tor-browser.ftl",
+        "tor-browser.ftl",
+        transforms_from(
+            """
+rulesets-warning-heading = { COPY(path, "rulesets.warningTitle") }
+rulesets-warning-description = { COPY(path, "rulesets.warningDescription") }
+rulesets-warning-checkbox = { COPY(path, "rulesets.warningEnable") }
+rulesets-warning-continue-button = { COPY(path, "rulesets.warningButton") }
+
+rulesets-side-panel-heading = { COPY(path, "rulesets.rulesets") }
+rulesets-side-panel-no-rules = { COPY(path, "rulesets.noRulesets") }
+
+rulesets-update-never = { COPY(path, "rulesets.neverUpdated") }
+rulesets-update-rule-disabled = { COPY(path, "rulesets.disabled") }
+
+rulesets-details-edit-button = { COPY(path, "rulesets.edit") }
+rulesets-details-enable-checkbox = { COPY(path, "rulesets.enable") }
+rulesets-details-update-button = { COPY(path, "rulesets.checkUpdates") }
+rulesets-details-save-button = { COPY(path, "rulesets.save") }
+rulesets-details-cancel-button = { COPY(path, "rulesets.cancel") }
+rulesets-details-jwk-input =
+    .placeholder = { COPY(path, "rulesets.jwkPlaceholder") }
+rulesets-details-jwk-input-invalid = { COPY(path, "rulesets.jwkInvalid") }
+rulesets-details-path = { COPY(path, "rulesets.pathPrefix") }
+rulesets-details-path-input =
+    .placeholder = { COPY(path, "rulesets.pathPrefixPlaceholder") }
+rulesets-details-path-input-invalid = { COPY(path, "rulesets.pathPrefixInvalid") }
+rulesets-details-scope = { COPY(path, "rulesets.scope") }
+rulesets-details-scope-input =
+    .placeholder = { COPY(path, "rulesets.scopePlaceholder") }
+rulesets-details-scope-input-invalid = { COPY(path, "rulesets.scopeInvalid") }
+""",
+            path=legacy_path,
+        )
+        + [
+            # Replace "%1$S" with "{ DATETIME($date, dateStyle: "long") }"
+            FTL.Message(
+                FTL.Identifier("rulesets-update-last"),
+                value=REPLACE(
+                    legacy_path,
+                    "rulesets.lastUpdated",
+                    {
+                        "%1$S": FTL.FunctionReference(
+                            FTL.Identifier("DATETIME"),
+                            arguments=FTL.CallArguments(
+                                positional=[
+                                    FTL.VariableReference(FTL.Identifier("date"))
+                                ],
+                                named=[
+                                    FTL.NamedArgument(
+                                        FTL.Identifier("dateStyle"),
+                                        value=FTL.StringLiteral("long"),
+                                    )
+                                ],
+                            ),
+                        )
+                    },
+                ),
+            ),
+        ],
+    )



View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/08ed48facde83cda84f83b16bff3d69337ebfb75...8c14330efa6a56429f65f9a2726e868d552d2662

-- 
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/08ed48facde83cda84f83b16bff3d69337ebfb75...8c14330efa6a56429f65f9a2726e868d552d2662
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tbb-commits/attachments/20240416/a447dcd1/attachment-0001.htm>


More information about the tbb-commits mailing list