| ... | ... | @@ -448,10 +448,6 @@ const gConnectionPane = (function () { | 
| 448 | 448 |        const bridgeCards = prefpane.querySelector(selectors.bridges.cards);
 | 
| 449 | 449 |        const bridgeMenu = prefpane.querySelector(selectors.bridges.cardMenu);
 | 
| 450 | 450 |  
 | 
| 451 |  | -      let emojiAnnotations;
 | 
| 452 |  | -      const emojiListPromise = fetch(
 | 
| 453 |  | -        "chrome://browser/content/torpreferences/bridgemoji/bridge-emojis.json"
 | 
| 454 |  | -      ).then(response => response.json());
 | 
| 455 | 451 |        this._addBridgeCard = bridgeString => {
 | 
| 456 | 452 |          const card = bridgeTemplate.cloneNode(true);
 | 
| 457 | 453 |          card.removeAttribute("id");
 | 
| ... | ... | @@ -484,16 +480,8 @@ const gConnectionPane = (function () { | 
| 484 | 480 |          const emojis = makeBridgeId(bridgeString).map(emojiIndex => {
 | 
| 485 | 481 |            const img = document.createElement("img");
 | 
| 486 | 482 |            img.classList.add("emoji");
 | 
| 487 |  | -          emojiListPromise.then(emojiList => {
 | 
| 488 |  | -            const emoji = emojiList[emojiIndex];
 | 
| 489 |  | -            const cp = emoji.codePointAt(0).toString(16);
 | 
| 490 |  | -            img.setAttribute(
 | 
| 491 |  | -              "src",
 | 
| 492 |  | -              `chrome://browser/content/torpreferences/bridgemoji/svgs/${cp}.svg`
 | 
| 493 |  | -            );
 | 
| 494 |  | -            img.setAttribute("alt", emoji);
 | 
| 495 |  | -            img.setAttribute("title", emojiAnnotations[cp]);
 | 
| 496 |  | -          });
 | 
|  | 483 | +          // Image is set in _updateBridgeEmojis.
 | 
|  | 484 | +          img.dataset.emojiIndex = emojiIndex;
 | 
| 497 | 485 |            return img;
 | 
| 498 | 486 |          });
 | 
| 499 | 487 |          const idString = TorStrings.settings.bridgeId;
 | 
| ... | ... | @@ -699,6 +687,9 @@ const gConnectionPane = (function () { | 
| 699 | 687 |            shownCards--;
 | 
| 700 | 688 |          }
 | 
| 701 | 689 |  
 | 
|  | 690 | +        // Newly added emojis.
 | 
|  | 691 | +        this._updateBridgeEmojis();
 | 
|  | 692 | +
 | 
| 702 | 693 |          // And finally update the buttons
 | 
| 703 | 694 |          removeAll.hidden = false;
 | 
| 704 | 695 |          showAll.classList.toggle("primary", TorSettings.bridges.enabled);
 | 
| ... | ... | @@ -729,26 +720,7 @@ const gConnectionPane = (function () { | 
| 729 | 720 |            bridgeCards.classList.remove("list-collapsed");
 | 
| 730 | 721 |          }
 | 
| 731 | 722 |        };
 | 
| 732 |  | -      // Use a promise to avoid blocking the population of the page
 | 
| 733 |  | -      // FIXME: Stop using a JSON file, and switch to properties
 | 
| 734 |  | -      const annotationPromise = fetch(
 | 
| 735 |  | -        "chrome://browser/content/torpreferences/bridgemoji/annotations.json"
 | 
| 736 |  | -      );
 | 
| 737 |  | -      annotationPromise.then(async res => {
 | 
| 738 |  | -        const annotations = await res.json();
 | 
| 739 |  | -        const bcp47 = Services.locale.appLocaleAsBCP47;
 | 
| 740 |  | -        const dash = bcp47.indexOf("-");
 | 
| 741 |  | -        const lang = dash !== -1 ? bcp47.substring(0, dash) : bcp47;
 | 
| 742 |  | -        if (bcp47 in annotations) {
 | 
| 743 |  | -          emojiAnnotations = annotations[bcp47];
 | 
| 744 |  | -        } else if (lang in annotations) {
 | 
| 745 |  | -          emojiAnnotations = annotations[lang];
 | 
| 746 |  | -        } else {
 | 
| 747 |  | -          // At the moment, nb does not have annotations!
 | 
| 748 |  | -          emojiAnnotations = annotations.en;
 | 
| 749 |  | -        }
 | 
| 750 |  | -        this._populateBridgeCards();
 | 
| 751 |  | -      });
 | 
|  | 723 | +      this._populateBridgeCards();
 | 
| 752 | 724 |        this._updateConnectedBridges = () => {
 | 
| 753 | 725 |          for (const card of bridgeCards.querySelectorAll(
 | 
| 754 | 726 |            ".currently-connected"
 | 
| ... | ... | @@ -785,7 +757,7 @@ const gConnectionPane = (function () { | 
| 785 | 757 |            this._updateConnectedBridges();
 | 
| 786 | 758 |          }
 | 
| 787 | 759 |        };
 | 
| 788 |  | -      annotationPromise.then(this._checkConnectedBridge.bind(this));
 | 
|  | 760 | +      this._checkConnectedBridge();
 | 
| 789 | 761 |  
 | 
| 790 | 762 |        // Add a new bridge
 | 
| 791 | 763 |        prefpane.querySelector(selectors.bridges.addHeader).textContent =
 | 
| ... | ... | @@ -879,6 +851,7 @@ const gConnectionPane = (function () { | 
| 879 | 851 |  
 | 
| 880 | 852 |        Services.obs.addObserver(this, TorConnectTopics.StateChange);
 | 
| 881 | 853 |        Services.obs.addObserver(this, TorMonitorTopics.BridgeChanged);
 | 
|  | 854 | +      Services.obs.addObserver(this, "intl:app-locales-changed");
 | 
| 882 | 855 |      },
 | 
| 883 | 856 |  
 | 
| 884 | 857 |      init() {
 | 
| ... | ... | @@ -903,6 +876,7 @@ const gConnectionPane = (function () { | 
| 903 | 876 |        Services.obs.removeObserver(this, TorSettingsTopics.SettingChanged);
 | 
| 904 | 877 |        Services.obs.removeObserver(this, TorConnectTopics.StateChange);
 | 
| 905 | 878 |        Services.obs.removeObserver(this, TorMonitorTopics.BridgeChanged);
 | 
|  | 879 | +      Services.obs.removeObserver(this, "intl:app-locales-changed");
 | 
| 906 | 880 |      },
 | 
| 907 | 881 |  
 | 
| 908 | 882 |      // whether the page should be present in about:preferences
 | 
| ... | ... | @@ -939,6 +913,60 @@ const gConnectionPane = (function () { | 
| 939 | 913 |            }
 | 
| 940 | 914 |            break;
 | 
| 941 | 915 |          }
 | 
|  | 916 | +        case "intl:app-locales-changed": {
 | 
|  | 917 | +          this._updateBridgeEmojis();
 | 
|  | 918 | +          break;
 | 
|  | 919 | +        }
 | 
|  | 920 | +      }
 | 
|  | 921 | +    },
 | 
|  | 922 | +
 | 
|  | 923 | +    /**
 | 
|  | 924 | +     * Update the bridge emojis to show their corresponding emoji with an
 | 
|  | 925 | +     * annotation that matches the current locale.
 | 
|  | 926 | +     */
 | 
|  | 927 | +    async _updateBridgeEmojis() {
 | 
|  | 928 | +      if (!this._emojiPromise) {
 | 
|  | 929 | +        this._emojiPromise = Promise.all([
 | 
|  | 930 | +          fetch(
 | 
|  | 931 | +            "chrome://browser/content/torpreferences/bridgemoji/bridge-emojis.json"
 | 
|  | 932 | +          ).then(response => response.json()),
 | 
|  | 933 | +          fetch(
 | 
|  | 934 | +            "chrome://browser/content/torpreferences/bridgemoji/annotations.json"
 | 
|  | 935 | +          ).then(response => response.json()),
 | 
|  | 936 | +        ]);
 | 
|  | 937 | +      }
 | 
|  | 938 | +      const [emojiList, emojiAnnotations] = await this._emojiPromise;
 | 
|  | 939 | +      let langCode;
 | 
|  | 940 | +      // Find the first desired locale we have annotations for.
 | 
|  | 941 | +      // Add "en" as a fallback.
 | 
|  | 942 | +      for (const bcp47 of [...Services.locale.appLocalesAsBCP47, "en"]) {
 | 
|  | 943 | +        langCode = bcp47;
 | 
|  | 944 | +        if (langCode in emojiAnnotations) {
 | 
|  | 945 | +          break;
 | 
|  | 946 | +        }
 | 
|  | 947 | +        // Remove everything after the dash, if there is one.
 | 
|  | 948 | +        langCode = bcp47.replace(/-.*/, "");
 | 
|  | 949 | +        if (langCode in emojiAnnotations) {
 | 
|  | 950 | +          break;
 | 
|  | 951 | +        }
 | 
|  | 952 | +      }
 | 
|  | 953 | +      for (const img of document.querySelectorAll(".emoji[data-emoji-index]")) {
 | 
|  | 954 | +        const emoji = emojiList[img.dataset.emojiIndex];
 | 
|  | 955 | +        if (!emoji) {
 | 
|  | 956 | +          // Unexpected.
 | 
|  | 957 | +          console.error(`No emoji for index ${img.dataset.emojiIndex}`);
 | 
|  | 958 | +          img.removeAttribute("src");
 | 
|  | 959 | +          img.removeAttribute("alt");
 | 
|  | 960 | +          img.removeAttribute("title");
 | 
|  | 961 | +          continue;
 | 
|  | 962 | +        }
 | 
|  | 963 | +        const cp = emoji.codePointAt(0).toString(16);
 | 
|  | 964 | +        img.setAttribute(
 | 
|  | 965 | +          "src",
 | 
|  | 966 | +          `chrome://browser/content/torpreferences/bridgemoji/svgs/${cp}.svg`
 | 
|  | 967 | +        );
 | 
|  | 968 | +        img.setAttribute("alt", emoji);
 | 
|  | 969 | +        img.setAttribute("title", emojiAnnotations[langCode][cp]);
 | 
| 942 | 970 |        }
 | 
| 943 | 971 |      },
 | 
| 944 | 972 |  
 |