Skip to content

Instantly share code, notes, and snippets.

@raphaelbadia
Last active June 19, 2023 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raphaelbadia/82f1c202e57b557bf88ea04cbbc0be29 to your computer and use it in GitHub Desktop.
Save raphaelbadia/82f1c202e57b557bf88ea04cbbc0be29 to your computer and use it in GitHub Desktop.
Trans component from lingui
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
ComponentType,
createElement,
ElementType,
isValidElement,
ReactElement,
ReactNode,
} from 'react';
import { i18n } from '@lingui/core';
// getMsgs: (language: string) => Promise<Record<string, string>>;
// const language = getLanguage();
// const messages = await getMsgs(language);
// i18n.loadAndActivate({ locale: language, messages });
import { formatElements } from './format';
export type TransRenderProps = {
id: string;
translation: ReactNode;
children: ReactNode;
message?: string | null;
isTranslated: boolean;
};
export type TransRenderCallbackOrComponent =
| {
component?: undefined;
render?: (props: TransRenderProps) => ReactElement<any, any> | null;
}
| {
component?: ComponentType<TransRenderProps> | null;
render?: undefined;
};
const DefaultI18n = ({ isTranslated, children }) => (
<span style={{ color: isTranslated ? undefined : 'red' }}>{children}</span>
);
export type TransProps = {
id: string;
message?: string;
values?: Record<string, unknown>;
components?: Record<string, ElementType | any>;
formats?: Record<string, unknown>;
children?: ReactNode;
} & TransRenderCallbackOrComponent;
export async function TransServer({
render,
component,
id,
message,
formats = {},
values,
components = {},
}: TransProps): Promise<ReactElement<any, any> | null> {
const defaultComponent = DefaultI18n;
if (values) {
Object.keys(values).forEach((key) => {
const value = values[key];
const valueIsReactEl =
isValidElement(value) || (Array.isArray(value) && value.every((el) => isValidElement(el)));
if (!valueIsReactEl) {
return;
}
const index = Object.keys(components).length;
components[index] = value;
values[key] = `<${index}/>`;
});
}
console.log(i18n.messages);
const _translation: string =
i18n && typeof i18n._ === 'function' ? i18n._(id, values, { message, formats }) : id; // i18n provider isn't loaded at all
const translation = _translation ? formatElements(_translation, components) : null;
console.log({ translation });
if (render === null || component === null) {
// Although `string` is a valid react element, types only allow `Element`
// Upstream issue: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20544
return translation as unknown as ReactElement<any, any>;
}
const FallbackComponent: ComponentType<TransRenderProps> = defaultComponent || RenderFragment;
const i18nProps: TransRenderProps = {
id,
message,
translation,
isTranslated: id !== translation && message !== translation,
children: translation, // for type-compatibility with `component` prop
};
// Validation of `render` and `component` props
if (render && component) {
console.error(
"You can't use both `component` and `render` prop at the same time. `component` is ignored.",
);
} else if (render && typeof render !== 'function') {
console.error(
`Invalid value supplied to prop \`render\`. It must be a function, provided ${render}`,
);
} else if (component && typeof component !== 'function') {
// Apparently, both function components and class components are functions
// See https://stackoverflow.com/a/41658173/1535540
console.error(
`Invalid value supplied to prop \`component\`. It must be a React component, provided ${component}`,
);
return createElement(FallbackComponent, i18nProps, translation);
}
// Rendering using a render prop
if (typeof render === 'function') {
// Component: render={(props) => <a title={props.translation}>x</a>}
return render(i18nProps);
}
// `component` prop has a higher precedence over `defaultComponent`
const Component: ComponentType<TransRenderProps> = component || FallbackComponent;
return createElement(Component, i18nProps, translation);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment