Bug 1375799 - (Part 1) [Form Autofill] Use localized strings instead of hardcoded strings. r=lchang,MattN
MozReview-Commit-ID: DgWLFN2EDc8
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -6,16 +6,17 @@
this.EXPORTED_SYMBOLS = ["FormAutofillUtils"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const ADDRESS_REFERENCES = "chrome://formautofill/content/addressReferences.js";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
this.FormAutofillUtils = {
get AUTOFILL_FIELDS_THRESHOLD() { return 3; },
_fieldNameInfo: {
"name": "name",
"given-name": "name",
"additional-name": "name",
@@ -197,41 +198,47 @@ this.FormAutofillUtils = {
loadDataFromScript(url, sandbox = {}) {
let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
scriptLoader.loadSubScript(url, sandbox, "utf-8");
return sandbox;
},
/**
+ * Get country address data. Fallback to US if not found.
+ * @param {string} country
+ * @returns {object}
+ */
+ getCountryAddressData(country) {
+ // Load the addressData if needed
+ if (!this._addressDataLoaded) {
+ Object.assign(this, this.loadDataFromScript(ADDRESS_REFERENCES));
+ this._addressDataLoaded = true;
+ }
+ return this.addressData[`data/${country}`] || this.addressData["data/US"];
+ },
+
+ /**
* Find the option element from select element.
* 1. Try to find the locale using the country from address.
* 2. First pass try to find exact match.
* 3. Second pass try to identify values from address value and options,
* and look for a match.
* @param {DOMElement} selectEl
* @param {object} address
* @param {string} fieldName
* @returns {DOMElement}
*/
findSelectOption(selectEl, address, fieldName) {
let value = address[fieldName];
if (!value) {
return null;
}
- // Load the addressData if needed
- if (!this._addressDataLoaded) {
- Object.assign(this, this.loadDataFromScript(ADDRESS_REFERENCES));
- this._addressDataLoaded = true;
- }
-
- // Set dataset to "data/US" as fallback
- let dataset = this.addressData[`data/${address.country}`] ||
- this.addressData["data/US"];
+ let dataset = this.getCountryAddressData(address.country);
let collator = new Intl.Collator(dataset.lang, {sensitivity: "base", ignorePunctuation: true});
for (let option of selectEl.options) {
if (this.strCompare(value, option.value, collator) ||
this.strCompare(value, option.text, collator)) {
return option;
}
}
@@ -298,12 +305,43 @@ this.FormAutofillUtils = {
* @param {string} a
* @param {string} b
* @param {object} collator
* @returns {boolean}
*/
strCompare(a = "", b = "", collator) {
return !collator.compare(a, b);
},
+
+ /**
+ * Get formatting information of a given country
+ * @param {string} country
+ * @returns {object}
+ * {
+ * {string} addressLevel1Label
+ * {string} postalCodeLabel
+ * }
+ */
+ getFormFormat(country) {
+ const dataset = this.getCountryAddressData(country);
+ return {
+ "addressLevel1Label": dataset.state_name_type || "province",
+ "postalCodeLabel": dataset.zip_name_type || "postalCode",
+ };
+ },
+
+ /**
+ * Localize elements with "data-localization" attribute
+ * @param {string} bundleURI
+ * @param {DOMElement} root
+ */
+ localizeMarkup(bundleURI, root) {
+ const bundle = Services.strings.createBundle(bundleURI);
+ let elements = root.querySelectorAll("[data-localization]");
+ for (let element of elements) {
+ element.textContent = bundle.GetStringFromName(element.getAttribute("data-localization"));
+ element.removeAttribute("data-localization");
+ }
+ },
};
this.log = null;
this.FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
--- a/browser/extensions/formautofill/content/editAddress.js
+++ b/browser/extensions/formautofill/content/editAddress.js
@@ -1,40 +1,78 @@
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+const AUTOFILL_BUNDLE_URI = "chrome://formautofill/locale/formautofill.properties";
+const REGIONS_BUNDLE_URI = "chrome://global/locale/regionNames.properties";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
function EditDialog() {
this._address = window.arguments && window.arguments[0];
window.addEventListener("DOMContentLoaded", this, {once: true});
}
EditDialog.prototype = {
- init() {
- this._elements = {
+ get _elements() {
+ if (this._elementRefs) {
+ return this._elementRefs;
+ }
+ this._elementRefs = {
+ title: document.querySelector("title"),
+ addressLevel1Label: document.querySelector("#address-level1-container > span"),
+ postalCodeLabel: document.querySelector("#postal-code-container > span"),
+ country: document.getElementById("country"),
controlsContainer: document.getElementById("controls-container"),
cancel: document.getElementById("cancel"),
save: document.getElementById("save"),
};
+ return this._elementRefs;
+ },
+
+ set _elements(refs) {
+ this._elementRefs = refs;
+ },
+
+ init() {
this.attachEventListeners();
},
uninit() {
this.detachEventListeners();
this._elements = null;
},
/**
+ * Format the form based on country. The address-level1 and postal-code labels
+ * should be specific to the given country.
+ * @param {string} country
+ */
+ formatForm(country) {
+ // TODO: Use fmt to show/hide and order fields (Bug 1383687)
+ const {addressLevel1Label, postalCodeLabel} = FormAutofillUtils.getFormFormat(country);
+ this._elements.addressLevel1Label.dataset.localization = addressLevel1Label;
+ this._elements.postalCodeLabel.dataset.localization = postalCodeLabel;
+ FormAutofillUtils.localizeMarkup(AUTOFILL_BUNDLE_URI, document);
+ },
+
+ localizeDocument() {
+ if (this._address) {
+ this._elements.title.dataset.localization = "editDialogTitle";
+ }
+ FormAutofillUtils.localizeMarkup(REGIONS_BUNDLE_URI, this._elements.country);
+ this.formatForm(this._address && this._address.country);
+ },
+
+ /**
* Asks FormAutofillParent to save or update an address.
* @param {object} data
* {
* {string} guid [optional]
* {object} address
* }
*/
saveAddress(data) {
@@ -72,17 +110,16 @@ EditDialog.prototype = {
*
* @param {DOMEvent} event
*/
handleEvent(event) {
switch (event.type) {
case "DOMContentLoaded": {
this.init();
if (this._address) {
- document.title = "Edit Address";
this.loadInitialValues(this._address);
}
break;
}
case "click": {
this.handleClick(event);
break;
}
@@ -156,9 +193,9 @@ EditDialog.prototype = {
*/
detachEventListeners() {
window.removeEventListener("keypress", this);
this._elements.controlsContainer.removeEventListener("click", this);
document.removeEventListener("input", this);
},
};
-new EditDialog();
+window.dialog = new EditDialog();
--- a/browser/extensions/formautofill/content/editAddress.xhtml
+++ b/browser/extensions/formautofill/content/editAddress.xhtml
@@ -1,68 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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 xmlns="http://www.w3.org/1999/xhtml">
<head>
- <title>Add New Address</title>
+ <title data-localization="addNewDialogTitle"/>
<link rel="stylesheet" href="chrome://formautofill-shared/skin/editAddress.css" />
<link rel="stylesheet" href="chrome://formautofill/skin/editAddress.css" />
<script src="chrome://formautofill/content/editAddress.js"></script>
</head>
<body>
<form autocomplete="off">
<label id="given-name-container">
- <span>First Name</span>
+ <span data-localization="givenName"/>
<input id="given-name" type="text"/>
</label>
<label id="additional-name-container">
- <span>Middle Name</span>
+ <span data-localization="additionalName"/>
<input id="additional-name" type="text"/>
</label>
<label id="family-name-container">
- <span>Last Name</span>
+ <span data-localization="familyName"/>
<input id="family-name" type="text"/>
</label>
<label id="organization-container">
- <span>Company</span>
+ <span data-localization="organization"/>
<input id="organization" type="text"/>
</label>
<label id="street-address-container">
- <span>Street Address</span>
+ <span data-localization="streetAddress"/>
<textarea id="street-address" rows="3"/>
</label>
<label id="address-level2-container">
- <span>City/Town</span>
+ <span data-localization="city"/>
<input id="address-level2" type="text"/>
</label>
<label id="address-level1-container">
- <span>State/Province</span>
+ <span/>
<input id="address-level1" type="text"/>
</label>
<label id="postal-code-container">
- <span>Zip/Postal</span>
+ <span/>
<input id="postal-code" type="text"/>
</label>
<label id="country-container">
- <span>Country</span>
+ <span data-localization="country"/>
<select id="country">
<option/>
- <option value="US">United States</option>
+ <option value="US" data-localization="us"/>
</select>
</label>
<label id="email-container">
- <span>Email</span>
+ <span data-localization="email"/>
<input id="email" type="email"/>
</label>
<label id="tel-container">
- <span>Phone</span>
+ <span data-localization="tel"/>
<input id="tel" type="tel"/>
</label>
</form>
<div id="controls-container">
- <button id="cancel">Cancel</button>
- <button id="save" disabled="disabled">Save</button>
+ <button id="cancel" data-localization="cancel"/>
+ <button id="save" disabled="disabled" data-localization="save"/>
</div>
+ <script type="application/javascript"><![CDATA[
+ "use strict";
+ // Localize strings before DOMContentLoaded to prevent flash
+ window.dialog.localizeDocument();
+ ]]></script>
</body>
</html>
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -174,25 +174,26 @@
*
* @private
* @param {string|string[]} categories
* A list of categories that used to generate the message.
* @param {boolean} hasExtraCategories
* Used to determine if it has the extra categories other than the focued category. If
* the value is true, we show "Also fill ...", otherwise, show "Fill ..." only.
*/
+ const namespace = "category.";
this._updateText = (categories = this._allFieldCategories, hasExtraCategories = true) => {
let warningTextTmplKey = hasExtraCategories ? "phishingWarningMessage" : "phishingWarningMessage2";
let sep = this._stringBundle.GetStringFromName("fieldNameSeparator");
// Show the categories in certain order to conform with the spec.
let orderedCategoryList = ["address", "name", "organization", "tel", "email"];
let showCategories = hasExtraCategories ?
orderedCategoryList.filter(category => categories.includes(category) && category != this._focusedCategory) :
[this._focusedCategory];
- let categoriesText = showCategories.map(this._stringBundle.GetStringFromName).join(sep);
+ let categoriesText = showCategories.map(category => this._stringBundle.GetStringFromName(namespace + category)).join(sep);
this._warningTextBox.textContent = this._stringBundle.formatStringFromName(warningTextTmplKey,
[categoriesText], 1);
this.parentNode.parentNode.adjustHeight();
};
/**
* A handler for updating warning message once selectedIndex has been changed.
--- a/browser/extensions/formautofill/content/manageAddresses.js
+++ b/browser/extensions/formautofill/content/manageAddresses.js
@@ -1,16 +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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const EDIT_ADDRESS_URL = "chrome://formautofill/content/editAddress.xhtml";
+const AUTOFILL_BUNDLE_URI = "chrome://formautofill/locale/formautofill.properties";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
this.log = null;
FormAutofillUtils.defineLazyLogGetter(this, "manageAddresses");
@@ -52,16 +53,20 @@ ManageAddressDialog.prototype = {
},
uninit() {
log.debug("uninit");
this.detachEventListeners();
this._elements = null;
},
+ localizeDocument() {
+ FormAutofillUtils.localizeMarkup(AUTOFILL_BUNDLE_URI, document);
+ },
+
/**
* Load addresses and render them.
*
* @returns {promise}
*/
loadAddresses() {
return this.getRecords({collectionName: "addresses"}).then(addresses => {
log.debug("addresses:", addresses);
@@ -297,9 +302,9 @@ ManageAddressDialog.prototype = {
window.removeEventListener("keypress", this);
this._elements.addresses.removeEventListener("change", this);
this._elements.addresses.removeEventListener("click", this);
this._elements.controlsContainer.removeEventListener("click", this);
Services.obs.removeObserver(this, "formautofill-storage-changed");
},
};
-new ManageAddressDialog();
+window.dialog = new ManageAddressDialog();
--- a/browser/extensions/formautofill/content/manageAddresses.xhtml
+++ b/browser/extensions/formautofill/content/manageAddresses.xhtml
@@ -1,29 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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 xmlns="http://www.w3.org/1999/xhtml">
<head>
- <title>Saved Addresses</title>
+ <title data-localization="manageDialogTitle"/>
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
<link rel="stylesheet" href="chrome://formautofill/content/manageAddresses.css" />
<script src="chrome://formautofill/content/manageAddresses.js"></script>
</head>
<body>
<p style="padding-left: 30px; background: url(chrome://browser/skin/warning.svg) no-repeat left center">
Autofill of addresses is only ready for testing with United States addresses on <input>s and some <select> elements.
Improvements to form field type detection are in progress.
<a href="https://luke-chang.github.io/autofill-demo/basic.html" target="_blank">Demo page</a>
</p>
<fieldset>
- <legend>Addresses</legend>
+ <legend data-localization="addressListHeader"/>
<select id="addresses" size="9" multiple="multiple"/>
</fieldset>
<div id="controls-container">
- <button id="remove" disabled="disabled">Remove</button>
- <button id="add">Add…</button>
- <button id="edit" disabled="disabled">Edit…</button>
+ <button id="remove" disabled="disabled" data-localization="remove"/>
+ <button id="add" data-localization="add"/>
+ <button id="edit" disabled="disabled" data-localization="edit"/>
</div>
+ <script type="application/javascript">
+ "use strict";
+ // Localize strings before DOMContentLoaded to prevent flash
+ window.dialog.localizeDocument();
+ </script>
</body>
</html>
--- a/browser/extensions/formautofill/locale/en-US/formautofill.properties
+++ b/browser/extensions/formautofill/locale/en-US/formautofill.properties
@@ -13,21 +13,45 @@ changeAutofillOptionsOSX = Change Form A
updateAddressMessage = Would you like to update your address with this new information?
createAddressLabel = Create New Address
updateAddressLabel = Update Address
openAutofillMessagePanel = Open Form Autofill message panel
autocompleteFooterOption = Form Autofill Options
autocompleteFooterOptionShort = More Options
autocompleteFooterOptionOSX = Form Autofill Preferences
autocompleteFooterOptionOSXShort = Preferences
-address = address
-name = name
-organization = company
-tel = phone
-email = email
+category.address = address
+category.name = name
+category.organization = company
+category.tel = phone
+category.email = email
# LOCALIZATION NOTE (fieldNameSeparator): This is used as a separator between categories.
fieldNameSeparator = ,\u0020
# LOCALIZATION NOTE (phishingWarningMessage, phishingWarningMessage2): The warning
# text that is displayed for informing users what categories are about to be filled.
# "%S" will be replaced with a list generated from the pre-defined categories.
# The text would be e.g. Also fill company, phone, email
phishingWarningMessage = Also autofills %S
phishingWarningMessage2 = Autofills %S
+
+manageDialogTitle = Saved Addresses
+addressListHeader = Addresses
+remove = Remove
+add = Add…
+edit = Edit…
+
+addNewDialogTitle = Add New Address
+editDialogTitle = Edit Address
+givenName = First Name
+additionalName = Middle Name
+familyName = Last Name
+organization = Company
+streetAddress = Street Address
+city = City
+province = Province
+state = State
+postalCode = Postal Code
+zip = Zip Code
+country = Country
+tel = Phone
+email = Email
+cancel = Cancel
+save = Save