From 1844afe49f853f3c1d8e05ba0bdc84cd598c22d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sta=C5=9B=20Ma=C5=82olepszy?= Date: Wed, 26 Sep 2018 09:22:08 +0200 Subject: [PATCH] Upgrade to fluent 0.8.0, fluent-react 0.8.1 (#4935) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Upgrade to fluent 0.8.0, fluent-react 0.8.1 * Add the attrs prop to Localized where needed Starting with fluent-react 0.6.0, requires the attrs prop to be passed in order to set any localized attributes as props on the wrapped component. attrs should be an object with attribute names as keys and booleans as values. For instance: * Use a server-side markup parser * Use Localized overlay for TimeDiffs can take other React elements as props. If an element of the same name is then found in the translation, the element passed as prop is inserted into the translation (keeping its props) and its children are set to the text content of the element found in the translation. * Use Localized overlay in AdBanner --- locales/en-US/server.ftl | 18 +- package-lock.json | 495 ++++++++++++++++--- package.json | 5 +- server/src/ad-banner.js | 18 +- server/src/delete-shot-button.js | 6 +- server/src/header.js | 2 +- server/src/l10n.js | 26 +- server/src/pages/homepage/homepage-header.js | 2 +- server/src/pages/homepage/view.js | 6 +- server/src/pages/leave-screenshots/view.js | 4 +- server/src/pages/not-found/view.js | 2 +- server/src/pages/settings/view.js | 6 +- server/src/pages/shot/color-picker.js | 18 +- server/src/pages/shot/crop-tool.js | 4 +- server/src/pages/shot/editor.js | 18 +- server/src/pages/shot/footer.js | 2 +- server/src/pages/shot/promo-dialog.js | 2 +- server/src/pages/shot/shotpage-header.js | 8 +- server/src/pages/shot/text-tool.js | 8 +- server/src/pages/shot/view.js | 14 +- server/src/pages/shotindex/view.js | 22 +- server/src/reactrender.js | 14 + server/src/reactruntime.js | 24 +- server/src/share-buttons.js | 10 +- server/src/signin-button.js | 4 +- 25 files changed, 554 insertions(+), 184 deletions(-) diff --git a/locales/en-US/server.ftl b/locales/en-US/server.ftl index 37a0bd5a82..154079ccb7 100644 --- a/locales/en-US/server.ftl +++ b/locales/en-US/server.ftl @@ -18,6 +18,7 @@ buttonSignIn = screenshotsLogo = .title = Screenshots Home bannerMessage = Sign in or sign up to access your shots across devices and save your favorites forever. +bannerUpsell = {gScreenshotsDescription} Get Firefox now ## Footer @@ -98,6 +99,8 @@ shotPageConfirmDelete = Are you sure you want to delete this shot permanently? shotPageShareButton = .title = Share shotPageCopy = Copy +shotPageCopyButton = + .title = Copy image to clipboard shotPageCopied = Copied shotPageShareFacebook = .title = Share on Facebook @@ -112,8 +115,8 @@ shotPagePrivacyMessage = Anyone with the link can view this shot. shotPageCopyImageText = .label = Copy image text shotPageConfirmDeletion = Are you sure you want to delete this shot permanently? -# Note: { $timediff } is a placeholder for a future relative time clause like 'in 3 days' or 'tomorrow' -shotPageExpirationMessage = If you do nothing, this shot will be permanently deleted { $timediff }. +# Note: is a placeholder for a future relative time clause like 'in 3 days' or 'tomorrow' +shotPageTimeExpirationMessage = If you do nothing, this shot will be permanently deleted . # Note: { $date } is a placeholder for a localized future date as returned by Date.toLocaleString. # For example, in en-US, { $date } could be "7/12/2017, 1:52:50 PM". shotPageRestoreButton = restore until { $date } @@ -140,7 +143,6 @@ shotPageDraw = Draw shotPageFavorite = Favorite shotPageDelete = Delete shotPageScreenshotsDescription = Screenshots made simple. Take, save, and share screenshots without leaving Firefox. -shotPageUpsellFirefox = Get Firefox now shotPageDMCAMessage = This shot is no longer available due to a third party intellectual property claim. # Note: { $dmca } is a placeholder for a link to send email (a 'mailto' link) shotPageDMCAContact = Please email { $dmca } to request further information. @@ -164,10 +166,10 @@ shotPageKeepOneMonth = 1 Month shotPageSaveExpiration = save shotPageCancelExpiration = cancel shotPageDoesNotExpire = does not expire -# Note: { $timediff } is a placeholder for a future relative time clause, like "in 1 week" or "tomorrow" -shotPageExpiresIn = expires { $timediff } -# Note: { $timediff } is a placeholder for a past relative time clause, like "1 week ago" or "yesterday" -shotPageExpired = expired { $timediff } +# Note: is a placeholder for a future relative time clause, like "in 1 week" or "tomorrow" +shotPageTimeExpiresIn = expires +# Note: is a placeholder for a past relative time clause, like "1 week ago" or "yesterday" +shotPageTimeExpired = expired timeDiffJustNow = just now timeDiffMinutesAgo = { $number -> [one] 1 minute ago @@ -298,8 +300,6 @@ shotIndexPageSearchResultsTitle = My Shots: search for { $searchTerm } shotIndexPageErrorRendering = Error rendering page: { $error } shotIndexPageSearchPlaceholder = .placeholder = Search my shots -shotIndexPageSearchButton = - .title = Search shotIndexPageNoShotsMessage = No saved shots. shotIndexPageNoShotsInvitation = Go on, create some. shotIndexPageLookingForShots = Looking for your shots… diff --git a/package-lock.json b/package-lock.json index 0dd239a281..afea8170b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,6 +62,11 @@ "through": ">=2.2.7 <3" } }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==" + }, "abbrev": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", @@ -97,6 +102,22 @@ "integrity": "sha1-9HPdR+AnegjijpvsWu6wR1HwuMk=", "dev": true }, + "acorn-globals": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", + "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.1.tgz", + "integrity": "sha512-SiwgrRuRD2D1R6qjwwoopKcCTkmmIWjy1M15Wv+Nk/7VUsBad4P8GOPft2t6coDZG0TuR5dq9o1v0g8wo7F6+A==" + } + } + }, "acorn-jsx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", @@ -124,6 +145,11 @@ "xtend": "^4.0.1" } }, + "acorn-walk": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.0.1.tgz", + "integrity": "sha512-PqVQ8c6a3kyqdsUZlC7nljp3FFuxipBRHKu+7C1h8QygBFlzTaDX5HD383jej3Peed+1aDG8HwkfB1Z1HMNPkw==" + }, "adbkit": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/adbkit/-/adbkit-2.11.0.tgz", @@ -573,7 +599,6 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -815,6 +840,11 @@ "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", "dev": true }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" + }, "array-filter": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", @@ -964,6 +994,11 @@ "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", "dev": true }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2117,6 +2152,11 @@ "umd": "^3.0.0" } }, + "browser-process-hrtime": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz", + "integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44=" + }, "browser-resolve": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", @@ -2455,6 +2495,11 @@ } } }, + "cached-iterable": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cached-iterable/-/cached-iterable-0.2.1.tgz", + "integrity": "sha1-cjlY9eetx0yWvtsQtCa9/ZXy/m0=" + }, "cached-path-relative": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", @@ -3277,6 +3322,19 @@ } } }, + "cssom": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", + "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==" + }, + "cssstyle": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.1.1.tgz", + "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==", + "requires": { + "cssom": "0.3.x" + } + }, "csurf": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.9.0.tgz", @@ -3327,6 +3385,16 @@ "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", "dev": true }, + "data-urls": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.1.tgz", + "integrity": "sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg==", + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^7.0.0" + } + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -3424,8 +3492,7 @@ "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "deepcopy": { "version": "0.6.3", @@ -3895,6 +3962,14 @@ "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", "dev": true }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "requires": { + "webidl-conversions": "^4.0.2" + } + }, "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", @@ -4726,8 +4801,7 @@ "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" }, "esquery": { "version": "1.0.1", @@ -4750,14 +4824,12 @@ "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "etag": { "version": "1.8.1", @@ -5100,8 +5172,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "fast-redact": { "version": "1.2.0", @@ -5362,9 +5433,9 @@ "dev": true }, "fluent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/fluent/-/fluent-0.4.3.tgz", - "integrity": "sha1-qcVZlMlvrs290FaY4HyPLAbnLfI=" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/fluent/-/fluent-0.8.0.tgz", + "integrity": "sha1-KgkJ5ZEDE1gfXA0QjtIWPZ4IARE=" }, "fluent-intl-polyfill": { "version": "0.1.0", @@ -5386,14 +5457,31 @@ "integrity": "sha512-SzRtXNaIcCyRabIpcv+AQd0gn+tXv1wfDDvej3wtBo1/XV0iDnCw5XzbARRRmZMW+IEg+Q26jup6vYgnDam4dg==" }, "fluent-react": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/fluent-react/-/fluent-react-0.4.1.tgz", - "integrity": "sha512-5cPA0xyuqQ9JTGmrSyknnXLABBgKdK4L1WFyUUCWa9NBhu97V/fa1jp46qx5s0Bi7wSwZySRvWi/yJRES97rwQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/fluent-react/-/fluent-react-0.8.1.tgz", + "integrity": "sha1-N/aYvifnFg+2Ti3JNCi2ds9fy1U=", "requires": { - "fluent": "^0.4.1", - "prop-types": "^15.5.0" + "cached-iterable": "^0.2.1", + "fluent-sequence": "^0.2.0", + "prop-types": "^15.6.0" + }, + "dependencies": { + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha1-BdXKd7RFPphdYPx/+MhZCUpJcQI=", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + } } }, + "fluent-sequence": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/fluent-sequence/-/fluent-sequence-0.2.0.tgz", + "integrity": "sha1-81HZPgGUGC3mDG1d+9s8lncoE/g=" + }, "fluent-syntax": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/fluent-syntax/-/fluent-syntax-0.7.0.tgz", @@ -5526,8 +5614,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -5545,13 +5632,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5564,18 +5649,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -5678,8 +5760,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -5689,7 +5770,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5702,20 +5782,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.2.4", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5732,7 +5809,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5805,8 +5881,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -5816,7 +5891,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5892,8 +5966,7 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -5923,7 +5996,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5941,7 +6013,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5980,13 +6051,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.2", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -6298,7 +6367,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, - "optional": true, "requires": { "is-glob": "^2.0.0" } @@ -6744,6 +6812,14 @@ "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", "dev": true }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, "htmlescape": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", @@ -7269,8 +7345,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-finite": { "version": "1.0.2", @@ -7295,7 +7370,6 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -8019,6 +8093,213 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "jsdom": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-12.0.0.tgz", + "integrity": "sha512-42RgZYXWwyClG0pN6Au7TExAQqRvzbtJhlcIvu58cJj4yr1bIbqZkgxHqn1btxKu80axZXPZLvldeTzg2auKow==", + "requires": { + "abab": "^2.0.0", + "acorn": "^5.7.1", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.1", + "domexception": "^1.0.1", + "escodegen": "^1.11.0", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.0.8", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.4.3", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.4", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^7.0.0", + "ws": "^6.0.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "escodegen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "har-validator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + } + } + }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", @@ -8284,7 +8565,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -8455,15 +8735,13 @@ "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true, - "optional": true + "dev": true }, "loose-envify": { "version": "1.3.1", @@ -12337,6 +12615,11 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "nwsapi": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz", + "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==" + }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -12507,7 +12790,6 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -13117,6 +13399,11 @@ "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", "dev": true }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" + }, "po2json": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz", @@ -13218,8 +13505,7 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "prepend-http": { "version": "1.0.4", @@ -13380,8 +13666,7 @@ "psl": { "version": "1.1.29", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", - "dev": true + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" }, "pstree.remy": { "version": "1.1.0", @@ -14150,6 +14435,24 @@ } } }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "requires": { + "lodash": "^4.13.1" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16024,6 +16327,11 @@ } } }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "stream-browserify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", @@ -16495,6 +16803,11 @@ "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", "dev": true }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=" + }, "syntax-error": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", @@ -16918,7 +17231,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, "requires": { "punycode": "^2.1.0" }, @@ -16926,8 +17238,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -16998,7 +17309,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -17473,6 +17783,14 @@ "integrity": "sha1-oV13YsTEj6a/nzMJohNA8A7SMGM=", "dev": true }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, "watchpack": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.5.0.tgz", @@ -19197,19 +19515,40 @@ "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-encoding": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz", + "integrity": "sha512-vM9KWN6MP2mIHZ86ytcyIv7e8Cj3KTfO2nd2c8PFDqcI4bxFmQp83ibq4wadq7rL9l9sZV6o9B0LTt8ygGAAXg==", + "requires": { + "iconv-lite": "0.4.23" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } }, "whatwg-fetch": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" }, + "whatwg-mimetype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz", + "integrity": "sha512-5YSO1nMd5D1hY3WzAQV3PzZL83W3YeyR1yW9PcH26Weh1t+Vzh9B6XkDh7aXm83HBZ4nSMvkjvN2H2ySWIvBgw==" + }, "whatwg-url": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", - "dev": true, "requires": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", @@ -19277,8 +19616,7 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, "wrap-ansi": { "version": "2.1.0", @@ -19327,11 +19665,24 @@ "signal-exit": "^3.0.2" } }, + "ws": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz", + "integrity": "sha512-c2UlYcAZp1VS8AORtpq6y4RJIkJ9dQz18W32SpR/qXGfLDZ2jU4y4wKvvZwqbi7U6gxFQTeE+urMbXU/tsDy4w==", + "requires": { + "async-limiter": "~1.0.0" + } + }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, "xml2js": { "version": "0.4.17", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", diff --git a/package.json b/package.json index 304e35aa21..54ca5ba294 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,14 @@ "envc": "2.5.0", "escape-html": "1.0.3", "express": "4.16.3", - "fluent": "0.4.3", + "fluent": "0.8.0", "fluent-intl-polyfill": "0.1.0", "fluent-langneg": "0.1.0", - "fluent-react": "0.4.1", + "fluent-react": "0.8.1", "form-data": "2.3.2", "hawk": "7.0.7", "jpm": "1.3.1", + "jsdom": "12.0.0", "keygrip": "1.0.3", "mobile-detect": "1.4.3", "morgan": "1.9.1", diff --git a/server/src/ad-banner.js b/server/src/ad-banner.js index c2fd728009..8248b16875 100644 --- a/server/src/ad-banner.js +++ b/server/src/ad-banner.js @@ -16,16 +16,14 @@ exports.AdBanner = class AdBanner extends React.Component { let bannerContent = null; if (this.props.shouldGetFirefox) { - bannerContent = [ - -

Screenshots made simple. Take, save and share screenshots without leaving Firefox.

-
, - - Get Firefox now - , - ]; + const upsellLink = Get Firefox now; + bannerContent = +

+ Screenshots made simple. Take, save and share screenshots without leaving Firefox. {upsellLink} +

+
; } else if (this.props.isOwner && !this.props.hasFxa) { bannerContent =

diff --git a/server/src/delete-shot-button.js b/server/src/delete-shot-button.js index 30f0235e6c..32a98c20c8 100644 --- a/server/src/delete-shot-button.js +++ b/server/src/delete-shot-button.js @@ -64,10 +64,10 @@ exports.DeleteShotButton = class DeleteShotButton extends React.Component {

Are you sure you want to delete this shot?
- + - +
@@ -88,7 +88,7 @@ exports.DeleteShotButton = class DeleteShotButton extends React.Component { return (
- +
: null; diff --git a/server/src/l10n.js b/server/src/l10n.js index ed448ba007..e6bd0fb496 100644 --- a/server/src/l10n.js +++ b/server/src/l10n.js @@ -2,11 +2,11 @@ const path = require("path"); const globby = require("globby"); require("fluent-intl-polyfill/compat"); const { negotiateLanguages } = require("fluent-langneg/compat"); -const { MessageContext } = require("fluent/compat"); +const { FluentBundle } = require("fluent/compat"); const mozlog = require("./logging").mozlog("l10n"); const rawStrings = {}; -const messagesContexts = {}; +const fluentBundles = {}; let initPromise; exports.init = function(localeStringMap) { @@ -47,18 +47,18 @@ exports.init = function(localeStringMap) { }; exports.getText = function(locales) { - const contexts = {}; + const bundles = {}; const availableLocales = exports.getUserLocales(locales); availableLocales.forEach((locale) => { - contexts[locale] = getMessageContext(locale); + bundles[locale] = getFluentBundle(locale); }); return function(l10nID, args) { for (const locale of availableLocales) { - if (contexts[locale].hasMessage(l10nID)) { - const msg = contexts[locale].getMessage(l10nID); - return contexts[locale].format(msg, args); + if (bundles[locale].hasMessage(l10nID)) { + const msg = bundles[locale].getMessage(l10nID); + return bundles[locale].format(msg, args); } } return ""; @@ -92,12 +92,12 @@ function useLocaleData(localeStringMap) { return initPromise; } -function getMessageContext(locale) { - if (!messagesContexts[locale]) { - const mc = new MessageContext(locale); - mc.addMessages(rawStrings[locale]); - messagesContexts[locale] = mc; +function getFluentBundle(locale) { + if (!fluentBundles[locale]) { + const bundle = new FluentBundle(locale); + bundle.addMessages(rawStrings[locale]); + fluentBundles[locale] = bundle; } - return messagesContexts[locale]; + return fluentBundles[locale]; } diff --git a/server/src/pages/homepage/homepage-header.js b/server/src/pages/homepage/homepage-header.js index 16abc0c9d1..419623363f 100644 --- a/server/src/pages/homepage/homepage-header.js +++ b/server/src/pages/homepage/homepage-header.js @@ -24,7 +24,7 @@ exports.HomePageHeader = class HomePageHeader extends React.Component { render() { let myShots; if (this.props.isOwner) { - myShots = + myShots = My Shots diff --git a/server/src/pages/homepage/view.js b/server/src/pages/homepage/view.js index 1416890133..eb9af3ebad 100644 --- a/server/src/pages/homepage/view.js +++ b/server/src/pages/homepage/view.js @@ -19,16 +19,16 @@ class Head extends React.Component { - + - + - + diff --git a/server/src/pages/leave-screenshots/view.js b/server/src/pages/leave-screenshots/view.js index a603e542d3..7c529131e5 100644 --- a/server/src/pages/leave-screenshots/view.js +++ b/server/src/pages/leave-screenshots/view.js @@ -30,7 +30,7 @@ class Body extends React.Component { return (
- + no Shots found
@@ -58,7 +58,7 @@ class Body extends React.Component { return (
- + no Shots found
diff --git a/server/src/pages/not-found/view.js b/server/src/pages/not-found/view.js index b612cf0dde..e5f075eaf4 100644 --- a/server/src/pages/not-found/view.js +++ b/server/src/pages/not-found/view.js @@ -32,7 +32,7 @@ class Body extends React.Component {
- + no Shots found diff --git a/server/src/pages/settings/view.js b/server/src/pages/settings/view.js index e0108ddf8d..2ccbc682de 100644 --- a/server/src/pages/settings/view.js +++ b/server/src/pages/settings/view.js @@ -28,7 +28,7 @@ class Body extends React.Component { diff --git a/server/src/pages/shot/color-picker.js b/server/src/pages/shot/color-picker.js index 068df7ec91..53f8a2f9e6 100644 --- a/server/src/pages/shot/color-picker.js +++ b/server/src/pages/shot/color-picker.js @@ -71,35 +71,35 @@ exports.ColorPicker = class ColorPicker extends React.Component {
-
-
-
-
-
-
-
-
-
diff --git a/server/src/pages/shot/crop-tool.js b/server/src/pages/shot/crop-tool.js index a9584f4b01..8ad99a119b 100644 --- a/server/src/pages/shot/crop-tool.js +++ b/server/src/pages/shot/crop-tool.js @@ -124,10 +124,10 @@ exports.CropTool = class CropTool extends React.Component { renderToolbar() { return
- + - +
; diff --git a/server/src/pages/shot/editor.js b/server/src/pages/shot/editor.js index dfad1160ff..f2367f491b 100644 --- a/server/src/pages/shot/editor.js +++ b/server/src/pages/shot/editor.js @@ -186,42 +186,42 @@ exports.Editor = class Editor extends React.Component { return
- + - + - + - + - + - + - +
- + - +
diff --git a/server/src/pages/shot/footer.js b/server/src/pages/shot/footer.js index a2083f06f5..e4e6e65a66 100644 --- a/server/src/pages/shot/footer.js +++ b/server/src/pages/shot/footer.js @@ -13,7 +13,7 @@ exports.ShotFooter = class ShotFooter extends Footer { const dmcaIdx = this.links.findIndex(link => link.key === "dmca"); if (dmcaIdx !== -1) { this.links.splice(dmcaIdx, 0, -
  • +
  • - + diff --git a/server/src/pages/shot/shotpage-header.js b/server/src/pages/shot/shotpage-header.js index b1736659bb..6a03639740 100644 --- a/server/src/pages/shot/shotpage-header.js +++ b/server/src/pages/shot/shotpage-header.js @@ -16,7 +16,7 @@ exports.ShotPageHeader = class ShotPageHeader extends React.Component { // FIXME: this means that on someone else's shot they won't see a My Shots link: if (!this.props.isOwner) { return ( - + @@ -31,7 +31,7 @@ exports.ShotPageHeader = class ShotPageHeader extends React.Component { ); } return ( - + All Shots @@ -60,9 +60,9 @@ exports.ShotPageHeader = class ShotPageHeader extends React.Component { const expired = this.props.expireTime < Date.now(); const expireTimeDiff = ; if (expired) { - expirationSubtitle = expired {expireTimeDiff}; + expirationSubtitle = expired {expireTimeDiff}; } else { - expirationSubtitle = expires {expireTimeDiff}; + expirationSubtitle = expires {expireTimeDiff}; } } diff --git a/server/src/pages/shot/text-tool.js b/server/src/pages/shot/text-tool.js index bfa9d60637..16e07dbe63 100644 --- a/server/src/pages/shot/text-tool.js +++ b/server/src/pages/shot/text-tool.js @@ -116,7 +116,7 @@ exports.TextTool = class TextTool extends React.Component { return [
    - + @@ -128,7 +128,7 @@ exports.TextTool = class TextTool extends React.Component { renderToolbar() { return
    - + this.searchInput = searchInput} maxLength="100" placeholder="search my shots" defaultValue={this.state.defaultSearch} onChange={this.onChangeSearch.bind(this)} /> - +
    @@ -316,19 +316,19 @@ class Card extends React.Component { let favoriteIndicator = null; if (!shot.expireTime) { - favoriteIndicator = + favoriteIndicator =
    ; } else if (this.props.hasFxa) { - favoriteIndicator = + favoriteIndicator =
    ; } let syncedShotIndicator = null; if (shot.isSynced) { - syncedShotIndicator = + syncedShotIndicator =
    ; } @@ -360,7 +360,7 @@ class Card extends React.Component {
    - + this.downloadButton = downloadButton} /> diff --git a/server/src/reactrender.js b/server/src/reactrender.js index 77d9c82935..ff0d760996 100644 --- a/server/src/reactrender.js +++ b/server/src/reactrender.js @@ -2,6 +2,18 @@ const { addReactScripts } = require("./reactutils"); const ReactDOMServer = require("react-dom/server"); const { getGitRevision } = require("./linker"); +const { JSDOM } = require("jsdom"); +const dom = new JSDOM(""); +const template = dom.window.document.querySelector("template"); + +// Used by the LocalizationProvider to sanitize markup in translations on the +// server side. During runtime it uses document.createElement("template"). +function parseMarkup(textContent) { + // eslint-disable-next-line no-unsanitized/property + template.innerHTML = textContent; + return Array.from(template.content.childNodes); +} + exports.render = function(req, res, page) { const modelModule = require("./" + page.modelModuleName); const viewModule = page.viewModule; @@ -22,6 +34,7 @@ exports.render = function(req, res, page) { csrfToken, abTests: req.abTests, userLocales: req.userLocales, + parseMarkup, }, jsonModel); serverModel = Object.assign({ authenticated: !!req.deviceId, @@ -33,6 +46,7 @@ exports.render = function(req, res, page) { abTests: req.abTests, userLocales: req.userLocales, messages: req.messages, + parseMarkup, }, serverModel); if (req.query.data === "json") { if (req.query.pretty !== undefined) { diff --git a/server/src/reactruntime.js b/server/src/reactruntime.js index d1a5dc43b9..976a069eed 100644 --- a/server/src/reactruntime.js +++ b/server/src/reactruntime.js @@ -5,18 +5,18 @@ const ReactDOM = require("react-dom"); const PropTypes = require("prop-types"); const linker = require("./linker"); require("fluent-intl-polyfill/compat"); -const { MessageContext } = require("fluent/compat"); +const { FluentBundle } = require("fluent/compat"); const { LocalizationProvider } = require("fluent-react/compat"); const { getLocaleMessages } = require("./locale-messages"); -function generateMessages(messages, locales) { - const contexts = []; +function generateBundles(messages, locales) { + const bundles = []; for (const locale of locales) { - const cx = new MessageContext(locale); - cx.addMessages(messages[locale]); - contexts.push(cx); + const bundle = new FluentBundle(locale); + bundle.addMessages(messages[locale]); + bundles.push(bundle); } - return contexts; + return bundles; } exports.HeadTemplate = class HeadTemplate extends React.Component { @@ -40,7 +40,9 @@ exports.HeadTemplate = class HeadTemplate extends React.Component { const wantsAuth = (!this.props.authenticated) || (this.props.authenticated && !this.props.hasFxa && this.props.authFxa); return ( - + {this.props.title} @@ -71,13 +73,16 @@ exports.HeadTemplate.propTypes = { authenticated: PropTypes.bool, hasFxa: PropTypes.bool, authFxa: PropTypes.bool, + parseMarkup: PropTypes.func, }; exports.BodyTemplate = class Body extends React.Component { render() { return ( - +
    {this.props.children}
    @@ -91,6 +96,7 @@ exports.BodyTemplate.propTypes = { children: PropTypes.node, messages: PropTypes.object, userLocales: PropTypes.array, + parseMarkup: PropTypes.func, }; exports.Page = class Page { diff --git a/server/src/share-buttons.js b/server/src/share-buttons.js index aeb9303214..cac6cd5a53 100644 --- a/server/src/share-buttons.js +++ b/server/src/share-buttons.js @@ -30,7 +30,7 @@ exports.ShareButton = class ShareButton extends React.Component { "newicon": useNewIcon, }); return
    - +