UNPKG

react-intl

Version:

Internationalize React apps. This library provides React components and an API to format dates, numbers, and strings, including pluralization and handling translations.

98 lines (97 loc) 4.51 kB
/* * Copyright 2015, Yahoo Inc. * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ // Since rollup cannot deal with namespace being a function, // this is to interop with TypeScript since `invariant` // does not export a default // https://github.com/rollup/rollup/issues/1267 import * as invariant_ from 'invariant'; const invariant = invariant_.default || invariant_; import { createError, escape } from '../utils'; import IntlMessageFormat from 'intl-messageformat'; function setTimeZoneInOptions(opts, timeZone) { return Object.keys(opts).reduce((all, k) => { all[k] = Object.assign({ timeZone }, opts[k]); return all; }, {}); } function deepMergeOptions(opts1, opts2) { const keys = Object.keys(Object.assign({}, opts1, opts2)); return keys.reduce((all, k) => { all[k] = Object.assign({}, (opts1[k] || {}), (opts2[k] || {})); return all; }, {}); } function deepMergeFormatsAndSetTimeZone(f1, timeZone) { if (!timeZone) { return f1; } const mfFormats = IntlMessageFormat.formats; return Object.assign({}, mfFormats, f1, { date: deepMergeOptions(setTimeZoneInOptions(mfFormats.date, timeZone), setTimeZoneInOptions(f1.date || {}, timeZone)), time: deepMergeOptions(setTimeZoneInOptions(mfFormats.time, timeZone), setTimeZoneInOptions(f1.time || {}, timeZone)) }); } export function formatMessage({ locale, formats, messages, defaultLocale, defaultFormats, onError, timeZone, }, state, messageDescriptor = { id: '' }, values = {}) { const { id, defaultMessage } = messageDescriptor; // `id` is a required field of a Message Descriptor. invariant(id, '[React Intl] An `id` must be provided to format a message.'); const message = messages && messages[id]; formats = deepMergeFormatsAndSetTimeZone(formats, timeZone); defaultFormats = deepMergeFormatsAndSetTimeZone(defaultFormats, timeZone); let formattedMessageParts = []; if (message) { try { let formatter = state.getMessageFormat(message, locale, formats, { formatters: state, }); formattedMessageParts = formatter.formatHTMLMessage(values); } catch (e) { onError(createError(`Error formatting message: "${id}" for locale: "${locale}"` + (defaultMessage ? ', using default message as fallback.' : ''), e)); } } else { // This prevents warnings from littering the console in development // when no `messages` are passed into the <IntlProvider> for the // default locale, and a default message is in the source. if (!defaultMessage || (locale && locale.toLowerCase() !== defaultLocale.toLowerCase())) { onError(createError(`Missing message: "${id}" for locale: "${locale}"` + (defaultMessage ? ', using default message as fallback.' : ''))); } } if (!formattedMessageParts.length && defaultMessage) { try { let formatter = state.getMessageFormat(defaultMessage, defaultLocale, defaultFormats); formattedMessageParts = formatter.formatHTMLMessage(values); } catch (e) { onError(createError(`Error formatting the default message for: "${id}"`, e)); } } if (!formattedMessageParts.length) { onError(createError(`Cannot format message: "${id}", ` + `using message ${message || defaultMessage ? 'source' : 'id'} as fallback.`)); if (typeof message === 'string') { return message || defaultMessage || id; } return defaultMessage || id; } if (formattedMessageParts.length === 1 && typeof formattedMessageParts[0] === 'string') { return formattedMessageParts[0] || defaultMessage || id; } return formattedMessageParts; } export function formatHTMLMessage(config, state, messageDescriptor = { id: '' }, rawValues = {}) { // Process all the values before they are used when formatting the ICU // Message string. Since the formatted message might be injected via // `innerHTML`, all String-based values need to be HTML-escaped. let escapedValues = Object.keys(rawValues).reduce((escaped, name) => { let value = rawValues[name]; escaped[name] = typeof value === 'string' ? escape(value) : value; return escaped; }, {}); return formatMessage(config, state, messageDescriptor, escapedValues); }