news 2026/9/25 3:02:38

Comp AI CRM 多语言化改造方案(ADR):基于 next-intl 的目录化文案架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Comp AI CRM 多语言化改造方案(ADR):基于 next-intl 的目录化文案架构
  • 后端
  • 前端
  • CRM
  • 人工智能
  • AI Agent

【免费下载链接】crm

Comp AI CRM is an open source, CRM designed for AI agents. Agentic-first CRM.

项目地址:https://gitcode.com/gh_mirrors/crm48/crm
点击查看免费下载

这是一篇围绕仓库内 adrs/i18n.md 架构决策记录展开的技术解读。Comp AI CRM(项目根目录)目前将全部用户可见文案硬编码为英文,该 ADR 提出引入 next-intl 目录(catalog)机制,让"新增一种语言"从一次全局重构变成一次纯翻译提交。读完本文,你将掌握这套方案的设计边界(哪些字符串要进目录、哪些格式不翻译)、语言选择与路由策略(cookie +user.locale,不引入 URL segment)、packages/ui的零依赖设计、CI 强制检查与伪语言校验手段,以及约十个 PR 的渐进式落地路线。

一、背景与动机:为什么需要让 CRM 说多种语言

ADR 以真实使用场景开场:提案作者同时在越南的两家公司(一家初创、一家成熟企业)重度使用本 CRM。当前仓库里所有文案都硬编码为英文——打开 apps/app 下的任意页面组件,都能看到直接写在 JSX 里的句子。这种做法的直接后果是:

  • 本地化即 fork 风暴:想让某个地区使用自己的语言,就必须 fork 每一个渲染句子的文件;
  • 上游同步成本极高:一旦上游更新文案或组件结构,fork 后的本地化补丁需要重新逐文件对账,工作量巨大;
  • 社区贡献无入口:其他国家的用户即使愿意贡献语言包,也没有一个统一的、可被自动化校验的载体。

因此提案的核心诉求是:把"说另一种语言"从一次重构降级为一次翻译任务。这也是adrs/README.md所鼓励的提案格式——说明想改什么、为什么现有行为是问题、替代方案会破坏什么。

从当前仓库现状看,该 ADR 属于"提案待落地"状态:apps/app/package.json的依赖列表中尚没有next-intl,packages/db/prisma/schema.prisma的User模型也还没有locale列。文中所有方案描述均以 ADR 提案为准,并标注可对照的源码证据。

二、方案设计:一切用户可见字符串进入统一目录

2.1 目标范围:apps/app与packages/ui

提案明确圈定改造范围:apps/app和packages/ui中每一个用户可见字符串都必须经由目录(catalog)输出。这一范围覆盖了 Web 前端的所有渲染层——包括 app 目录 下的页面组件,以及 packages/ui/src/components 下的通用组件库。

这一约束非常彻底:不仅是页面正文,还包括可翻译的属性(translatable attributes),例如aria-label、placeholder、title等;以及toast 通知文案。当前仓库中 toast 是 sonner 驱动的,例如 create-company-sheet.tsx/[slug]/companies/create-company-sheet.tsx#L76-L89) 中的toast.success(\${company.name} added.`)与toast.error(error.message)`,这些都属于必须进入目录的字符串。

2.2 本轮只做英文:语言是翻译工作,不是重构

方案采用 next-intl 作为基础设施,但本轮只内置英文。这背后的设计意图值得注意:

"Strings only; date, number and currency formatting stay."

即只翻译字符串,不翻译格式。日期、数字、货币的呈现格式保持现状不动。从源码看,packages/ui的日历组件 calendar.tsx 已经通过react-day-picker的Locale类型与locale?.code参数支持了按区域设置格式化(如date.toLocaleString(locale?.code, { month: "short" })),说明"格式层"已有独立的国际化能力,与文案层天然解耦,这正是该边界可行性的底层依据。

之所以"英文优先",是为了把改造风险降到最低:渲染出的英文文本与改造前逐字一致,整个工作是"管道铺设(plumbing)"而非"文案校对(copy edit)"——CI 可以据此验证没有引入任何措辞变化。

2.3 语言选择与路由策略:cookie +user.locale,不要 URL segment

这是本方案最有个性的设计决策。常见的多语言站点会在 URL 上挂语言段(如/vi/companies)并配套 middleware 重写,但 ADR 明确拒绝这条路,理由是本应用整体位于登录墙之后:

  • 无 URL segment:不在路径中引入/en/、/vi/前缀;
  • 无 middleware:不为语言切换增加任何请求拦截逻辑;
  • 一个 cookie 加一个user.locale列即可:语言偏好存储在客户端 cookie(快速响应)+ 用户表列(持久化)。

当前仓库的 proxy.ts 展示了应用的门控结构:未登录请求会被重定向到/sign-in,登录后按 workspace 门控分流到[slug]路径。整个应用处于认证之后,因此语言偏好完全可以通过登录态携带,无需依赖 URL 暴露。从数据结构看,schema.prisma 的User模型当前还没有locale字段,这正是 ADR 提出要新增的列;而其下AppSetting单行 upsert 的读写模式(参见 packages/db/src/settings.ts 的SETTINGS_ID = "app"与upsert用法)可作为"设置类字段持久化"的现成参考实现。

三、packages/ui的零 i18n 依赖策略

ADR 对组件库提出了一条硬性约束:packages/ui不引入任何 i18n 依赖。

设计模式是:

  • 包内自带英文默认值:组件库本身直接书写英文文案,保持其独立可运行、可测试;
  • 通过 Provider 覆盖:由上层应用(apps/app)注入翻译覆盖,组件渲染时优先取注入的翻译,取不到则回退英文。

这样做的好处是双重的。其一,组件库保持纯净,任何不关心 i18n 的消费方(包括测试环境、文档演示)都能零成本使用;其二,将"翻译职责"收敛到应用层,packages/ui的消费者只需对接一个 provider 契约。这与上面日历组件locale作为可选 prop 透传的风格一致——组件库只提供"接缝",由上层决定注入什么。

四、强制检查:让目录成为唯一事实来源

只靠约定无法长期维持"所有文案进目录",因此 ADR 配套了两层强制执行机制:

4.1 CI 中的 AST 检查器

在 CI 中运行一个基于 AST(抽象语法树)的静态检查器,出现以下情况即构建失败:

  • 硬编码的 JSX 文本:例如直接写在 JSX 里的New company、Add company、Cancel(当前大量存在于 create-company-sheet.tsx/[slug]/companies/create-company-sheet.tsx#L41-L48) 这类组件中);
  • 可翻译属性:placeholder、aria-label等属性上的硬编码字符串;
  • toast 文案:sonner 的toast.success(...)/toast.error(...)传入的字面量。

该检查器的存在意味着每新增一个字符串都必须进入目录,否则 CI 失败——文案的"单一来源"由机制保证,而非开发者的自觉。这与仓库现有工程纪律一脉相承:仓库内已有自定义 oxlint 插件集(见 tools/oxlint/anti-slop),通过@oxlint/plugins定义了一系列拒绝低质量模式的规则,说明"以自定义静态检查约束代码模式"在该项目中是成熟的实践路径。

4.2 伪语言(pseudo-locale)兜底

静态分析无法发现所有问题——比如字符串拼接、隐式插值、运行时才暴露的硬编码。为此 ADR 提出伪语言校验:用一套刻意加长的伪翻译(例如把每个字符替换为带重音符号的变体并拉长文本)渲染整个应用,人工或截图对比即可发现:

  • 哪些文案没有被目录接管(仍显示纯英文);
  • 哪些布局在文本变长后会溢出、截断或错位(硬编码宽度/固定高度的隐患)。

这层校验捕捉的是"静态分析看不到的东西",两者互补形成完整防线。

五、成本与取舍

ADR 不回避代价,明确列出两条:

  1. /(落地页)放弃完整静态预渲染,改为输出一个静态外壳(static shell),动态部分(如语言偏好)在客户端解析。当前落地页 page.tsx/page.tsx#L11-L15) 是带metadata的纯静态页面,改造后其预渲染范围会收窄;
  2. 其他预渲染路由保持原有预渲染能力——只有依赖 cookie 的页面受影响,不会波及全部路由。这里可参考apps/app/lib/env.ts的isMarketing()逻辑(IS_MARKETING环境变量控制落地页是否对外公开,见 env.ts),落地页与非营销页面本就分流处理,改造影响面可控。

其余成本约束包括:每个新字符串必须进目录否则 CI 失败;英文保持唯一内置语言;语言包以贡献形式合入,缺失的 key 按字符串粒度回退到英文,因此发布流程永远不必等待某一种翻译完成。

六、落地路线:约十个 PR,渐进式推进

ADR 给出的执行计划是分片落地、每片小且绿(small and green):

  • 第 1 片:基础设施——引入 next-intl、搭建目录结构与 Provider、建立 CI 检查器与伪语言管线;
  • 后续 N 片:按功能区域逐个提取文案——公司/联系人/商机/设置/仪表盘等模块各自一个 PR,将硬编码英文迁移进目录;
  • 全部改造已在提案作者的 fork 上验证运行。

最终形态是:英文是唯一内置语言,越南语作为第一个社区语言包由提案作者贡献,并附带"如何用编码 Agent 最高效地翻译语言包"的指南——这也呼应了本仓库 apps/agent 所代表的 Agent 优先定位:翻译工作本身也可借助 Agent 完成。

从仓库现状看,apps/app 下还有大量待迁移的硬编码文案(例如各处 settings 页面的按钮、表格、sheet 标题),这与 ADR 描述的"本轮全量英文迁移"工作量一致;而 packages/ui 的组件文本同样如此。任何贡献者若想跟进该方案,都可以从"基础设施 PR"或"单个模块的提取 PR"入手,并遵守目录 key 的命名约定与 CI 检查。

七、总结:一份可以照着实现的 i18n 决策记录

这份 ADR 的价值在于它把"多语言支持"这个常见但容易失控的需求,收敛成了一组清晰、可执行、有边界的决策:

决策点方案
基础设施next-intl 目录(catalog),本轮仅内置英文
翻译边界只翻译字符串;日期、数字、货币格式保持现状
语言选择cookie +user.locale列;无 URL segment、无 middleware
组件库策略packages/ui零 i18n 依赖:英文默认值 + Provider 覆盖
强制机制CI AST 检查器(JSX 文本/可翻译属性/toast)+ 伪语言兜底
回退策略缺失 key 按字符串粒度回退英文,发布不等待翻译
性能取舍/转为静态外壳,其余预渲染路由保持
落地节奏约十个 PR:基础设施先行,再按模块分片提取

对想要参与 Comp AI CRM 的开发者而言,这份文档既是一份待执行的技术蓝图,也提供了清晰的第一贡献入口;对任何正在为"Agent 优先"产品设计多语言方案的技术团队,它则是一份可迁移的决策模板——尤其是"语言是翻译工作而非重构"与"静态检查 + 伪语言双重防线"这两个判断,值得直接复用。

  • 后端
  • 前端
  • CRM
  • 人工智能
  • AI Agent

【免费下载链接】crm

Comp AI CRM is an open source, CRM designed for AI agents. Agentic-first CRM.

项目地址:https://gitcode.com/gh_mirrors/crm48/crm
点击查看免费下载
上一篇:C++ Insights属性语法解析:GNU和标准属性的区别
下一篇:VideoSrt字幕文件处理:SRT格式解析与批量翻译转换终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 3:02:34

本地开发接入Jev模型:TaoToken测试Key的配置与踩坑实践

最近在本地做一个 Jev 接入的小项目,要敲定开发阶段的接入方案,结果卡在一个非常典型的决策上:TaoToken 那边只发测试 Key,正式环境的 Key 暂时拿不到。很多人遇到这种情况,第一反应就是“那怎么搞,没法联调…

作者头像 李华
网站建设 2026/9/25 3:02:30

DeepSeek V4.1 Flash内测实操指南:API接入、Codex配置与64GB内存临界验证

1. 这不是“又一个大模型API接入教程”,而是V4.1 Flash内测期的真实水位线DeepSeek V4.1 Flash刚放出内测通道时,我第一时间填了申请表——不是冲着“最新版”这个名头,而是被它官网技术文档里一句轻描淡写的“64GB内存可本地承载全量推理”钉…

作者头像 李华
网站建设 2026/9/25 3:01:32

MindSpeed LLM支持哪些模型?Qwen3/DeepSeek/GLM等100+大模型清单全解

MindSpeed LLM支持哪些模型?Qwen3/DeepSeek/GLM等100大模型清单全解 【免费下载链接】MindSpeed-LLM 昇腾LLM分布式训练框架 项目地址: https://gitcode.com/Ascend/MindSpeed-LLM MindSpeed LLM 是面向华为昇腾(Ascend)芯片生态的大语…

作者头像 李华