☰
Weblate 翻译管理实战:新增字符串、语言文件、字符串变体与标签全解析
2026/10/11 11:52:40 网站建设 项目流程
  • 后端
  • 开发工具

【免费下载链接】weblate

Web based localization tool with tight version control integration.

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

本篇技术指南聚焦 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)完整实现了上述流程,其关键调用链为:

  1. can_add_new_language()检查当前用户与语言是否被允许(component.py);
  2. format_new_language_code(language)计算生成的文件语言代码(component.py);
  3. 通过language_regex正则校验语言代码合法性,超时会记录Component language filter timed out错误;
  4. 调用file_format_cls.get_language_filename(self.filemask, code)解析目标文件名,然后file_format.add_language(fullname, language, base_filename, ...)在仓库锁内创建文件;
  5. 发出translation_post_add信号,并执行translation.git_commit(...)提交,最终触发对新增文件的解析。

2.3 语言代码样式与语言别名

新语言文件的文件名由组件配置language_code_style决定,该字段定义于 component.py,可选值多达 14 种(inherited_settings.py):

取值样式说明
(空)默认,基于文件格式
posixPOSIX 风格,下划线分隔
posix_lowercasePOSIX 风格,下划线分隔,小写
bcpBCP 风格,连字符分隔
posix_longPOSIX 风格,含国家代码
posix_long_lowercasePOSIX 风格,含国家代码,小写
bcp_longBCP 风格,含国家代码
bcp_legacyBCP 风格,旧语言代码
bcp_lowerBCP 风格,连字符分隔,小写
androidAndroid 风格
appstoreApple App Store 元数据风格
googleplayGoogle Play 元数据风格
linuxLinux 风格
linux_lowercaseLinux 风格,小写

此外,项目级配置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 删除部分字符串的两种方式

如果只想删除个别字符串(而非整个语言/组件),文档给出两条路径:

  1. 在源文件中手动删除:直接在仓库的源文件中移除该字符串,Weblate 在后续仓库更新时会将对应词条从翻译项目中同步移除;
  2. 在 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)

为字符串打标签的常规途径:

  1. 批量编辑(bulk editing):在字符串列表页使用“附加(additional)”功能批量给筛选出的字符串添加标签(对应labels字段批量赋值);
  2. 批量操作插件:使用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)的缓存机制,避免并发下统计错乱。

六、实战要点速查

  1. 新增字符串:优先在源仓库基础文件中添加;需在 Weblate 内直接添加时,开启组件manage_units,并善用 Context 与“自动调整 Context”避免双语格式的键冲突;
  2. 新增语言:按团队流程选择new_lang(add/existing/contact/url/none),设置new_base决定新语言文件的初始内容形态,用language_code_style控制文件名风格,必要时在项目层配置language_aliases以反向映射出符合仓库历史的语言代码;
  3. 删除:语言/组件/项目级删除需输入slug确认;删除个别字符串优先在源文件操作(仓库同步后生效),也可在开启manage_units的组件中用编辑界面的 Remove 按钮;
  4. 变体:单语翻译用variant_regex自动分组(匹配部分即根键差异);双语或无键场景用手动variant:SOURCE标志(源字符串 ≤ 768 字符);二者最终都汇聚到Variant模型,翻译界面统一分组展示;
  5. 标签:项目级创建(名称/描述/颜色),通过批量编辑或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.

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询