Bug 1749435 - Use Fluent to localize `bookmarks.html` at run-time rather than build-time. r=flod,mak,fluent-reviewers
authorNick Alexander <nalexander@mozilla.com>
Wed, 19 Jan 2022 17:02:26 +0000 (2022-01-19)
changeset 604907 da061e3d46331401fd507491155fe4984ded90ad
parent 604906 fdb8148fec201a3096cb068549d7bef437e4ea9f
child 604908 a83511601780caa4d0e31770623594d9c7635bb4
push id39165
push usermlaza@mozilla.com
push dateWed, 19 Jan 2022 21:47:18 +0000 (2022-01-19)
treeherdermozilla-central@cc33400f0ff8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflod, mak, fluent-reviewers
bugs1749435
milestone98.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 1749435 - Use Fluent to localize `bookmarks.html` at run-time rather than build-time. r=flod,mak,fluent-reviewers This modernizes an old part of the build system to not require build-time localization at all. That's generally preferable. The most significant changes to the in-product functionality is to make import localize HTML so that we can use Fluent's `data-l10n-id`. The locale used is the user's current locale. This is different than the existing approach, which always uses the build-time (repack) locale. I believe this is a strictly superior user experience and it may lead to future improvements where-in the default bookmarks become truly dynamic and vary with the user's chosen locale rather than being point-in-time decisions. I tried to restrict these changes to only applen when we import the default bookmarks, but I think the various layers of flags no longer achieve this restriction in practice and the formatting and localization will apply to all imported `bookmarks.html` files. Since we don't anticipate (nor ourselves write) these new things in (respectively, to) `bookmarks.html`, and the file is already user-controlled, I don't think this exposes any meaningful change in functionality (or in security surface). Some notes: 1) There's no migration of `.inc` -> `.ftl` because this is the lone `.inc` file. 2) I elected to prefix all strings with `default-bookmarks-`, since the existing names were very short and likely to collide (now or in the future). 3) I elected to change the HTML file name for easier searching. 4) Since the `default-bookmarks.html` file is product-specific and the existing tests are in `toolkit/`, I elected to not test the file directly in automation. 5) We removed the explicit locale (or equivalent `%LOCALE%`) since Mozilla properties will redirect to the appropriate language automatically. Differential Revision: https://phabricator.services.mozilla.com/D135816
browser/base/content/default-bookmarks.html
browser/base/jar.mn
browser/components/BrowserGlue.jsm
browser/components/migration/MigrationUtils.jsm
browser/locales/en-US/browser/profile/default-bookmarks.ftl
browser/locales/en-US/profile/bookmarks.inc
browser/locales/generate_bookmarks.py
browser/locales/generic/profile/bookmarks.html.in
browser/locales/jar.mn
browser/locales/moz.build
toolkit/components/places/BookmarkHTMLUtils.jsm
toolkit/components/places/tests/unit/bookmarks_html_localized.html
toolkit/components/places/tests/unit/test_bookmarks_html_localized.js
toolkit/components/places/tests/unit/xpcshell.ini
rename from browser/locales/generic/profile/bookmarks.html.in
rename to browser/base/content/default-bookmarks.html
--- a/browser/locales/generic/profile/bookmarks.html.in
+++ b/browser/base/content/default-bookmarks.html
@@ -1,49 +1,59 @@
 #filter substitution
-#include @BOOKMARKS_INCLUDE_PATH@
 
 #define mozilla_icon data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E %3Cpath d='M0 0h16v16H0z'/%3E %3Cpath d='M13.994 10.356H15V12h-3.171V7.741c0-1.308-.435-1.81-1.29-1.81-1.04 0-1.46.737-1.46 1.8v2.63h1.006V12H6.918V7.741c0-1.308-.435-1.81-1.291-1.81-1.039 0-1.459.737-1.459 1.8v2.63h1.441V12H1v-1.644h1.006V6.079H1V4.435h3.168v1.139a2.507 2.507 0 0 1 2.3-1.29A2.452 2.452 0 0 1 8.931 5.91 2.535 2.535 0 0 1 11.4 4.284 2.448 2.448 0 0 1 14 6.9v3.458z' fill='%23fff'/%3E %3C/svg%3E
 
 #define firefox_icon data:image/png;base64,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
 
 #define bugzilla_icon data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnYCL7J0pY9wwETY9kYEM9AAAAAEBAYAhVVVUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1bjTOS1Vb/wAA2/8JEqT/Q0g8kQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJnMqoiJtJ/0haST/NEkp/yQnW/8AAPD8AAHY/RsgP/JZUI+GKitih4ObUEAAAAAAAAAAAAAAAAAAAAAAKnouwip5Lv9ooW//a6Jz/y9GIv8JBXb/AADO/gEBvf8AAK7/FRJp/z9BfP8iLGj1AAAAAAAAAAAAAAAAL4YzwiB0I/+UwJ3/bK+C/02eZ/9CTjz/DBa1/wABxf8BAOj/AACp/w8Oc/sJCv//EhCN9AAAAAAAAAAANJA6iC2MMv93tYL/TZ5U/3mzjP9NoWr/NEss/wYIU/8CBOn/ARCX/wwNqP0TD6X/Cgyex5qacDAAAAAAAAAAADKUN/ZirWj/d76R/0SgXf9Ln1P/eLSM/1mda/8rOkb/CQiD/wMQvf8UEnT/MTAt4P//MwUhZyN8AAAAAAAAAAAznDf5UqlZ/228jP9NqnD/Qp9c/0yiVP+Dv5b/VaVw/0VxXf9PZXD/S3pQ/y54Nf8jcCf/I2wn/wAAAAA0ozjIM6E4/zOeOP+Uz6z/XLR+/06scv9BoV3/TqZX/4XBmP9XqHP/hr6Z/yp+Lf8leSr1JXUqbQAAAAA3rTz7Nqo7/zWmOqM3oz7rUK1W/43Mpf9etYD/T61z/0KjXf9Rqln/msup/46/lf8pgy7/JFg6sAAAAAAAAAAAOK8+8jqvOiMAAAAAAAAAADSlOv85pT//kM6o/2K5hP9Ysnv/YLJ2/ziXPv8piS3/V6Ri/yZQQ9wAAAAAAAAAAAAAAAAAAAAAAAAAADetP0E2qzz/OKg98UWsS/+e1K3/pNe4/4XDjv8ojy3/T7df/5fIqv8sjTH/K4kw/yqFLv8AAAAAAAAAAAAAAAA4sT3xN7A8+QAAAAA4qz3yNag6/zSlOf80oTn/csJ+/6/jwv9fjHj/MmRMdQAAAAAAAAAAAAAAAAAAAAAAAAAAOrdA/zm0QHQAAAAAAAAAADasO/k2qTvuRX5lpjqGT/gznDr/O3FXigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADq9QiMAAAAAAAAAAAAAAAA4sj7/Nq09s0uOaSI1qTplM6U68wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOrc//zu0P0EAAAAAOK4+UjWsPPgAAAAAAAAAAAAAAAAAAAAA/48AAP8HAAD4AQAA8AAAAOAAAADAAQAAwAMAAMAAAACAAwAAAAMAAHADAADwAAAA5AcAAO4HAAD+bwAA/u8AAA==
 
 #define mdn_icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAABgElEQVR4AWPouPiRpmjUAjgatSBj+aG0OVuyVhymsgWl2y475zXySikwwIC4lpFDVk3avG0BrXP9mmeV7bhCvgXuxW3M7JwMeAGfpByZFpjHFzAQB2KmrSfZAtuMKgaiAZ+MUuLc7SRY4FbYwkA60HAJiJm8uubQAwIWeJV1MlAAOAREHDJrcFqQMG+ngIK6oKyykLwqAyMjeXZwiUjgtKD+yGMIwyGzmoGBTAs4hcXrgObgi4OiVkpCiUtYov7YU5wW1B194t0ww69ldvjktYouwWRYIGdkQ1Q+iJ28hp2Xn7B5zKzIPAlNw6S52wlbkL3mJJecOq+CBqeIJC6TjUJTMlcdz9lwLmriSuPgJBVbj/D+5SSXRequQVhNN4nIoEJhV77jKgs7B6bprJw85XtuU8GCpNlbSS3gSA4ii4QiTAvElDWpWeH41kxg5eZDSypUrtFKd1zTcA1EpHRDS5rUyQEts+VN7JjYOGR0TWhY6RdsOhc/Y9NoswUJjVoAAE+h555Rgcg2AAAAAElFTkSuQmCC
 
 #define addon_icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABOFBMVEUAAAAAzdwAydcAyNgA//8AzOYAydcAyNgAyNgA2NgAytoAzNkAytgAydgA29sA0egAyNgAyNgA//8AyNgAydgA//8Ay9cAydcAytkAz90Ay9gA1eoAydgAytsAyNgAytgAydkAydgAydgAyNgAydgAyNcAy9oAydgA//8AytsAy9kAytkAyNgAydgAydkAy9kAzP8AydgAydgAydgAz98AzN0AyNcAyNsAydcAydgAydgAydcAytgAytcAydcAydcAytcAydcAyNcAydcAy9gAztgAydcAydgAzOAAydcAyNgAyNgAytwAyNcAyNgAy9wAyNcAyNcAyNgAydgAyNcAydcAydgA0uEAydkAyNgAyeQA4+MAyNgAydkAzN0AyNsA1f8AyNgAydgAydcA1eMAydgAydcAyNdj6PGJAAAAZ3RSTlMAJFpBAQqm8qwNPiiPygcLv8QEw5cDQMA1JU4MwiuDbl/+6+m4+0XLAj9KePz9cjYFvervEA/IDsfFr+xcgeaOYIDo+ica1OMZ9bXlHe73LM3M35itxs8Rf5ATCbFeHjgGttC5ErzO3WvwaAAAAWxJREFUOMt9kudCwkAQhFcITQWCoaggiBqxoaixYUVsYMMGCmLXff838LIXCJAL84fvmCHsTg4AYMDhlIDkcnu8Po4w6BjiIA0joj+gY1BmGKLEiMIwHNFR9xGjuh8jpMQoYZjRGBGOA8QTHDEUB4hynABwcEqCT8GW2DNSnCYBnJzSoSk0NT2jcphlM/rRXpk5NkRgfmFxSWBml6MrOWNlWBUEEmDKtyYIrGttP66gSP4Nww8mUKzNLd5/zHaJbb1Tl9xnzR2WcGM/5QE8BLvJvf0Dc4HDo8IxUVECL5Vywv7s9Mzwz/WLcFHSsWy8w0sa9+qa/JtbOlUY3mnGLbjnCz9Q4JEfnhCrNb5nXi3w754p8MIPKVWpt6psGJ+vFJBbBUO3GlozzYdsSmCV1NlntiTnegNvPQ29Wx7h7fKrEUvg47PD/6oLpgh8m7//AZEav4b/J/bbb75SAzvR3crY+6y8fLGsQV9ZSvwHF4LQIhDjT+8AAAAASUVORK5CYII=
 <!-- 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 NETSCAPE-Bookmark-file-1>
-<meta charset="UTF-8">
-<title>@bookmarks_title@</title>
-<h1>@bookmarks_heading@</h1>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <!-- These localization links are not automatically applied to any XHR
+         response body and must be applied manually as well.  They are included
+         so that viewing the file directly shows the results. -->
+    <link rel="localization" href="branding/brand.ftl"/>
+    <link rel="localization" href="browser/profile/default-bookmarks.ftl"/>
+    <title data-l10n-id="default-bookmarks-title">default-bookmarks-title</title>
+</head>
+<body>
+<h1 data-l10n-id="default-bookmarks-heading">default-bookmarks-heading</h1>
 
 <dl><p>
-    <dt><h3 personal_toolbar_folder="true">@bookmarks_toolbarfolder@</h3></dt>
-    <dd>@bookmarks_toolbarfolder_description@
+    <dt><h3 personal_toolbar_folder="true" data-l10n-id="default-bookmarks-toolbarfolder">default-bookmarks-toolbarfolder</h3></dt>
+    <dd data-l10n-id="default-bookmarks-toolbarfolder-description">default-bookmarks-toolbarfolder-description</dd>
 #ifndef NIGHTLY_BUILD
-        <dl>
-            <p><dt><a href="https://www.mozilla.org/@AB_CD@/firefox/central/" icon="@firefox_icon@">@getting_started@</a></dt>
-        </dl>
-    <p><dt><h3>@firefox_heading@</h3></dt>
+        <dl><p>
+            <dt><a href="https://www.mozilla.org/firefox/central/" icon="@firefox_icon@" data-l10n-id="default-bookmarks-getting-started">default-bookmarks-getting-started</a></dt>
+        </dl><p>
+    <dt><h3 data-l10n-id="default-bookmarks-firefox-heading">default-bookmarks-firefox-heading</h3></dt>
         <dl><p>
-            <dt><a href="https://support.mozilla.org/@AB_CD@/products/firefox" icon="@firefox_icon@">@firefox_get_help@</a>
-            <dt><a href="https://support.mozilla.org/@AB_CD@/kb/customize-firefox-controls-buttons-and-toolbars?utm_source=firefox-browser&utm_medium=default-bookmarks&utm_campaign=customize" icon="@firefox_icon@">@firefox_customize@</a>
-            <dt><a href="https://www.mozilla.org/@AB_CD@/contribute/" icon="@mozilla_icon@">@firefox_community@</a>
-            <dt><a href="https://www.mozilla.org/@AB_CD@/about/" icon="@mozilla_icon@">@firefox_about@</a>
-        </dl>
+            <dt><a href="https://support.mozilla.org/products/firefox" icon="@firefox_icon@" data-l10n-id="default-bookmarks-firefox-get-help">default-bookmarks-firefox-get-help</a></dt>
+            <dt><a href="https://support.mozilla.org/kb/customize-firefox-controls-buttons-and-toolbars?utm_source=firefox-browser&utm_medium=default-bookmarks&utm_campaign=customize" icon="@firefox_icon@" data-l10n-id="default-bookmarks-firefox-customize">default-bookmarks-firefox-customize</a></dt>
+            <dt><a href="https://www.mozilla.org/contribute/" icon="@mozilla_icon@" data-l10n-id="default-bookmarks-firefox-community">default-bookmarks-firefox-community</a></dt>
+            <dt><a href="https://www.mozilla.org/about/" icon="@mozilla_icon@" data-l10n-id="default-bookmarks-firefox-about">default-bookmarks-firefox-about</a></dt>
+        </dl><p>
 #else
-        <dl>
-            <p><dt><a href="https://www.mozilla.org/@AB_CD@/contribute/" icon="@mozilla_icon@">@firefox_community@</a>
-        </dl>
-    <p><dt><h3>@nightly_heading@</h3></dt>
+        <dl><p>
+            <dt><a href="https://www.mozilla.org/contribute/" icon="@mozilla_icon@" data-l10n-id="default-bookmarks-firefox-community">default-bookmarks-firefox-community</a></dt>
+        </dl><p>
+    <dt><h3 data-l10n-id="default-bookmarks-nightly-heading">default-bookmarks-nightly-heading</h3></dt>
         <dl><p>
-            <dt><a href="https://blog.nightly.mozilla.org/" icon="@mozilla_icon@">@nightly_blog@</a>
-            <dt><a href="https://bugzilla.mozilla.org/" icon="@bugzilla_icon@" shortcuturl="bz">@bugzilla@</a>
-            <dt><a href="https://developer.mozilla.org/" icon="@mdn_icon@" shortcuturl="mdn">@mdn@</a>
-            <dt><a href="https://addons.mozilla.org/@AB_CD@/firefox/addon/nightly-tester-tools/" icon="@addon_icon@">@nightly_tester_tools@</a>
-            <dt><a href="about:crashes" icon="@mozilla_icon@">@crashes@</a>
-            <dt><a href="https://planet.mozilla.org/" icon="@mozilla_icon@">@planet@</a>
-        </dl>
+            <dt><a href="https://blog.nightly.mozilla.org/" icon="@mozilla_icon@" data-l10n-id="default-bookmarks-nightly-blog">default-bookmarks-nightly-blog</a></dt>
+            <dt><a href="https://bugzilla.mozilla.org/" icon="@bugzilla_icon@" shortcuturl="bz" data-l10n-id="default-bookmarks-bugzilla">default-bookmarks-bugzilla</a></dt>
+            <dt><a href="https://developer.mozilla.org/" icon="@mdn_icon@" shortcuturl="mdn" data-l10n-id="default-bookmarks-mdn">default-bookmarks-mdn</a></dt>
+            <dt><a href="https://addons.mozilla.org/firefox/addon/nightly-tester-tools/" icon="@addon_icon@" data-l10n-id="default-bookmarks-nightly-tester-tools">default-bookmarks-nightly-tester-tools</a></dt>
+            <dt><a href="about:crashes" icon="@mozilla_icon@" data-l10n-id="default-bookmarks-crashes">default-bookmarks-crashes</a></dt>
+            <dt><a href="https://planet.mozilla.org/" icon="@mozilla_icon@" data-l10n-id="default-bookmarks-planet">default-bookmarks-planet</a></dt>
+        </dl><p>
 #endif
 </dl>
+</body>
+</html>
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -101,14 +101,15 @@ browser.jar:
 *       content/browser/license.html                  (/toolkit/content/license.html)
 % override chrome://global/content/license.html chrome://browser/content/license.html
         content/browser/blockedSite.xhtml               (content/blockedSite.xhtml)
         content/browser/blockedSite.js                  (content/blockedSite.js)
         content/browser/upgradeDialog.html            (content/upgradeDialog.html)
         content/browser/upgradeDialog.js              (content/upgradeDialog.js)
         content/browser/spotlight.html                (content/spotlight.html)
         content/browser/spotlight.js                  (content/spotlight.js)
+*       content/browser/default-bookmarks.html        (content/default-bookmarks.html)
 
 % override chrome://global/content/netError.xhtml chrome://browser/content/certerror/aboutNetError.xhtml
 
 # L10n resources and overrides.
 % override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties
 % override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -3218,18 +3218,19 @@ BrowserGlue.prototype = {
           await this._distributionCustomizer.applyBookmarks();
         } catch (e) {
           Cu.reportError(e);
         }
       } else {
         // An import operation is about to run.
         let bookmarksUrl = null;
         if (restoreDefaultBookmarks) {
-          // User wants to restore bookmarks.html file from default profile folder
-          bookmarksUrl = "chrome://browser/locale/bookmarks.html";
+          // User wants to restore the default set of bookmarks shipped with the
+          // browser, those that new profiles start with.
+          bookmarksUrl = "chrome://browser/content/default-bookmarks.html";
         } else if (await IOUtils.exists(BookmarkHTMLUtils.defaultPath)) {
           bookmarksUrl = PathUtils.toFileURI(BookmarkHTMLUtils.defaultPath);
         }
 
         if (bookmarksUrl) {
           // Import from bookmarks.html file.
           try {
             if (Services.policies.isAllowed("defaultBookmarks")) {
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -451,17 +451,17 @@ var MigratorPrototype = {
         // Tell nsBrowserGlue we're importing default bookmarks.
         let browserGlue = Cc["@mozilla.org/browser/browserglue;1"].getService(
           Ci.nsIObserver
         );
         browserGlue.observe(null, TOPIC_WILL_IMPORT_BOOKMARKS, "");
 
         // Import the default bookmarks. We ignore whether or not we succeed.
         await BookmarkHTMLUtils.importFromURL(
-          "chrome://browser/locale/bookmarks.html",
+          "chrome://browser/content/default-bookmarks.html",
           {
             replace: true,
             source: PlacesUtils.bookmarks.SOURCES.RESTORE_ON_STARTUP,
           }
         ).catch(Cu.reportError);
 
         // We'll tell nsBrowserGlue we've imported bookmarks, but before that
         // we need to make sure we're going to know when it's finished
rename from browser/locales/en-US/profile/bookmarks.inc
rename to browser/locales/en-US/browser/profile/default-bookmarks.ftl
--- a/browser/locales/en-US/profile/bookmarks.inc
+++ b/browser/locales/en-US/browser/profile/default-bookmarks.ftl
@@ -1,68 +1,52 @@
 # 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/.
-#filter emptyLines
 
-# LOCALIZATION NOTE: The 'en-US' strings in the URLs will be replaced with
-# your locale code, and link to your translated pages as soon as they're
-# live.
+# This file intentionally uses hard-coded brand names instead of Fluent terms.
+# This approach minimizes issues across multiple release channels and rebranded
+# versions.
 
-#define bookmarks_title Bookmarks
-#define bookmarks_heading Bookmarks
+default-bookmarks-title = Bookmarks
+default-bookmarks-heading = Bookmarks
 
-#define bookmarks_toolbarfolder Bookmarks Toolbar Folder
-#define bookmarks_toolbarfolder_description Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar
-
-# LOCALIZATION NOTE (getting_started):
-# link title for https://www.mozilla.org/en-US/firefox/central/
-#define getting_started Getting Started
+default-bookmarks-toolbarfolder = Bookmarks Toolbar Folder
+default-bookmarks-toolbarfolder-description = Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar
 
-# LOCALIZATION NOTE (firefox_heading):
-# Firefox links folder name
-#define firefox_heading Mozilla Firefox
+# link title for https://www.mozilla.org/firefox/central/
+default-bookmarks-getting-started = Getting Started
 
-# LOCALIZATION NOTE (firefox_get_help):
-# link title for https://www.mozilla.org/en-US/firefox/help/
-#define firefox_get_help Get Help
+# Firefox links folder name
+default-bookmarks-firefox-heading = Mozilla Firefox
 
-# LOCALIZATION NOTE (firefox_customize):
-# link title for https://www.mozilla.org/en-US/firefox/customize/
-#define firefox_customize Customize Firefox
+# link title for https://www.mozilla.org/firefox/help/
+default-bookmarks-firefox-get-help = Get Help
 
-# LOCALIZATION NOTE (firefox_community):
-# link title for https://www.mozilla.org/en-US/contribute/
-#define firefox_community Get Involved
+# link title for https://www.mozilla.org/firefox/customize/
+default-bookmarks-firefox-customize = Customize Firefox
 
-# LOCALIZATION NOTE (firefox_about):
-# link title for https://www.mozilla.org/en-US/about/
-#define firefox_about About Us
+# link title for https://www.mozilla.org/contribute/
+default-bookmarks-firefox-community = Get Involved
 
-# LOCALIZATION NOTE (nightly_heading):
-# Firefox Nightly links folder name
-#define nightly_heading Firefox Nightly Resources
+# link title for https://www.mozilla.org/about/
+default-bookmarks-firefox-about = About Us
 
-# LOCALIZATION NOTE (nightly_blog):
-# Nightly builds only, link title for https://blog.nightly.mozilla.org/
-#define nightly_blog Firefox Nightly blog
+# Firefox Nightly links folder name
+default-bookmarks-nightly-heading = Firefox Nightly Resources
 
-# LOCALIZATION NOTE (bugzilla):
-# Nightly builds only, link title for https://bugzilla.mozilla.org/
-#define bugzilla Mozilla Bug Tracker
+# Nightly builds only, link title for https://blog.nightly.mozilla.org/
+default-bookmarks-nightly-blog = Firefox Nightly blog
 
-# LOCALIZATION NOTE (mdn):
-# Nightly builds only, link title for https://developer.mozilla.org/
-#define mdn Mozilla Developer Network
+# Nightly builds only, link title for https://bugzilla.mozilla.org/
+default-bookmarks-bugzilla = Mozilla Bug Tracker
 
-# LOCALIZATION NOTE (nightly_tester_tools):
-# Nightly builds only, link title for https://addons.mozilla.org/en-US/firefox/addon/nightly-tester-tools/
-#define nightly_tester_tools Nightly Tester Tools
+# Nightly builds only, link title for https://developer.mozilla.org/
+default-bookmarks-mdn = Mozilla Developer Network
 
-# LOCALIZATION NOTE (crashes):
-# Nightly builds only, link title for about:crashes
-#define crashes All your crashes
+# Nightly builds only, link title for https://addons.mozilla.org/firefox/addon/nightly-tester-tools/
+default-bookmarks-nightly-tester-tools = Nightly Tester Tools
 
-# LOCALIZATION NOTE (planet):
+# Nightly builds only, link title for about:crashes
+default-bookmarks-crashes = All your crashes
+
 # Nightly builds only, link title for https://planet.mozilla.org/
-#define planet Planet Mozilla
-
-#unfilter emptyLines
+default-bookmarks-planet = Planet Mozilla
deleted file mode 100644
--- a/browser/locales/generate_bookmarks.py
+++ /dev/null
@@ -1,45 +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/.
-
-# Generate bookmarks.html by interpolating the included (localized)
-# `bookmarks.inc` file into the given (unlocalized) `bookmarks.html.in` input.
-
-from __future__ import absolute_import, unicode_literals, print_function
-
-import buildconfig
-import sys
-
-from mozbuild import preprocessor
-
-
-def main(output, bookmarks_html_in, bookmarks_inc, locale=None):
-    if not locale:
-        raise ValueError("locale must be specified!")
-
-    CONFIG = buildconfig.substs
-
-    # Based on
-    # https://searchfox.org/l10n-central/search?q=path%3Abookmarks.inc+%23if&redirect=true,
-    # no localized input uses the preprocessor conditional #if (really,
-    # anything but #define), so it's safe to restrict the set of defines to
-    # what's used in mozilla-central directly.
-    defines = {}
-    defines["AB_CD"] = locale
-    if defines["AB_CD"] == "ja-JP-mac":
-        defines["AB_CD"] = "ja"
-
-    defines["BOOKMARKS_INCLUDE_PATH"] = bookmarks_inc
-
-    for var in ("NIGHTLY_BUILD",):
-        if var in CONFIG:
-            defines[var] = CONFIG[var]
-
-    includes = preprocessor.preprocess(
-        includes=[bookmarks_html_in], defines=defines, output=output
-    )
-    return includes
-
-
-if __name__ == "__main__":
-    main(sys.argv[1:])
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -11,19 +11,16 @@
   preview/ion.ftl                                  (../components/ion/content/ion.ftl)
   preview/protections.ftl                          (../components/protections/content/protections.ftl)
   preview/interventions.ftl                        (../components/urlbar/content/interventions.ftl)
   preview/firefoxSuggest.ftl                       (../components/urlbar/content/firefoxSuggest.ftl)
   browser                                          (%browser/**/*.ftl)
 
 @AB_CD@.jar:
 % locale browser @AB_CD@ %locale/browser/
-# bookmarks.html is produced by LOCALIZED_GENERATED_FILES.
-    locale/browser/bookmarks.html                  (bookmarks.html)
-
     locale/browser/accounts.properties             (%chrome/browser/accounts.properties)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
     locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
     locale/browser/uiDensity.properties            (%chrome/browser/uiDensity.properties)
     locale/browser/search.properties               (%chrome/browser/search.properties)
     locale/browser/siteData.properties             (%chrome/browser/siteData.properties)
     locale/browser/sitePermissions.properties      (%chrome/browser/sitePermissions.properties)
     locale/browser/shellservice.properties         (%chrome/browser/shellservice.properties)
--- a/browser/locales/moz.build
+++ b/browser/locales/moz.build
@@ -20,26 +20,16 @@ if CONFIG["MOZ_UPDATER"]:
         "en-US/updater/updater.ini",
         "../installer/windows/nsis/updater_append.ini",
     ]
     # Yes, this is weird, but what can you do? This file doesn't want to be in the DIST_SUBDIR,
     # but we can't really move it to a different directory until we change how locale repacks
     # work.
     LOCALIZED_FILES[".."] += ["!updater.ini"]
 
-LOCALIZED_GENERATED_FILES += ["bookmarks.html"]
-bookmarks = LOCALIZED_GENERATED_FILES["bookmarks.html"]
-bookmarks.script = "generate_bookmarks.py"
-bookmarks.inputs = [
-    # This input will not be considered for localization.
-    "generic/profile/bookmarks.html.in",
-    # The `locales/en-US/` will be rewritten to the locale-specific path.
-    "en-US/profile/bookmarks.inc",
-]
-
 with Files("**"):
     BUG_COMPONENT = ("Firefox Build System", "General")
 
 with Files("all-locales"):
     BUG_COMPONENT = ("Core", "Localization")
 
 with Files("en-US/**"):
     BUG_COMPONENT = ("Core", "Localization")
--- a/toolkit/components/places/BookmarkHTMLUtils.jsm
+++ b/toolkit/components/places/BookmarkHTMLUtils.jsm
@@ -835,16 +835,35 @@ BookmarkImporter.prototype = {
 
   /**
    * Imports data into the places database from the supplied url.
    *
    * @param {String} href The url to import data from.
    */
   async importFromURL(href) {
     let data = await fetchData(href);
+
+    if (this._isImportDefaults && data) {
+      // Localize default bookmarks.  Find rel="localization" links and manually
+      // localize using them.
+      let hrefs = [];
+      let links = data.head.querySelectorAll("link[rel='localization']");
+      for (let link of links) {
+        if (link.getAttribute("href")) {
+          // We need the text, not the fully qualified URL, so we use `getAttribute`.
+          hrefs.push(link.getAttribute("href"));
+        }
+      }
+
+      if (hrefs.length) {
+        let domLoc = new DOMLocalization(hrefs);
+        await domLoc.translateFragment(data.body);
+      }
+    }
+
     this._walkTreeForImport(data);
     await this._importBookmarks();
   },
 };
 
 function BookmarkExporter(aBookmarksTree) {
   // Create a map of the roots.
   let rootsMap = new Map();
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/bookmarks_html_localized.html
@@ -0,0 +1,21 @@
+<!DOCTYPE NETSCAPE-Bookmark-file-1>
+<!-- This is an automatically generated file.
+     It will be read and overwritten.
+     DO NOT EDIT! -->
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
+<TITLE>Bookmarks</TITLE>
+<LINK REL="localization" HREF="bookmarks_html_localized.ftl">
+</HEAD>
+<BODY>
+<H1 LAST_MODIFIED="1177541029">Bookmarks</H1>
+
+<DL><p>
+    <DT><H3 ID="rdf:#$ZvPhC3" data-l10n-id="bookmarks-html-localized-folder">bookmarks-html-localized-folder</H3>
+    <DL><p>
+        <DT><A HREF="http://www.mozilla.com/firefox/help/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" ID="rdf:#$22iCK1" data-l10n-id="bookmarks-html-localized-bookmark">bookmarks-html-localized-bookmark</A>
+    </DL><p>
+</DL><p>
+</BODY>
+</HTML>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_bookmarks_html_localized.js
@@ -0,0 +1,51 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const { BookmarkHTMLUtils } = ChromeUtils.import(
+  "resource://gre/modules/BookmarkHTMLUtils.jsm"
+);
+
+add_task(async function setup_l10n() {
+  // A single localized string.
+  const mockSource = L10nFileSource.createMock(
+    "test",
+    "app",
+    ["en-US"],
+    "/localization/{locale}/",
+    [
+      {
+        path: "/localization/en-US/bookmarks_html_localized.ftl",
+        source: `
+bookmarks-html-localized-folder = Localized Folder
+bookmarks-html-localized-bookmark = Localized Bookmark
+`,
+      },
+    ]
+  );
+
+  L10nRegistry.getInstance().registerSources([mockSource]);
+});
+
+add_task(async function test_bookmarks_html_localized() {
+  let bookmarksFile = OS.Path.join(
+    do_get_cwd().path,
+    "bookmarks_html_localized.html"
+  );
+  await BookmarkHTMLUtils.importFromFile(bookmarksFile, { replace: true });
+
+  let root = PlacesUtils.getFolderContents(PlacesUtils.bookmarks.menuGuid).root;
+  Assert.equal(root.childCount, 1);
+  let folder = root.getChild(0);
+  PlacesUtils.asContainer(folder).containerOpen = true;
+  // Folder title is localized.
+  Assert.equal(folder.title, "Localized Folder");
+  Assert.equal(folder.childCount, 1);
+  let bookmark = folder.getChild(0);
+  Assert.equal(bookmark.uri, "http://www.mozilla.com/firefox/help/");
+  // Bookmark title is localized.
+  Assert.equal(bookmark.title, "Localized Bookmark");
+  folder.containerOpen = false;
+});
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 head = head_bookmarks.js
 firefox-appdir = browser
 support-files =
   bookmarks.corrupt.html
   bookmarks.json
   bookmarks_corrupt.json
   bookmarks.preplaces.html
+  bookmarks_html_localized.html
   bookmarks_html_singleframe.html
   mobile_bookmarks_folder_import.json
   mobile_bookmarks_folder_merge.json
   mobile_bookmarks_multiple_folders.json
   mobile_bookmarks_root_import.json
   mobile_bookmarks_root_merge.json
   places.sparse.sqlite
 
@@ -41,16 +42,17 @@ skip-if = os == "linux" # Bug 821781
 [test_async_transactions.js]
 [test_bookmark-tags-changed_frequency.js]
 [test_bookmarks_json.js]
 [test_bookmarks_json_corrupt.js]
 [test_bookmarks_html.js]
 [test_bookmarks_html_corrupt.js]
 [test_bookmarks_html_escape_entities.js]
 [test_bookmarks_html_import_tags.js]
+[test_bookmarks_html_localized.js]
 [test_bookmarks_html_singleframe.js]
 [test_bookmarks_restore_notification.js]
 [test_broken_folderShortcut_result.js]
 [test_browserhistory.js]
 [test_childlessTags.js]
 [test_frecency_decay.js]
 [test_frecency_zero_updated.js]
 [test_getChildIndex.js]