diff --git a/shared/js/ui/react-elements/i18n/index.tsx b/shared/js/ui/react-elements/i18n/index.tsx index ab77d642..db51cd91 100644 --- a/shared/js/ui/react-elements/i18n/index.tsx +++ b/shared/js/ui/react-elements/i18n/index.tsx @@ -1,19 +1,38 @@ import * as React from "react"; import {parseMessageWithArguments} from "tc-shared/ui/frames/chat"; -import {cloneElement} from "react"; +import {cloneElement, ReactNode} from "react"; let instances = []; -export class Translatable extends React.Component<{ children: string, __cacheKey?: string, trIgnore?: boolean, enforceTextOnly?: boolean }, { translated: string }> { +export class Translatable extends React.Component<{ + children: string | (string | React.ReactElement)[], + __cacheKey?: string, + trIgnore?: boolean, + enforceTextOnly?: 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(typeof this.props.children === "string" ? this.props.children : (this.props as any).message) + translated: /* @tr-ignore */ tr(text) } } render() { - return this.state.translated; + return this.state.translated.split("\n").reduce((previousValue, currentValue, currentIndex, array) => { + previousValue.push({currentValue}); + if(currentIndex + 1 !== array.length) + previousValue.push(
); + return previousValue; + }, []); } componentDidMount(): void { diff --git a/tools/trgen/ts_generator.ts b/tools/trgen/ts_generator.ts index 9291222b..ee2d8bf4 100644 --- a/tools/trgen/ts_generator.ts +++ b/tools/trgen/ts_generator.ts @@ -370,16 +370,29 @@ export function replace_processor(config: Configuration, cache: VolatileTransfor throw new Error(source_location(ignoreAttribute) + ": Invalid attribute value of type " + SyntaxKind[ignoreAttribute.expression.kind]); } - if(element.children.length !== 1) - throw new Error(source_location(element) + ": Element has been called with an invalid arguments (" + (element.children.length === 0 ? "too few" : "too many") + ")"); + if(element.children.length < 1) { + throw new Error(source_location(element) + ": Element has been called with an invalid arguments (too few)"); + } - const text = element.children[0] as ts.JsxText; - if(text.kind != SyntaxKind.JsxText) - throw new Error(source_location(element) + ": Element has invalid children. Expected JsxText but got " + SyntaxKind[text.kind]); + let text = element.children.map(element => { + if(element.kind === SyntaxKind.JsxText) { + return element.text; + } else if(element.kind === SyntaxKind.JsxSelfClosingElement) { + if(element.tagName.kind !== SyntaxKind.Identifier) { + throw new Error(source_location(element.tagName) + ": Expected a JsxSelfClosingElement, but received " + SyntaxKind[element.tagName.kind]); + } + + if(element.tagName.escapedText !== "br") { + throw new Error(source_location(element.tagName) + ": Expected a br element, but received " + element.tagName.escapedText); + } + + return "\n"; + } + }).join(""); let { line, character } = source_file.getLineAndCharacterOfPosition(node.getStart()); cache.translations.push({ - message: text.text, + message: text, line: line, character: character, filename: (source_file || {fileName: "unknown"}).fileName,