Bug 1734221 - Migrate datetimebox strings from DTD to FTL. r=emilio,fluent-reviewers,flod

As the widget requires the individual fields' placeholder values to
be known during their build, the DOMLocalization instance used here
needs to have sync methods enabled. For the same reason, the
placeholder strings need to be separate messages, rather than
attributes on the same message as the corresponding label.

Differential Revision: https://phabricator.services.mozilla.com/D154448
This commit is contained in:
Eemeli Aro 2022-08-24 08:32:13 +00:00
parent 540be5aee2
commit 0b78e9e392
5 changed files with 120 additions and 95 deletions

View File

@ -0,0 +1,46 @@
# 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 transforms_from
from fluent.migrate.helpers import COPY
def migrate(ctx):
"""Bug 1734221 - Migrate datetimebox strings from DTD to FTL, part {index}"""
ctx.add_transforms(
"toolkit/toolkit/global/datetimebox.ftl",
"toolkit/toolkit/global/datetimebox.ftl",
transforms_from(
"""
datetime-reset =
.aria-label = { COPY(path1, "datetime.reset.label") }
datetime-year-placeholder = { COPY(path1, "date.year.placeholder") }
datetime-month-placeholder = { COPY(path1, "date.month.placeholder") }
datetime-day-placeholder = { COPY(path1, "date.day.placeholder") }
datetime-time-placeholder = { COPY(path1, "time.hour.placeholder") }
datetime-year =
.aria-label = { COPY(path1, "date.year.label") }
datetime-month =
.aria-label = { COPY(path1, "date.month.label") }
datetime-day =
.aria-label = { COPY(path1, "date.day.label") }
datetime-hour =
.aria-label = { COPY(path1, "time.hour.label") }
datetime-minute =
.aria-label = { COPY(path1, "time.minute.label") }
datetime-second =
.aria-label = { COPY(path1, "time.second.label") }
datetime-millisecond =
.aria-label = { COPY(path1, "time.millisecond.label") }
datetime-dayperiod =
.aria-label = { COPY(path1, "time.dayperiod.label") }
""",
path1="toolkit/chrome/global/datetimebox.dtd",
),
)

View File

@ -17,6 +17,15 @@ this.DateTimeBoxWidget = class {
this.element = shadowRoot.host;
this.document = this.element.ownerDocument;
this.window = this.document.defaultView;
// The DOMLocalization instance needs to allow for sync methods so that
// the placeholder value may be determined and set during the
// createEditFieldAndAppend() call.
this.l10n = new this.window.DOMLocalization(
["toolkit/global/datetimebox.ftl"],
/* aSync = */ true
);
this.l10n.connectRoot(this.shadowRoot);
}
/*
@ -67,6 +76,9 @@ this.DateTimeBoxWidget = class {
this.mDateTimeBoxElement.removeEventListener(eventName, this);
});
this.l10n.disconnectRoot(this.shadowRoot);
this.l10n = null;
this.removeEditFields();
this.mInputElement = null;
@ -223,13 +235,8 @@ this.DateTimeBoxWidget = class {
* Remove it when migrate to Fluent (bug 1504363).
*/
const parser = new this.window.DOMParser();
parser.forceEnableDTD();
let parserDoc = parser.parseFromString(
`<!DOCTYPE bindings [
<!ENTITY % datetimeboxDTD SYSTEM "chrome://global/locale/datetimebox.dtd">
%datetimeboxDTD;
]>
<div class="datetimebox" xmlns="http://www.w3.org/1999/xhtml" role="none">
`<div class="datetimebox" xmlns="http://www.w3.org/1999/xhtml" role="none">
<link rel="stylesheet" type="text/css" href="chrome://global/content/bindings/datetimebox.css" />
<div class="datetime-input-box-wrapper" id="input-box-wrapper" role="presentation">
<span class="datetime-input-edit-wrapper"
@ -238,52 +245,22 @@ this.DateTimeBoxWidget = class {
- elements here -->
</span>
<button class="datetime-reset-button" id="reset-button" tabindex="-1" aria-label="&datetime.reset.label;">
<button class="datetime-reset-button" id="reset-button" tabindex="-1" data-l10n-id="datetime-reset">
<svg xmlns="http://www.w3.org/2000/svg" class="datetime-reset-button-svg" width="12" height="12" viewBox="0 0 12 12">
<path d="M 3.9,3 3,3.9 5.1,6 3,8.1 3.9,9 6,6.9 8.1,9 9,8.1 6.9,6 9,3.9 8.1,3 6,5.1 Z M 12,6 A 6,6 0 0 1 6,12 6,6 0 0 1 0,6 6,6 0 0 1 6,0 6,6 0 0 1 12,6 Z"/>
</svg>
</button>
</div>
<div id="strings"
data-m-year-place-holder="&date.year.placeholder;"
data-m-year-label="&date.year.label;"
data-m-month-place-holder="&date.month.placeholder;"
data-m-month-label="&date.month.label;"
data-m-day-place-holder="&date.day.placeholder;"
data-m-day-label="&date.day.label;"
data-m-hour-place-holder="&time.hour.placeholder;"
data-m-hour-label="&time.hour.label;"
data-m-minute-place-holder="&time.minute.placeholder;"
data-m-minute-label="&time.minute.label;"
data-m-second-place-holder="&time.second.placeholder;"
data-m-second-label="&time.second.label;"
data-m-millisecond-place-holder="&time.millisecond.placeholder;"
data-m-millisecond-label="&time.millisecond.label;"
data-m-day-period-place-holder="&time.dayperiod.placeholder;"
data-m-day-period-label="&time.dayperiod.label;"
></div>
</div>`,
"application/xml"
);
/*
* The <div id="strings"> is also parsed in the document so that there is no
* need to create another XML document just to get the strings.
*/
let stringsElement = parserDoc.getElementById("strings");
stringsElement.remove();
for (let key in stringsElement.dataset) {
// key will be camelCase version of the attribute key above,
// like mYearPlaceHolder.
this[key] = stringsElement.dataset[key];
}
this.shadowRoot.importNodeAndAppendChildAt(
this.shadowRoot,
parserDoc.documentElement,
true
);
this.l10n.translateRoots();
}
get FIELD_EVENTS() {
@ -331,8 +308,8 @@ this.DateTimeBoxWidget = class {
}
createEditFieldAndAppend(
aPlaceHolder,
aLabel,
aL10nId,
aPlaceholderId,
aIsNumeric,
aMinDigits,
aMaxLength,
@ -343,17 +320,19 @@ this.DateTimeBoxWidget = class {
let root = this.shadowRoot.getElementById("edit-wrapper");
let field = this.shadowRoot.createElementAndAppendChildAt(root, "span");
field.classList.add("datetime-edit-field");
field.textContent = aPlaceHolder;
field.placeholder = aPlaceHolder;
field.setAttribute("aria-valuetext", "");
this.setFieldTabIndexAttribute(field);
const placeholder = this.l10n.formatValueSync(aPlaceholderId);
field.placeholder = placeholder;
field.textContent = placeholder;
this.l10n.setAttributes(field, aL10nId);
field.setAttribute("readonly", this.mInputElement.readOnly);
field.setAttribute("disabled", this.mInputElement.disabled);
// Set property as well for convenience.
field.disabled = this.mInputElement.disabled;
field.readOnly = this.mInputElement.readOnly;
field.setAttribute("aria-label", aLabel);
// Used to store the non-formatted value, cleared when value is
// cleared.
@ -776,8 +755,8 @@ this.DateTimeBoxWidget = class {
switch (part.type) {
case "year":
this.mYearField = this.createEditFieldAndAppend(
this.mYearPlaceHolder,
this.mYearLabel,
"datetime-year",
"datetime-year-placeholder",
true,
this.mYearLength,
this.mMaxYear.toString().length,
@ -789,8 +768,8 @@ this.DateTimeBoxWidget = class {
break;
case "month":
this.mMonthField = this.createEditFieldAndAppend(
this.mMonthPlaceHolder,
this.mMonthLabel,
"datetime-month",
"datetime-month-placeholder",
true,
this.mMonthDayLength,
this.mMonthDayLength,
@ -802,8 +781,8 @@ this.DateTimeBoxWidget = class {
break;
case "day":
this.mDayField = this.createEditFieldAndAppend(
this.mDayPlaceHolder,
this.mDayLabel,
"datetime-day",
"datetime-day-placeholder",
true,
this.mMonthDayLength,
this.mMonthDayLength,
@ -815,8 +794,8 @@ this.DateTimeBoxWidget = class {
break;
case "hour":
this.mHourField = this.createEditFieldAndAppend(
this.mHourPlaceHolder,
this.mHourLabel,
"datetime-hour",
"datetime-time-placeholder",
true,
this.mMaxLength,
this.mMaxLength,
@ -828,8 +807,8 @@ this.DateTimeBoxWidget = class {
break;
case "minute":
this.mMinuteField = this.createEditFieldAndAppend(
this.mMinutePlaceHolder,
this.mMinuteLabel,
"datetime-minute",
"datetime-time-placeholder",
true,
this.mMaxLength,
this.mMaxLength,
@ -841,8 +820,8 @@ this.DateTimeBoxWidget = class {
break;
case "second":
this.mSecondField = this.createEditFieldAndAppend(
this.mSecondPlaceHolder,
this.mSecondLabel,
"datetime-second",
"datetime-time-placeholder",
true,
this.mMaxLength,
this.mMaxLength,
@ -860,8 +839,8 @@ this.DateTimeBoxWidget = class {
);
span.textContent = this.mMillisecSeparatorText;
this.mMillisecField = this.createEditFieldAndAppend(
this.mMillisecPlaceHolder,
this.mMillisecLabel,
"datetime-millisecond",
"datetime-time-placeholder",
true,
this.mMillisecMaxLength,
this.mMillisecMaxLength,
@ -874,8 +853,8 @@ this.DateTimeBoxWidget = class {
break;
case "dayPeriod":
this.mDayPeriodField = this.createEditFieldAndAppend(
this.mDayPeriodPlaceHolder,
this.mDayPeriodLabel,
"datetime-dayperiod",
"datetime-time-placeholder",
false
);
this.addEventListenersToField(this.mDayPeriodField);

View File

@ -1,35 +0,0 @@
<!-- 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/. -->
<!-- Placeholders for input type=time -->
<!ENTITY time.hour.placeholder "--">
<!ENTITY time.minute.placeholder "--">
<!ENTITY time.second.placeholder "--">
<!ENTITY time.millisecond.placeholder "--">
<!ENTITY time.dayperiod.placeholder "--">
<!-- Field labels for input type=time -->
<!ENTITY time.hour.label "Hours">
<!ENTITY time.minute.label "Minutes">
<!ENTITY time.second.label "Seconds">
<!ENTITY time.millisecond.label "Milliseconds">
<!ENTITY time.dayperiod.label "AM/PM">
<!-- Placeholders for input type=date -->
<!ENTITY date.year.placeholder "yyyy">
<!ENTITY date.month.placeholder "mm">
<!ENTITY date.day.placeholder "dd">
<!-- Field labels for input type=date -->
<!ENTITY date.year.label "Year">
<!ENTITY date.month.label "Month">
<!ENTITY date.day.label "Day">
<!-- Date/time clear button -->
<!ENTITY datetime.reset.label "Clear">

View File

@ -0,0 +1,36 @@
# 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/.
# Date/time clear button
datetime-reset =
.aria-label = Clear
## Placeholders for date and time inputs
datetime-year-placeholder = yyyy
datetime-month-placeholder = mm
datetime-day-placeholder = dd
datetime-time-placeholder = --
## Field labels for input type=date
datetime-year =
.aria-label = Year
datetime-month =
.aria-label = Month
datetime-day =
.aria-label = Day
## Field labels for input type=time
datetime-hour =
.aria-label = Hours
datetime-minute =
.aria-label = Minutes
datetime-second =
.aria-label = Seconds
datetime-millisecond =
.aria-label = Milliseconds
datetime-dayperiod =
.aria-label = AM/PM

View File

@ -16,7 +16,6 @@
locale/@AB_CD@/global/browser.properties (%chrome/global/browser.properties)
locale/@AB_CD@/global/commonDialogs.properties (%chrome/global/commonDialogs.properties)
locale/@AB_CD@/global/contentAreaCommands.properties (%chrome/global/contentAreaCommands.properties)
locale/@AB_CD@/global/datetimebox.dtd (%chrome/global/datetimebox.dtd)
#ifndef MOZ_FENNEC
locale/@AB_CD@/global/editMenuOverlay.dtd (%chrome/global/editMenuOverlay.dtd)
#endif