Skip to content

Commit

Permalink
Revert "Revert "CHECKOUT-8519: Switch messageformat library to be com…
Browse files Browse the repository at this point in the history
…patible with strict-dynamic CSP header""
  • Loading branch information
davidchin authored Oct 8, 2024
1 parent 616553d commit cb2ed25
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 7 deletions.
183 changes: 183 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"core-js": "^3.31.0",
"current-script-polyfill": "^1.0.0",
"iframe-resizer": "^3.6.6",
"intl-messageformat": "^10.5.14",
"local-storage-fallback": "^4.1.2",
"lodash": "^4.17.15",
"messageformat": "^2.3.0",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/locale/language-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,30 @@ export default interface LanguageConfig {
locale: string;
locales: Locales;
translations: Translations;
/**
* @hidden This property is intended for toggling an experimental change only.
*/
isCspNonceExperimentEnabled?: boolean;
}

export interface TransformedLanguageConfig {
defaultTranslations: Translations;
defaultLocale?: string;
fallbackTranslations?: Translations;
fallbackLocale?: string;
locale: string;
locales: Locales;
translations: TransformedTranslations;
}

export interface Translations {
[key: string]: string | Translations;
}

export interface TransformedTranslations {
[key: string]: string;
}

export interface Locales {
[key: string]: string;
}
7 changes: 6 additions & 1 deletion packages/core/src/locale/language-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('LanguageService', () => {
'optimized_checkout.test.continue_as_guest_action': 'Continue as guest',
'optimized_checkout.test.email_label': 'Email Address',
'optimized_checkout.test.order_number_text': 'Your order number is {orderNumber}',
'optimized_checkout.test.thank_you_text': '<strong>Thank you<strong>',
},
};

Expand All @@ -51,6 +52,10 @@ describe('LanguageService', () => {
);
});

it('returns translated HTML strings', () => {
expect(langService.translate('test.thank_you_text')).toBe('<strong>Thank you<strong>');
});

it('pluralizes strings using ICU format', () => {
expect(langService.translate('test.item_count_text', { count: 0 })).toBe('0 Items');
expect(langService.translate('test.item_count_text', { count: 1 })).toBe('1 Item');
Expand All @@ -70,7 +75,7 @@ describe('LanguageService', () => {

expect(langService.translate('test.days_text', { count: 1 })).toBe('1 den');
expect(langService.translate('test.days_text', { count: 2 })).toBe('2 dny');
expect(langService.translate('test.days_text', { count: 1.5 })).toBe('1.5 dne');
expect(langService.translate('test.days_text', { count: 1.5 })).toBe('1,5 dne');
expect(langService.translate('test.days_text', { count: 100 })).toBe('100 dní');
});

Expand Down
33 changes: 27 additions & 6 deletions packages/core/src/locale/language-service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { IntlMessageFormat } from 'intl-messageformat';
import { isObject, union } from 'lodash';
import MessageFormat from 'messageformat';

import { bindDecorator as bind } from '@bigcommerce/checkout-sdk/utility';

import { Logger } from '../common/log';

import LanguageConfig, { Locales, Translations } from './language-config';
import LanguageConfig, {
Locales,
TransformedLanguageConfig,
TransformedTranslations,
Translations,
} from './language-config';

const DEFAULT_LOCALE = 'en';
const KEY_PREFIX = 'optimized_checkout';
Expand All @@ -23,8 +29,9 @@ const KEY_PREFIX = 'optimized_checkout';
export default class LanguageService {
private _locale: string;
private _locales: Locales;
private _translations: Translations;
private _translations: TransformedTranslations;
private _formatters: { [key: string]: any };
private _isCspNonceExperimentEnabled: boolean;

/**
* @internal
Expand All @@ -36,6 +43,7 @@ export default class LanguageService {
this._locales = locales;
this._translations = translations;
this._formatters = {};
this._isCspNonceExperimentEnabled = config.isCspNonceExperimentEnabled ?? true;
}

/**
Expand Down Expand Up @@ -95,6 +103,19 @@ export default class LanguageService {
return prefixedKey;
}

if (this._isCspNonceExperimentEnabled) {
if (!this._formatters[prefixedKey]) {
this._formatters[prefixedKey] = new IntlMessageFormat(
this._translations[prefixedKey] || '',
this._locales[prefixedKey],
undefined,
{ ignoreTag: true },
);
}

return this._formatters[prefixedKey].format(this._transformData(data));
}

if (!this._formatters[prefixedKey]) {
const messageFormat = new MessageFormat(this._locales[prefixedKey]);

Expand All @@ -106,8 +127,8 @@ export default class LanguageService {
return this._formatters[prefixedKey](this._transformData(data));
}

private _transformConfig(config: Partial<LanguageConfig> = {}): LanguageConfig {
const output: LanguageConfig = {
private _transformConfig(config: Partial<LanguageConfig> = {}): TransformedLanguageConfig {
const output: TransformedLanguageConfig = {
defaultLocale: '',
defaultTranslations: {},
translations: {},
Expand Down Expand Up @@ -143,9 +164,9 @@ export default class LanguageService {

private _flattenObject(
object: Translations,
result: Translations = {},
result: TransformedTranslations = {},
parentKey = '',
): Translations {
): TransformedTranslations {
try {
Object.keys(object).forEach((key) => {
const value = object[key];
Expand Down

0 comments on commit cb2ed25

Please sign in to comment.