Bug 1580599 - Migrate DevTools toolbox meatball menu to fluent; r=devtools-reviewers,fluent-reviewers,nchevobbe,flod

Differential Revision: https://phabricator.services.mozilla.com/D134419
This commit is contained in:
Greg Tatum 2022-01-10 17:09:16 +00:00
Родитель b732cde303
Коммит c6eeab3adf
11 изменённых файлов: 172 добавлений и 80 удалений

Просмотреть файл

@ -80,7 +80,9 @@ class MeatballMenu extends PureComponent {
// Function to turn the disable pop-up autohide behavior on / off.
toggleNoAutohide: PropTypes.func,
// Localization interface.
// Bug 1709191 - The help shortcut key is localized without Fluent, and still needs
// to be migrated. This is the only remaining use of the legacy L10N object.
// Everything else should prefer the Fluent API.
L10N: PropTypes.object.isRequired,
// Callback function that will be invoked any time the component contents
@ -122,22 +124,22 @@ class MeatballMenu extends PureComponent {
for (const hostType of this.props.hostTypes) {
// This is more verbose than it needs to be but lets us easily search for
// l10n entities.
let l10nkey;
let l10nID;
switch (hostType.position) {
case "window":
l10nkey = "toolbox.meatballMenu.dock.separateWindow.label";
l10nID = "toolbox-meatball-menu-dock-separate-window-label";
break;
case "bottom":
l10nkey = "toolbox.meatballMenu.dock.bottom.label";
l10nID = "toolbox-meatball-menu-dock-bottom-label";
break;
case "left":
l10nkey = "toolbox.meatballMenu.dock.left.label";
l10nID = "toolbox-meatball-menu-dock-left-label";
break;
case "right":
l10nkey = "toolbox.meatballMenu.dock.right.label";
l10nID = "toolbox-meatball-menu-dock-right-label";
break;
default:
@ -149,7 +151,7 @@ class MeatballMenu extends PureComponent {
MenuItem({
id: `toolbox-meatball-menu-dock-${hostType.position}`,
key: `dock-${hostType.position}`,
label: this.props.L10N.getStr(l10nkey),
l10nID,
onClick: hostType.switchHost,
checked: hostType.position === this.props.currentHostType,
className: "iconic",
@ -163,14 +165,14 @@ class MeatballMenu extends PureComponent {
// Split console
if (this.props.currentToolId !== "webconsole") {
const l10nkey = this.props.isSplitConsoleActive
? "toolbox.meatballMenu.hideconsole.label"
: "toolbox.meatballMenu.splitconsole.label";
const l10nID = this.props.isSplitConsoleActive
? "toolbox-meatball-menu-hideconsole-label"
: "toolbox-meatball-menu-splitconsole-label";
items.push(
MenuItem({
id: "toolbox-meatball-menu-splitconsole",
key: "splitconsole",
label: this.props.L10N.getStr(l10nkey),
l10nID,
accelerator: "Esc",
onClick: this.props.toggleSplitConsole,
className: "iconic",
@ -187,9 +189,7 @@ class MeatballMenu extends PureComponent {
MenuItem({
id: "toolbox-meatball-menu-noautohide",
key: "noautohide",
label: this.props.L10N.getStr(
"toolbox.meatballMenu.noautohide.label"
),
l10nID: "toolbox-meatball-menu-noautohide-label",
type: "checkbox",
checked: this.props.disableAutohide,
onClick: this.props.toggleNoAutohide,
@ -203,7 +203,9 @@ class MeatballMenu extends PureComponent {
MenuItem({
id: "toolbox-meatball-menu-settings",
key: "settings",
label: this.props.L10N.getStr("toolbox.meatballMenu.settings.label"),
l10nID: "toolbox-meatball-menu-settings-label",
// Bug 1709191 - The help key is localized without Fluent, and still needs to
// be migrated.
accelerator: this.props.L10N.getStr("toolbox.help.key"),
onClick: this.props.toggleOptions,
className: "iconic",
@ -217,9 +219,7 @@ class MeatballMenu extends PureComponent {
MenuItem({
id: "toolbox-meatball-menu-documentation",
key: "documentation",
label: this.props.L10N.getStr(
"toolbox.meatballMenu.documentation.label"
),
l10nID: "toolbox-meatball-menu-documentation-label",
onClick: openDevToolsDocsLink,
})
);
@ -229,7 +229,7 @@ class MeatballMenu extends PureComponent {
MenuItem({
id: "toolbox-meatball-menu-community",
key: "community",
label: this.props.L10N.getStr("toolbox.meatballMenu.community.label"),
l10nID: "toolbox-meatball-menu-community-label",
onClick: openCommunityLink,
})
);

Просмотреть файл

@ -10,7 +10,6 @@ const {
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { div, button } = dom;
const DebugTargetInfo = createFactory(
require("devtools/client/framework/components/DebugTargetInfo")
);
@ -36,6 +35,11 @@ loader.lazyGetter(this, "MenuList", function() {
require("devtools/client/shared/components/menu/MenuList")
);
});
loader.lazyGetter(this, "LocalizationProvider", function() {
return createFactory(
require("devtools/client/shared/vendor/fluent-react").LocalizationProvider
);
});
loader.lazyRequireGetter(
this,
@ -119,6 +123,8 @@ class ToolboxToolbar extends Component {
runtimeInfo: PropTypes.object.isRequired,
targetType: PropTypes.string.isRequired,
}),
// The loaded Fluent localization bundles.
fluentBundles: PropTypes.array.isRequired,
};
}
@ -466,7 +472,7 @@ class ToolboxToolbar extends Component {
* render functions for how each of the sections is rendered.
*/
render() {
const { L10N, debugTargetData, toolbox } = this.props;
const { L10N, debugTargetData, toolbox, fluentBundles } = this.props;
const classnames = ["devtools-tabbar"];
const startButtons = this.renderToolboxButtonsStart();
const endButtons = this.renderToolboxButtonsEnd();
@ -494,7 +500,10 @@ class ToolboxToolbar extends Component {
? DebugTargetInfo({ debugTargetData, L10N, toolbox })
: null;
return div({}, debugTargetInfo, toolbar);
return LocalizationProvider(
{ bundles: fluentBundles },
div({}, debugTargetInfo, toolbar)
);
}
}

Просмотреть файл

@ -33,6 +33,7 @@ add_task(async function() {
"resource://devtools/client/shared/vendor/react-dom-factories.js",
"resource://devtools/client/shared/vendor/react-prop-types.js",
"resource://devtools/client/shared/vendor/redux.js",
"resource://devtools/client/shared/vendor/fluent-react.js",
]);
runMetricsTest({

Просмотреть файл

@ -39,6 +39,7 @@ add_task(async function() {
"resource://devtools/client/shared/components/menu/MenuButton.js",
"resource://devtools/client/shared/components/menu/MenuItem.js",
"resource://devtools/client/shared/components/menu/MenuList.js",
"resource://devtools/client/shared/vendor/fluent-react.js",
"resource://devtools/client/shared/vendor/react.js",
"resource://devtools/client/shared/vendor/react-dom.js",
"resource://devtools/client/shared/vendor/react-prop-types.js",

Просмотреть файл

@ -33,6 +33,10 @@ var Telemetry = require("devtools/client/shared/telemetry");
const { getUnicodeUrl } = require("devtools/client/shared/unicode-url");
var { DOMHelpers } = require("devtools/shared/dom-helpers");
const { KeyCodes } = require("devtools/client/shared/keycodes");
const {
FluentL10n,
} = require("devtools/client/shared/fluent-l10n/fluent-l10n");
var Startup = Cc["@mozilla.org/devtools/startup-clh;1"].getService(
Ci.nsISupports
).wrappedJSObject;
@ -845,6 +849,12 @@ Toolbox.prototype = {
*/
open: function() {
return async function() {
// Kick off async loading the Fluent bundles.
const fluentL10n = new FluentL10n();
const fluentInitPromise = fluentL10n.init([
"devtools/client/toolbox.ftl",
]);
const isToolboxURL = this.win.location.href.startsWith(this._URL);
if (isToolboxURL) {
// Update the URL so that onceDOMReady watch for the right url.
@ -944,7 +954,9 @@ Toolbox.prototype = {
// Get the DOM element to mount the ToolboxController to.
this._componentMount = this.doc.getElementById("toolbox-toolbar-mount");
this._mountReactComponent();
await fluentInitPromise;
this._mountReactComponent(fluentL10n.getBundles());
this._buildDockOptions();
this._buildTabs();
@ -1889,10 +1901,11 @@ Toolbox.prototype = {
}
},
_mountReactComponent: function() {
_mountReactComponent(fluentBundles) {
// Ensure the toolbar doesn't try to render until the tool is ready.
const element = this.React.createElement(this.ToolboxController, {
L10N,
fluentBundles,
currentToolId: this.currentToolId,
selectTool: this.selectTool,
toggleOptions: this.toggleOptions,

Просмотреть файл

@ -0,0 +1,29 @@
# 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/.
### These messages are used in the DevTools toolbox.
## These labels are shown in the "..." menu in the toolbox, and represent different
## commands such as the docking of DevTools, toggling features, and viewing some
## external links. Some of the commands have the keyboard shortcut shown next to
## the label.
toolbox-meatball-menu-dock-bottom-label = Dock to Bottom
toolbox-meatball-menu-dock-left-label = Dock to Left
toolbox-meatball-menu-dock-right-label = Dock to Right
toolbox-meatball-menu-dock-separate-window-label = Separate Window
toolbox-meatball-menu-splitconsole-label = Show Split Console
toolbox-meatball-menu-hideconsole-label = Hide Split Console
toolbox-meatball-menu-settings-label = Settings
toolbox-meatball-menu-documentation-label = Documentation…
toolbox-meatball-menu-community-label = Community…
# This menu item is only available in the browser toolbox. It forces the popups/panels
# to stay visible on blur, which is primarily useful for addon developers and Firefox
# contributors.
toolbox-meatball-menu-noautohide-label = Disable Popup Auto-Hide
##

Просмотреть файл

@ -168,42 +168,6 @@ toolbox.showFrames.key=Alt+Down
# for the "..." button on the developer tools toolbox.
toolbox.meatballMenu.button.tooltip=Customize Developer Tools and Get Help
# LOCALIZATION NOTE (toolbox.meatballMenu.dock.*.label): These labels are shown
# in the "..." menu in the toolbox and represent the different arrangements for
# docking (or undocking) the developer tools toolbox.
toolbox.meatballMenu.dock.bottom.label=Dock to Bottom
toolbox.meatballMenu.dock.left.label=Dock to Left
toolbox.meatballMenu.dock.right.label=Dock to Right
toolbox.meatballMenu.dock.separateWindow.label=Separate Window
# LOCALIZATION NOTE (toolbox.meatballMenu.{splitconsole,hideconsole}.label):
# These are the labels in the "..." menu in the toolbox for toggling the split
# console window.
# The keyboard shortcut will be shown to the side of the label.
toolbox.meatballMenu.splitconsole.label=Show Split Console
toolbox.meatballMenu.hideconsole.label=Hide Split Console
# LOCALIZATION NOTE (toolbox.meatballMenu.noautohide.label): This is the label
# in the "..." menu in the toolbox to force the popups/panels to stay visible on
# blur.
# This is only visible in the browser toolbox as it is meant for
# addon developers and Firefox contributors.
toolbox.meatballMenu.noautohide.label=Disable Popup Auto-Hide
# LOCALIZATION NOTE (toolbox.meatballMenu.settings.label): This is the label for
# the item in the "..." menu in the toolbox that brings up the Settings
# (Options) panel.
# The keyboard shortcut will be shown to the side of the label.
toolbox.meatballMenu.settings.label=Settings
# LOCALIZATION NOTE (toolbox.meatballMenu.documentation.label): This is the
# label for the Documentation menu item.
toolbox.meatballMenu.documentation.label=Documentation…
# LOCALIZATION NOTE (toolbox.meatballMenu.community.label): This is the label
# for the Community menu item.
toolbox.meatballMenu.community.label=Community…
# LOCALIZATION NOTE (toolbox.closebutton.tooltip): This is the tooltip for
# the close button the developer tools toolbox.
toolbox.closebutton.tooltip=Close Developer Tools

Просмотреть файл

@ -8,12 +8,16 @@
// A command in a menu.
const {
createFactory,
createRef,
PureComponent,
} = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { button, li, span } = dom;
loader.lazyGetter(this, "Localized", () =>
createFactory(require("devtools/client/shared/vendor/fluent-react").Localized)
);
class MenuItem extends PureComponent {
static get propTypes() {
@ -46,8 +50,11 @@ class MenuItem extends PureComponent {
// An optional ID to be assigned to the item.
id: PropTypes.string,
// The item label.
label: PropTypes.string.isRequired,
// The item label for use with legacy localization systems.
label: PropTypes.string,
// The Fluent ID for localizing the label.
l10nID: PropTypes.string,
// An optional callback to be invoked when the item is selected.
onClick: PropTypes.func,
@ -153,11 +160,32 @@ class MenuItem extends PureComponent {
attr["aria-checked"] = true;
}
const textLabel = span(
{ key: "label", className: "label", ref: this.labelRef },
this.props.label
);
const children = [textLabel];
const children = [];
const className = "label";
// Add the text label.
if (this.props.l10nID) {
// Fluent localized label.
children.push(
Localized(
{ id: this.props.l10nID, key: "label" },
span({ className, ref: this.labelRef })
)
);
} else {
children.push(
span({ key: "label", className, ref: this.labelRef }, this.props.label)
);
}
if (this.props.l10nID && this.props.label) {
console.warn(
"<MenuItem> should only take either an l10nID or a label, not both"
);
}
if (!this.props.l10nID && !this.props.label) {
console.warn("<MenuItem> requires either an l10nID, or a label prop.");
}
if (typeof this.props.accelerator !== "undefined") {
const acceleratorLabel = span(

Просмотреть файл

@ -5,10 +5,6 @@
const TEST_URI =
"data:text/html;charset=utf-8,<!DOCTYPE html>Web Console test for splitting";
const { LocalizationHelper } = require("devtools/shared/l10n");
const L10N = new LocalizationHelper(
"devtools/client/locales/toolbox.properties"
);
// Test is slow on Linux EC2 instances - Bug 962931
requestLongerTimeout(4);
@ -122,8 +118,7 @@ add_task(async function() {
let label;
if (menuItem && menuItem.querySelector(".label")) {
label =
menuItem.querySelector(".label").textContent ===
L10N.getStr("toolbox.meatballMenu.hideconsole.label")
menuItem.querySelector(".label").textContent === "Hide Split Console"
? "hide"
: "split";
}

Просмотреть файл

@ -5,11 +5,6 @@
// Test that the split console state is persisted.
const { LocalizationHelper } = require("devtools/shared/l10n");
const L10N = new LocalizationHelper(
"devtools/client/locales/toolbox.properties"
);
const TEST_URI =
"data:text/html;charset=utf-8,<!DOCTYPE html><p>Web Console test for splitting</p>";
@ -121,8 +116,7 @@ async function doesMenuSayHide(toolbox) {
const result =
menuItem &&
menuItem.querySelector(".label") &&
menuItem.querySelector(".label").textContent ===
L10N.getStr("toolbox.meatballMenu.hideconsole.label");
menuItem.querySelector(".label").textContent === "Hide Split Console";
toolbox.doc.addEventListener(
"popuphidden",

Просмотреть файл

@ -0,0 +1,58 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
import fluent.syntax.ast as FTL
from fluent.migrate.transforms import COPY
def migrate(ctx):
"""Bug 1580599 - Convert toolbox.properties to Fluent, part {index}."""
source = "devtools/client/toolbox.properties"
target = "devtools/client/toolbox.ftl"
ctx.add_transforms(
target,
target,
[
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-dock-bottom-label"),
value=COPY(source, "toolbox.meatballMenu.dock.bottom.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-dock-left-label"),
value=COPY(source, "toolbox.meatballMenu.dock.left.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-dock-right-label"),
value=COPY(source, "toolbox.meatballMenu.dock.right.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-dock-separate-window-label"),
value=COPY(source, "toolbox.meatballMenu.dock.separateWindow.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-splitconsole-label"),
value=COPY(source, "toolbox.meatballMenu.splitconsole.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-hideconsole-label"),
value=COPY(source, "toolbox.meatballMenu.hideconsole.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-noautohide-label"),
value=COPY(source, "toolbox.meatballMenu.noautohide.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-settings-label"),
value=COPY(source, "toolbox.meatballMenu.settings.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-documentation-label"),
value=COPY(source, "toolbox.meatballMenu.documentation.label"),
),
FTL.Message(
id=FTL.Identifier("toolbox-meatball-menu-community-label"),
value=COPY(source, "toolbox.meatballMenu.community.label"),
),
],
)