Skip to content

Commit

Permalink
[i18n] support user defined component
Browse files Browse the repository at this point in the history
  • Loading branch information
ym committed Oct 4, 2021
1 parent 43dec8b commit 775b3fa
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/components/context/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface I18nShape {
[key: string]: Renderable<object>;
};
mappingFunc?: (value: string) => string;
componentRenderFunc?: (children: any[]) => FunctionComponent<any>;
formatNumber?: (x: number) => string;
formatDateTime?: (x: Date) => string;
locale?: string;
Expand Down
31 changes: 31 additions & 0 deletions src/components/i18n/__snapshots__/i18n.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,37 @@ exports[`EuiI18n mapped tokens handles single token without values 1`] = `
</EuiContext>
`;

exports[`EuiI18n mapped tokens i18nComponentRenderFunc uses user defined component render function 1`] = `
<EuiContext
i18n={
Object {
"componentRenderFunc": [Function],
}
}
>
<Component>
<section>
<Component
inside={
<span>
inside
</span>
}
>
<div>
placeholder
<span
key="1"
>
inside
</span>
</div>
</Component>
</section>
</Component>
</EuiContext>
`;

exports[`EuiI18n mapped tokens mappingFunc calls the mapping function with the source string 1`] = `
<EuiContext
i18n={
Expand Down
21 changes: 21 additions & 0 deletions src/components/i18n/i18n.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,5 +409,26 @@ describe('EuiI18n', () => {
expect(component).toMatchSnapshot();
});
});

describe('i18nComponentRenderFunc', () => {
it('uses user defined component render function', () => {
const Component = () => {
const value = useEuiI18n('test', 'placeholder {inside}', {
inside: <span>inside</span>,
});
return <section>{value}</section>;
};
const component = mount(
<EuiContext
i18n={{
componentRenderFunc: (children) => () => <div>{children}</div>,
}}
>
<Component />
</EuiContext>
);
expect(component).toMatchSnapshot();
});
});
});
});
46 changes: 36 additions & 10 deletions src/components/i18n/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ function lookupToken<
i18nMapping: I18nShape['mapping'],
valueDefault: DEFAULT,
i18nMappingFunc?: (token: string) => string,
values?: I18nTokenShape<T, DEFAULT>['values']
values?: I18nTokenShape<T, DEFAULT>['values'],
i18nComponentRenderFunc?: (children: any[]) => FunctionComponent<any>
): RESOLVED {
let renderable = (i18nMapping && i18nMapping[token]) || valueDefault;

Expand All @@ -64,9 +65,11 @@ function lookupToken<
return children as RESOLVED;
}

const Component: FunctionComponent<any> = () => {
return <Fragment>{children}</Fragment>;
};
const Component: FunctionComponent<any> = i18nComponentRenderFunc
? i18nComponentRenderFunc(children)
: () => {
return <Fragment>{children}</Fragment>;
};

// same reasons as above, we can't promise the transforms match the default's type
return React.createElement(Component, values) as RESOLVED;
Expand Down Expand Up @@ -111,11 +114,19 @@ const EuiI18n = <
) => (
<EuiI18nConsumer>
{(i18nConfig) => {
const { mapping, mappingFunc } = i18nConfig;
const { mapping, mappingFunc, componentRenderFunc } = i18nConfig;

if (isI18nTokensShape(props)) {
return props.children(
props.tokens.map((token, idx) =>
lookupToken(token, mapping, props.defaults[idx], mappingFunc)
lookupToken(
token,
mapping,
props.defaults[idx],
mappingFunc,
undefined,
componentRenderFunc
)
)
);
}
Expand All @@ -125,7 +136,8 @@ const EuiI18n = <
mapping,
props.default,
mappingFunc,
props.values
props.values,
componentRenderFunc
);
if (props.children) {
return props.children(tokenValue);
Expand Down Expand Up @@ -159,15 +171,29 @@ function useEuiI18n<DEFAULTS extends Array<string | ReactElement>>(
): Array<DefaultsRenderType<DEFAULTS>>;
function useEuiI18n(...props: any[]) {
const i18nConfig = useContext(I18nContext);
const { mapping, mappingFunc } = i18nConfig;
const { mapping, mappingFunc, componentRenderFunc } = i18nConfig;

if (typeof props[0] === 'string') {
const [token, defaultValue, values] = props;
return lookupToken(token, mapping, defaultValue, mappingFunc, values);
return lookupToken(
token,
mapping,
defaultValue,
mappingFunc,
values,
componentRenderFunc
);
} else {
const [tokens, defaultValues] = props as [string[], string[]];
return tokens.map((token, idx) =>
lookupToken(token, mapping, defaultValues[idx], mappingFunc)
lookupToken(
token,
mapping,
defaultValues[idx],
mappingFunc,
undefined,
componentRenderFunc
)
);
}
}
Expand Down

0 comments on commit 775b3fa

Please sign in to comment.