Mixed and nested structures
While simple messages are easy to extract, mixed and nested messages are
not. But wuchale
handles them seamlessly. When writing them in the .po
files, it uses a simple convention that is easy
to work with for translators.
Text mixed with expressions
Section titled “Text mixed with expressions”These are created when extracting template literals and markup message with expressions in the middle. For example,
const msg = `Hello ${userName}, welcome to ${appName}!`
And
<p>Hello {userName}, welcome to ${appName}!</p>
Are both extracted into the catalogs:
msgid "Hello {0}, welcome to {1}!"msgstr ""
Then it gets compiled into the optimized form to require as few operations as possible to render:
export let c = [["Hello ", 0, ", welcome to ", 1, "!"]]
And the code is turned into a version that gets it by index (in this case 0
)
and give it the dynamic values in the same order:
const msg = _w_runtime_.t(0, [userName, appName])
And
<p>{_w_runtime_.t(0, [userName, appName])}</p>
This makes the job of the Runtime.t
method
very simple during runtime. No replace, no weird regex. Just concatenate in the
order getting the references by index and return.
And this enables it to accomodate any change in the translation. If the translator changes the order of things, it will just follow and use the that order.
Nested content (advanced)
Section titled “Nested content (advanced)”Text mixed with markup that contains other text or expressions:
<p>Welcome to <i>the app {appName}</i>, <b>{userName}</b>!</p>
This is extracted as:
msgid "Welcome to <0>the app {0}</0>, <1/>!"msgstr ""
This example shows two behaviours wuchale
has when handling nesting content.
- When the nested content contains only text or text mixed with something else,
it is extracted in numeric HTML-like tags with both opening and closing tags
<0>...</0>
. - When it doesn’t contain any text, the whole thing is extracted as a
self-closing numeric tag
<1/>
. Because the translator doesn’t need to know what is inside the tag because it is not translatable. They can translated without being overwhelmed with unnecessary details.
Then it gets compiled into the optimized form:
export let c = [["Welcome to ", [0, "the app ", 0], ", ", [1], "!"]]
And depending on the adapter, the code is transformed into:
Uses a simple W_tx_
implementation (JSX)
<p> <W_tx_ tags={[ _w_ctx_ => <i key="_0">{_w_runtime_.tx(_w_ctx_, [appName])}</i>, () => <b key="_0">{userName}</b>, ]} ctx={_w_runtime_.cx(0)} /></p>
Uses a simple W_tx_
implementation (Svelte)
<p> {#snippet wuchaleSnippet0(_w_ctx_)} <i>{_w_runtime_.tx(_w_ctx_, [appName])}</i> {/snippet} {#snippet wuchaleSnippet1()} <b>{userName}</b> {/snippet} <W_tx_ tags={[wuchaleSnippet0, wuchaleSnippet1]} ctx={_w_runtime_.cx(0)} /></p>
Basically, the W_tx_
does the same simple job: looping through the
elements of the array and rendering them. This makes it very performant by
avoiding string manipulations during runtime.
Escaping
Section titled “Escaping”When compiling the translations, you may think, how do I escape special
characters like <>{}
? wuchale
comes with its own message compiler that is
very strict, so strict that it makes escaping unnecessary. If the message is
valid in the PO syntax, it should work.
The way it works is this: it only considers valid numeric tags and numeric references as special, nothing else. And it is not tolerant to whitespace mistakes.
Numeric tags
Section titled “Numeric tags”Example: <0>...</0>
and </0>
These are the only supported syntax to signal nested content. And outside of translations, they are not valid HTML anyway. That means you can, for example, extract HTML without a problem, which may be stored in a string (extracted if the heuristic allows).
msgid "<b>the number 0</b> < <i><0>the number 1</0></i>"msgstr ""
You would think that the above would need escaping but it doesn’t when using
wuchale
because it is very strict. It only considers the <0>...</0>
as
special and treats the rest as text.
Numeric references
Section titled “Numeric references”Example: {0}
These are used to reference the expression values in interpolations. Also you will almost never use them in other contexts and therefore it recognizes them as special. For example,
msgid "You may use { and } freely and {a} is not special. {0} is, { 0 } is not"msgstr ""
In the above, everything except {0}
is just text and will not cause problems.