Doxygen 内置了对多种语言的支持。这意味着 doxygen 生成的文本片段可以用英语(默认语言)以外的语言生成。通过配置文件(默认名称为 Doxyfile)中的配置选项 OUTPUT_LANGUAGE 来选择输出语言。要在注释块内切换语言,可以使用 \~ 命令。
当前(版本 1.14.0),支持 42 种语言(按字母顺序排列):南非荷兰语、阿拉伯语、亚美尼亚语、巴西葡萄牙语、保加利亚语、加泰罗尼亚语、中文、繁体中文、克罗地亚语、捷克语、丹麦语、荷兰语、英语、世界语、芬兰语、法语、德语、希腊语、印地语、匈牙利语、印度尼西亚语、意大利语、日语(+En)、韩语(+En)、拉脱维亚语、立陶宛语、马其顿语、挪威语、波斯语、波兰语、葡萄牙语、罗马尼亚语、俄语、塞尔维亚语、塞尔维亚语西里尔文、斯洛伐克语、斯洛文尼亚语、西班牙语、瑞典语、土耳其语、乌克兰语和越南语。
下表列出了有关支持语言的信息。表格按语言名称字母顺序排序。状态 列是根据源代码生成的,大致显示了翻译器最后一次更新的版本。
|
列表中的大多数人都表示他们也在忙其他事情,因此如果您想帮忙加快进度,请告知他们(或我)。
如果您想添加对尚未列出的语言的支持,请阅读下一节。
这个简短的操作指南解释了如何向 doxygen 添加新语言的支持
只需遵循以下步骤
<value name='YourLanguage'/>
编辑 doxygen/src/language.cpp:添加以下代码
#include<translator_xx.h>
现在,在 setTranslator()
中添加
case OUTPUT_LANGUAGE_t::YourLanguage: theTranslator = new TranslatorYourLanguage; break;
doxygen/src/translator_xx.h
TRANSLATOR_EN_H
重命名为 TRANSLATOR_XX_H
两次(即在文件开头的 #ifndef
和 #define
预处理器命令中)。TranslatorEnglish
重命名为 TranslatorYourLanguage
idLanguage()
中,将 "english" 更改为您语言的名称(仅使用小写字母)。根据语言的不同,您可能还需要更改成员函数 latexLanguageSupportCommand() 以及其他函数(开始工作时会识别出来)。tr
开头的成员函数返回的字符串。尽量匹配标点和大小写!要输入特殊字符(带重音符号),您可以ä
; 表示带分音符的 a
(即 ä
)。有关代码,请参阅 HTML 规范。doxygen/doc/maintainers.txt
并将自己添加到维护者列表中,格式如下:OUTPUT_LANGUAGE = your_language_name
来生成您语言的输出。translator_xx.h
发送给我,以便我将其添加到 doxygen 中。同时发送您的姓名和电子邮件地址,以便将其包含在 maintainers.txt
列表中。新版本的 doxygen 可能会使用新的翻译句子。在这种情况下,Translator
类需要实现新的方法——它的接口会发生变化。当然,英语句子需要翻译成其他语言。至少,与语言相关的翻译器类必须实现新方法;否则,doxygen 甚至无法编译。等待所有语言维护者翻译完新句子并发送结果是不太实际的。以下文本描述了如何使用翻译器适配器来解决这个问题。
翻译器适配器的作用。 每当 Translator
类接口在新版本中发生变化时,新的 TranslatorAdapter_x_y_z
类就会添加到 translator_adapter.h
文件中(这里的 x、y 和 z 是对应当前 doxygen 官方版本的数字)。所有先前继承自 Translator
类的翻译器现在都继承自此适配器类。
TranslatorAdapter_x_y_z
类实现了新的、所需的方法。如果新方法替换了某些相似但已过时的方法(例如,如果参数数量发生变化,或者旧方法的功能被更改或丰富),TranslatorAdapter_x_y_z
类可能会使用已过时的方法来获取与目标语言中旧结果尽可能接近的结果。如果不可能,则使用英语翻译器获取结果(默认翻译),英语翻译器(根据定义)始终是最新状态。
例如, 当引入带参数(用于确定首字母大写和单复数形式)的新方法 trFile()
以替换不带参数的旧方法 trFiles()
时,其中一个翻译器适配器类中出现了以下代码
/*! This is the default implementation of the obsolete method * used in the documentation of a group before the list of * links to documented files. This is possibly localized. */ virtual QCString trFiles() { return "Files"; } /*! This is the localized implementation of newer equivalent * using the obsolete method trFiles(). */ virtual QCString trFile(bool first_capital, bool singular) { if (first_capital && !singular) return trFiles(); // possibly localized, obsolete method else return english.trFile(first_capital, singular); }
trFiles()
方法不存在于 TranslatorEnglish
类中,因为它已被标记为过时并移除。但是,它一直被使用,并且其调用已被替换为
trFile(true, false)
在 doxygen 源文件中。可能许多语言翻译器实现了已过时的方法,因此在这些情况下使用相同的依赖于语言的结果是完全合理的。TranslatorEnglish
没有实现旧方法。它继承自抽象的 Translator
类。另一方面,另一种语言的旧翻译器没有实现新的 trFile()
方法。因此,它继承自另一个基类——TranslatorAdapter_x_y_z
。TranslatorAdapter_x_y_z
类必须实现新的、必需的 trFile()
方法。然而,如果 trFiles()
方法没有实现,翻译器适配器将无法编译。这就是在翻译器适配器类中实现旧方法(使用从 TranslatorEnglish 中删除的相同代码)的原因。
最简单的方法是将参数传递给英语翻译器并返回其结果。相反,适配器在一个特殊情况下使用旧的 trFiles()
方法——当调用新的 trFile(true, false)
时。这是引入新方法时最常用的情况——见上文。虽然这可能看起来过于复杂,但这种技术允许核心源代码的开发者更改 Translator 接口,而用户甚至可能不会注意到这种变化。当然,当使用不同的参数调用新的 trFile()
时,将返回英文结果,非英语用户会注意到这一点。在这种情况下,语言翻译器的维护者至少应该实现这一个特定的方法。
语言翻译器的基类说明了什么? 如果语言翻译器类继承自任何适配器类,则需要维护。在这种情况下,该语言翻译器被认为不是最新版本。另一方面,如果语言翻译器直接继承自抽象类 Translator
,则该语言翻译器是最新版本。
翻译器适配器类是链式的,以便较旧的翻译器适配器类使用更新一步的翻译器适配器作为基类。较新的适配器比旧的适配器执行的适配工作更少。最旧的适配器类(间接)继承自所有适配器类。适配器类的名称选择方式是,其后缀派生自不需要适配器的上一个官方 doxygen 版本。这样,就可以大致知道语言翻译器类最后一次更新的时间——详见下文。
最新的翻译器适配器继承自抽象类 TranslatorAdapterBase
,该类直接继承自抽象类 Translator
。它仅添加了私有的 English-translator 成员,以便于在适配器类内部实现默认翻译,并且它还强制实现了一个方法,用于通知用户语言翻译不是最新状态(因此生成的文件中可能出现一些英文句子)。
一旦没有任何语言翻译器使用最旧的适配器类,就可以将其从 doxygen 项目中移除。维护者应该努力达到适配器类数量最少的状态。
为了简化支持语言的翻译器类的维护, 开发了 translator.py
Python 脚本(位于 doxygen/doc
目录中)。它从每种语言的源文件中提取有关已过时和新方法的重要信息。这些信息存储在翻译器报告 ASCII 文件 (translator_report.txt
) 中。
您可以在此处找到此文件:translator_report.txt
。
通过查看语言翻译器的基类,脚本还可以猜测翻译器的状态——见上表语言列表的最后一列。生成 doxygen 文档时会自动调用 translator.py
。您也可以随时手动运行此脚本,如果觉得它能帮助您。当然,您不必强制使用脚本的结果。通过查看适配器类及其基类,您也可以找到相同的信息。
我应该如何更新我的语言翻译器? 首先,您应该是该语言的维护者,或者您应该通知他/她有关更改。以下文本的主要受众是语言维护者。
更新语言时有几种方法。如果您不是很忙,您应该始终选择最彻底的方法。如果更新所需的时间比您预期的要长得多,您随时可以决定使用合适的翻译器适配器稍后完成更改,同时仍使您的翻译器能够工作。
更新语言翻译器最彻底的方法 是使您的翻译器类直接继承自抽象类 Translator
,并提供所需实现方法的翻译——如果您忘记实现其中一些方法,编译器会告诉您。如果您有疑问,可以查看 TranslatorEnglish
类以了解已实现方法的用途。查看之前使用的适配器类有时可能会有所帮助,但也可能具有误导性,因为适配器类也实现了已过时的方法(参见之前的 trFiles()
示例)。
换句话说,最新状态的语言翻译器根本不需要 TranslatorAdapter_x_y_z
类,您也无需实现 Translator 类所需的方法以外的任何内容(即 Translator
的纯虚方法——它们以 =0;
结尾)。
如果一切编译顺利,请尝试运行 translator.py
,并查看 doxygen/doc
目录中的翻译器报告(ASCII 文件)。只有当脚本未检测到任何特殊情况时,您的翻译器才会被标记为最新状态。如果翻译器使用 Translator
基类,可能仍然存在与您的源代码相关的一些备注。在这种情况下,翻译器被标记为几乎最新状态。具体来说,完全未使用的已过时方法可能会在您的语言部分中列出。只需删除它们的代码(并再次运行 translator.py
)。此外,如果您忘记将翻译器类的基类更改为某个较新的适配器类或直接更改为 Translator 类,您也会收到通知。
如果您没有时间完成所有更新, 您仍然应该从上面描述的最彻底的方法开始。您可以随时将基类更改为实现了所有尚未实现方法的翻译器适配器类。
如果您更喜欢逐步更新您的翻译器, 可以查看 TranslatorEnglish
(即 translator_en.h
文件)。在其中,您会发现诸如 new since 1.2.4
的注释,这些注释总是分隔在该版本中实现的一组方法。请实现位于使用与您的翻译器适配器类相同版本号的注释下方的方法组。(例如,如果您的翻译器类未实现注释 new since 1.2.4
下方的方法,则必须使用 TranslatorAdapter_1_2_4
。当您实现这些方法后,您的类应该使用更新的翻译器适配器。
偶尔运行 translator.py
脚本,并向其提供您的 xx
标识(来自 translator_xx.h
),以生成更短(也更快)的翻译器报告——它将只包含与您的翻译器相关的信息。一旦您达到需要将基类更改为某个较新适配器的状态,您将在翻译器报告中看到相应的提示。
警告:别忘了编译 doxygen,以检查它是否可编译。translator.py
不检查与编译器相关的所有内容是否正确。因此,它有时可能会误报所需的基类。
最过时的语言翻译器 会导致实现过于复杂的适配器。因此,doxygen 开发者可能会决定让此类翻译器继承自 TranslatorEnglish
类,根据定义,该类始终是最新状态。
这样做时,所有缺失的方法将由英文翻译替换。这意味着未实现的方法将始终返回英文结果。此类翻译器使用单词 obsolete
进行标记。您应该将其理解为确实已过时。无法推测其最后一次更新时间。
通常,可以根据已过时的方法构建更好的结果。因此,如果可能,应使用翻译器适配器类。另一方面,为确实已过时的翻译器实现适配器会带来过多的维护和运行时开销。