I am using typescript and i18next for our project,
I would like to summarize the experience of strongly applying the type check of the i18n JSON file.
First, the following is how i18n was being used.
i18n is used to display text in multiple languages on the same webpage, meaning to display it in a language with one key, multiple values.
const i18nJSON = {
'simple-example': 'This is example text',
'values-example': 'I need to show {0} value',
'line-break-example': 'Hello. \n I am FE developer'
} as const
First, there is an object in the form of Key-Value as above. The object may be a JSON or an object of a typescript.
import tFunction from 'utils';
tFunction('simple-example')
tFunction('values-example', [15])
tFunction('line-break-example')
Second, tFunction
is used to insert the i18n key to obtain a string that fits the key.
In some cases, the string including the value that fits each text may be returned by inserting a variable such as values-example
.
In the last line-break-example
, the \n
line break character is converted to the <br/>
tag so that it can be line break on React.
This article uses a function called tFunction
as a method for applying i18n.
Since it mainly deals with content at the type level, not JS logic, it will not deal with what actually happens to internal logic.
It can be said that it plays the same role as a function such as i18next.t.
Here, it may be seen what value the returned value in tFunction
is. Then, what is the type of each return value?
import tFunction from 'utils';
tFunction('simple-example')
tFunction('values-example', [15])
tFunction('line-break-example')
It may be considered that L3 and L6 are string types.
However, in L9, ReactElement is returned because there is \n
in the i18n text.
To support the line break by returning the string without returning to ReactElement
,
dangerouslySetInnerHTML shall be used.
However, since there are many limitations, return to ReactElement instead of string.
If the variable values-example
contains JSX such as atag instead of 15
, the return type of values-example
is also different.
import tFunction from 'utils';
tFunction('values-example', [15])
tFunction('values-example', [<a href="/about">more</a>])
Even if the values-example
I18n key is used as above, the type must vary depending on what value comes to values.
This is because a tag
must also be returned to a component that is a ReactElement, not a string, as in <br/>
.
It was found that the i18n Text type varies as string and ReactElement depending on the case.
So what is the problem?
tFunction
is that it does not intelligently infer types as mentioned above.
What is the problem if the type is not properly inferred here?
<input
type='input'
placeholder={tFunction('line-break-example')}
/>
In many cases, typically when using HTML tags, attributes defined as strings may contain i18n values rather than strings.
In this case, [object Object]
is displayed in the placeholder instead of the xlt text.
Of course, it's obviously strange to have an a tag in the placeholder or a line change like \n.
However, there may be cases where the i18n key is incorrectly used, or there may be cases where the i18n text is incorrectly registered.
In other words, there are the above problems in that the type is not properly inferred when using typescript, and it can cause another problem.
In this article, we will talk about how to define the type by format of i18n text.
This article is basically related to typescript Template Literal Types, although i18n is an example.
- General knowledge of
typescript 4.1+
- Interest in Template Literal Types
- The experience of
i18n system
(optional)