
写这题我很有发言权因为我也踩过不少坑。你在一家中大型前端团队里做 Vue3 项目UI 组件库选了 ant-design-vue本来以为都是中文组件库、开箱就能显示中文结果日期选择器一打开是英文的、Pagination 翻页显示的是Next Page弹窗确认按钮的Cancel也原封不动躺在界面上。这个问题看起来是个小配置实际上涉及组件库的国际化机制、底层日期库的语言包、以及 Vue 应用入口的组织方式处理不好会恶心很久。先说结论ant-design-vue 并不是默认中文的组件库它的默认语言就是英文哪怕你整个网站都是中文产品也必须通过 ConfigProvider 传 locale 才能让内置组件文案变成中文。这篇文章我会从配置原理讲起把全局中文、日期组件本地化、按需引入、动态切换、常见翻车点全部讲清楚保证你看完照着做就能复现一套干净的中文界面。1. 为什么要单独设置中文ant-design-vue 的语言机制拆解1.1 默认英文背后的设计逻辑Ant Design 的 Vue 实现源自 Ant Design 的 React 版本而 Ant Design 是阿里系开源组件库却一直是英文默认的国际化组件库。这不是疏忽而是组件库的定位决定的它面向的不只是中文开发者而是全球用户。因此所有内置文案从分页器的 Page, Items per page到日期面板的 Today, Month, Year再到 Modal 的 OK 和 Cancel全部以英文为基准语言中文通过语言包来切换。这就带来一个非常常见的认知错位很多同学以为用 ant-design-vue 写中文网站不需要处理语言环境结果项目一上线日期选择器、空状态、确认框纷纷露馅。所以第一步是转变观念ant-design-vue 组件库本身是纯英文状态中文化不是默认能力而是你必须主动完成的配置。1.2 ConfigProvider全局配置的中枢入口ant-design-vue 在 v3 之后提供了 ConfigProvider 组件职责是向子树内的所有组件下发全局配置其中最重要的就是locale属性。它的工作方式很像 Vue 的provide/inject在组件树顶层传一个配置对象子组件通过注入拿到这些配置并据此渲染文案。这个设计有几个好处第一你不需要在每个组件上单独设置中文一处配置全树生效第二它支持嵌套覆盖比如某个页面需要特殊语言环境可以在局部再包一个 ConfigProvider 覆盖第三它可以结合响应式数据实现运行时切换语言而无需刷新页面。需要注意ConfigProvider 的locale只影响 ant-design-vue 组件自身的文案不会帮你把dayjs的日期语言也切了。日期选择器内部的日历面板一部分文案来自 ant-design-vue 的 locale比如确定按钮、清空按钮另一部分来自 dayjs 的语言设置比如月份名、星期名。所以完整的中文方案必须同时配置两个地方。1.3 三个语言层缺一不可我习惯把 ant-design-vue 的中文化拆成三个层级来看组件文案层由组件库的 locale 文件控制负责分页、弹窗、空状态、表格操作列等 UI 文案。日期底层层由 dayjs 的 locale 控制负责日期面板里月份、星期、时间段等格式。业务代码层你自己写的表单校验提示、模板文字、接口返回消息这部分组件库管不到。很多教程只讲了第一层导致日期选择器里月历还是英文其实就是漏了第二层。我自己在项目里还见过一个更隐蔽的问题dayjs的 locale 全局设置成功但某个日期范围选择器还是显示英文排查到最后发现是某个组件内部直接引入了dayjs()而非dayjs(locale)的实例这个问题我在第四节详细讲。2. 动手前必须确认的三件事版本、包形式、构建模式2.1 ant-design-vue 版本差异会直接影响配置写法ant-design-vue 在不同版本里中文 locale 的引入路径和组件名称有差异。我刚做项目时停留在 v1那时候组件库的包名结构、语言包路径都跟现在不一样。如果你在 v3/v4 项目里照着旧博客抄代码很容易出现Cannot find module或者配置不生效。当前主流的 v3/v4 版本语言包统一在ant-design-vue/es/locale/zh_CN组件是a-config-provider。但要注意 v2 及更早版本有些语言包路径还在ant-design-vue/lib/...下有些 ConfigProvider 属性命名也有区别。建议你开工前先在package.json里确认版本号再去node_modules/ant-design-vue目录里翻一翻locale目录是否存在、有哪些文件这样才不会瞎猜。2.2 全量引入和按需引入对配置的影响ant-design-vue 支持全量引入和按需引入两种方式。全量引入时直接import zhCN from ant-design-vue/es/locale/zh_CN就能拿到语言包对象。按需引入时很多项目会配合unplugin-vue-components自动按需注册组件这种情况下 ConfigProvider 本身也可能被自动导入你需要确保语言包独立导入。这里有一个常见的坑按需引入项目里如果你只在App.vue里包了a-config-provider但组件是自动导入的而 ConfigProvider 是手动引入的可能因为路径或别名不同导致出现两份组件包一份带 locale 配置一份不带最终界面上部分组件中文、部分组件英文。排查方法是用vue-devtools看组件实例是否渲染了 ConfigProvider 的属性或者直接在组件上临时写死:localezhCN验证。2.3 必须准备 dayjs 语言包ant-design-vue v3 开始内置了日期依赖 dayjs不再依赖 moment这是一个很重要的变化。dayjs 是极简化的日期库默认也是英文所以中文配置要单独加载dayjs/locale/zh-cn。需要注意两个细节第一加载语言包之后要用dayjs.locale(zh-cn)把它设为全局语言否则语言包文件只是被加载并没有生效第二dayjs.locale()是全局生效的如果你项目里有多个子应用或者需要多语言切换就得考虑局部 locale 用法也就是dayjs().locale(en)这种别让全局 locale 污染其他模块。3. 实操从零实现 ant-design-vue 组件中文配置3.1 最简方案在 App.vue 里配置全局中文这是最直接、最适合中小项目的做法。假设你的项目是 Vue3 Vite ant-design-vue v3/v4主入口文件通常长这样// main.ts import { createApp } from vue import App from ./App.vue // 完整引入组件库样式如果你是全量引入 import ant-design-vue/dist/reset.css const app createApp(App) app.mount(#app)接下来在App.vue里加入 ConfigProvider!-- App.vue -- script setup import zhCN from ant-design-vue/es/locale/zh_CN import dayjs from dayjs import dayjs/locale/zh-cn dayjs.locale(zh-cn) /script template a-config-provider :localezhCN RouterView / /a-config-provider /template这套配置做完ant-design-vue 的组件文案基本都会变中文。分页器会变成共 x 条每页 x 条弹窗按钮会变成确定取消空状态会变成暂无数据。但这里有个细节我要重点提醒dayjs.locale(zh-cn)写在外面不代表所有日期组件都一定用上。如果你某个组件直接导入了独立的 dayjs 实例而不走全局配置那这个组件还是英文。这种问题在用了某些第三方封装的日期组件时尤其常见。3.2 封装一个 LocaleProvider 组件集中管理语言状态如果你做的项目不止一个页面后续还可能做多语言切换那么把语言配置写死在 App.vue 里会越来越难维护。我更推荐的方式是封装一个LocaleProvider.vue把语言状态、dayjs 同步切换、ConfigProvider 下放集中管理。!-- components/LocaleProvider.vue -- script setup import { computed, ref } from vue import zhCN from ant-design-vue/es/locale/zh_CN import enUS from ant-design-vue/es/locale/en_US import dayjs from dayjs import dayjs/locale/zh-cn import dayjs/locale/en const localeMap { zh: { antd: zhCN, dayjs: zh-cn }, en: { antd: enUS, dayjs: en } } const currentLocale ref(zh) const antdLocale computed(() localeMap[currentLocale.value].antd) function changeLocale(lang) { currentLocale.value lang dayjs.locale(localeMap[lang].dayjs) } defineExpose({ changeLocale, currentLocale }) /script template a-config-provider :localeantdLocale slot / /a-config-provider /template然后你在App.vue里只需要这样用template LocaleProvider RouterView / /LocaleProvider /template这个封装的好处是后续做语言切换时只需要调用changeLocale方法ant-design-vue 的 locale 和 dayjs 的 locale 会同步切换不会出现界面按钮变英文了而日期面板还是中文这种割裂现象。我实际项目里还会在LocaleProvider里增加一个locale响应式对象通过provide提供给其他组件这样非 ant-design-vue 组件的业务文案也能跟着语言包走等于把国际化统一管理起来。3.3 按需引入场景下的配置变体按需引入是目前很多新项目的默认选择因为能大幅缩小打包体积。用unplugin-vue-components的方案时组件会自动按需加载但你仍然需要手动引入语言包和 dayjs 语言包。// vite.config.ts import Components from unplugin-vue-components/vite import { AntDesignVueResolver } from unplugin-vue-components/resolvers export default defineConfig({ plugins: [ // ...其他插件 Components({ resolvers: [ AntDesignVueResolver({ importStyle: less }) ] }) ] })这种情况下ConfigProvider 仍然可以写在 App.vue 里但需要注意的是zhCN这个语言包对象本身会引入整个 locale 文件属于一次性引入不会影响按需组件的收益。因为语言包本质上就是一个静态对象体积很小不必为此做二次拆分。另一个需要注意的地方如果你在组件里使用了App.use(antd)全量注册又在插件里配置了按需引入二者会冲突导致组件重复注册或样式丢失。实际踩坑时我还发现重复注册会破坏 ConfigProvider 的注入上下文某些组件拿不到语言包表现成部分中文化。正确做法是二选一推荐全按需。3.4 如何验证配置确实生效了配置完成后光靠肉眼容易漏看。我建议你在控制台里做一次快速抽查在某个页面上打开浏览器Vue插件查看ConfigProvider实例的locale属性展开后能看到一个类似{ locale: zh-cn, Pagination: { prev: 上一页, next: 下一页 } }的对象说明组件库语言包已注入。再抽查 dayjs在控制台执行dayjs().format(MMMM)如果返回二月而不是February说明日期语言包生效。这个验证方法在排查问题时会非常有用。4. 核心组件的中文细节日期、分页、弹窗、空状态、表格4.1 日期选择器不止是 ConfigProviderdayjs locale 必须同步日期选择器是全套组件里最容易出现“中英文混杂”的组件。界面上常见的现象是按钮和占位符都是中文一打开日历面板月份和星期变成英文。原因就是我前面说的日历面板里的月份、星期来自底层日期库不由组件库的 locale 控制。解决办法分两步。先引入组件库语言包确保按钮中文再引入并设置 dayjs 语言包。import zhCN from ant-design-vue/es/locale/zh_CN import dayjs from dayjs import dayjs/locale/zh-cn dayjs.locale(zh-cn)这样配置之后DatePicker 的月份会显示二月三月星期会显示一二三年份选择器也会显示2026年。这里我要强调另一个细节DatePicker 支持传入:localelocale属性吗答案是支持但这个 locale 属性是组件级别的会覆盖 ConfigProvider 的配置。项目里如果你在某个页面单独给 DatePicker 传了不完整的 locale 对象它可能会覆盖全局配置导致部分文案丢失。所以非必要不传组件级 locale全局配置最稳妥。4.2 分页器常见的中文案遗漏点分页器Pagination默认英文文案是Page、Items per page、Go to设置中文后会显示页、每页、跳至。这些文案来自组件库 locale所以只要 ConfigProvider 配置好就会生效。但要注意如果你自定义了showSizeChanger和showQuickJumper那这两块的文案也会受 locale 控制配置正确都会中文。还有一个实际开发中容易遇到的问题Pagination组件如果同时接收了total和showTotal自定义函数showTotal里返回的文案是你自己写的组件库管不到。比如你写showTotal{(total) 共 ${total} 条}那么这里已经是中文与 locale 无关。如果团队里有人用了showTotal但写的是英文模板那不管 locale 怎么配都是英文这种问题要靠代码规范约束。4.3 空状态、表格筛选、确认弹窗的默认文案空状态组件 Empty 的默认描述是暂无数据这个文案在组件库 locale 里。表格的筛选器默认按钮文字是确定/重置排序文字是升序/降序这些也都随 locale 切换。弹窗 Modal 的默认按钮是确定/取消Popconfirm 的默认按钮也是确定/取消。有些项目没有对这些做处理用户点击删除后弹窗英文按钮体验很突兀所以必须全局统一配置。我建议在项目里做一次组件文案复查清单像这样组件默认英文中文化后配置来源ModalOK / Cancel确定 / 取消组件库 localePopconfirmOK / Cancel确定 / 取消组件库 localePaginationPage / Items per page页 / 每页组件库 localeEmptyNo data暂无数据组件库 localeDatePickerFebruary / Monday二月 / 星期一dayjs localeTable filterOK / Reset确定 / 重置组件库 locale这样可以快速检查你自己项目里是否还有遗漏。4.4 Select、Upload、Transfer 等组件的内置文案Select 组件的暂无数据、Upload 的点击或将文件拖拽到此区域、Transfer 的搜索、TreeSelect 的请选择等这些组件的静态文案都受组件库 locale 影响。全局配置好之后通常不需要单独处理。但要注意a-select的notFoundContent属性可以自定义空状态内容如果项目里有人传入自定义的英文内容它会覆盖 locale 默认文案。这也是常见坑全局配置没问题单个组件却显示英文多半是局部属性覆盖了全局默认。碰到这种情况我的排查习惯是三步走先用浏览器开发工具选中该组件看它的 props 里是否传了notFoundContent、okText、cancelText等相关属性再看组件是否被嵌套在另一个局部的 ConfigProvider 里最后才考虑是不是版本或路径问题。5. 常见问题与排查技巧实录5.1 日期组件还是英文怎么办这是最高频的问题。按照我前面的分析日期组件文案来源有两处但还有一个容易忽略的点如果你在组件里自己写了import dayjs from dayjs然后又单独调用了dayjs.extend(...)此时 dayjs 的全局 locale 设置可能不受影响也可能会被某个插件重置。我遇到过一个场景项目里引入了某个第三方日期范围选择封装它内部引用了 core-js 里的 dayjs 副本跟我们项目里的 dayjs 不是同一个实例导致全局 locale 对那个组件无效。解决方案是检查package.json里是否同时存在多个 dayjs 版本用npm dedupe或者在打包配置里用resolve.alias强制指向同一个 dayjs 实例。如果确认只有一个 dayjs那问题基本就是没调用dayjs.locale(zh-cn)或者调用顺序在组件渲染之后。注意把 locale 初始化放在应用挂载之前最好而不是放在某个组件的onMounted里。5.2 ConfigProvider 配置了不生效可能原因盘点配置不生效有几个常见原因。首先是版本不匹配ant-design-vue的 locale 对象结构在不同大版本之间有差异你从 v2 旧项目拷贝的zh_CN对象塞到 v3 里某些属性名对不上组件自然读不到。建议总是从当前版本源码里导入语言包而不是从网上复制。其次是包引用混乱。项目里如果同时通过ant-design-vue主包和ant-design/icons-vue或某个二次封装包间接引用了 ant-design-vue会因为组件注册来源不同导致 ConfigProvider 上下文无法传递。排查方法是把node_modules/ant-design-vue复制出现多次的情况处理好确保依赖唯一。再次是没有正确嵌套。ConfigProvider 需要包裹真正用到组件的内容。如果你把a-config-provider放在了路由出口的下方或者某个子组件渲染在 Teleport 到 body 下那么 Teleport 出去的内容不在 ConfigProvider 的注入范围内需要给 Teleport 的目标容器单独再包一个 ConfigProvider。5.3 动态切换语言时如何保持联动实际产品中语言切换通常不止切换组件库文案还要切换 dayjs、路由守卫、axois 请求头、用户偏好存储等。我的做法是维护一个全局的语言状态例如用 Pinia// store/locale.ts import { defineStore } from pinia export const useLocaleStore defineStore(locale, { state: () ({ lang: localStorage.getItem(lang) || zh }), actions: { setLang(lang) { this.lang lang localStorage.setItem(lang, lang) } } })然后在 LocaleProvider 里监听这个状态变化时同步更新给 ConfigProvider 和 dayjs。使用响应式数据的好处是当语言切换时组件树会重新渲染所有文案都会立即刷新。这里有一个细节很多人忽略语言切换后如果页面里有已经弹出的 Modal 或 Drawer它们在语言切换前已经渲染好了可能不会刷新文案。这个时候需要手动关闭并重新打开这些浮层或者给浮层绑定一个key绑定语言变量强制重建。遇到这种业务场景我一般会让Modal或者Drawer的key等于当前语言这样切换语言时它们会重新挂载确保文案一致。5.4 表格工具栏和自定义插槽的“伪中文”问题ant-design-vue 的 Table 组件支持自定义工具栏区域很多项目会在 toolbar 里添加搜索框、刷新按钮、导出按钮。这些区域的内容完全由业务代码控制不代表组件库中文化。我见过不少项目因为全局 locale 配好了却忽略了工具栏里自己拼的英文按钮最终界面还是混着英文用户一反馈就怪到组件库头上。这种问题只能靠团队规范解决比如约定所有用户可见文案必须抽到语言包资源文件里或者在代码评审时用脚本扫描中文包不允许在组件模板里硬编码英文界面文案。另外要注意 Table 的默认插槽里如果使用customRender返回的 VNode 文案也属于业务代码层不会自动被中文化。6. 进阶建议把中文化做进团队规范里6.1 在项目初始化阶段就配置好别留到测试阶段我见过很多项目都是开发到一半才想起来要设置中文结果日期组件散落各处临时补配置容易遗漏。正确做法是在项目脚手架搭建阶段就把 ConfigProvider、dayjs locale、语言包状态管理这些基础配置一次性弄好后续新增页面默认就是中文不会出现组件行为不一致。6.2 在代码抽屉清单里加上语言检查每个迭代的测试用例里建议加入一项“检查页面内 ant-design-vue 组件是否有英文文案”并把 DatePicker 打开、Pagination 切换页、Modal 打开、Select 下拉打开这几项列为必查项。这些高频组件最容易在版本升级或局部覆盖时暴露出英文残留。6.3 防御性地处理版本升级ant-design-vue 升级时locale 对象结构有可能变化尤其是从 v3 升到 v4、或者将来升 v5。升级后第一件事就是核对 locale 目录下是否还有zh_CN以及引入路径是否有 break。我过去在升级时遇到过语言包路径从ant-design-vue/es/locale/zh_CN变为ant-design-vue/es/locale/zh_CN.js的情况由于构建工具不支持后缀缺省页面直接白屏。这种问题在发布前如果没跑到这个路径就不会暴露建议每次升级都跑一遍全局搜索。在写 ant-design-vue 组件中文化这个主题时我最想分享的一个经验是不要只盯着 ConfigProvider而是要建立起“组件库文案 日期库 locale 业务文案”三层思维把它当作一个全局基础设施来维护。实际项目中多语言切换、局部覆盖、版本升级这些问题都会不断挑战这个基础设施提前把它做扎实后面省下的时间成本远比你第一次配置时多得多。