良好实践

网页

使用 Markdown 模式可以提高可读性并简化维护,这对译者和您的网站脚本(用于提取内容)都很有益。
对于多语言网站中的命名锚点,一种有趣的方法是使用 Markdown 设计“硬编码”链接。
例如:对于带锚点的 <h2/> 标签

当前语言标签

LLM 在保护链接方面比人类更有效,LSDE 允许您检测不同语言版本之间的问题。
因此,您可以共享一个在所有语言中都有效的链接,并使用 LSDE 来管理废弃锚点的替换。


代码歧义

在使用数据驱动模型时,避免歧义。
示例:
不良实践: 术语 'key' 不明确,导致难以查找。

ts
const PRODUCTS: Product[] = [
	{
		id: 'fcf7o',
		logo: '/icons/fcf7o-icon-40.webp',
		label: 'FCF7O',
		key: 'game:fcf7o.words.game_title',
	},
	{
		id: 'lsde',
		logo: '/icons/lsde-icon-40.webp',
		label: '<c1>LSDE</c1>',
		key: 'software:lsde.name',
	},
	{
		id: 'lsge',
		logo: '/icons/lsge.webp',
		label: 'LSGE',
		key: 'software:lsge.name',
	},
];


良好实践: 采用单一且一致的约定。
术语 i18nKey 非常明确,可以通过正则表达式(Regex)精确查找此值。
ts
const PRODUCTS: Product[] = [
	{
		id: 'fcf7o',
		logo: '/icons/fcf7o-icon-40.webp',
		label: 'FCF7O',
		i18nKey: 'game:fcf7o.words.game_title',
	},
	{
		id: 'lsde',
		logo: '/icons/lsde-icon-40.webp',
		label: '<c1>LSDE</c1>',
		i18nKey: 'software:lsde.name',
	},
	{
		id: 'lsge',
		logo: '/icons/lsge.webp',
		label: 'LSGE',
		i18nKey: 'software:lsge.name',
	},
];




懒惰

糟糕的想法源于懒惰。

不要试图通过执行操作来检索内容,从而节省键。
示例:
javascript
const [title, subtitle] = t( 'game:game.title' ).split( /[::]/ );

这是一个伪好主意,因为在某些语言中,字符可能不同,词序也可能改变。



标签格式

最大限度地减少直接在文本中用于设计的代码,以便从代码库中对其进行控制。
例如,您可以指示图像的位置,但不能指示其样式或渲染方式。
如果您必须进行设计更改,您肯定不想仅仅为了更改标签样式而被迫将文本重新翻译成 10 种语言!

标签可以包含一个标识符,但通常强烈不建议添加额外信息,这是一种不良实践。
示例:不要这样做
<img src='url' left />
而是这样做
<img id=1 />
然后您将获取图像标签的 ID,以便在代码库中应用所需的样式。
ID 应该按字面意思使用,而不是通过它们的索引。
因为在不同的语言中,标签可能会被移动,不再与初始索引对应。
使用自然索引还会给开发人员带来复杂性;试图猜测图像或标签对应的索引是一个真正的难题。
因此,当您希望在插值后能够自定义标签时,请使用带标识符的标签。



CSS

对于网站翻译,当您有段落时,请在翻译后选择最小高度 (`min-height`),以避免在语言切换时出现视觉偏移。
例如:`mih={'3lh'}`
这允许您根据占用行数最多的语言定义最小高度,从而确保一致且简洁的用户体验(UX)。

命名空间


始终在您的翻译键中包含“命名空间”,即使您只有一个。
这极大地简化了设置正则表达式模式以查找您的键的过程。
例如:game:a.b.c, common:a.b.c

GIT 版本控制

.lsde 项目是 JSON 格式的文件,这使得它们非常易于使用 Git 等工具进行版本管理。
强烈建议将您的项目保存在 Git 仓库中,以获得完整的历史记录并提高安全性。
虽然 LSDE 内置了自己的备份系统,但使用 Git 仍然是管理数据文件的最佳方案。

上下文与编写

为每个键提供清晰的上下文
明确的上下文可以存在于键名、访问路径(层级结构)、相邻项(父/子键)或元数据中。
避免使用会产生歧义并导致猜测的键。如果读取一个键需要去代码中验证其用途,那么说明您的数据架构需要改进。

明确的键示例:
game:.scenes.001.events.001.1
game:.scenes.001.events.001.2
game:.scenes.the-ice-land.events.the-lost-house.1
game:.scenes.the-ice-land.events.the-lost-house.2
game:.ui.menus.new-game.label
game:.ui.menus.new-game.description

这些键能让人立刻明白它们指向的是对话或界面元素。
前两个使用了数字标识符(ID):这对于美术设计(DA)灵活且可能在不影响技术结构的情况下演进的动作游戏来说是一种高效的方法。
接下来的两个使用了语义化 ID:对于内容与代码紧密相关的叙事类游戏来说必不可少。这可以避免破坏叙事与游戏逻辑之间的耦合。
最后两个清楚地描述了菜单元素(标签和描述)。

不良实践示例:
game:events.001.1(太模糊:这个事件在哪里使用?)
game:.scenes-events-the-lost-house.1(路径冗余)
game:.ui-menus.new-game-label(不必要的拼接)

避免在路径中出现冗余。如果您需要简化搜索,与其破坏 JSON 数据的结构,不如导出一个包含拼接键的类型文件。

避免对隐性上下文的任何依赖
一个字符串绝不应依赖外部元素(屏幕位置、颜色、图标)才能被理解。
例如:避免使用
"点击此处继续"
优选
"继续前往支付"
即使脱离用户界面(UI),文本也必须保持可理解性。
某些语言可能没有对应的翻译,或者根据动作和文本位置会有不同的表述方式。
动作文本必须描述动作和对象:“前往支付”、“下载 PDF 报告”,而不是不加说明的“点击此处”或“了解更多”。

避免句子碎片化和过度模块化
不要将编程原则(如 S.O.L.I.D.)搬到 i18n 内容编写中。编写和代码是不同的学科。
优先使用完整的句子而非片段,因为每种语言都有其独特的语法。
虽然像 `i18next` 这样的框架支持嵌套(“nesting”),但这通常会产生不必要的复杂性。如果需要变化,请完整重写句子。将插值限制在简单的变量上,如姓名或数字。

注明显示限制 (UI)
如果界面有字符限制或长度约束,请在元数据中注明并提供视觉参考(截图或原型图)。
翻译人员根据限制性界面调整文本,要比程序员为世界上所有语言制作动态 UI 简单得多。将这种管理交给编写者可以确保更好的用户体验(UX)。

禁止未经控制的表情符号 (emojis)
不要直接在文本中插入特殊字符或表情符号。
请通过变量(例如:<t title=)进行操作,以便通过代码控制它们的渲染。表情符号的渲染效果会因操作系统和用户环境的不同而有很大差异。

避免文化隐喻
在通用字符串中应避免使用习语、谐音梗和本土隐喻。
在一种语言中很清晰的内容,在另一种语言中可能会变得荒谬或无法翻译。

假设翻译人员看不到应用程序
编写时请假设翻译人员既无法访问代码也无法查看 UI。
理解所需的一切信息都必须存在于键名、其层级结构或元数据中。

I18n 技术


命名且明确的占位符
相比于位置索引(`{0}`, `{1}`),优先使用命名占位符(`{username}`, `{count}`)。LSDE 提供了一个专门的变量部分,用于定义它们的上下文并确保在项目中的可追溯性。

每个概念一个占位符
每个占位符都必须是原子化的,并代表一个唯一的数据(姓名、日期、数字)。避免使用通用或多态变量,以免增加翻译和理解的难度。

RTL (Right-to-Left) 兼容性
预先考虑从右至左书写语言的显示效果。渲染应保持流畅且结构正确,无需手动修改字符串。

禁止字符串拼接
切勿通过组合多个翻译键来构造句子。为了遵循每种语言特有的句法和语法规则,每个完整的句子都必须对应一个唯一的键。