Merge pull request #29786 from backstage/rugvip/i18n-jsx
core-{app,plugin}-api: add support for JSX in translation messages
This commit is contained in:
+46
@@ -94,6 +94,52 @@ describe('MockTranslationApi', () => {
|
||||
expect(snapshot.t('foo', { qux: 'Deep' })).toBe('Foo Nested Baz Deep');
|
||||
});
|
||||
|
||||
it('should support jsx interpolation', () => {
|
||||
const snapshot = snapshotWithMessages({
|
||||
empty: 'derp',
|
||||
jsx: '={{ x }}',
|
||||
jsxNested: '={{ x.y.z }}',
|
||||
jsxDeep: '<$t(jsx)>',
|
||||
});
|
||||
|
||||
expect(snapshot.t('jsx', { x: <h1>hello</h1> })).toMatchInlineSnapshot(`
|
||||
<React.Fragment>
|
||||
=
|
||||
<h1>
|
||||
hello
|
||||
</h1>
|
||||
</React.Fragment>
|
||||
`);
|
||||
expect(snapshot.t('jsx', { replace: { x: <h1>hello</h1> } }))
|
||||
.toMatchInlineSnapshot(`
|
||||
<React.Fragment>
|
||||
=
|
||||
<h1>
|
||||
hello
|
||||
</h1>
|
||||
</React.Fragment>
|
||||
`);
|
||||
expect(
|
||||
snapshot.t('jsxNested', { replace: { x: { y: { z: <h1>hello</h1> } } } }),
|
||||
).toMatchInlineSnapshot(`
|
||||
<React.Fragment>
|
||||
=
|
||||
<h1>
|
||||
hello
|
||||
</h1>
|
||||
</React.Fragment>
|
||||
`);
|
||||
expect(snapshot.t('jsxDeep', { x: <h1>hello</h1> })).toMatchInlineSnapshot(`
|
||||
<React.Fragment>
|
||||
<=
|
||||
<h1>
|
||||
hello
|
||||
</h1>
|
||||
>
|
||||
</React.Fragment>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should support formatting', () => {
|
||||
const snapshot = snapshotWithMessages({
|
||||
plain: '= {{ x }}',
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import {
|
||||
TranslationApi,
|
||||
TranslationFunction,
|
||||
TranslationRef,
|
||||
TranslationSnapshot,
|
||||
} from '@backstage/core-plugin-api/alpha';
|
||||
@@ -27,6 +26,8 @@ import { Observable } from '@backstage/types';
|
||||
// Internal import to avoid code duplication, this will lead to duplication in build output
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { toInternalTranslationRef } from '../../../../../core-plugin-api/src/translation/TranslationRef';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { JsxInterpolator } from '../../../../../core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi';
|
||||
|
||||
const DEFAULT_LANGUAGE = 'en';
|
||||
|
||||
@@ -41,6 +42,8 @@ export class MockTranslationApi implements TranslationApi {
|
||||
supportedLngs: [DEFAULT_LANGUAGE],
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
// Used for the JsxInterpolator format hook
|
||||
alwaysFormat: true,
|
||||
},
|
||||
ns: [],
|
||||
defaultNS: false,
|
||||
@@ -55,14 +58,18 @@ export class MockTranslationApi implements TranslationApi {
|
||||
throw new Error('i18next was unexpectedly not initialized');
|
||||
}
|
||||
|
||||
return new MockTranslationApi(i18n);
|
||||
const interpolator = JsxInterpolator.fromI18n(i18n);
|
||||
|
||||
return new MockTranslationApi(i18n, interpolator);
|
||||
}
|
||||
|
||||
#i18n: I18n;
|
||||
#interpolator: JsxInterpolator;
|
||||
#registeredRefs = new Set<string>();
|
||||
|
||||
private constructor(i18n: I18n) {
|
||||
private constructor(i18n: I18n, interpolator: JsxInterpolator) {
|
||||
this.#i18n = i18n;
|
||||
this.#interpolator = interpolator;
|
||||
}
|
||||
|
||||
getTranslation<TMessages extends { [key in string]: string }>(
|
||||
@@ -81,10 +88,9 @@ export class MockTranslationApi implements TranslationApi {
|
||||
);
|
||||
}
|
||||
|
||||
const t = this.#i18n.getFixedT(
|
||||
null,
|
||||
internalRef.id,
|
||||
) as TranslationFunction<TMessages>;
|
||||
const t = this.#interpolator.wrapT<TMessages>(
|
||||
this.#i18n.getFixedT(null, internalRef.id),
|
||||
);
|
||||
|
||||
return {
|
||||
ready: true,
|
||||
|
||||
Reference in New Issue
Block a user