Bug 1500353 - Update localization for document title r=ladybenko,jdescottes
authorOla Gasidlo <ogasidlo@mozilla.com>
Fri, 11 Jan 2019 13:29:56 +0000
changeset 453499 696de1cfcb5eab4e11a5234f5bcda72476010278
parent 453498 5686d29392e8aecb57c0f75414bedebf54631447
child 453500 5b651dea28d8891be33a372e61dea9ce3c2422c3
push id35357
push usernerli@mozilla.com
push dateFri, 11 Jan 2019 21:54:07 +0000
treeherdermozilla-central@0ce024c91511 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersladybenko, jdescottes
bugs1500353
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1500353 - Update localization for document title r=ladybenko,jdescottes - added localization module - added test Differential Revision: https://phabricator.services.mozilla.com/D14415
devtools/client/aboutdebugging-new/aboutdebugging.js
devtools/client/aboutdebugging-new/index.html
devtools/client/aboutdebugging-new/src/components/App.js
devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_routes.js
devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
--- a/devtools/client/aboutdebugging-new/aboutdebugging.js
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.js
@@ -8,16 +8,19 @@ const Services = require("Services");
 
 const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
 const { createFactory } = require("devtools/client/shared/vendor/react");
 const { render, unmountComponentAtNode } =
   require("devtools/client/shared/vendor/react-dom");
 const Provider =
   createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
 
+const FluentReact = require("devtools/client/shared/vendor/fluent-react");
+const LocalizationProvider = createFactory(FluentReact.LocalizationProvider);
+
 const actions = require("./src/actions/index");
 const { configureStore } = require("./src/create-store");
 const {
   setDebugTargetCollapsibilities,
 } = require("./src/modules/debug-target-collapsibilities");
 
 const { l10n } = require("./src/modules/l10n");
 
@@ -54,22 +57,23 @@ const AboutDebugging = {
 
     await l10n.init();
 
     render(
       Provider(
         {
           store: this.store,
         },
-        Router(
-          {},
-          App(
-            {
-              fluentBundles: l10n.getBundles(),
-            }
+        LocalizationProvider(
+          { messages: l10n.getBundles() },
+          Router(
+            {},
+            App(
+              {}
+            )
           )
         )
       ),
       this.mount
     );
 
     this.onNetworkLocationsUpdated();
     addNetworkLocationsObserver(this.onNetworkLocationsUpdated);
--- a/devtools/client/aboutdebugging-new/index.html
+++ b/devtools/client/aboutdebugging-new/index.html
@@ -1,14 +1,15 @@
 <!-- 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/. -->
 <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8" />
+    <title>Debugging</title>
     <link rel="stylesheet" href="chrome://devtools/content/aboutdebugging-new/aboutdebugging.css"/>
     <script type="application/javascript" src="resource://devtools/client/aboutdebugging-new/initializer.js"></script>
   </head>
   <body>
     <div id="mount"></div>
   </body>
 </html>
--- a/devtools/client/aboutdebugging-new/src/components/App.js
+++ b/devtools/client/aboutdebugging-new/src/components/App.js
@@ -5,50 +5,70 @@
 "use strict";
 
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const FluentReact = require("devtools/client/shared/vendor/fluent-react");
-const LocalizationProvider = createFactory(FluentReact.LocalizationProvider);
+const Localized = createFactory(FluentReact.Localized);
 
 const Route = createFactory(require("devtools/client/shared/vendor/react-router-dom").Route);
 const Switch = createFactory(require("devtools/client/shared/vendor/react-router-dom").Switch);
 const Redirect = createFactory(require("devtools/client/shared/vendor/react-router-dom").Redirect);
-const { withRouter } = require("devtools/client/shared/vendor/react-router-dom");
 
 const Types = require("../types/index");
 const { RUNTIMES } = require("../constants");
 
 const ConnectPage = createFactory(require("./connect/ConnectPage"));
 const RuntimePage = createFactory(require("./RuntimePage"));
 const Sidebar = createFactory(require("./sidebar/Sidebar"));
 
 class App extends PureComponent {
   static get propTypes() {
     return {
       adbAddonStatus: PropTypes.string,
       // The "dispatch" helper is forwarded to the App component via connect.
       // From that point, components are responsible for forwarding the dispatch
       // property to all components who need to dispatch actions.
       dispatch: PropTypes.func.isRequired,
-      fluentBundles: PropTypes.arrayOf(PropTypes.object).isRequired,
+      // getString prop is injected by the withLocalization wrapper
+      getString: PropTypes.func.isRequired,
       isScanningUsb: PropTypes.bool.isRequired,
       networkEnabled: PropTypes.bool.isRequired,
       networkLocations: PropTypes.arrayOf(PropTypes.string).isRequired,
       networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
       selectedPage: PropTypes.string,
       selectedRuntime: PropTypes.string,
       usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
       wifiEnabled: PropTypes.bool.isRequired,
     };
   }
 
+  componentDidUpdate() {
+    this.updateTitle();
+  }
+
+  updateTitle() {
+    const { getString, selectedPage, selectedRuntime } = this.props;
+
+    const runtimeTitle = selectedRuntime ?
+                          getString(
+                            "about-debugging-page-title-with-runtime",
+                            { selectedPage, selectedRuntime }
+                          )
+                          : getString(
+                            "about-debugging-page-title",
+                            { selectedPage }
+                          );
+
+    document.title = runtimeTitle;
+  }
+
   renderConnect() {
     const {
       adbAddonStatus,
       dispatch,
       networkEnabled,
       networkLocations,
       wifiEnabled,
     } = this.props;
@@ -131,26 +151,25 @@ class App extends PureComponent {
       })
     );
   }
 
   render() {
     const {
       adbAddonStatus,
       dispatch,
-      fluentBundles,
       isScanningUsb,
       networkRuntimes,
       selectedPage,
       selectedRuntime,
       usbRuntimes,
     } = this.props;
 
-    return LocalizationProvider(
-      { messages: fluentBundles },
+    return Localized(
+      { },
       dom.div(
         { className: "app" },
         Sidebar({
           adbAddonStatus,
           className: "app__sidebar",
           dispatch,
           isScanningUsb,
           networkRuntimes,
@@ -177,9 +196,11 @@ const mapStateToProps = state => {
     wifiEnabled: state.ui.wifiEnabled,
   };
 };
 
 const mapDispatchToProps = dispatch => ({
   dispatch,
 });
 
-module.exports = withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
+module.exports = FluentReact
+  .withLocalization(
+      connect(mapStateToProps, mapDispatchToProps)(App));
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_routes.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_routes.js
@@ -13,49 +13,64 @@ add_task(async function() {
   info("Check root route redirects to 'This Firefox'");
   const { document, tab } = await openAboutDebugging();
   is(document.location.hash, "#/runtime/this-firefox");
 
   await removeTab(tab);
 });
 
 /**
- * Test that the routes in about:debugging show the proper views
+ * Test that the routes in about:debugging show the proper views and document.title
  */
 add_task(async function() {
   // enable USB devices mocks
   const mocks = new Mocks();
 
   const { document, tab } = await openAboutDebugging();
 
   info("Check 'This Firefox' route");
   document.location.hash = "#/runtime/this-firefox";
   await waitUntil(() => document.querySelector(".js-runtime-page"));
   const infoLabel = document.querySelector(".js-runtime-info").textContent;
   // NOTE: when using USB Mocks, we see only "Firefox" as the device name
   ok(infoLabel.includes("Firefox"), "Runtime is displayed as Firefox");
   ok(!infoLabel.includes(" on "), "Runtime is not associated to any device");
+  is(
+      document.title,
+      "Debugging - Runtime / this-firefox",
+      "Checking title for 'runtime' page"
+    );
 
   info("Check 'Connect' page");
   document.location.hash = "#/connect";
   await waitUntil(() => document.querySelector(".js-connect-page"));
   ok(true, "Connect page has been shown");
+  is(
+      document.title,
+      "Debugging - Connect",
+      "Checking title for 'connect' page"
+    );
 
   info("Check 'USB device runtime' page");
   // connect to a mocked USB runtime
   mocks.createUSBRuntime("1337id", {
     deviceName: "Fancy Phone",
     name: "Lorem ipsum",
   });
   mocks.emitUSBUpdate();
   await connectToRuntime("Fancy Phone", document);
   // navigate to it via URL
   document.location.hash = "#/runtime/1337id";
   await waitUntil(() => document.querySelector(".js-runtime-page"));
   const runtimeLabel = document.querySelector(".js-runtime-info").textContent;
+  is(
+      document.title,
+      "Debugging - Runtime / 1337id",
+      "Checking title for 'runtime' page with USB device"
+    );
   ok(runtimeLabel.includes("Lorem ipsum"), "Runtime is displayed with the mocked name");
 
   await removeTab(tab);
 });
 
 /**
  * Test that an invalid route redirects to / (currently This Firefox page)
  */
@@ -65,12 +80,17 @@ add_task(async function() {
 
   info("Waiting for a non-runtime page to load");
   document.location.hash = "#/connect";
   await waitUntil(() => document.querySelector(".js-connect-page"));
 
   info("Update hash & wait for a redirect to root ('This Firefox')");
   document.location.hash = "#/lorem-ipsum";
   await waitUntil(() => document.querySelector(".js-runtime-page"));
+  is(
+      document.title,
+      "Debugging - Runtime / this-firefox",
+      "Checking title for 'runtime' page after redirect to root"
+    );
   is(document.location.hash, "#/runtime/this-firefox", "Redirected to root");
 
   await removeTab(tab);
 });
--- a/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
+++ b/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
@@ -237,8 +237,25 @@ about-debugging-runtime-info-with-model 
 
 # Text of the connection prompt button displayed in Runtime pages, when the preference
 # "devtools.debugger.prompt-connection" is false on the target runtime.
 about-debugging-connection-prompt-enable-button = Enable connection prompt
 
 # Text of the connection prompt button displayed in Runtime pages, when the preference
 # "devtools.debugger.prompt-connection" is true on the target runtime.
 about-debugging-connection-prompt-disable-button = Disable connection prompt
+
+# Title of the application displayed in the tab
+-application-title = Debugging
+
+# Page title of connect / runtime page
+# Part of "about-debugging-page-title" string defined below
+about-debugging-page-title-selected-page = 
+  { $selectedPage -> 
+     [connect] Connect
+     *[runtime] Runtime
+  }
+
+# Page title with the runtime displayed in the tab
+about-debugging-page-title-with-runtime = { -application-title } - { about-debugging-page-title-selected-page } / { $selectedRuntime }
+
+# Page title without the runtime displayed in the tab
+about-debugging-page-title = { -application-title } - { about-debugging-page-title-selected-page }