TeaWeb/shared/js/ui/react-elements/i18n/index.tsx
2021-03-20 15:15:28 +01:00

96 lines
No EOL
3 KiB
TypeScript

import * as React from "react";
import {cloneElement} from "react";
import {parseMessageWithArguments} from "tc-shared/ui/frames/chat";
let instances = [];
export class Translatable extends React.Component<{
children: string | (string | React.ReactElement<HTMLBRElement>)[],
trIgnore?: boolean,
}, { translated: string }> {
protected renderElementIndex = 0;
constructor(props) {
super(props);
let text;
if(Array.isArray(this.props.children)) {
text = (this.props.children as any[]).map(e => typeof e === "string" ? e : "\n").join("");
} else {
text = this.props.children;
}
this.state = {
translated: /* @tr-ignore */ tr(text)
}
}
render() {
return this.state.translated.split("\n").reduce((previousValue, currentValue, currentIndex, array) => {
previousValue.push(<React.Fragment key={++this.renderElementIndex}>{currentValue}</React.Fragment>);
if(currentIndex + 1 !== array.length) {
previousValue.push(<br key={++this.renderElementIndex} />);
}
return previousValue;
}, []);
}
componentDidMount(): void {
instances.push(this);
}
componentWillUnmount(): void {
const index = instances.indexOf(this);
if(index === -1) {
/* TODO: Log warning */
return;
}
instances.splice(index, 1);
}
}
let renderBrElementIndex = 0;
export type VariadicTranslatableChild = React.ReactElement | string | number;
export const VariadicTranslatable = (props: { text: string, children?: VariadicTranslatableChild[] | VariadicTranslatableChild }) => {
const args = Array.isArray(props.children) ? props.children : [props.children];
const argsUseCount = [...new Array(args.length)].map(() => 0);
const translated = /* @tr-ignore */ tr(props.text);
return (<>
{
parseMessageWithArguments(translated, args.length).map(e => {
if(typeof e === "string") {
return e.split("\n").reduce((result, element) => {
if(result.length > 0) {
result.push(<br key={++renderBrElementIndex}/>);
}
result.push(element);
return result;
}, []);
}
let element = args[e];
if(argsUseCount[e]) {
if(typeof element === "string" || typeof element === "number") {
/* do nothing */
} else {
element = cloneElement(element);
}
}
argsUseCount[e]++;
return <React.Fragment key={"argument-" + e + "-" + argsUseCount[e]}>{element}</React.Fragment>;
})
}
</>);
};
declare global {
interface Window {
i18nInstances: Translatable[];
}
}
window.i18nInstances = instances;