ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Better Auth i18n 插件完全指南:基于语言检测的认证错误消息国际化方案

Better Auth i18n 插件完全指南:基于语言检测的认证错误消息国际化方案 Better Auth i18n 插件完全指南基于语言检测的认证错误消息国际化方案【免费下载链接】better-authThe most comprehensive authentication framework项目地址: https://gitcode.com/GitHub_Trending/be/better-auth导读better-auth/i18n是 Better Auth 官方提供的国际化i18n插件用于根据检测到的用户语言区域locale自动翻译认证接口返回的错误消息例如把INVALID_EMAIL_OR_PASSWORD从英文 Invalid email or password 翻译为法文、德文或中文。本文以 packages/i18n/README.md 为骨架结合 插件核心实现、类型定义 与 完整测试用例完整讲解插件的安装、四种语言检测策略、全部配置项以及源码级工作原理帮助你在一键启用 22 种内置语言的同时掌握自定义翻译与兜底机制的实战技巧。一、安装better-auth/i18n是一个独立的 npm 包与better-auth主框架配合使用可通过 pnpm / npm / yarn 安装npm install better-auth/i18n从 packages/i18n/package.json 可以看到该包声明better-auth与better-auth/core为 peerDependenciesworkspace:^即它必须与 Better Auth 核心框架在同一项目中共同使用包本身以 ESM 形式发布main/module均指向./dist/index.mjs并提供了三个导出入口.主入口导出i18n插件工厂与locales内置语言集合./client客户端入口导出i18nClient用于在createAuthClient中获得服务端插件的类型推断./locales单独导出全部内置翻译字典。当前仓库中该包的版本为1.7.3见 CHANGELOG.md22 种内置语言在 1.7.0 版本引入。二、内置翻译开箱即用的 22 种语言插件随包携带 22 种语言的完整翻译字典覆盖了全球主要语种。全部语言文件位于 packages/i18n/src/locales/并通过 locales/index.ts 统一导出| 代码 | 语言 | | 代码 | 语言 | |------|------|-|------|------| |ar| 阿拉伯语 | |nl| 荷兰语 | |bn| 孟加拉语 | |pl| 波兰语 | |de| 德语 | |pt| 葡萄牙语 | |en| 英语 | |ru| 俄语 | |es| 西班牙语 | |sv| 瑞典语 | |fa| 波斯语法尔西语 | |th| 泰语 | |fr| 法语 | |tr| 土耳其语 | |hi| 印地语 | |uk| 乌克兰语 | |id| 印度尼西亚语 | |vi| 越南语 | |it| 意大利语 | |zh| 简体中文 | |ja| 日语 | |ko| 韩语 |每种语言都是一个TranslationDictionary对象。以 英文默认字典 为例它覆盖了 34 个核心错误码包括USER_NOT_FOUND、INVALID_EMAIL_OR_PASSWORD、PASSWORD_TOO_SHORT、TOKEN_EXPIRED、EMAIL_NOT_VERIFIED、SESSION_EXPIRED、ACCOUNT_NOT_FOUND等认证场景中的高频错误。简体中文翻译见 zh.ts例如INVALID_EMAIL_OR_PASSWORD对应邮箱或密码无效SESSION_EXPIRED对应会话已过期请重新验证身份以执行此操作。从测试用例 i18n.test.ts 可以确认项目对每种内置语言都做了完整性校验USER_NOT_FOUND、INVALID_PASSWORD、INVALID_EMAIL、INVALID_EMAIL_OR_PASSWORD、EMAIL_NOT_VERIFIED、PASSWORD_TOO_SHORT、PASSWORD_TOO_LONG、USER_ALREADY_EXISTS、SESSION_EXPIRED、ACCOUNT_NOT_FOUND这 10 个关键错误码必须存在于所有语言字典中且值必须是非空字符串。使用全部内置语言在betterAuth配置中挂载插件translations直接传入locales即可启用全部 22 种语言import { betterAuth } from better-auth; import { i18n, locales } from better-auth/i18n; export const auth betterAuth({ plugins: [ i18n({ translations: locales }), ], });使用语言子集如果只需要服务特定市场可以只挑选部分语言减小打包体积import { i18n, locales } from better-auth/i18n; export const auth betterAuth({ plugins: [ i18n({ translations: { en: locales.en, fr: locales.fr, }, }), ], });注意translations中实际提供的语言代码就是插件可识别的全部语言集合——检测到不在集合中的语言时会回退到默认语言详见下文语言检测与兜底。三、覆盖与扩展翻译覆盖特定错误消息当某个内置翻译不符合你的产品文案风格时可以基于内置字典做浅合并覆盖无需重建整个字典import { i18n, locales } from better-auth/i18n; export const auth betterAuth({ plugins: [ i18n({ translations: { ...locales, fr: { ...locales.fr, USER_NOT_FOUND: Membre introuvable, }, }, }), ], });添加自定义语言TranslationDictionary的类型是Partial错误码集合 Recordstring, string见 types.ts即除了内置错误码你还可以为插件扩展的其他错误码提供翻译甚至加入自己的自定义键import { i18n, locales } from better-auth/i18n; import type { TranslationDictionary } from better-auth/i18n; const myLocale: TranslationDictionary { USER_NOT_FOUND: ..., INVALID_EMAIL_OR_PASSWORD: ..., // ... 其他错误码 }; export const auth betterAuth({ plugins: [ i18n({ translations: { ...locales, xx: myLocale, }, }), ], });值得说明的是TranslationDictionary通过UnionToIntersection类型体操自动聚合了 Better Auth 插件注册表中所有插件声明的错误码见 types.ts因此当你同时使用其他插件如组织、API Key 等并为其声明了$ERROR_CODES时自定义字典会获得这些错误码的完整类型提示在编译期就能发现遗漏。四、语言检测策略header / cookie / session / callback插件根据detection数组中的策略按优先级顺序逐一尝试检测用户语言命中即返回。支持四种策略见 types.ts其实现全部位于 src/index.ts策略说明检测来源header解析请求的Accept-Language头ctx.headerscookie读取指定名称的 Cookie 值Cookie头session读取当前会话用户记录中的语言字段ctx.context.session.usercallback调用自定义的getLocale函数用户自定义逻辑1. header默认策略默认配置下插件只启用header策略。它会先调用内部的parseAcceptLanguage函数src/index.ts解析Accept-Language头按;拆分出每个语言及其q质量值按质量值降序排序并把形如fr-CA的区域码裁剪为基础语言码fr然后返回第一个存在于translations中的语言。例如请求头Accept-Language: es;q0.9, fr;q0.8, en;q0.7而你的translations只有 en/fr/de 时检测结果会是fr因为es不在支持集合内测试见 i18n.test.ts请求头fr-CA也会正确落到fr测试见 i18n.test.ts。2. cookie当用户在应用内手动切换语言时通常希望把选择持久化到 Cookie。启用cookie策略后插件会解析Cookie头并读取localeCookie指定的 Cookie默认名为locale若其值在支持的语言集合中则采用i18n({ translations: { en: locales.en, fr: locales.fr }, detection: [cookie, header], // cookie 优先header 兜底 localeCookie: lang, // 自定义 Cookie 名称 })测试用例验证了优先级行为当Cookie: langfr且Accept-Language: de同时存在、detection顺序为[cookie, header]时最终使用 Cookie 中的法语见 i18n.test.ts。3. session对于登录用户可以直接读取用户资料中保存的语言偏好。插件从ctx.context.session.user中读取userLocaleField指定的字段默认字段名也是locale。这意味着你可以在用户表上扩展一个locale字段让用户的语言选择跟随账号跨设备同步。4. callbackcallback策略提供最大灵活性它调用getLocale(ctx)函数你可以从任意来源决定语言例如自定义请求头、子域名或数据库查询i18n({ translations: { en: locales.en, fr: locales.fr }, detection: [callback], getLocale: (ctx) { return ctx.headers?.get(X-Custom-Locale) ?? null; }, })从测试可见getLocale既支持同步返回值也支持Promise见 types.ts并且即使请求对象未定义如直接调用auth.api的场景回调仍会被正常调用见 i18n.test.ts。五、完整配置项一览所有配置项汇总如下均来自 types.ts 与 src/index.ts 的默认值合并逻辑配置项类型默认值说明translations{ [locale]: TranslationDictionary }必填语言代码到翻译字典的映射为空时插件直接抛出i18n plugin: translations object is empty错误测试见 i18n.test.tsdefaultLocalestringen所有检测策略都失败时使用的兜底语言。规则显式指定且存在于translations时优先使用否则若集合中有en则用enen也不存在时使用集合中第一个语言detectionLocaleDetectionStrategy[][header]语言检测策略数组按数组顺序依次尝试第一个命中即生效localeCookiestringlocalecookie策略读取的 Cookie 名称userLocaleFieldstringlocalesession策略读取的用户字段名getLocale(ctx) string \| null \| Promise...无callback策略使用的自定义检测函数defaultLocale的解析逻辑见 src/index.ts它优先采纳显式传入且存在于翻译集合中的值否则当集合包含en时回退为enen缺失时采用集合中第一个语言。测试用例覆盖了这三种情况以及未提供defaultLocale且无en时保持原始英文消息的行为见 i18n.test.ts。六、工作原理after 钩子 APIError 重抛了解插件如何翻译错误有助于你排查自定义场景。插件实现位于 src/index.ts它注册了一个匹配所有请求的after钩子拦截错误响应从ctx.context.returned取出请求返回结果仅当它是APIErrorisAPIError判断时才继续处理——正常响应、非错误响应直接跳过测试验证了成功响应不会被改动见 i18n.test.ts提取错误码从错误体returned.body中取出code字符串这是后续查字典的键检测语言调用detectLocale(ctx)按detection顺序解析当前请求的语言查字典并重抛在opts.translations[locale]?.[errorCode]中查找翻译。若找到则用原 HTTP 状态码和错误码重新抛出一个APIError新错误体包含三个字段code原始错误码保持不变message翻译后的本地化消息originalMessage翻译前的原始英文消息便于调试与日志记录。若找不到对应翻译例如该错误码未收录则保持原样返回不进行任何修改见 i18n.test.ts 的兜底行为验证。由于翻译发生在服务端统一的after钩子中所有认证端点登录、注册、找回密码、会话校验等的错误消息都会自动本地化客户端无需改动任何请求逻辑。七、客户端类型推断i18nClient虽然翻译完全在服务端完成官方仍建议在客户端同步挂载i18nClient以获得服务端插件配置的类型推断例如$InferServerPlugin带来的端到端类型安全import { createAuthClient } from better-auth/client; import { i18nClient } from better-auth/i18n/client; export const client createAuthClient({ plugins: [i18nClient()], });客户端实现见 src/client.ts它声明了与服务端相同的插件id: i18n并通过$InferServerPlugin完成类型关联。注意客户端不承担翻译逻辑——错误消息已经由服务端按检测到的语言翻译完毕客户端插件只负责类型层面的衔接。八、验证与测试仓库为插件提供了覆盖全面的单元测试 i18n.test.ts共覆盖八个维度基于Accept-Language头的检测法语、德语、质量值排序、fr-CA基础码裁剪、不可用语言回退基于 Cookie 的检测及其与 header 的优先级翻译缺失时的兜底行为getLocale回调检测及无请求场景非错误响应不被改动defaultLocale的三种解析分支与空翻译集合报错内置语言的完整性22 个语言全部导出、10 个关键错误码非空。你可以在仓库根目录运行对应包测试来验证当前行为pnpm --filter better-auth/i18n test总结better-auth/i18n用极低的接入成本一个插件、一个translations配置为 Better Auth 的认证错误消息提供了完整的国际化能力22 种内置语言开箱即用header/cookie/session/callback四种检测策略覆盖从浏览器自动匹配到用户手动选择、跨设备同步的全部场景defaultLocale与翻译缺失保持原文的双重兜底机制保证了任何情况下接口都不会出现空消息。若需深度定制TranslationDictionary类型会随插件注册表自动聚合错误码配合getLocale回调你可以将任何自定义语言检测逻辑无缝接入认证流程。【免费下载链接】better-authThe most comprehensive authentication framework项目地址: https://gitcode.com/GitHub_Trending/be/better-auth创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表