diff --git a/packages/react/src/Trans.test.tsx b/packages/react/src/Trans.test.tsx
index 0b89b813b..26015daa8 100644
--- a/packages/react/src/Trans.test.tsx
+++ b/packages/react/src/Trans.test.tsx
@@ -108,6 +108,33 @@ describe("Trans component", function () {
expect(translation).toEqual("Hello John")
})
+ it("should render named component in components", function () {
+ const translation = html(
+ }}
+ />
+ )
+ expect(translation).toEqual(`Read the docs`)
+ })
+
+ it("should render nested named components in components", function () {
+ const translation = html(
+ , strong: }}
+ />
+ )
+ expect(translation).toEqual(`Read the docs`)
+ })
+
+ it("should render non-named component in components", function () {
+ const translation = html(
+ }} />
+ )
+ expect(translation).toEqual(`Read the docs`)
+ })
+
it("should render translation inside custom component", function () {
const Component = (props) =>
{props.children}
const html1 = html()
diff --git a/packages/react/src/format.test.tsx b/packages/react/src/format.test.tsx
index ca7f9e32b..016ccf506 100644
--- a/packages/react/src/format.test.tsx
+++ b/packages/react/src/format.test.tsx
@@ -30,6 +30,25 @@ describe("formatElements", function () {
).toEqual('About')
})
+ it("should preserve named element props", function () {
+ expect(
+ html(
+ formatElements("About", { named: })
+ )
+ ).toEqual('About')
+ })
+
+ it("should preserve nested named element props", function () {
+ expect(
+ html(
+ formatElements("About us", {
+ named: ,
+ b: ,
+ })
+ )
+ ).toEqual('About us')
+ })
+
it("should format nested elements", function () {
expect(
html(
@@ -52,35 +71,54 @@ describe("formatElements", function () {
)
})
- it("should ignore non existing element", function() {
+ it("should ignore non existing element", function () {
expect(html(formatElements("<0>First0>"))).toEqual("First")
expect(html(formatElements("<0>First0>Second"))).toEqual("FirstSecond")
- expect(html(formatElements("First<0>Second0>Third")))
- .toEqual("FirstSecondThird")
+ expect(html(formatElements("First<0>Second0>Third"))).toEqual(
+ "FirstSecondThird"
+ )
expect(html(formatElements("Fir<0/>st"))).toEqual("First")
+ expect(html(formatElements("text"))).toEqual("text")
+ expect(html(formatElements("text "))).toEqual("text ")
})
- it("should ignore incorrect tags and print them as a text", function() {
+ it("should ignore incorrect tags and print them as a text", function () {
expect(html(formatElements("text0>"))).toEqual("text</0>")
expect(html(formatElements("text<0 />"))).toEqual("text<0 />")
- expect(html(formatElements("text")))
- .toEqual("<tag>text</tag>")
- expect(html(formatElements("text "))).toEqual("text <br/>")
})
- it("should ignore unpaired element used as paired", function() {
- expect(html(formatElements("<0>text0>", {0: }))).toEqual("text")
+ it("should ignore unpaired element used as paired", function () {
+ expect(html(formatElements("<0>text0>", { 0: }))).toEqual("text")
+ })
+
+ it("should ignore unpaired named element used as paired", function () {
+ expect(
+ html(formatElements("text", { named: }))
+ ).toEqual("text")
+ })
+
+ it("should ignore paired element used as unpaired", function () {
+ expect(html(formatElements("text<0/>", { 0: }))).toEqual(
+ "text"
+ )
})
- it("should ignore paired element used as unpaired", function() {
- expect(html(formatElements("text<0/>", {0: })))
- .toEqual("text")
+ it("should ignore paired named element used as unpaired", function () {
+ expect(html(formatElements("text", { named: }))).toEqual(
+ "text"
+ )
})
- it("should create two children with different keys", function() {
- const cleanPrefix = (str: string): number => Number.parseInt(str.replace("$lingui$_", ""), 10)
- const childElements = formatElements("
<0/><0/>
", { 0: hi }) as Array
- const childKeys = childElements.map(el => el?.key).filter(Boolean);
+ it("should create two children with different keys", function () {
+ const cleanPrefix = (str: string): number =>
+ Number.parseInt(str.replace("$lingui$_", ""), 10)
+ const elements = formatElements("
<0/><0/>
", {
+ 0: hi,
+ }) as Array
+
+ expect(elements).toHaveLength(1)
+ const childElements = elements[0].props.children
+ const childKeys = childElements.map((el) => el?.key).filter(Boolean)
expect(cleanPrefix(childKeys[0])).toBeLessThan(cleanPrefix(childKeys[1]))
})
})
diff --git a/packages/react/src/format.ts b/packages/react/src/format.ts
index 2c5f814a5..b46210ae3 100644
--- a/packages/react/src/format.ts
+++ b/packages/react/src/format.ts
@@ -1,7 +1,7 @@
import React from "react"
-// match <0>paired0> and <1/> unpaired tags
-const tagRe = /<(\d+)>(.*?)<\/\1>|<(\d+)\/>/
+// match paired and unpaired tags
+const tagRe = /<([a-zA-Z0-9]+)>(.*?)<\/\1>|<([a-zA-Z0-9]+)\/>/
const nlRe = /(?:\r\n|\r|\n)/g
// For HTML, certain tags should omit their close tag. We keep a whitelist for
@@ -22,13 +22,13 @@ const voidElementTags = {
source: true,
track: true,
wbr: true,
- menuitem: true
+ menuitem: true,
}
/**
* `formatElements` - parse string and return tree of react elements
*
- * `value` is string to be formatted with <0>Paired<0/> or <0/> (unpaired)
+ * `value` is string to be formatted with Paired or (unpaired)
* placeholders. `elements` is a array of react elements which indexes
* correspond to element indexes in formatted string
*/
@@ -36,7 +36,7 @@ function formatElements(
value: string,
elements: { [key: string]: React.ReactElement } = {}
): string | Array {
- const uniqueId = makeCounter(0, '$lingui$')
+ const uniqueId = makeCounter(0, "$lingui$")
const parts = value.replace(nlRe, "").split(tagRe)
// no inline elements, return
@@ -101,7 +101,7 @@ function getElements(parts) {
const [paired, children, unpaired, after] = parts.slice(0, 4)
- return [[parseInt(paired || unpaired), children || "", after]].concat(
+ return [[paired || unpaired, children || "", after]].concat(
getElements(parts.slice(4, parts.length))
)
}
diff --git a/website/docs/misc/react-intl.md b/website/docs/misc/react-intl.md
index a6a87607f..5549640c0 100644
--- a/website/docs/misc/react-intl.md
+++ b/website/docs/misc/react-intl.md
@@ -55,14 +55,12 @@ In [react-intl](https://github.com/yahoo/react-intl), this would be translated a
``` jsx
- ]}
+ message='Read the documentation.'
+ components={{ link: }}
/>
```
-and the translator gets the message in one piece: `Read the <0>documentation0>`.
+and the translator gets the message in one piece: `Read the documentation`.
However, let's go yet another level deeper.
diff --git a/website/docs/ref/react.md b/website/docs/ref/react.md
index eb95966b6..9ba3dc5a4 100644
--- a/website/docs/ref/react.md
+++ b/website/docs/ref/react.md
@@ -92,9 +92,9 @@ It's also possible to use `Trans` component directly without macros. In that cas
// number of tag corresponds to index in `components` prop
]}
-/>;
+ id="Read Description below."
+ components={{ link: }}
+/>
```
#### Plurals