- 后端
- 开发工具
【免费下载链接】weblate
Web based localization tool with tight version control integration.
本篇技术指南聚焦 Weblate 开源本地化平台(Web based localization tool with tight version control integration)的翻译管理工作流,系统讲解如何向组件添加新字符串、新增/删除翻译语言、利用字符串变体(Variants)分组翻译以及用标签(Labels)分类管理词条。读者阅读完本篇后,将掌握组件配置项(如new_base、new_lang、language_code_style、variant_regex)的完整语义与取值范围,并能结合源码理解 Weblate 底层如何生成语言文件、计算变体分组与维护标签数据。本文以 docs/devel/translations.rst 为骨架,辅以 Component 模型、Variant 模型、Label 模型 及对应测试进行纵深印证。
一、添加新字符串:从基础文件到 Weblate 内部管理
1.1 新字符串的来源:组件基础文件(new_base)
在 Weblate 中,新字符串默认不会凭空产生,而是来源于组件的基础文件(base file)。当字符串出现在基础文件中,它们即可被翻译;该基础文件的路径由组件配置项new_base指定,其字段定义位于 component.py:
new_base = models.CharField( verbose_name=gettext_lazy("Template for new translations"), max_length=FILENAME_LENGTH, blank=True, help_text=gettext_lazy( "Filename of file used for creating new translations. " "For gettext choose .pot file." ), validators=[validate_filename], )几个关键点:
- 对于gettext 格式(
.po),建议选择.pot模板文件作为new_base,因为 pot 只含源字符串,是天然的“待翻译清单”; - 对于大多数单语(monolingual)翻译流,例如 Android 资源、JSON 等格式,通常不需要独立的基础文件,可以从空文件开始,新字符串由开发者写入源文件后同步进 Weblate;
blank=True表示该字段可留空,此时 Weblate 是否能够创建新翻译文件取决于文件格式是否支持“空文件起步”。
1.2 在 Weblate 内直接添加字符串
对于大多数文件格式,Weblate 支持直接在现有文件中添加新字符串(前提是组件启用了对应能力,见后文manage_units)。添加时可以设置以下选项:
- Context(上下文):适用于双语(bilingual)格式,用来区分在不同上下文中出现的相同字符串。例如 gettext 中同一个英文文本出现在不同 msgctxt 下,就靠 Context 区分;
- Auto-adjust context when an identical string already exists(当已存在相同字符串时自动调整上下文):开启后,若目标字符串已存在于翻译中,Weblate 会自动为 Context 追加数字后缀,避免冲突。例如已存在
Context,自动生成Context (1)、Context (2)。
关于 Context 在各文件格式中的具体语义,可进一步参阅 文件格式文档 中针对各格式的说明(如 gettext 格式、xliff 格式)。
1.3 底层支撑:manage_units 与内部单元管理
“在 Weblate 内直接增删字符串”依赖组件的manage_units开关,其定义同样位于 component.py:
manage_units = models.BooleanField( verbose_name=gettext_lazy("Manage strings"), default=False, help_text=gettext_lazy( "Enables adding, removing, and editing source strings and keys in Weblate. If your " "strings are extracted from the source code or managed externally you ..." ), )从源码结构看,该开关默认关闭(default=False),因为多数项目的源字符串由代码仓库统一管理;只有当团队希望把字符串维护工作也搬进 Weblate 时(例如纯运营团队维护文案),才应开启。开关开启后,翻译界面中的“工具(Tools)”菜单才会提供增删字符串的入口,这与后文“手动添加变体”“移除字符串”等能力是配套的。
二、添加新翻译:语言文件的生命周期
2.1 请求模式:new_lang 的五种行为
当用户请求为组件添加一种新语言时,Weblate 的行为由组件配置new_lang控制。该字段在 component.py 中定义,可选值及其文案定义在 inherited_settings.py:
| 取值 | 行为说明 |
|---|---|
contact | 联系维护者(需要人工介入处理) |
url | 指向翻译说明 URL(引导用户查看项目说明文档) |
add | 直接创建新的语言文件(默认值) |
existing | 仅创建项目已有语言;新语言需联系维护者 |
none | 禁用添加新翻译 |
其中none与url属于“禁用模式”,inherited_settings.py 中还定义了DISABLED_NEW_LANGUAGE_MODES = ("none", "url")以及复杂的继承过滤逻辑,用于在项目/分类/组件三层继承结构中正确识别哪些组件不允许新增语言。
同时,new_lang与language_code_style等配置一样支持继承(inherit_new_lang字段,默认True),即组件可继承其所属分类或项目的设置,覆盖后即断开继承,详见 INHERITABLE_COMPONENT_SETTINGS。
2.2 新语言文件如何生成:格式差异与 new_base 的作用
不同的文件格式对“新语言文件”的初始化方式差异很大,文档中列举了典型场景:
- 只包含已翻译字符串:部分格式期望新语言文件为空文件、仅收录翻译过的字符串,例如Android 资源(见 android.rst);
- 包含全部键:另一些格式期望所有键(keys)都存在于每个语言文件中,例如gettext(见 gettext.rst);
- 复制源文档并标记待编辑:基于文档的格式(例如ODF 电子表格/文档,见 odf.rst)会以源文档的副本作为起点,其中所有字符串被标记为“需要编辑”;
- 取决于处理框架:某些情况下行为并不取决于格式本身,而是取决于你处理翻译的框架约定,例如JSON(见 json.rst)在不同生态中两种做法都存在。
配置new_base后,Weblate 会以该文件为模板启动新翻译——注意:启动时会从该文件中移除所有已有的翻译内容(它只用作模板,不保留译文)。若new_base为空且文件格式支持,则创建空文件,新字符串在翻译完成后按需追加写入。
源码层面,Component.add_new_language()(component.py)完整实现了上述流程,其关键调用链为:
can_add_new_language()检查当前用户与语言是否被允许(component.py);format_new_language_code(language)计算生成的文件语言代码(component.py);- 通过
language_regex正则校验语言代码合法性,超时会记录Component language filter timed out错误; - 调用
file_format_cls.get_language_filename(self.filemask, code)解析目标文件名,然后file_format.add_language(fullname, language, base_filename, ...)在仓库锁内创建文件; - 发出
translation_post_add信号,并执行translation.git_commit(...)提交,最终触发对新增文件的解析。
2.3 语言代码样式与语言别名
新语言文件的文件名由组件配置language_code_style决定,该字段定义于 component.py,可选值多达 14 种(inherited_settings.py):
| 取值 | 样式说明 |
|---|---|
| (空) | 默认,基于文件格式 |
posix | POSIX 风格,下划线分隔 |
posix_lowercase | POSIX 风格,下划线分隔,小写 |
bcp | BCP 风格,连字符分隔 |
posix_long | POSIX 风格,含国家代码 |
posix_long_lowercase | POSIX 风格,含国家代码,小写 |
bcp_long | BCP 风格,含国家代码 |
bcp_legacy | BCP 风格,旧语言代码 |
bcp_lower | BCP 风格,连字符分隔,小写 |
android | Android 风格 |
appstore | Apple App Store 元数据风格 |
googleplay | Google Play 元数据风格 |
linux | Linux 风格 |
linux_lowercase | Linux 风格,小写 |
此外,项目级配置language_aliases(语言别名)会被反向应用:即如果别名把zh-Hant映射到zh_Hant,那么生成文件名时会把计算出的zh_Hant反解回zh-Hant。这一逻辑在format_new_language_code()中可见:
def format_new_language_code(self, language): code = self.file_format_cls.get_language_code( language.code, self.effective_language_code_style ) # Apply language aliases language_aliases = {v: k for k, v in self.project.language_aliases_dict.items()} if code in language_aliases: code = language_aliases[code] return code反向别名映射正是为了让生成的仓库文件名符合团队约定(例如仓库历史上一直使用 BCP 风格的pt-BR而非 POSIX 的pt_BR)。语言代码的解析规则可进一步参考 语言代码解析 与 语言代码风格配置。
2.4 通过远程仓库添加语言文件
如果在连接的远程仓库中直接新增了语言文件,那么当 Weblate 更新本地仓库(触发sync_git_repo/update_branch流程)时,对应翻译会自动被加入组件——无需在 Weblate 界面重复操作。仓库更新行为由 VCS 更新配置控制,详见 VCS 相关文档 与 连续翻译/自动更新。
三、移除现有翻译
3.1 删除语言、组件或项目
语言(Language)、组件(Component)或其所属项目(Project)都可以从 Weblate 中删除,操作入口统一在对应对象的菜单Operations(操作)→ Removal(移除)。发起移除后,界面会列出将被删除的组件清单,并要求输入对象的slug进行确认——slug即该对象的路径名,可从其 URL 中直接看到。确认后删除生效,若组件关联了远程仓库,相关文件也会随之从仓库移除。
3.2 删除部分字符串的两种方式
如果只想删除个别字符串(而非整个语言/组件),文档给出两条路径:
- 在源文件中手动删除:直接在仓库的源文件中移除该字符串,Weblate 在后续仓库更新时会将对应词条从翻译项目中同步移除;
- 在 Weblate 界面删除(4.5 版本新增):编辑字符串时,通过Operations(操作)→ Remove(移除)按钮删除。该能力在不同文件格式下的表现有差异,具体取决于组件的
manage_units配置(component.py),因为“在 Weblate 内删除词条”本质上与“管理字符串”是同一能力体系。
与 2.4 对称:若在远程仓库中删除语言文件,Weblate 更新本地仓库后,相应翻译也会从组件中移除。
从源码看,字符串删除最终会落在 Translation 的删除方法(如translation.delete_unit,见 test_variants.py 中通过translation.delete_unit(None, unit)删除单元后变体计数归零的测试),删除后 Weblate 会清理关联的变体、标签与统计缓存。
四、字符串变体(Variants):把相关词条聚成一簇
4.1 变体的价值
变体(Variants)用于把若干相似/相关的字符串聚合在一起,让译者在同一个地方看到某一词条的所有变体,从而保证译法一致性。典型的例子是缩写(abbreviation):monthShort(月份缩写)与month(完整月份)在翻译时应保持同一套术语体系。
4.2 自动变体:基于键的正则表达式
对于单语翻译,可在组件配置中设置variant_regex正则表达式,Weblate 会自动按翻译键(Key)分组生成变体。该字段定义在 component.py:
variant_regex = RegexField( verbose_name=gettext_lazy("Variants regular expression"), validators=[validate_re_nonempty], max_length=190, default="", blank=True, help_text=gettext_lazy( "Regular expression used to determine variants of a string." ), )工作机制:当某个翻译键匹配该正则时,匹配部分会被移除,得到根键(root key);所有拥有相同根键的字符串(包括键恰好等于根键的那条)构成一个变体组。
在组件配置中定义变体正则表达式,Weblate 据此自动为单语翻译分组。
文档给出了两个典型示例:
| 使用场景 | 正则表达式 | 被匹配的翻译键 |
|---|---|---|
| 后缀识别 | (Short|Min)$ | monthShort、monthMin、month |
| 内联识别 | #[SML] | dial#S.key、dial#M.key、dial.key |
后缀识别示例:正则(Short|Min)$匹配monthShort与monthMin,移除匹配部分后根键都是month,而month本身也恰好等于根键,于是三者归入同一变体组。内联识别示例:#[SML]匹配dial#S.key、dial#M.key中的#S/#M,根键为dial.key,三条键聚为一组。
测试 test_variants.py 验证了该行为:为组件设置variant_regex = "(Min|Short|Max)$"并添加bar、barMin、barShort三个单元后,Variant.objects.count() == 1且该变体组的unit_set.count() == 6(单语组件中每个键同时存在于源语言与目标语言,故 3 键 × 2 语言 = 6 个单元);清除正则后变体记录归零。内联场景测试则验证了//(SCRTEXT_S|SCRTEXT_M|...)这类键中部匹配的正则同样生效。
4.3 手动变体:variant:SOURCE 标志
自动正则依赖“键”的存在,因此双语格式(bilingual)或键名互不匹配的字符串无法自动分组。为此,Weblate 4.5 起支持手动变体:为字符串设置variant:SOURCE标志即可把它与SOURCE这条字符串链接为变体。
- 用法:在字符串的额外标志(extra flags)中写入
variant:'Default string'(注意 SOURCE 需加引号,内容为源字符串文本); - 适用场景:双语翻译中键不存在的场合,或键不同但翻译时应当一起考虑的字符串;
- 硬性限制:变体源字符串最长 768 字符(超出无法作为变体源);
- 快捷入口:当组件开启
manage_units时,翻译过程中可通过Tools(工具)菜单为字符串追加额外变体; - 清理机制:移除标志后变体自动解散;若某变体组中最后一个定义单元被删除,变体记录随之删除(见 test_variants.py 的删除测试)。
4.4 变体的底层模型与同步逻辑
变体在数据库中由独立模型Variant承载(variant.py):
class Variant(models.Model): component = models.ForeignKey("trans.Component", ...) variant_regex = RegexField(max_length=VARIANT_REGEX_LENGTH, blank=True) key = models.TextField() defining_units = models.ManyToManyField("trans.Unit", related_name="defined_variants")- 一个
Variant记录同时绑定component与variant_regex(自动变体)或空正则(手动变体); key即根键或variant:SOURCE中的源字符串;defining_units多对多关联“定义单元”,数据库层用MD5("key") + component + variant_regex构造唯一约束,兼顾长键索引效率与唯一性;- 模型强制要求 PostgreSQL 后端(
required_db_vendor = "postgresql")。
单元侧的逻辑在 unit.py 的update_variants()中:单元保存/变更时,若标志含variant则创建/更新手动变体链接;若组件配置了variant_regex则用regex_findall对self.context(单语翻译的键)做匹配;正则执行设有时长保护,超时会记录Component variant regex timed out警告并跳过匹配,避免恶意正则拖垮性能。
翻译时,属于同一变体组的字符串集中展示,译者可在同一位置对照翻译所有变体。
4.5 相关主题延伸
- 变体与检查项的联动,可参考 用户端检查项文档;
- 术语表(Glossary)中的变体处理,可参考 术语表文档。
五、字符串标签(Labels):按文本与颜色分类管理
5.1 标签的作用与创建
标签(Labels)用于在项目配置层面把组件内的翻译字符串按文本描述 + 颜色划分成不同类别,从而在大规模项目中快速定位某类词条(例如“UI 文案”“法律条款”“占位符说明”等)。标签属于项目级概念:标签挂在 Project 上,可被该项目下所有组件复用。
在项目配置中创建带颜色标识的标签,用于分类组件内的翻译字符串。
源码层面的Label模型位于 label.py:
class Label(models.Model): color = models.CharField(...) # 颜色取自 ColorChoices ...- 每个标签包含名称(name)、**描述(description)与颜色(color)**三要素;
LabelQuerySet提供按名称排序等查询能力;测试 test_labels.py 验证了列表按名称字典序(Alpha → Middle → Zulu)展示;- 同项目内标签名唯一,重复创建会被拒绝(提示
Label with this Project and Label name already exists.,见 test_labels.py)。
5.2 标签如何绑定到字符串
标签与字符串(Unit)之间是多对多关系,字段定义于 unit.py:
labels = ManyToManyField("Label", verbose_name=gettext_lazy("Labels"), blank=True)为字符串打标签的常规途径:
- 批量编辑(bulk editing):在字符串列表页使用“附加(additional)”功能批量给筛选出的字符串添加标签(对应
labels字段批量赋值); - 批量操作插件:使用
weblate.flags.bulk插件(见 addons.rst)通过标志规则批量设置标签。
标签在单元上还以**标志(flag)**形式存在:Label.get_label_flag()返回label:{name}形式的标志(见 label.py),这意味着标签可与 Weblate 的标志体系互通,例如通过weblate.flags.bulk插件按标志批量赋值标签。
5.3 标签删除与统计维护
从测试 test_labels.py 可见,删除仍被字符串引用的标签是允许的(级联清理单元上的关联),并且 Weblate 会刷新受影响的统计缓存(test_delete_assigned_refreshes_totals);对源字符串的修改也会触发标签统计的增量更新(test_source_change_recalculates_cached_label_stats),说明标签统计走的是带版本号(generation)的缓存机制,避免并发下统计错乱。
六、实战要点速查
- 新增字符串:优先在源仓库基础文件中添加;需在 Weblate 内直接添加时,开启组件
manage_units,并善用 Context 与“自动调整 Context”避免双语格式的键冲突; - 新增语言:按团队流程选择
new_lang(add/existing/contact/url/none),设置new_base决定新语言文件的初始内容形态,用language_code_style控制文件名风格,必要时在项目层配置language_aliases以反向映射出符合仓库历史的语言代码; - 删除:语言/组件/项目级删除需输入
slug确认;删除个别字符串优先在源文件操作(仓库同步后生效),也可在开启manage_units的组件中用编辑界面的 Remove 按钮; - 变体:单语翻译用
variant_regex自动分组(匹配部分即根键差异);双语或无键场景用手动variant:SOURCE标志(源字符串 ≤ 768 字符);二者最终都汇聚到Variant模型,翻译界面统一分组展示; - 标签:项目级创建(名称/描述/颜色),通过批量编辑或
weblate.flags.bulk插件按label:标志批量赋值,删除时系统自动维护统计缓存。
所有配置字段(new_base、new_lang、language_code_style、variant_regex、manage_units)的完整校验逻辑均可在 weblate/trans/models/component.py 中查阅,选项定义集中在 weblate/trans/inherited_settings.py,行为验证可复现于 test_variants.py 与 test_labels.py。
- 后端
- 开发工具
【免费下载链接】weblate
Web based localization tool with tight version control integration.
相关推荐
Thunderbird for Android 字符串与语言管理实践指南:从源字符串到 Weblate 全流程
Thunderbird for Android 字符串与语言管理实践指南:从源字符串到 Weblate 全流程 Thunderbird for Android(
移动开发企业应用Weblate PHP 字符串翻译格式(PHP strings)详解:单语翻译、组件配置与源码实现
Weblate PHP 字符串翻译格式(PHP strings)详解:单语翻译、组件配置与源码实现 PHP 项目的本地化文件通常以 lang/ /texts.p
后端开发工具Stl.Fusion核心概念解析:揭秘DREAM架构的魔力
Stl.Fusion核心概念解析:揭秘DREAM架构的魔力 Stl.Fusion是一个革命性的开源框架,它通过DREAM(分布式反应式记忆化)架构让开发者能够轻
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考