文章目录
- 前言
前言
这个项目采用的是“轻量客户端 i18n”,目标是控制复杂度,而不是一开始引入完整国际化框架。
核心实现:
RootLayout->LocaleProvider->useLocale()->locale/setLocale/t(key)locale-provider.tsx 做三件事:
- 默认状态是
en,所以首次访问默认英文。 - 用
messages[locale][key]保存中英文文案,组件通过t("upload")取文案。 - 用户切换语言后写入
localStorage,并更新<html lang>。
language-switcher.tsx 是纯 UI 控件,只负责调用setLocale("en")或setLocale("zh-CN")。工作台和登录页共享同一个 Provider,因此切换后会一起刷新。
这套方案适合当前项目,因为页面少、语言只有两种、文本量有限,也不需要 SEO 按语言分发页面。
高级面试会问什么
为什么不用 next-intl?
答:当前需求只需中英文客户端切换,Context + 字典的依赖和维护成本最低。若需要/en、/zh-CN独立 URL、服务端按 locale 渲染、SEO、复数规则、日期货币格式、翻译文件按路由拆包,我会换成next-intl,并在路由层管理 locale。
为什么默认语言写在 useState,而不是读取 localStorage?
答:localStorage只能在浏览器访问。Next.js 会先服务端渲染;若首屏服务端按英文、浏览器首次渲染直接按 localStorage 中文,会产生 hydration mismatch。这里先稳定渲染英文,挂载后再读取用户偏好。
localStorage 保存语言有什么问题?
答:它只能用于客户端偏好,不会发送给服务器,不能让 SSR 首屏按用户语言渲染。需要 SSR 国际化时,应使用 URL locale、Cookie 或请求头Accept-Language。
为什么翻译 key 不直接写中文?
答:稳定 key 是业务语义,例如activityTitle、deleteWarning;组件不依赖任意语言文本。以后翻译文案变化、增加日语或接入翻译平台时,不需要改业务组件。
国际化中最容易遗漏什么?
答:不只是按钮文本,还包括:
aria-label、Tooltip、空状态、错误提示。- 日期、数字、文件大小、货币和复数规则。
<html lang>。- 服务端错误消息和邮件、通知等非前端渠道。
- 用户输入、文件名、后端领域数据不应被错误翻译。
本项目目前的局限?
答:后端错误信息仍保持原样;displayDate()目前固定为zh-CN,应该进一步接受 locale;翻译字典在客户端打包;没有 ICU 复数规则;没有 locale URL,因此 SEO 与 SSR 语言能力有限。
如何演进到生产级?
答:
Context 字典->按功能拆分 messages->Intl.DateTimeFormat/Intl.NumberFormat->Cookie 或/[locale]路由->next-intl 服务端与客户端翻译->翻译管理平台、缺失 key 检查、伪语言测试一句面试总结:
当前项目通过 Context 提供 locale 和翻译函数,默认英文并用 localStorage 持久化用户选择,适合轻量客户端国际化。生产级 Next.js 国际化则需要把 locale 纳入 URL 或 Cookie,在服务端确定首屏语言,并使用标准 Intl API 和成熟框架解决 SEO、格式化、复数与翻译资源管理。