Translating JSX - How to use Conditionals
Introduction
One of the most common mistakes I see in internationalisation is the tendency to split simple ternary statements into multiple translation calls. It often looks something like this:
const gt = useGT()
return (
<>
<span>
<T> Dark Mode: </T>
</span>
<Button>{enabled ? gt('On') : gt('Off')}</Button>
</>
)For the most part, this works as intended. Before implementing i18n, the code probably looked something like { enabled ? 'On' : 'Off' }.
Adding the gt() function for i18n was probably just a natural extension of the existing code structure.
Every time I see this, I wince a little. This is not at all how the library was designed to be used. There are two reasons why this is a mistake, especially in the context of machine translation: (1) Context and (2) Flexibility.
Context
Meaning is not only embedded in the words themselves, but also in how they are presented. The word "back", if shown on a back arrow, probably means something very different from the word "back" on a chiropractor's CV. Additionally, without broader context, translators (even human ones) might have difficulty translating the word correctly. There's a famous story of WhatsApp's i18n department translating the word "crop" in an image editing tool to "crop" as in farming in German.
To get around this context issue, we can pass information about how content is presented with the <T> and <Branch> components.
In our example, this would give our "translator" a clearer picture of what "on" and "off" mean.
<T>
<span>Dark Mode:</span>
<Button>
<Branch branch={enabled.toString()} true="On" false="Off" />
</Button>
</T>Flexibility
Beyond context, another useful way to leverage LLM translation is through its understanding of code. Let's look at an example where the order of components might change depending on the language:
<T>
I eat lunch at <Branch branch={atHome.toString()} true="home" false="work" />.
</T>So we have two possible sentences:
- "I eat lunch at home"
- "I eat lunch at work"
In Mandarin we would have:
- "我在家吃午餐"
- "我在公司吃午餐"
The <T> component recognises that the sentence order needs to change here, and rearranges its children
accordingly—something that is not easy to do when using ternary operators with string translation.
<T>
我在
<Branch branch={atHome.toString()} true="家" false="公司" />
吃午餐。
</T>Conclusion
If you take anything away from this article, you should always look for ways to make use of context and flexibility in your code.
Using the <Branch /> component is probably one of the easiest ways to do this.
See the <Branch /> component documentation for more details.