using i18n (react-i18next) with tanstack form
How do I use i18n with ts form in a typesafe way? Currently I'm doing it like this:
But the problem is that the form's errors dont change when the locale changes (I guess this is because form uses signals under the hood and doesn't pick up the changes from react). Is there a recommended way to do this in a typesafe way so the locale changes get propagated to the form's state?
6 Replies
adverse-sapphire•5mo ago
When a validator runs it sets the error in the form internal state, so if the validator returns a string, that's what is stored in the form state. It's just a string, not a function or something that can update when the language is changed.
What I would do instead is to just return the localization key in the error (the string
title
in your snippet) so that form handles validation and the localization library handles localization
Speaking of typesafety I don't have any quick idea right now as StandardSchemaV1Issue["message"]
is just a stringeastern-cyanOP•5mo ago
yeah thats the issue, currently i can use TFunction to have type safety for error messages, but im not aware how i could to this with just the keys in the locale files without too much boilerplate and type casting
adverse-sapphire•5mo ago
It's more a zod & i18n thing
eastern-cyanOP•5mo ago
yeah, i havent found a nice way of having it be typesafe so i was thinking of trying to "hack" around with form. Do you think triggering validation on language change is a good idea? For eg:
Could probably be extracted into a hook, but I need a corresponding wrapper like
withForm
where I can pass the form as an argumentadverse-sapphire•5mo ago
It might work, but you're basically re-running the entire validation logic to simply change a translated string
eastern-cyanOP•5mo ago
dont know how would i update the error fields directly with this approach (passing
t
instead of locale keys)
in the end, i tinkered around with typescript a bit and made typesafe wrapper functions to handle this, feel like its the best solution:
now the usage in app becomes:
and error display component: