虚幻引擎 中的文本是本地化的主要组件。它是一个专用的字符串,用C++中的[`FText`]类型表示。当您需要本地化面向用户的文本时,应该使用这种方法。
在内部,FText
被作为TSharedRef
实现到ITextData
。这使得复制成本非常低廉,而且FTextSnapshot
工具提供了一种有效的方法来检测缓存的FText值是否确实发生了更改。
在 FText
实例中保存的数据因 FText
的创建方式而异。这种差异由内部"文本历史记录"(FTextHistory
)处理。文本历史记录支持文本的正确文化重建,并构成以下几个方面的关键组成部分:
实时文化切换。
通过网络发送`FText`。
创建文化不变源。
将`FText`转换为FString
通常是一种有损操作,因为它会丢失文本历史记录。只有当您不再需要本地化数据时才应该这样做。例如,如果有一个处理字符串的低级别API,则由一个监视文本更改(如[`STextBlock`](https://api.unrealengine.com/INT/API/Runtime/Slate/Widgets/Text/STextBlock/index.html)的高级别API管理。当将数据传递到只接受字符串的外部API时,也可以使用这种转换。
如果需要不可本地化的文本(例如将播放器名称从外部API转换为可以在UI中显示的内容),可以使用FText::AsCultureInvariant
,它生成一个没有本地化数据(且不能本地化)的`FText`实例。`INVTEXT`宏可以对文字字符串执行同样的操作。
文本文字值
可本地化文本由三个组件组成:一个 命名空间;一个 密钥(形成其标识);和一个 源字符串(这是被翻译内容的基础,并对`陈旧的`翻译进行验证)。在UE4中创建可本地化文本的最常见方法是使用文本文字值。
使用C++创建文本文字值
可以使用宏的LOCTEXT系列使用C++创建文本文字值。
文本文字值宏
宏 |
说明 |
---|---|
NSLOCTEXT |
通过定义命名空间、密钥和源字符串创建本地化的文本片段。 |
LOCTEXT |
通过定义密钥和源字符串创建本地化的文本片段,并使用`LOCTEXT_NAMESPACE`定义命名空间。 |
示例:
// 定义要与LOCTEXT一起使用的命名空间
// 这只在单个文件中有效,并且必须在文件结束前取消定义
#define LOCTEXT_NAMESPACE "MyNamespace"
// 创建文本文字值
constFTextHelloWorld= NSLOCTEXT("MyOtherNamespace","HelloWorld","Hello World!")
constFTextGoodbyeWorld= LOCTEXT("GoodbyeWorld","Goodbye World!")
// 在文件结束前取消定义命名空间
#undef LOCTEXT_NAMESPACE
在INI文件中创建文本文字值
文本文字值可以在INI文件中使用NSLOCTEXT
宏语法创建。
在资源中创建文本文字值
文本文字值可以使用`FText`属性创建。将自动为您生成密钥,但是您可以使用文本字段旁边的高级组合为文本定义自定义命名空间或密钥。也可以使用默认命名空间或密钥。
文本格式化
文本格式化提供了一种将文本组合起来,以更便于进行本地化的方法,它使用可本地化的格式模式来组合文本,该模式注入实际文本来替换格式占位符。
格式占位符包含在一对花括号中,可以是数字(用于基于索引的格式化)或字符串(用于基于名称的格式化)。例如:
您还剩 {0} 点生命值。
您还剩 {CurrentHealth} 点生命值。
格式占位符还可以指定一个函数(称为`参数修饰符`)在其参数数据上运行。它们被指定为一个管道,后面跟着函数名和参数。例如:
"{NumCats} {NumCats}|plural(one=cat,other=cats)"
反引号(`) 字符可用于换码大括号和直线符,从而避免将它们视为格式化标记。也可用于对自身进行换码,生成文字 `字符。
范例:
以下表格假设 Res
是一个整数,其值为 10。
输入 |
格式化文本结果 |
---|---|
|
|
|
|
使用C++进行文本格式化
使用C++进行文本格式化由FText::Format
系列函数处理。每个函数都接受一个FTextFormat
模式,该模式将隐式地从一个`FText`实例构造,后面跟着其他参数,详见下表定义。
参数 |
格式化类型 |
说明 |
---|---|---|
FText::Format |
一般文本格式化。 |
要么接受基于索引的参数(使用 |
基于可变索引的格式化。 |
接受可用于构造 |
|
基于可变名称的格式化。 |
接受连续名称(任何可用于构造`FString`的名称),然后对参数赋值(任何可用于构造`FFormatArgumentValue`的值)。 |
您应该考虑将经常使用的格式模式预编译为`FTextFormat`,以提高格式化性能。如果活动文化发生更改,则编译后的模式将自动重新编译。
蓝图中的文本格式化
蓝图中的文本格式化由 Format Text 节点处理。此节点可以接受文本格式模式,也可以将该模式链接到另一个文本引脚。
当指定文字格式模式时,将自动生成格式参数引脚。
当格式模式链接到另一个文本引脚时,必须使用节点的详情(Details)面板手动指定格式的参数。
参数修饰符
参数修饰符提供了一种在参数被添加到格式化字符串之前对其进行预处理的方法。参数修饰符是可扩展的。您可以通过实现ITextFormatArgumentModifier
接口来创建参数修饰符,并为给定的关键字注册一个工厂函数(请参阅FTextFormatter::RegisterTextArgumentModifier
)。
UE在默认情况下提供了一些参数修饰符:有多个修饰符,用于复数、性别和韩语后置词。
复数形式
复数形式允许您基于文本格式的给定数值变量使用不同的文本。复数形式可以是基数形式(例如`有1只猫`或`有4只猫),也可以是序数形式(例如`你第一个完成了!
或`你第二个完成了!`)。复数形式被指定为键值对,并支持以下任何关键字(由CLDR数据为您的文化定义):0、1、2、一些、很多和其他。值是可选的引用字符串,也可以包含格式标记。
基数格式示例:
"There {NumCats}|plural(one=is,other=are) {NumCats} {NumCats}|plural(one=cat,other=cats)"
序数格式示例:
"You came {Place}{Place}|ordinal(one=st,two=nd,few=rd,other=th)!"
性别形式
性别形式允许您根据文本格式的给定ETextGender
值使用不同的文本,比如`Le guerrier est fort`或`La guerrière est forte`。性别形式被指定为一个值列表,其顺序为[阳性、阴性、中性],中性是可选的。值是可选的引用字符串,也可能包含格式标记。
格式示例:
"{Gender}|gender(Le,La) {Gender}|gender(guerrier,guerrière) est {Gender}|gender(fort,forte)"
韩语后置词
韩语后置词帮助您遵循韩语的语法规则,并根据插入的值以辅音还是元音结尾来插入正确的字形,如`사람은`或`사자는`。韩语后置词被指定为一个值列表,其顺序为[辅音、元音]。值是可选的引用字符串。
格式示例:
"{Arg}|hpp(은,는)"
文本格式化最佳实践
当注入一个影响句子的数字时,使用复数形式的参数修饰符处理这些差异,而不是用代码分支。当您使用复数形式时,该句子将被正确地翻译为不使用源语言复数规则的语言。
当插入一个人称代词时,要确保您包括了这个人的性别参数。这对于具有性别语法规则的语言非常重要,因为它能让翻译人员根据性别转换译文(请参阅性别形式)。
避免为对象注入名词(如`桌子
、
门`或`椅子`),或做好可本地化的准备。这些名词在一种语言中可能有某种性别,在另一种语言中可能有另一种性别。这使得格式模式字符串不可能在没有依据文化的元数据的情况下精确本地化。理想情况下,您应该包括完整的句子而不仅仅是名词。这可以确保译文准确。UE未来版本可能包含一个函数,可以让翻译人员使用元数据来标记表示名词的文本,这样稍后他们可以以格式模式进行分支,以生成准确的翻译。
避免串联部分句子。这可能会导致问题,因为每个子句或部分都有可能翻译正确,但整体的翻译可能不正确。最好把文本改写成完整的句子,这样才能保证翻译正确。
文本生成
文本生成使用国际化数据来生成不依赖于直接本地化的正确文化文本。文本生成有三种类型:数值型、时间型和变换型。
数值型文本生成
数值型生成用于将数值类型转换为便于人类阅读的文本表示形式。这方面的确切规则是特定于文化的,如果需要更具体的控制,还可以在每一代的基础上进行调整。
例如,依照默认生成规则,浮点数`1234.5`将生成为英语格式的`1,234.5,法语格式的`1 234,5
,和阿拉伯语格式的`١٬٢٣٤٫٥`。
使用C++进行数值型生成
使用C++进行数值型生成由以下函数处理。
函数 |
说明 |
---|---|
将UE支持的任何数值类型转换为用户友好的文本表示形式( |
|
将浮点数或双精度浮点数转换为百分比文本表示形式(`0.2`变为20%)。 |
|
将值(以字节为单位)转换为用户友好的内存表示形式( |
|
将采用基本表示形式的货币值转换为用户友好的货币表示形式( |
表中的大多数函数都使用一个可选的[FNumberFormattingOptions](https://api.unrealengine.com/INT/API/Runtime/Core/Internationalization/FNumberFormattingOptions/index.html)
来控制输出(默认值来自活动区域设置),以及一个可选的文化(默认值是活动区域设置)。
蓝图中的数值型生成
蓝图中的数值型生成由以下节点处理。
节点 |
说明 |
---|---|
ToText (byte), ToText (integer), ToText (float) |
将支持的数值类型转换为用户友好的文本表示形式( |
AsPercent |
将浮点数或双精度浮点数转换为百分比文本表示形式(`0.2`变为20%)。 |
AsCurrency |
将采用基本表示形式的货币值转换为用户友好的货币表示形式( |
表中的大多数节点都使用高级参数来控制输出。
时间型
时间型生成用于将日期和时间类型转换为便于人类阅读的文本表示形式。这方面的确切规则是特定于文化的,如果需要更具体的控制,还可以在每一代的基础上对日期/时间样式进行调整。
按照默认生成规则,表示1998年5月22日的日期将生成英语(美国)格式的`May 22, 1998,英语(英国)格式的`22 May 1998
,法语格式的`22 mai 1998`和阿拉伯语格式的`٢٢/٠٥/١٩٩٨`。
使用C++进行时间型生成
使用C++进行时间型生成由以下函数处理。
函数 |
说明 |
---|---|
将FDateTime值转换为用户友好的日期表示形式。 |
|
将FDateTime值转换为用户友好的时间表示形式。 |
|
将FDateTime值转换为用户友好的日期和时间表示形式。 |
|
将FTimespan值转换为用户友好的时间增量表示形式(采用小时、分钟和秒)。 |
上面的大多数方法都使用EDateTimeStyle来控制输出(默认值取自活动区域设置,但可以设置为`短(short)、
中(medium)、
长(long)或`全部(full)
)。
时间型生成在默认情况下预期会得到一个基于UTC的时间(它将转换为本地时区)。如果给定时间不是基于UTC(例如如果已使用本地时间),则您应将[FText::GetInvariantTimeZone()](https://api.unrealengine.com/INT/API/Runtime/Core/Internationalization/FText/GetInvariantTimeZone/index.html)
作为时区参数传递。
蓝图中的时间型生成
蓝图中的时间型生成由以下节点处理。
节点 |
说明 |
---|---|
AsDate |
将基于非UTC的`DateTime`值转换为用户友好的原始日期表示形式(无需调整到本地时区)。 |
AsDate (from UTC) |
将基于UTC的`DateTime`值转换为用户友好的日期表示形式(调整到本地时区)。 |
AsTime |
将基于非UTC的`DateTime`值转换为用户友好的原始时间表示形式(无需调整到本地时区)。 |
AsTime (from UTC) |
将基于UTC的`DateTime`值转换为用户友好的时间表示形式(调整到本地时区)。 |
AsDateTime |
将基于非UTC的`DateTime`值转换为用户友好的原始日期和时间表示形式(无需调整到本地时区)。 |
AsDateTime (from UTC) |
将基于UTC的`DateTime`值转换为用户友好的日期和时间表示形式(调整到本地时区)。 |
AsTimespan |
将`Timespan`值转换为用户友好的时间增量表示形式(采用小时、分钟和秒)。 |
变换型
变换型生成用于将文本转换为自身的不同表示形式。例如,您可以将小写文本转换为大写文本,或者将大写文本转换为小写文本。
使用C++进行变换型生成
使用C++进行变换型生成由以下函数处理。
函数 |
说明 |
---|---|
以符合unicode标准的方式将FText实例转换为其小写形式。 |
|
以符合unicode标准的方式将FText实例转换为其大写形式。 |
蓝图中的变换型生成
蓝图中的变换型生成由以下节点处理。
节点 |
说明 |
---|---|
Text to Lower |
以符合unicode标准的方式将`文本(Text)`实例转换为其小写形式。 |
Text to Upper |
以符合unicode标准的方式将`文本(Text)`实例转换为其大写形式。 |
字符串表
字符串表提供了一种方法,可以将已本地化的文本集中到一个(或多个)已知位置,然后以一种稳健的方式从其他资源或代码引用字符串表中的条目,从而方便地重用已本地化的文本。
字符串表可以在C++中定义,可以使用CSV文件加载,也可以作为资源创建。详情请参阅字符串表页面。
文本值编组
文本值可以无损地编组为字符串(使用 FTextStringHelper
或是ImportText
和UTextProperty
的`ExportText`函数)。
支持以下格式:
文本文字值 |
说明 |
---|---|
指定命名空间、密钥和源字符串的文本文字值。 |
|
|
指定密钥和源字符串的文本文字值。 |
|
字符串表引用。 |
|
文化不变文本片段(请参阅 |
|
从数字生成的文字片段(请参阅 |
|
在启用分组的情况下从数字生成的文本片段(请参阅`FText::AsNumber`和 |
|
在禁用分组的情况下从数字生成的文本片段(请参阅`FText::AsNumber`和 |
|
使用自定义格式化选项从数字生成的文本片段(请参阅`FText::AsNumber`和 |
|
以百分比的形式从数字生成的文本片段(请参阅 |
|
在启用分组的情况下以百分比的形式从数字生成的文本片段(请参阅`FText::AsPercent`和`FNumberFormattingOptions::DefaultWithGrouping`)。 |
|
在禁用分组的情况下以百分比的形式从数字生成的文本片段(请参阅`FText::AsPercent`和`FNumberFormattingOptions::DefaultNoGrouping`)。 |
|
使用自定义格式化选项以百分比的形式从数字生成的文本片段(请参阅`FText::AsPercent`和`FNumberFormattingOptions`)。 |
|
以货币的形式从数字生成的文本片段(请参阅 |
|
从UTC日期生成的文本片段,并调整到指定时区或本地时区(请参阅 |
|
从非UTC日期生成的文本片段,无需时区调整(请参阅`FText::AsDate`)。 |
|
从UTC时间生成的文本片段,并调整到指定时区或本地时区(请参阅 |
|
从非UTC时间生成的文本片段,无需时区调整(请参阅`FText::AsTime`)。 |
|
从UTC日期和时间生成的文本片段,并调整到指定时区或本地时区(请参阅`FText::AsDateTime`)。 |
|
从非UTC日期和时间生成的文本片段,无需时区调整(请参阅`FText::AsDateTime`)。 |
|
以符合unicode标准的方式转换为小写的文本片段(请参阅`FText::ToLower`)。 |
|
以符合unicode标准的方式转换为大写的文本片段(请参阅`FText::ToUpper`)。 |
|
使用基于索引的参数从格式化模式生成的文本片段(请参阅 |
|
使用基于名称的参数从格式化模式生成的文本片段(请参阅 |
`原始`字符串也可以导入,但是每次导入都会生成一个新的密钥。这将为本地化生成不稳定的密钥。
数据表
导致本地化密钥不稳定的一个常见原因是以迭代方式将原始字符串从CSV文件导入数据表,因为这将导致在每次导入之后生成一个新密钥。有一个办法可以解决这个问题,那就是覆盖行结构体上的`OnPostDataImport`函数,并调用`FText::ChangeKey`来分配新密钥,从而在导入后为导入的文本分配一个确定性的密钥。
通常,我们使用数据表名作为命名空间,行名和属性名的组合作为密钥。例如:
voidFMyTableRow::OnPostDataImport(constUDataTable*InDataTable,constFNameInRowName,TArray&OutCollectedImportProblems)
{
#if WITH_EDITOR
MyTextProperty = FText::ChangeKey(
InDataTable->GetName(),
FString::Printf(TEXT("%s_%s"),*InRowName.ToString(), GET_MEMBER_NAME_STRING_CHECKED(FMyTableRow,MyTextProperty)),
MyTextProperty
);
#endif// WITH_EDITOR
}
自4.22版本起,确定性密钥已经应用于已导入到数据表中的所有原始字符串,但是如果需要自定义密钥创建行为,仍然可以覆盖`OnPostDataImport`。
Polyglot数据
Polyglot数据允许在运行时添加新的本地化数据,或者与外部系统连接,或者允许在不构建新的`LocRes`文件的情况下热修复本地化。
Polyglot数据包括:命名空间和密钥(其标识);一个原生字符串;文本的类别(如游戏、引擎、编辑器),以控制何时使用polyglot数据;一个可选的本地语言(如果未设置,则返回该类别的本地语言);以及一系列的依据文化的翻译。
如果希望使用polyglot数据覆盖现有翻译,则必须确保polyglot数据的命名空间、密钥和原生字符串与要替换的源文本匹配。
使用C++的Polyglot数据
使用C++的Polyglot数据由FPolyglotTextData
类型表示,可以直接使用(用FPolyglotTextData::GetText
以将polyglot解析为文本实例),或可传递到FTextLocalizationManager::RegisterPolyglotTextData
(以修补现有的文本条目)。
蓝图中的Polyglot数据
蓝图中的Polyglot数据由 Polyglot文本 数据类型表示,可以与 Polyglot Data to Text 函数一起使用,将Polyglot数据解析为文本实例。
已本地化的文本源
已本地化的文本源是UE4文本本地化管理器发现和处理本地化文本数据的主要方法。UE4默认提供其中两个源:FLocalizationResourceTextSource
(托管`LocRes`支持)和`FPolyglotTextSource`(托管polyglot数据支持)。
已本地化的文本源可以提供与外部系统连接的方法,并且可以通过创建和注册派生自ILocalizedTextSource
的类型,在每个项目的基础上添加这些源。