第4章 资源文件管理:JSON/YAML/Properties格式选择、文件目录结构设计、命名规范
资源文件管理这事儿,看着简单,其实坑不少。我见过太多项目,一开始随便选个格式,目录结构随性一搭,结果到了后期维护成本直线飙升。今天咱们就聊聊这块,把我这些年踩过的坑和总结的经验都倒出来。
4.1 三种格式的选型:JSON、YAML、Properties
先说结论:没有银弹。每种格式都有自己的脾气,选对了事半功倍,选错了天天加班。
| 特性 | JSON | YAML | Properties |
|---|---|---|---|
| 可读性 | 中等 | 优秀 | 良好 |
| 层级支持 | 原生支持 | 原生支持 | 需约定(如用点号) |
| 注释支持 | 不支持 | 支持 | 支持(#号) |
| 多语言场景 | 适合 | 适合 | 传统Java项目常用 |
| 工具链成熟度 | 极高 | 高 | 中等 |
我的建议:
- 前端项目:优先用JSON。浏览器原生支持,解析零成本。
- 后端Java项目:Properties依然能打,但YAML更适合复杂配置。
- 配置文件需要写注释的:别选JSON,选YAML或Properties。
我在项目中遇到过一件事:有个团队用JSON做多语言文件,结果翻译人员看不懂嵌套结构,经常把括号搞丢。后来换成YAML,翻译同事直接上手,再也没出过格式错误。你想想看,工具选对了,沟通成本能降一大截。
4.2 文件目录结构设计
目录结构这事儿,说白了就是给资源文件找个家。家找对了,找东西方便;家找错了,翻箱倒柜都找不到。
我个人习惯用这种结构:
locales/
├── en/
│ ├── common.json
│ ├── login.json
│ ├── dashboard.json
│ └── errors.json
├── zh-CN/
│ ├── common.json
│ ├── login.json
│ ├── dashboard.json
│ └── errors.json
├── ja/
│ ├── common.json
│ ├── login.json
│ ├── dashboard.json
│ └── errors.json
└── index.js // 统一导出入口
为什么要按语言分文件夹?嗯,这里要注意:
- 按语言分文件夹:方便CI/CD按需打包。比如只部署中文版时,直接忽略其他文件夹。
- 按模块分文件:避免单个文件过大。我见过一个项目把所有中文翻译塞进一个文件,足足5000行,每次改个文案都要搜索半天。
- 统一入口文件:方便做懒加载。比如用户切换到日语时,只加载ja文件夹下的内容。
小技巧:文件名尽量用短横线命名法(kebab-case)。比如user-profile.json,而不是userProfile.json或user_profile.json。为什么?因为文件系统对大小写敏感的问题,在Linux上容易翻车。
4.3 命名规范:别让命名成为技术债
命名规范这事儿,我曾经吃过亏。早期一个项目,翻译key命名随心所欲,有的用驼峰,有的用下划线,有的直接用中文拼音。结果到了后期,想找个文案,得全局搜索半天。
我总结了一套规则,用了好几年,团队反馈不错:
// 推荐格式:[模块].[子模块].[具体描述]
{
"login.title": "登录",
"login.username.placeholder": "请输入用户名",
"login.password.placeholder": "请输入密码",
"login.button.submit": "提交",
"login.error.invalid_credentials": "用户名或密码错误"
}
规则要点:
- 用点号分隔层级:清晰表达从属关系。比如
login.error.invalid_credentials,一看就知道是登录模块下的错误信息。 - 统一用英文小写:避免大小写问题。翻译key不是给人看的,是给代码用的,小写最安全。
- 描述性要强:
login.button.submit比login.btn1好一万倍。你想想看,半年后你回来改代码,看到btn1是什么鬼? - 避免数字后缀:
title1、title2这种命名,迟早会出问题。用语义化的描述代替。
避坑指南:我曾经在一个项目里看到有人用common.ok、common.cancel这种命名。乍一看没问题,但后来需求变了,有的页面"确定"要改成"我知道了",有的页面保持"确定"。结果因为key太通用,改一个全变了。正确的做法是按页面或组件细分:dialog.confirm.ok、dialog.info.got_it。
4.4 实战:一个完整的资源文件示例
说了这么多理论,咱们看个实际例子。这是一个登录页面的多语言文件:
// zh-CN/login.json
{
"login.page.title": "欢迎回来",
"login.page.subtitle": "请登录您的账户",
"login.form.username.label": "用户名",
"login.form.username.placeholder": "请输入邮箱或手机号",
"login.form.password.label": "密码",
"login.form.password.placeholder": "请输入密码",
"login.form.remember_me": "记住我",
"login.form.forgot_password": "忘记密码?",
"login.button.submit": "登录",
"login.button.loading": "登录中...",
"login.error.required": "请填写所有必填项",
"login.error.invalid_email": "邮箱格式不正确",
"login.error.too_many_attempts": "登录尝试次数过多,请{minutes}分钟后再试"
}
// en/login.json
{
"login.page.title": "Welcome Back",
"login.page.subtitle": "Sign in to your account",
"login.form.username.label": "Username",
"login.form.username.placeholder": "Enter email or phone",
"login.form.password.label": "Password",
"login.form.password.placeholder": "Enter your password",
"login.form.remember_me": "Remember me",
"login.form.forgot_password": "Forgot password?",
"login.button.submit": "Sign In",
"login.button.loading": "Signing in...",
"login.error.required": "Please fill in all required fields",
"login.error.invalid_email": "Invalid email format",
"login.error.too_many_attempts": "Too many attempts. Please try again in {minutes} minutes"
}
注意看几个细节:
- 占位符用
{minutes}这种花括号语法,方便动态替换。 - 错误信息单独归类到
login.error下,方便统一管理。 - 按钮状态分
submit和loading,避免在代码里拼接字符串。
4.5 工具链推荐
光有规范还不够,工具也得跟上。我常用的几个:
- i18next-scanner:自动扫描代码中的翻译key,生成资源文件。省去手动维护的麻烦。
- FormatJS CLI:检查资源文件是否有遗漏的key,避免上线后出现英文文案。
- Lokalise / Crowdin:如果团队有专业翻译人员,用这些平台管理翻译流程,比直接改JSON文件靠谱得多。
最后说一句:资源文件管理这事儿,前期多花点心思,后期能省下大把时间。别等到项目上线了,才发现翻译key乱成一锅粥,那时候再改就晚了。