packages/fxa-content-server/app/scripts/lib/strings.js (44 lines of code) (raw):

/* 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 t = (msg) => msg; const HTML_CHAR_CODE = /&(\D+|#\d+);/i; const HTML_TAG = /<.*>/; const NAMED_VARIABLE = /\%\(([a-zA-Z]+)\)s/g; const UNNAMED_VARIABLE = /%s/g; // safe variables have an `escaped` prefix. const UNSAFE_VARIABLE = /\%\(((?!escaped)[a-zA-Z]+)\)s/g; // temporary strings that can be extracted for the // l10n team to start translations. // Was needed by #2346, but later deemed unnecessary. We'll keep it around since // it's already being translated and may be used in the future. t( 'By proceeding, you agree to the <a id="service-tos" href="%(termsUri)s">Terms of Service</a> and' + '<a id="service-pp" href="%(privacyUri)s">Privacy Notice</a> of %(serviceName)s (%(serviceUri)s).' ); // Allow translators to include "help" links in additional contexts. // Including the string here means translators are free to use it // without triggering errors from our l10n linting procedure. // See e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=1131472 // for why this could be necessary. t( '<a href="https://support.mozilla.org/kb/im-having-problems-my-firefox-account">Help</a>' ); // We're temporarily changing the string for marketing optin, see #3792. // This keeps the old string around for if/when we need to change it back. t('Get the latest news about Mozilla and Firefox.'); // We are adding this in the auth-mailer for displaying location data t('%(city)s, %(country)s (estimated)'); t('%(country)s (estimated)'); t('IP address: %(ip)s'); t( 'For added security, please confirm this sign-in to begin syncing with this device:' ); // For #3128, PR #4916 - We added a 'msgctxt' comment to these buttons // to allow the l10n team differentiate between headers and buttons. This // string is kept and used as a fallback for locales that have it // translated but have not yet translated the contextualized variant. t('Sign in'); /** * Replace instances of %s and %(name)s with their corresponding values in * the context * @method interpolate * @param {String} string * @param {Object|Array} [context] - defaults to [] * @returns {String} */ function interpolate(string, context = []) { return string .replace(UNNAMED_VARIABLE, (match) => { // boot out non arrays and arrays with not enough items. if (!(context.shift && context.length > 0)) { return match; } return context.shift(); }) .replace(NAMED_VARIABLE, (match, name) => { return name in context ? context[name] : match; }); } /** * Check whether the string contains HTML. Very very loose interpretation of * what HTML means. If it contains an HTML character code-like thing, it's * considered HTML. If it contains <> with *anything* in the middle, it's * considered HTML. * * @param {String} string * @returns {Boolean} true if string has HTML, false otw. */ function hasHTML(string) { return HTML_CHAR_CODE.test(string) || HTML_TAG.test(string); } /** * Check whether all interpolation variables have an `escaped` prefix. * This is a gentle reminder to developers that they must properly escape * variables because the string is written to the DOM w/o HTML escaping. * * @param {String} string * @returns {Boolean} true if has unsafe variables, false otw. */ function hasUnsafeVariables(string) { return UNNAMED_VARIABLE.test(string) || UNSAFE_VARIABLE.test(string); } export default { hasHTML, hasUnsafeVariables, interpolate, };