docs/content/docs/plugins/i18n.mdx
The i18n plugin allows you to translate error messages returned by Better Auth based on the user's locale. It supports multiple locale detection strategies including HTTP headers, cookies, session data, and custom callbacks.
Better Auth already provides English error messages by default, so you only need to provide translations for other languages.
```package-install
@better-auth/i18n
```
```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { i18n } from "@better-auth/i18n"
export const auth = betterAuth({
plugins: [
i18n({
translations: {
fr: {
USER_NOT_FOUND: "Utilisateur non trouvé",
INVALID_EMAIL_OR_PASSWORD: "Email ou mot de passe invalide",
INVALID_PASSWORD: "Mot de passe invalide",
},
de: {
USER_NOT_FOUND: "Benutzer nicht gefunden",
INVALID_EMAIL_OR_PASSWORD: "Ungültige E-Mail oder Passwort",
INVALID_PASSWORD: "Ungültiges Passwort",
},
},
}),
],
})
```
The plugin automatically detects the user's locale and translates error messages accordingly. When an error is returned, the response will include both the translated message and the original message.
When an error occurs and a translation is available, the response will look like this:
{
"code": "INVALID_EMAIL_OR_PASSWORD",
"message": "Email ou mot de passe invalide",
"originalMessage": "Invalid email or password"
}
By default, the plugin detects the locale from the Accept-Language HTTP header. You can configure multiple detection strategies that are checked in order:
i18n({
translations: { /* ... */ },
detection: ["cookie", "header", "session"], // Priority order
})
Available detection strategies:
header - Uses the Accept-Language HTTP header (default)cookie - Reads locale from a cookiesession - Reads locale from the authenticated user's stored preferencecallback - Uses a custom function to determine localeThe plugin automatically parses the Accept-Language header, including quality values:
Accept-Language: fr-CA, fr;q=0.9, en;q=0.8
This would first try fr-CA (mapped to fr), then fr, then en.
To use cookie-based detection, add "cookie" to the detection strategies and optionally configure the cookie name:
i18n({
translations: { /* ... */ },
detection: ["cookie", "header"],
localeCookie: "lang", // Default is "locale"
})
If you store the user's locale preference in their profile, you can detect it from the session:
export const auth = betterAuth({
user: {
additionalFields: {
locale: { type: "string", required: false },
},
},
plugins: [
i18n({
translations: { /* ... */ },
detection: ["session", "header"],
userLocaleField: "locale", // Default is "locale"
}),
],
})
For advanced use cases, you can provide a custom locale detection function:
i18n({
translations: { /* ... */ },
detection: ["callback", "header"],
getLocale: (ctx) => {
// Custom logic: use query param, custom header, etc.
if (!ctx.request) return null;
const url = new URL(ctx.request.url);
return url.searchParams.get("lang");
},
})
The callback receives the full endpoint context. It should return the locale code or null.
The plugin translates error messages based on error codes. You can find all available error codes in the Error Codes Reference.
Common error codes include:
| Code | Default Message |
|---|---|
USER_NOT_FOUND | User not found |
INVALID_EMAIL_OR_PASSWORD | Invalid email or password |
INVALID_PASSWORD | Invalid password |
CREDENTIAL_ACCOUNT_NOT_FOUND | Credential account not found |
EMAIL_NOT_VERIFIED | Email not verified |
SESSION_EXPIRED | Session expired |
translationsType: Record<string, Record<string, string>>
Required: Yes
A dictionary of translations keyed by locale code. Each locale contains a mapping of error codes to translated messages. Since Better Auth already provides English messages, you typically only need to provide translations for other languages.
translations: {
fr: { USER_NOT_FOUND: "Utilisateur non trouvé" },
de: { USER_NOT_FOUND: "Benutzer nicht gefunden" },
}
defaultLocaleType: string
Default: "en" when possible, otherwise the first locale in the translations dictionary
The fallback locale to use when no locale can be detected or the detected locale is not in the translations.
detectionType: Array<"header" | "cookie" | "session" | "callback">
Default: ["header"]
An array of detection strategies to use, in priority order. The first strategy that returns a valid locale will be used.
localeCookieType: string
Default: "locale"
The name of the cookie to read when using the "cookie" detection strategy.
userLocaleFieldType: string
Default: "locale"
The field name on the user object that stores their locale preference when using the "session" detection strategy.
getLocaleType: (ctx: GenericEndpointContext) => string | null | Promise<string | null>
A custom function to detect the locale when using the "callback" detection strategy. Receives the full endpoint context. Returns the locale code or null.