Bug 1445084 - Migrate search results pane of Preferences to Fluent. r?flod,gijs draft
authorZibi Braniecki <zbraniecki@mozilla.com>
Mon, 12 Mar 2018 16:27:32 -0700
changeset 768545 e1ed724d953808149a8fe0044d121c7954c91ee2
parent 768523 47e1787284fbfad3d32eb7081ffdda58d2b086de
push id102904
push userbmo:gandalf@aviary.pl
push dateFri, 16 Mar 2018 14:38:56 +0000
reviewersflod, gijs
bugs1445084
milestone61.0a1
Bug 1445084 - Migrate search results pane of Preferences to Fluent. r?flod,gijs MozReview-Commit-ID: BNeocrSY5Fa
browser/components/preferences/in-content/findInPage.js
browser/components/preferences/in-content/preferences.xul
browser/components/preferences/in-content/searchResults.xul
browser/locales/en-US/browser/preferences/preferences.ftl
browser/locales/en-US/chrome/browser/preferences/preferences.dtd
browser/locales/en-US/chrome/browser/preferences/preferences.properties
python/l10n/fluent_migrations/bug_1444508_preferences_search_results.py
--- a/browser/components/preferences/in-content/findInPage.js
+++ b/browser/components/preferences/in-content/findInPage.js
@@ -22,20 +22,19 @@ var gSearchResultsPane = {
       this.searchInput.addEventListener("input", this);
       this.searchInput.addEventListener("command", this);
       window.addEventListener("DOMContentLoaded", () => {
         this.searchInput.focus();
       });
       // Initialize other panes in an idle callback.
       window.requestIdleCallback(() => this.initializeCategories());
     }
-    let strings = this.strings;
-    this.searchInput.placeholder = AppConstants.platform == "win" ?
-      strings.getString("searchInput.labelWin") :
-      strings.getString("searchInput.labelUnix");
+    let helpUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + "preferences";
+    let helpContainer = document.getElementById("need-help");
+    helpContainer.querySelector("a").href = helpUrl;
   },
 
   handleEvent(event) {
     // Ensure categories are initialized if idle callback didn't run sooo enough.
     this.initializeCategories();
     this.searchFunction(event);
   },
 
@@ -192,21 +191,16 @@ var gSearchResultsPane = {
                               .QueryInterface(Ci.nsISelectionController);
 
     let selection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
     selection.setColors("currentColor", "#ffe900", "currentColor", "#003eaa");
 
     return selection;
   },
 
-  get strings() {
-    delete this.strings;
-    return this.strings = document.getElementById("searchResultBundle");
-  },
-
   /**
    * Shows or hides content according to search input
    *
    * @param String event
    *    to search for filted query in
    */
   async searchFunction(event) {
     let query = event.target.value.trim().toLowerCase();
@@ -289,35 +283,25 @@ var gSearchResultsPane = {
       }
       // It hides Search Results header so turning it on
       srHeader.hidden = false;
       srHeader.classList.remove("visually-hidden");
 
       if (!resultsFound) {
         let noResultsEl = document.querySelector(".no-results-message");
         noResultsEl.setAttribute("query", this.query);
-        noResultsEl.hidden = false;
-
-        let strings = this.strings;
 
-        document.getElementById("sorry-message").textContent = AppConstants.platform == "win" ?
-          strings.getFormattedString("searchResults.sorryMessageWin", [this.query]) :
-          strings.getFormattedString("searchResults.sorryMessageUnix", [this.query]);
-        let helpUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + "preferences";
-        let brandName = document.getElementById("bundleBrand").getString("brandShortName");
-        let helpString = strings.getString("searchResults.needHelp3");
-        let helpContainer = document.getElementById("need-help");
-        let link = document.createElement("label");
-        link.className = "text-link";
-        link.setAttribute("href", helpUrl);
-        link.textContent = strings.getFormattedString("searchResults.needHelpSupportLink", [brandName]);
+        // XXX: This is potentially racy in case where Fluent retranslates the
+        // message and ereases the query within.
+        // The feature is not yet supported, but we should fix for it before
+        // we enable it. See bug 1446389 for details.
+        let msgQueryElem = document.getElementById("sorry-message-query");
+        msgQueryElem.textContent = this.query;
 
-        helpContainer.innerHTML = "";
-        let fragment = BrowserUtils.getLocalizedFragment(document, helpString, link);
-        helpContainer.appendChild(fragment);
+        noResultsEl.hidden = false;
       } else {
         // Creating tooltips for all the instances found
         for (let anchorNode of this.listSearchTooltips) {
           this.createSearchTooltip(anchorNode, this.query);
         }
 
         // Implant search telemetry probe after user stops typing for a while
         if (this.query.length >= 2) {
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -203,17 +203,17 @@
               <image class="info-icon"></image>
             </hbox>
             <hbox align="center" flex="1">
               <label class="policies-label" flex="1" data-l10n-id="policies-notice"></label>
             </hbox>
           </hbox>
           <textbox
             type="search" id="searchInput"
-            data-l10n-id="search-input"
+            data-l10n-id="search-input-box"
             data-l10n-attrs="style"
             hidden="true" clickSelectsAll="true"/>
         </hbox>
         <vbox id="mainPrefPane" class="prefpane prefwindow">
 #include searchResults.xul
 #include main.xul
 #include search.xul
 #include privacy.xul
--- a/browser/components/preferences/in-content/searchResults.xul
+++ b/browser/components/preferences/in-content/searchResults.xul
@@ -1,22 +1,24 @@
 <!-- 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/. -->
 
-<stringbundle id="searchResultBundle" src="chrome://browser/locale/preferences/preferences.properties"/>
-
 <hbox id="header-searchResults"
       class="subcategory"
       hidden="true"
       data-category="paneSearchResults">
-  <label class="header-name" flex="1">&paneSearchResults.title;</label>
+  <label class="header-name" flex="1" data-l10n-id="search-results-header" />
 </hbox>
 
 <groupbox class="no-results-message" data-category="paneSearchResults" hidden="true">
   <vbox class="no-results-container">
-    <label id="sorry-message"></label>
-    <label id="need-help"></label>
+    <label id="sorry-message" data-l10n-id="search-results-sorry-message">
+      <html:span id="sorry-message-query"/>
+    </label>
+    <label id="need-help" data-l10n-id="search-results-need-help">
+      <a class="text-link" target="_blank"></a>
+    </label>
   </vbox>
   <vbox class="no-results-container" align="center">
     <image></image>
   </vbox>
 </groupbox>
--- a/browser/locales/en-US/browser/preferences/preferences.ftl
+++ b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -11,24 +11,36 @@ do-not-track-option-always =
 
 pref-page =
     .title =
         { PLATFORM() ->
             [windows] Options
            *[other] Preferences
         }
 
+# This string is currently used only in Firefox 60 and will be removed when not
+# needed for x-channel. See bug 1445686 for details.
+search-input =
+    .style = width: 15.4em
+
 # This is used to determine the width of the search field in about:preferences,
 # in order to make the entire placeholder string visible
 #
+# Please keep the placeholder string short to avoid truncation.
+#
 # Notice: The value of the `.style` attribute is a CSS string, and the `width`
 # is the name of the CSS property. It is intended only to adjust the element's width.
 # Do not translate.
-search-input =
+search-input-box =
     .style = width: 15.4em
+    .placeholder =
+        { PLATFORM() ->
+            [windows] Find in Options
+           *[other] Find in Preferences
+        }
 
 policies-notice =
     { PLATFORM() ->
         [windows] Your organization has disabled the ability to change some options.
        *[other] Your organization has disabled the ability to change some preferences.
     }
 
 pane-general-title = General
@@ -60,16 +72,29 @@ close-button =
 
 feature-enable-requires-restart = { -brand-short-name } must restart to enable this feature.
 feature-disable-requires-restart = { -brand-short-name } must restart to disable this feature.
 should-restart-title = Restart { -brand-short-name }
 should-restart-ok = Restart { -brand-short-name } now
 cancel-no-restart-button = Cancel
 restart-later = Restart Later
 
+## Preferences UI Search Results
+
+search-results-header = Search Results
+
+# `<span></span>` will be replaced by the search term.
+search-results-sorry-message =
+    { PLATFORM() ->
+        [windows] Sorry! There are no results in Options for “<span></span>”.
+       *[other] Sorry! There are no results in Preferences for “<span></span>”.
+    }
+
+search-results-need-help = Need help? Visit <a>{ -brand-short-name } Support</a>
+
 ## General Section
 
 startup-header = Startup
 
 # { -brand-short-name } will be 'Firefox Developer Edition',
 # since this setting is only exposed in Firefox Developer Edition
 separate-profile-mode =
     .label = Allow { -brand-short-name } and Firefox to run at the same time
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
@@ -1,12 +1,10 @@
 <!-- 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/. -->
 
-<!ENTITY  paneSearchResults.title       "Search Results">
 <!ENTITY  paneContainers.title          "Container Tabs">
 
-
 <!ENTITY  browserPrivacy.label          "Browser Privacy">
 
 <!-- LOCALIZATION NOTE (paneSync1.title): This should match syncBrand.fxAccount.label in ../syncBrand.dtd -->
 <!ENTITY  paneSync1.title          "Firefox Account">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -212,31 +212,16 @@ removeContainerAlertTitle=Remove This Co
 # LOCALIZATION NOTE (removeContainerMsg): Semi-colon list of plural forms.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # #S is the number of container tabs
 removeContainerMsg=If you remove this Container now, #S container tab will be closed. Are you sure you want to remove this Container?;If you remove this Container now, #S container tabs will be closed. Are you sure you want to remove this Container?
 
 removeContainerOkButton=Remove this Container
 removeContainerButton2=Don’t remove this Container
 
-# Search Input
-# LOCALIZATION NOTE: Please keep the placeholder string shorter than around 30 characters to avoid truncation.
-searchInput.labelWin=Find in Options
-searchInput.labelUnix=Find in Preferences
-
-# Search Results Pane
-# LOCALIZATION NOTE %S will be replaced by the word being searched
-searchResults.sorryMessageWin=Sorry! There are no results in Options for “%S”.
-searchResults.sorryMessageUnix=Sorry! There are no results in Preferences for “%S”.
-# LOCALIZATION NOTE (searchResults.needHelp3): %S will be replaced with a link to the support page.
-# The label of the link is in searchResults.needHelpSupportLink .
-searchResults.needHelp3=Need help? Visit %S
-# LOCALIZATION NOTE (searchResults.needHelpSupportLink): %S will be replaced with the browser name.
-searchResults.needHelpSupportLink=%S Support
-
 # LOCALIZATION NOTE (extensionControlled.homepage_override):
 # This string is shown to notify the user that their home page is being controlled by an extension.
 extensionControlled.homepage_override2 = An extension, %S, is controlling your home page.
 
 # LOCALIZATION NOTE (extensionControlled.newTabURL):
 # This string is shown to notify the user that their new tab page is being controlled by an extension.
 extensionControlled.newTabURL2 = An extension, %S, is controlling your New Tab page.
 
new file mode 100644
--- /dev/null
+++ b/python/l10n/fluent_migrations/bug_1444508_preferences_search_results.py
@@ -0,0 +1,128 @@
+# coding=utf8
+
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+from __future__ import absolute_import
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import MESSAGE_REFERENCE, EXTERNAL_ARGUMENT
+from fluent.migrate import COPY, CONCAT, REPLACE
+
+
+def migrate(ctx):
+    """Bug 1445084 - Migrate search results pane of Preferences to Fluent, part {index}."""
+
+    ctx.add_transforms(
+        'browser/browser/preferences/preferences.ftl',
+        'browser/locales/en-US/browser/preferences/preferences.ftl',
+        [
+            FTL.Message(
+                id=FTL.Identifier('search-input-box'),
+                attributes=[
+                    FTL.Attribute(
+                        FTL.Identifier('style'),
+                        CONCAT(
+                            FTL.TextElement('width: '),
+                            COPY(
+                                'browser/chrome/browser/preferences/preferences.dtd',
+                                'searchField.width'
+                            )
+                        ),
+                    ),
+                    FTL.Attribute(
+                        FTL.Identifier('placeholder'),
+                        FTL.Pattern([
+                            FTL.Placeable(FTL.SelectExpression(
+                                expression=FTL.CallExpression(
+                                    callee=FTL.Identifier('PLATFORM')
+                                ),
+                                variants=[
+                                    FTL.Variant(
+                                        key=FTL.VariantName('windows'),
+                                        default=False,
+                                        value=COPY(
+                                            'browser/chrome/browser/preferences/preferences.properties',
+                                            'searchInput.labelWin'
+                                        )
+                                    ),
+                                    FTL.Variant(
+                                        key=FTL.VariantName('other'),
+                                        default=True,
+                                        value=COPY(
+                                            'browser/chrome/browser/preferences/preferences.properties',
+                                            'searchInput.labelUnix'
+                                        )
+                                    )
+                                ]
+                            ))
+                        ])
+                    ),
+                ]
+            ),
+            FTL.Message(
+                id=FTL.Identifier('search-results-header'),
+                value=COPY(
+                    'browser/chrome/browser/preferences/preferences.dtd',
+                    'paneSearchResults.title'
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier('search-results-sorry-message'),
+                value=FTL.Pattern(
+                    elements=[
+                        FTL.Placeable(
+                            expression=FTL.SelectExpression(
+                                expression=FTL.CallExpression(
+                                    callee=FTL.Identifier('PLATFORM')
+                                ),
+                                variants=[
+                                    FTL.Variant(
+                                        key=FTL.VariantName('windows'),
+                                        default=False,
+                                        value=REPLACE(
+                                            'browser/chrome/browser/preferences/preferences.properties',
+                                            'searchResults.sorryMessageWin',
+                                            {
+                                                '%S': FTL.TextElement("<span></span>")
+                                            },
+                                        )
+                                    ),
+                                    FTL.Variant(
+                                        key=FTL.VariantName('other'),
+                                        default=True,
+                                        value=REPLACE(
+                                            'browser/chrome/browser/preferences/preferences.properties',
+                                            'searchResults.sorryMessageUnix',
+                                            {
+                                                '%S': FTL.TextElement("<span></span>")
+                                            },
+                                        )
+                                    )
+                                ]
+                            )
+                        )
+                    ]
+                ),
+            ),
+            FTL.Message(
+                id=FTL.Identifier('search-results-need-help'),
+                value=REPLACE(
+                    'browser/chrome/browser/preferences/preferences.properties',
+                    'searchResults.needHelp3',
+                    {
+                        '%S': CONCAT(
+                            FTL.TextElement('<a>'),
+                            REPLACE(
+                                'browser/chrome/browser/preferences/preferences.properties',
+                                'searchResults.needHelpSupportLink',
+                                {
+                                    '%S': MESSAGE_REFERENCE('-brand-short-name'),
+                                },
+                            ),
+                            FTL.TextElement('</a>'),
+                        ),
+                    },
+                ),
+            ),
+        ]
+    )