We care a lot about DX at Woovi. We want to find the best workflow to make it easy for developers to work with i18n strings. Manually updating the code and the i18n locale JSON files is slow and error-prone.
Our current workflow after many iterations is like this:
- Write your i18n strings using t('key in english'), you write the string in English.
- We run i18next-scanner to extract all usages of
t
in the codebase - the developer just needs to fill the Portuguese and Spanish translations (we have some POCs to use Google Translate, ChatGPT or Copilot to autofill translations for us).
Avoiding i18n that can't be extracted
You can only extract static strings, you can't extract string interpolations or variables.
Here are 2 examples of bad usage of i18n
t(`CHARGE_STATUS.${charge.status}`)
We can't know all strings that need to be extracted when using a string interpolation and a variable
t(result.error)
We can't know all possible strings of result.error
neither.
To avoid this bad usages in our codebase, we decided to write a custom Eslint rule to catch this mistakes at pre-commit hook.
noVariableT eslint rule
module.exports = createRule({
create: (context) => ({
CallExpression(node) {
if (node.callee.name === 't') {
const arg = node.arguments[0];
if (arg.type === 'TemplateLiteral' && arg.expressions.length === 0) {
return;
}
if (!arg || arg.type !== 'Literal' || typeof arg.value !== 'string') {
context.report({
node,
message:
'Only string literals are allowed as arguments to the t() function.',
});
}
}
},
MemberExpression(node) {
if (node.property.name === 't') {
if (!node.parent.arguments) {
return;
}
const arg = node.parent.arguments[0];
if (arg.type === 'TemplateLiteral' && arg.expressions.length === 0) {
return;
}
if (!arg || arg.type !== 'Literal' || typeof arg.value !== 'string') {
context.report({
node,
message:
'Only string literals are allowed as arguments to the t() function.',
});
}
}
},
}),
name: 'no-variable-t',
meta: {
type: 'problem',
fixable: 'code',
docs: {
description: 'Using t(variable) breaks i18next-scanner',
recommended: 'error',
},
schema: [],
},
defaultOptions: [],
});
To understand what this eslint rule is doing, you need to understand how JavaScript AST works. You can explore it here https://astexplorer.net/
A CallExpression
represents a function call. The rule searches for all t
callExpression
that are not using a string literal, and report an error.
To sum up
DX is also how do you avoid developers making mistakes.
At Woovi we don't blame a person when an error is made, we try to understand the root cause, improve our process and automation to avoid this happening again.
How are you avoiding mistakes at your Startup? What automation do you have in place?
Woovi
Woovi is a Startup that enables shoppers to pay as they like. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.
If you want to work with us, we are hiring!
Top comments (1)
You should take a look at github.com/inlang/inlang/tree/main.... We just implemented "ESLint for translations". No need for custom eslint rules.
PS it is early though :)