Bug 1527653 - Port bug 1506102: Don't count lastFallbackLocale as installed when just fluent is included. r+a=jorgk
authorRichard Marti <richard.marti@gmail.com>
Wed, 20 Feb 2019 10:43:07 +0100
changeset 34358 eb2114dacbe9158f999ec1a153702d3f759a458a
parent 34357 43225f621c4ca63904f299ccf589e0bc5a88eebd
child 34359 f0d8075173240f2ebf16e56679a03e6d31a95901
push id389
push userclokep@gmail.com
push dateMon, 18 Mar 2019 19:01:53 +0000
bugs1527653, 1506102
Bug 1527653 - Port bug 1506102: Don't count lastFallbackLocale as installed when just fluent is included. r+a=jorgk
mail/components/preferences/advanced.js
mail/components/preferences/messengerLanguages.js
mail/components/preferences/preferences.js
--- a/mail/components/preferences/advanced.js
+++ b/mail/components/preferences/advanced.js
@@ -562,17 +562,17 @@ var gAdvancedPane = {
   },
 
   /**
    * Update the available list of locales and select the locale that the user
    * is "selecting". This could be the currently requested locale or a locale
    * that the user would like to switch to after confirmation.
    */
   async setMessengerLocales(selected) {
-    let available = Services.locale.availableLocales;
+    let available = await getAvailableLocales();
     let localeNames = Services.intl.getLocaleDisplayNames(undefined, available);
     let locales = available.map((code, i) => ({code, name: localeNames[i]}));
     locales.sort((a, b) => a.name > b.name);
 
     let fragment = document.createDocumentFragment();
     for (let {code, name} of locales) {
       let menuitem = document.createElement("menuitem");
       menuitem.setAttribute("value", code);
--- a/mail/components/preferences/messengerLanguages.js
+++ b/mail/components/preferences/messengerLanguages.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
+// This is exported by preferences.js but we can't import that in a subdialog.
+let {getAvailableLocales} = window.top;
+
 ChromeUtils.defineModuleGetter(this, "AddonManager",
                                "resource://gre/modules/AddonManager.jsm");
 ChromeUtils.defineModuleGetter(this, "AddonRepository",
                                "resource://gre/modules/addons/AddonRepository.jsm");
 
 /* This dialog provides an interface for managing what language the browser is
  * displayed in.
  *
@@ -237,18 +240,18 @@ class SortedItemSelectList {
   enableWithMessageId(messageId) {
     this.menulist.setAttribute("data-l10n-id", messageId);
     this.menulist.removeAttribute("image");
     this.menulist.disabled = this.menulist.itemCount == 0;
     this.button.disabled = !this.menulist.selectedItem;
   }
 }
 
-function getLocaleDisplayInfo(localeCodes) {
-  let availableLocales = new Set(Services.locale.availableLocales);
+async function getLocaleDisplayInfo(localeCodes) {
+  let availableLocales = new Set(await getAvailableLocales());
   let packagedLocales = new Set(Services.locale.packagedLocales);
   let localeNames = Services.intl.getLocaleDisplayNames(undefined, localeCodes);
   return localeCodes.map((code, i) => {
     return {
       id: "locale-" + code,
       label: localeNames[i],
       value: code,
       canRemove: !packagedLocales.has(code),
@@ -300,40 +303,40 @@ var gMessengerLanguagesDialog = {
     this.selectedLocales = selected;
 
     // This is a list of available locales that the user selected. It's more
     // restricted than the Intl notion of `requested` as it only contains
     // locale codes for which we have matching locales available.
     // The first time this dialog is opened, populate with appLocalesAsBCP47.
     let selectedLocales = this.selectedLocales || Services.locale.appLocalesAsBCP47;
     let selectedLocaleSet = new Set(selectedLocales);
-    let available = Services.locale.availableLocales;
+    let available = await getAvailableLocales();
     let availableSet = new Set(available);
 
     // Filter selectedLocales since the user may select a locale when it is
     // available and then disable it.
     selectedLocales = selectedLocales.filter(locale => availableSet.has(locale));
     // Nothing in available should be in selectedSet.
     available = available.filter(locale => !selectedLocaleSet.has(locale));
 
-    this.initSelectedLocales(selectedLocales);
+    await this.initSelectedLocales(selectedLocales);
     await this.initAvailableLocales(available, search);
 
     this.initialized = true;
   },
 
-  initSelectedLocales(selectedLocales) {
+  async initSelectedLocales(selectedLocales) {
     this._selectedLocales = new OrderedListBox({
       richlistbox: document.getElementById("selectedLocales"),
       upButton: document.getElementById("up"),
       downButton: document.getElementById("down"),
       removeButton: document.getElementById("remove"),
       onRemove: (item) => this.selectedLocaleRemoved(item),
     });
-    this._selectedLocales.setItems(getLocaleDisplayInfo(selectedLocales));
+    this._selectedLocales.setItems(await getLocaleDisplayInfo(selectedLocales));
   },
 
   async initAvailableLocales(available, search) {
     this._availableLocales = new SortedItemSelectList({
       menulist: document.getElementById("availableLocales"),
       button: document.getElementById("add"),
       compareFn: compareItems,
       onSelect: (item) => this.availableLanguageSelected(item),
@@ -377,23 +380,23 @@ var gMessengerLanguagesDialog = {
 
     // Store the available langpack info for later use.
     this.availableLangpacks = new Map();
     for (let {target_locale, url, hash} of availableLangpacks) {
       this.availableLangpacks.set(target_locale, {url, hash});
     }
 
     // Remove the installed locales from the available ones.
-    let installedLocales = new Set(Services.locale.availableLocales);
+    let installedLocales = new Set(await getAvailableLocales());
     let notInstalledLocales = availableLangpacks
       .filter(({target_locale}) => !installedLocales.has(target_locale))
       .map(lang => lang.target_locale);
 
     // Create the rows for the remote locales.
-    let availableItems = getLocaleDisplayInfo(notInstalledLocales);
+    let availableItems = await getLocaleDisplayInfo(notInstalledLocales);
     availableItems.push({
       label: await document.l10n.formatValue("messenger-languages-available-label"),
       className: "label-item",
       disabled: true,
       installed: false,
     });
 
     // Remove the search option and add the remote locales.
@@ -404,62 +407,79 @@ var gMessengerLanguagesDialog = {
     // Update the dropdown and enable it again.
     this._availableLocales.setItems(items);
     this._availableLocales.enableWithMessageId("messenger-languages-select-language");
   },
 
   async loadLocalesFromInstalled(available) {
     let items;
     if (available.length > 0) {
-      items = getLocaleDisplayInfo(available);
+      items = await getLocaleDisplayInfo(available);
       items.push(await this.createInstalledLabel());
     } else {
       items = [];
     }
     if (this.downloadEnabled) {
       items.push({
         label: await document.l10n.formatValue("messenger-languages-search"),
         value: "search",
       });
     }
     this._availableLocales.setItems(items);
   },
 
   async availableLanguageSelected(item) {
-    let available = new Set(Services.locale.availableLocales);
-
-    if (available.has(item.value)) {
-      this._selectedLocales.addItem(item);
-      if (available.size == this._selectedLocales.items.length) {
-        // Remove the installed label, they're all installed.
-        this._availableLocales.items.shift();
-        this._availableLocales.setItems(this._availableLocales.items);
-      }
+    if ((await getAvailableLocales()).has(item.value)) {
+      await this.requestLocalLanguage(item);
     } else if (this.availableLangpacks.has(item.value)) {
-      this._availableLocales.disableWithMessageId("messenger-languages-downloading");
-
-      let {url, hash} = this.availableLangpacks.get(item.value);
-      let install = await AddonManager.getInstallForURL(
-        url, "application/x-xpinstall", hash);
-
-      try {
-        await install.install();
-      } catch (e) {
-        this.showError();
-        return;
-      }
-
-      item.installed = true;
-      this._selectedLocales.addItem(item);
-      this._availableLocales.enableWithMessageId("messenger-languages-select-language");
+      await this.requestRemoteLanguage(item);
     } else {
       this.showError();
     }
   },
 
+  async requestLocalLanguage(item, available) {
+    this._selectedLocales.addItem(item);
+    let selectedCount = this._selectedLocales.items.length;
+    let availableCount = (await getAvailableLocales()).length;
+    if (selectedCount == availableCount) {
+      // Remove the installed label, they're all installed.
+      this._availableLocales.items.shift();
+      this._availableLocales.setItems(this._availableLocales.items);
+    }
+
+    // The label isn't always reset when the selected item is removed, so set it again.
+    this._availableLocales.enableWithMessageId("messenger-languages-select-language");
+  },
+
+  async requestRemoteLanguage(item) {
+    this._availableLocales.disableWithMessageId("messenger-languages-downloading");
+
+    let {url, hash} = this.availableLangpacks.get(item.value);
+    let addon;
+
+    try {
+      addon = await AddonManager.getInstallForURL(
+        url, "application/x-xpinstall", hash);
+      await addon.install();
+    } catch (e) {
+      this.showError();
+      return;
+    }
+
+    // If the add-on was previously installed, it might be disabled still.
+    if (addon.userDisabled) {
+      await addon.enable();
+    }
+
+    item.installed = true;
+    this._selectedLocales.addItem(item);
+    this._availableLocales.enableWithMessageId("messenger-languages-select-language");
+  },
+
   showError() {
     document.getElementById("warning-message").hidden = false;
     this._availableLocales.enableWithMessageId("messenger-languages-select-language");
 
     // The height has likely changed, find our SubDialog and tell it to resize.
     requestAnimationFrame(() => {
       let dialogs = window.opener.gSubDialog._dialogs;
       let index = dialogs.findIndex(d => d._frame.contentDocument == document);
--- a/mail/components/preferences/preferences.js
+++ b/mail/components/preferences/preferences.js
@@ -134,8 +134,30 @@ function showTab(pane, tabID, subdialogI
 }
 
 /**
  * Get the ID of the current pane.
  */
 function getCurrentPaneID() {
   return paneDeck.selectedPanel.id;
 }
+
+/**
+ * Filter the lastFallbackLocale from availableLocales if it doesn't have all
+ * of the needed strings.
+ *
+ * When the lastFallbackLocale isn't the defaultLocale, then by default only
+ * fluent strings are included. To fully use that locale you need the langpack
+ * to be installed, so if it isn't installed remove it from availableLocales.
+ */
+async function getAvailableLocales() {
+  let {availableLocales, defaultLocale, lastFallbackLocale} = Services.locale;
+  // If defaultLocale isn't lastFallbackLocale, then we still need the langpack
+  // for lastFallbackLocale for it to be useful.
+  if (defaultLocale != lastFallbackLocale) {
+    let lastFallbackId = `langpack-${lastFallbackLocale}@thunderbird.mozilla.org`;
+    let lastFallbackInstalled = await AddonManager.getAddonByID(lastFallbackId);
+    if (!lastFallbackInstalled) {
+      return availableLocales.filter(locale => locale != lastFallbackLocale);
+    }
+  }
+  return availableLocales;
+}