Providing error messages in the native language of your users can improve the user experience and adoption rate of your software. That is why I offer several flexible ways to easily implement i18n.

Official translations

The fastest way to get started with i18n is to use my official translations. They are provided in a separate package called @valibot/i18n.

If you are missing a translation, feel free to open an issue or pull request on GitHub.

Import translations

Each translation in this package is implemented modularly and exported as a submodule. This allows you to import only the translations you actually need to keep your bundle size small.

// Import every translation (not recommended)
import '@valibot/i18n';

// Import every translation for a specific language
import '@valibot/i18n/de';

// Import only the translation for schema functions
import '@valibot/i18n/de/schema';

// Import only the translation for a specific pipeline function
import '@valibot/i18n/de/minLength';

The submodules use sideeffects to load the translations into a global storage that the schema and validation functions access when adding the error message to an issue.

Select language

The language used is then selected by the lang configuration. You can set it globally with setGlobalConfig or locally when parsing unknown data via parse or safeParse.

import * as v from 'valibot';

// Set the language configuration globally
v.setGlobalConfig({ lang: 'de' });

// Set the language configuration locally
v.parse(Schema, input, { lang: 'de' });

Custom translations

You can use the same APIs as @valibot/i18n to add your own translations to my global storage. Alternatively, you can also pass them directly to a specific schema or validation function as the first optional argument.

You can either enter the translations manually or use an i18n library like Paraglide JS.

Set translations globally

You can add translations with setGlobalMessage, setSchemaMessage and setSpecificMessage in three different hierarchy levels. When creating an issue, I first check if a specific translation is available, then the translation for schema functions, and finally the global translation.

import * as v from 'valibot';

// Set the translation globally (can be used as a fallback)
v.setGlobalMessage((issue) => `Invalid input: ...`, 'en');

// Set the translation globally for every schema functions
v.setSchemaMessage((issue) => `Invalid type: ...`, 'en');

// Set the translation globally for a specific function
v.setSpecificMessage(v.minLength, (issue) => `Invalid length: ...`, 'en');

Set translations locally

If you prefer to define the translations individually, you can pass them as the first optional argument to schema and validation functions. We recommend using an i18n library like Paraglide JS in this case.

import * as v from 'valibot';
import * as m from './paraglide/messages.js';

const LoginSchema = object({
  email: string([
    minLength(1, m.emailRequired),
  password: string([
    minLength(1, m.passwordRequired),
    minLength(8, m.passwordInvalid),


Thanks to all the contributors who helped make this page better!

  • GitHub profile picture of fabian-hiller


Thanks to our partners who support the project ideally and financially.


Thanks to our GitHub sponsors who support the project financially.

  • GitHub profile picture of dailydotdev
  • GitHub profile picture of ivan-mihalic
  • GitHub profile picture of KATT
  • GitHub profile picture of osdiab
  • GitHub profile picture of Thanaen
  • GitHub profile picture of hyunbinseo
  • GitHub profile picture of caegdeveloper