From 432cf1b5626c0189f087a46455ec6227c78519f5 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Fri, 30 Nov 2018 14:19:08 +0100 Subject: [PATCH] [6.x] Skip React Intl placeholder during pseudo localization. (#26465) --- packages/kbn-i18n/src/react/provider.tsx | 25 +++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/kbn-i18n/src/react/provider.tsx b/packages/kbn-i18n/src/react/provider.tsx index f359b10a5662..da75ddbffc3a 100644 --- a/packages/kbn-i18n/src/react/provider.tsx +++ b/packages/kbn-i18n/src/react/provider.tsx @@ -25,6 +25,28 @@ import * as i18n from '../core'; import { isPseudoLocale, translateUsingPseudoLocale } from '../core/pseudo_locale'; import { injectI18n } from './inject'; +/** + * To translate label that includes nested `FormattedMessage` instances React Intl + * replaces them with special placeholders (@__uid__@ELEMENT-uid-counter@__uid__@) + * and maps them back with nested translations after `formatMessage` processes + * original string, so we shouldn't modify these special placeholders with pseudo + * translations otherwise React Intl won't be able to properly replace placeholders. + * It's implementation detail of the React Intl, but since pseudo localization is dev + * only feature we should be fine here. + * @param message + */ +function translateFormattedMessageUsingPseudoLocale(message: string) { + const formattedMessageDelimiter = message.match(/@__.{10}__@/); + if (formattedMessageDelimiter !== null) { + return message + .split(formattedMessageDelimiter[0]) + .map(part => (part.startsWith('ELEMENT-') ? part : translateUsingPseudoLocale(part))) + .join(formattedMessageDelimiter[0]); + } + + return translateUsingPseudoLocale(message); +} + /** * If pseudo locale is detected, default intl.formatMessage should be decorated * with the pseudo localization function. @@ -34,7 +56,8 @@ function wrapIntlFormatMessage(child: React.ReactNode) { return React.createElement( injectI18n(({ intl }) => { const formatMessage = intl.formatMessage; - intl.formatMessage = (...args) => translateUsingPseudoLocale(formatMessage(...args)); + intl.formatMessage = (...args) => + translateFormattedMessageUsingPseudoLocale(formatMessage(...args)); return React.Children.only(child); })