Commit f7c05810 authored by Alex Catarineu's avatar Alex Catarineu Committed by Pier Angelo Vendrame
Browse files

Add TorStrings module for localization

parent 359a0b76
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -37,6 +37,11 @@
<?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css" type="text/css"?>

<!DOCTYPE window [
  <!ENTITY % torbuttonDTD SYSTEM "chrome://torbutton/locale/torbutton.dtd">
%torbuttonDTD;
]>

<html id="main-window"
        xmlns:html="http://www.w3.org/1999/xhtml"
        xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+2 −0
Original line number Diff line number Diff line
@@ -225,6 +225,8 @@
@RESPATH@/browser/chrome/browser.manifest
@RESPATH@/chrome/pdfjs.manifest
@RESPATH@/chrome/pdfjs/*
@RESPATH@/chrome/torbutton.manifest
@RESPATH@/chrome/torbutton/*
@RESPATH@/chrome/toolkit@JAREXT@
@RESPATH@/chrome/toolkit.manifest
#ifdef MOZ_GTK
+4 −0
Original line number Diff line number Diff line
@@ -140,6 +140,10 @@
; Base Browser
@BINPATH@/components/SecurityLevel.manifest

; Torbutton
@BINPATH@/chrome/torbutton@JAREXT@
@BINPATH@/chrome/torbutton.manifest

; [Default Preferences]
; All the pref files must be part of base to prevent migration bugs
#ifndef MOZ_ANDROID_FAT_AAR_ARCHITECTURES
+346 −0
Original line number Diff line number Diff line
// 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/.

import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";

function getLocale() {
  const locale = Services.locale.appLocaleAsBCP47;
  return locale === "ja-JP-macos" ? "ja" : locale;
}

/*
  Tor Property String Bundle

  Property strings loaded from torbutton/tor-launcher, but provide a fallback in case they aren't available
*/
class TorPropertyStringBundle {
  constructor(aBundleURL, aPrefix) {
    try {
      this._bundle = Services.strings.createBundle(aBundleURL);
      this._bundleURL = aBundleURL;
    } catch (e) {
      console.error(`[TorStrings] Cannot load ${aBundleURL}`, e);
    }

    this._prefix = aPrefix;
  }

  getString(key, fallback) {
    const reportError =
      AppConstants.BASE_BROWSER_VERSION === "dev-build" && !!this._bundle;
    if (key) {
      try {
        return this._bundle.GetStringFromName(`${this._prefix}${key}`);
      } catch (e) {
        if (reportError) {
          console.warn(
            `[TorStrings] Cannot get ${this._prefix}${key} from ${this._bundleURL}`,
            e
          );
        }
      }
    }

    // on failure, assign the fallback if it exists
    if (fallback) {
      return fallback;
    }
    // otherwise return string key
    return `$(${key})`;
  }

  getStrings(strings, additionalPrefix = "") {
    return Object.fromEntries(
      Object.entries(strings).map(([key, fallback]) => [
        key,
        this.getString(additionalPrefix + key, fallback),
      ])
    );
  }
}

const Loader = {
  /*
    Tor about:preferences#connection Strings
  */
  settings() {
    const strings = {
      // Message box
      torPreferencesDescription:
        "Tor Browser routes your traffic over the Tor Network, run by thousands of volunteers around the world.",
      // Quickstart
      quickstartCheckbox: "Always connect automatically",
      bridgeLocation: "Your location",
      bridgeLocationAutomatic: "Automatic",
      bridgeLocationFrequent: "Frequently selected locations",
      bridgeLocationOther: "Other locations",
      bridgeChooseForMe: "Choose a Bridge For Me…",
    };

    const tsb = new TorPropertyStringBundle(
      "chrome://torbutton/locale/settings.properties",
      "settings."
    );
    return tsb.getStrings(strings);
  } /* Tor Network Settings Strings */,

  torConnect() {
    const strings = {
      torConnect: "Connect to Tor",

      torConnecting: "Establishing a Connection",

      tryingAgain: "Trying again…",

      noInternet: "Tor Browser couldn’t reach the Internet",
      noInternetDescription:
        "This could be due to a connection issue rather than Tor being blocked. Check your Internet connection, proxy and firewall settings before trying again.",
      torBootstrapFailed: "Tor failed to establish a Tor network connection.",
      couldNotConnect: "Tor Browser could not connect to Tor",
      configureConnection: "configure your connection",
      assistDescription:
        "If Tor is blocked in your location, trying a bridge may help. Connection assist can choose one for you using your location, or you can %S manually instead.",
      tryingBridge: "Trying a bridge…",

      tryingBridgeAgain: "Trying one more time…",
      errorLocation: "Tor Browser couldn’t locate you",
      errorLocationDescription:
        "Tor Browser needs to know your location in order to choose the right bridge for you. If you’d rather not share your location, %S manually instead.",
      isLocationCorrect: "Are these location settings correct?",
      isLocationCorrectDescription:
        "Tor Browser still couldn’t connect to Tor. Please check your location settings are correct and try again, or %S instead.",
      finalError: "Tor Browser still cannot connect",

      finalErrorDescription:
        "Despite its best efforts, connection assist was not able to connect to Tor. Try troubleshooting your connection and adding a bridge manually instead.",
      breadcrumbAssist: "Connection assist",
      breadcrumbLocation: "Location settings",
      breadcrumbTryBridge: "Try a bridge",

      restartTorBrowser: "Restart Tor Browser",

      torConfigure: "Configure Connection…",

      viewLog: "View logs…",

      torConnectButton: "Connect",

      cancel: "Cancel",

      torConnected: "Connected to the Tor network",

      tryAgain: "Try Again",

      yourLocation: "Your Location",
      unblockInternetIn: "Unblock the Internet in",

      tryBridge: "Try a Bridge",

      automatic: "Automatic",
      selectCountryRegion: "Select Country or Region",
      frequentLocations: "Frequently selected locations",
      otherLocations: "Other locations",

      // TorConnect error messages
      offline: "Internet not reachable",
      autoBootstrappingFailed: "Automatic configuration failed",
      autoBootstrappingAllFailed: "None of the configurations we tried worked",
      cannotDetermineCountry: "Unable to determine user country",
      noSettingsForCountry: "No settings available for your location",

      // Titlebar status.
      titlebarStatusName: "Tor connection",
      titlebarStatusNotConnected: "Not connected",
      titlebarStatusConnecting: "Connecting…",
      titlebarStatusPotentiallyBlocked: "Potentially blocked",
      titlebarStatusConnected: "Connected",
    };

    // Some strings were used through TorLauncherUtils.
    // However, we need to use them in about:torconnect, which cannot access
    // privileged code.
    const bootstrapStatus = {
      starting: "Starting",
      conn_pt: "Connecting to bridge",
      conn_done_pt: "Connected to bridge",
      conn_proxy: "Connecting to proxy",
      conn_done_proxy: "Connected to proxy",
      conn: "Connecting to a Tor relay",
      conn_done: "Connected to a Tor relay",
      handshake: "Negotiating with a Tor relay",
      handshake_done: "Finished negotiating with a Tor relay",
      onehop_create: "Establishing an encrypted directory connection",
      requesting_status: "Retrieving network status",
      loading_status: "Loading network status",
      loading_keys: "Loading authority certificates",
      requesting_descriptors: "Requesting relay information",
      loading_descriptors: "Loading relay information",
      enough_dirinfo: "Finished loading relay information",
      ap_conn_pt: "Building circuits: Connecting to bridge",
      ap_conn_done_pt: "Building circuits: Connected to bridge",
      ap_conn_proxy: "Building circuits: Connecting to proxy",
      ap_conn_done_proxy: "Building circuits: Connected to proxy",
      ap_conn: "Building circuits: Connecting to a Tor relay",
      ap_conn_done: "Building circuits: Connected to a Tor relay",
      ap_handshake: "Building circuits: Negotiating with a Tor relay",
      ap_handshake_done:
        "Building circuits: Finished negotiating with a Tor relay",
      circuit_create: "Building circuits: Establishing a Tor circuit",
      done: "Connected to the Tor network!",
    };
    const bootstrapWarning = {
      done: "done",
      connectrefused: "connection refused",
      misc: "miscellaneous",
      resourcelimit: "insufficient resources",
      identity: "identity mismatch",
      timeout: "connection timeout",
      noroute: "no route to host",
      ioerror: "read/write error",
      pt_missing: "missing pluggable transport",
    };

    const tsb = new TorPropertyStringBundle(
      "chrome://torbutton/locale/torConnect.properties",
      "torConnect."
    );
    const tlsb = new TorPropertyStringBundle(
      "chrome://torbutton/locale/torlauncher.properties",
      "torlauncher."
    );
    return {
      ...tsb.getStrings(strings),
      bootstrapFailedDetails: tlsb.getString(
        "tor_bootstrap_failed_details",
        "%1$S failed (%2$S)."
      ),
      bootstrapStatus: tlsb.getStrings(bootstrapStatus, "bootstrapStatus."),
      bootstrapWarning: tlsb.getStrings(bootstrapWarning, "bootstrapWarning."),
    };
  },

  /*
    Tor Onion Services Strings, e.g., for the authentication prompt.
  */
  onionServices() {
    const tsb = new TorPropertyStringBundle(
      "chrome://torbutton/locale/torbutton.properties",
      "onionServices."
    );
    const getString = tsb.getString.bind(tsb);

    const retval = {
      learnMore: getString("learnMore", "Learn more"),
      authPrompt: {
        description: getString(
          "authPrompt.description2",
          "%S is requesting that you authenticate."
        ),
        keyPlaceholder: getString(
          "authPrompt.keyPlaceholder",
          "Enter your key"
        ),
        done: getString("authPrompt.done", "Done"),
        doneAccessKey: getString("authPrompt.doneAccessKey", "d"),
        invalidKey: getString("authPrompt.invalidKey", "Invalid key"),
        failedToSetKey: getString(
          "authPrompt.failedToSetKey",
          "Failed to set key"
        ),
      },
      authPreferences: {
        header: getString(
          "authPreferences.header",
          "Onion Services Authentication"
        ),
        overview: getString(
          "authPreferences.overview",
          "Some onion services require that you identify yourself with a key"
        ),
        savedKeys: getString("authPreferences.savedKeys", "Saved Keys"),
        dialogTitle: getString(
          "authPreferences.dialogTitle",
          "Onion Services Keys"
        ),
        dialogIntro: getString(
          "authPreferences.dialogIntro",
          "Keys for the following onionsites are stored on your computer"
        ),
        onionSite: getString("authPreferences.onionSite", "Onionsite"),
        onionKey: getString("authPreferences.onionKey", "Key"),
        remove: getString("authPreferences.remove", "Remove"),
        removeAll: getString("authPreferences.removeAll", "Remove All"),
        failedToGetKeys: getString(
          "authPreferences.failedToGetKeys",
          "Failed to get keys"
        ),
        failedToRemoveKey: getString(
          "authPreferences.failedToRemoveKey",
          "Failed to remove key"
        ),
      },
    };

    return retval;
  } /* Tor Onion Services Strings */,

  /*
    OnionLocation
  */
  onionLocation() {
    const strings = {
      learnMore: "Learn more…",
      loadOnion: "Visit the .onion",
      loadOnionAccessKey: "V",
      notNow: "Not Now",
      notNowAccessKey: "n",
      description:
        "There's a more private and secure version of this site available over the Tor network via onion services. Onion services help website publishers and their visitors defeat surveillance and censorship.",
      tryThis: "Try Onion Services",
      onionAvailable: ".onion available",
    };

    const tsb = new TorPropertyStringBundle(
      ["chrome://torbutton/locale/onionLocation.properties"],
      "onionLocation."
    );
    return {
      ...tsb.getStrings(strings),
      learnMoreURL: "about:manual#onion-services",
      // XUL popups cannot open about: URLs, but we are online when showing the notification, so just use the online version
      learnMoreURLNotification: `https://tb-manual.torproject.org/${getLocale()}/onion-services/`,
    };
  } /* OnionLocation */,
};

export const TorStrings = {
  get settings() {
    if (!this._settings) {
      this._settings = Loader.settings();
    }
    return this._settings;
  },

  get torConnect() {
    if (!this._torConnect) {
      this._torConnect = Loader.torConnect();
    }
    return this._torConnect;
  },

  get onionServices() {
    if (!this._onionServices) {
      this._onionServices = Loader.onionServices();
    }
    return this._onionServices;
  },

  get onionLocation() {
    if (!this._onionLocation) {
      this._onionLocation = Loader.onionLocation();
    }
    return this._onionLocation;
  },
};
+1 −0
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ EXTRA_JS_MODULES += [
    "Sqlite.sys.mjs",
    "SubDialog.sys.mjs",
    "Timer.sys.mjs",
    "TorStrings.sys.mjs",
    "Troubleshoot.sys.mjs",
    "UpdateUtils.sys.mjs",
    "WebChannel.sys.mjs",
Loading