From f100d753cf6e9fcffe10e5ba0f8144275d6a93c8 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Sat, 21 Sep 2019 13:31:45 -0300 Subject: [PATCH] Report missing `en` locale messages to Sentry (#7197) Any missing messages in the `en` locale are now reported to Sentry as errors. They are printed to the console as an error upon the first encounter as well. If a missing message is found during e2e testing, the error is thrown. This will likely break the e2e test even if it isn't looking for console errors, as the UI with the missing message will fail to render. The `tOrDefault` method was updated to no longer attempt looking for messages with a key that is a falsey value (e.g. `undefined`). There are a few places where they key is determined dynamically, where it's expected during the normal flow for it to be `undefined` sometimes. In these cases we don't want the error to be thrown. --- .../higher-order-components/i18n-provider.js | 13 +++++------ ui/app/helpers/utils/i18n-helper.js | 22 +++++++++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ui/app/helpers/higher-order-components/i18n-provider.js b/ui/app/helpers/higher-order-components/i18n-provider.js index 1360cf5fd..d530c3425 100644 --- a/ui/app/helpers/higher-order-components/i18n-provider.js +++ b/ui/app/helpers/higher-order-components/i18n-provider.js @@ -3,12 +3,15 @@ const connect = require('react-redux').connect const PropTypes = require('prop-types') const { withRouter } = require('react-router-dom') const { compose } = require('recompose') -const t = require('../utils/i18n-helper').getMessage +const { getMessage } = require('../utils/i18n-helper') class I18nProvider extends Component { tOrDefault = (key, defaultValue, ...args) => { + if (!key) { + return defaultValue + } const { localeMessages: { current, en } = {}, currentLocale } = this.props - return t(currentLocale, current, key, ...args) || t(currentLocale, en, key, ...args) || defaultValue + return getMessage(currentLocale, current, key, ...args) || getMessage(currentLocale, en, key, ...args) || defaultValue } getChildContext () { @@ -22,11 +25,7 @@ class I18nProvider extends Component { * @return {string|undefined|null} The localized message if available */ t (key, ...args) { - if (key === undefined || key === null) { - return key - } - - return t(currentLocale, current, key, ...args) || t(currentLocale, en, key, ...args) || `[${key}]` + return getMessage(currentLocale, current, key, ...args) || getMessage(currentLocale, en, key, ...args) || `[${key}]` }, tOrDefault: this.tOrDefault, tOrKey: (key, ...args) => { diff --git a/ui/app/helpers/utils/i18n-helper.js b/ui/app/helpers/utils/i18n-helper.js index b9720acc7..cd3f1527d 100644 --- a/ui/app/helpers/utils/i18n-helper.js +++ b/ui/app/helpers/utils/i18n-helper.js @@ -1,7 +1,10 @@ // cross-browser connection to extension i18n API const log = require('loglevel') +const Sentry = require('@sentry/browser') const warned = {} +const missingMessageErrors = {} + /** * Returns a localized message for the given key * @param {string} localeCode The code for the current locale @@ -10,12 +13,21 @@ const warned = {} * @param {string[]} substitutions A list of message substitution replacements * @return {null|string} The localized message */ -const getMessage = (localeCode, localeMessages, key, substitutions) => { +export const getMessage = (localeCode, localeMessages, key, substitutions) => { if (!localeMessages) { return null } if (!localeMessages[key]) { - if (!warned[localeCode] || !warned[localeCode][key]) { + if (localeCode === 'en') { + if (!missingMessageErrors[key]) { + missingMessageErrors[key] = new Error(`Unable to find value of key "${key}" for locale "${localeCode}"`) + Sentry.captureException(missingMessageErrors[key]) + log.error(missingMessageErrors[key]) + if (process.env.IN_TEST === 'true') { + throw missingMessageErrors[key] + } + } + } else if (!warned[localeCode] || !warned[localeCode][key]) { if (!warned[localeCode]) { warned[localeCode] = {} } @@ -36,7 +48,7 @@ const getMessage = (localeCode, localeMessages, key, substitutions) => { return phrase } -async function fetchLocale (localeCode) { +export async function fetchLocale (localeCode) { try { const response = await fetch(`./_locales/${localeCode}/messages.json`) return await response.json() @@ -46,7 +58,3 @@ async function fetchLocale (localeCode) { } } -module.exports = { - getMessage, - fetchLocale, -}