Vue I18n
Use @verific/vue-i18n with a caller-owned Vue I18n 11 Composition API Composer. The same adapter powers the automatic Nuxt I18n integration.
Install and configure the application
pnpm add @verific/core @verific/vue-i18n vue vue-i18n zodimport type { MissingMessageMode } from '@verific/i18n'
import type { App } from 'vue'
import { createVerific } from '@verific/core'
import { vueI18nMessages } from '@verific/vue-i18n'
import { createI18n } from 'vue-i18n'
export const i18n = createI18n({
legacy: false,
locale: 'en',
fallbackLocale: 'en',
messages: {
en: { errors: { invalidEmail: 'Enter a valid email address' } },
es: { errors: { invalidEmail: 'Introduce una dirección de correo válida' } },
},
})
export function createValidationMessages(missing?: MissingMessageMode) {
return vueI18nMessages(i18n.global, {
fallbackPrefix: 'errors',
missing,
})
}
export function installValidation(app: App) {
app.use(i18n)
app.use(createVerific({ messages: createValidationMessages() }))
}Call installValidation(app) before mounting the application. This displayed source is compiled by the documentation test suite against the exported adapter.
Use it in a form
<script setup lang="ts">
import { useValidation } from '@verific/core'
import { reactive } from 'vue'
import { useI18n } from 'vue-i18n'
import { z } from 'zod'
const { locale } = useI18n()
const form = reactive({ email: '' })
const schema = z.object({ email: z.email() })
const { errorsFor, hasError, validate, validateFor } = useValidation(schema, form, {
messagePrefix: 'forms.signup',
})
async function submit() {
const result = await validate()
if (result.success) {
// Submit application-owned state.
}
}
</script>
<template>
<form novalidate @submit.prevent="submit">
<label for="email">Email</label>
<input
id="email"
v-model="form.email"
type="email"
:aria-invalid="hasError('email')"
aria-describedby="email-errors"
@blur="validateFor('email')"
>
<div id="email-errors" aria-live="polite" aria-atomic="true">
<p v-for="(error, index) in errorsFor('email')" :key="`${index}:${error}`">
{{ error }}
</p>
</div>
<button type="submit">
Continue
</button>
</form>
<button type="button" @click="locale = locale === 'en' ? 'es' : 'en'">
Change message language
</button>
</template>Changing locale updates the committed error text without another schema run. Vue I18n locale fallback is honoured, but Verific still applies the shared key-first order.
Local Composers
A component-local Composer can own form translations. Set fallbackRoot = false, then pass its adapter to the registration:
const composer = useI18n({ useScope: 'local', messages: localMessages })
composer.fallbackRoot = false
const { errorsFor, validate } = useValidation(schema, form, {
messagePrefix: 'forms.checkout',
messages: vueI18nMessages(composer),
})This lets a miss continue to inherited Verific resolvers instead of Vue I18n consulting its root Composer out of order.
Missing keys and SSR
Use missing: 'throw' in exercised tests and read an error selector after validation:
const messages = vueI18nMessages(i18n.global, {
fallbackPrefix: 'errors',
missing: 'throw',
})For SSR, obtain the Composer from the current application or request. @verific/nuxt does this automatically with @nuxtjs/i18n; see Nuxt automatic Vue I18n. Do not share a mutable Composer between requests.
See the shared missing-message policies and @verific/vue-i18n package README for the complete adapter surface.
