3.6 | Localization Editor 公测帖

Localization Editor 的优势

  1. 全程无代码操作,只需点点点即可完成全部流程操作,以后翻译的活可以转交给策划、商务或者渠道等,减轻技术大大们的工作压力

  2. 操作即所得,可以随时预览,也可以各种语言之间来回切换

  3. 可以接入外部翻译软件,点一点即可自动翻译

  4. 高度自动化,例如全自动一键扫描所需翻译软件、自动翻译、快速构建、智能匹配文件等等

                                          本帖仅用于问题反馈,请勿回复无关内容。
    

使用流程

流程分为三大步,只需点点点就行,具体如下:

  1. 收集内容

通过自动化扫描方式获取所需翻译的文本、ts代码、scene、prefab、video、audio、image文件

  1. 翻译内容

通过人工翻译或者外部软件自动化翻译工具将内容进行翻译

  1. 构建发布

通过构建发布功能将指定的语言进行打包

具体使用办法

工具入口

目前只能在 Cocos Creator 3.6及以上版本中使用,无需安装,点击即可使用,该工具入口位于顶部工具栏【面板】下:

Localization Editor界面

选择服务商

  1. 选择所需的服务商,官方暂时只接入了有道,后续会接入更多的服务商

  1. 用户输入服务商指定key,点击保存即可登入

API文档地址:localization-editor-api.rar (2.4 KB)

收集

注释:即收集所有需要翻译的内容,包含文字、图片

收集资源的具体操作如下:

  1. 选择本地开发语言

用户需要选择本地开发语言,该选择极为重要,影响到后续数据,需慎重选择

  1. 选择指定目录

目前暂时只支持项目目录下的asset文件夹包含的资源

  1. 设置文件扩展名、排除路径

为了方便用户快速筛选出需要翻译的资源,因此我们新增了文件扩展名(指定文件的扩展名)及排除路径(排除法)辅助功能

  1. 收集并且统计

用户点击【收集并且统计】按钮,系统开始收集需要翻译的原文、文件数量,并且统计出来

翻译

在翻译界面包含了以下的功能:

  1. 选择语言

注释:选择好翻译的目标语言

注意:请注意部分语言会包含多个分支,可以根据发行地区来选择

  1. 补全

注释:补全功能是用于解决有key无value的情况

注意:为什么会出现有key无value的情况?

该情况出现是由于在写代码时调用了Localization Editor工具或者是临时生成了个key,但是没有填写value,因此本模块是帮助用户补全这些内容。

填写完毕后,记得点击页面左上角的【保存】哦

【补全】按钮

手动补全有key无value情况

  1. 删除

注释:删除该语言的项目文件

  1. 翻译

注释:点击后进入翻译的界面,界面上包含多个功能,该界面完成翻译的核心流程

工具会将扫描出的内容分为文字、文件2个部分,文字部分均为文字,文件为带后缀的,例如:

各个功能介绍:

①手动编写译文

用户可以在界面手动翻译或者修改译文

②自动翻译

用户可以点击【翻译】按钮,此时工具会调用之前选择的服务商自动翻译的功能,对尚未翻译的内容进行自动翻译

注释:使用自动翻译会使用用户自身服务商的资源,费用由用户自行承担

③变体

变体功能专门用于解决翻译时遇到的复数问题,系统会根据变体的规则自动调整翻译的内容,用户也可以自由设定变体的规则

④保存

翻译的内容若想要在项目中生效,需要进行保存,点击保存后【未翻译】界面上已经填写好的内容将会保存到【已翻译】界面

⑤导入/智能匹配

该功能是用于多国语言下,将video、audio、image等非文本类文件进行绑定。

导入是将单个文件进行绑定,如下图:

匹配文件前需要按照指定的规则来命名文件,规则如下:

1) 源文文件和译文文件要附加语言类标识,例如中文:cn-abc001.jpg,英文为en-abc001.jpg,这样方便进行快速标记及替换。

2)相关语言表示可以在以下界面中看到:

19

3)点击智能匹配即弹出一个面板,该面板会提示一个二次确认框,点击确认后即开启 智能匹配

4)我们将通过文件名称来进行修改并且匹配,例如:

源文文件为: assets/aassb/cn-abc001.jpg,需将其翻译为英语,其译文文件为:

assets/aassb/en-abc001.jpg,我们将自动把assets/aassb/cn-abc001.jpg中的cn替换为en

5)当替换完成,并且成功绑定后,则代表匹配成功

6)译文文件需要放入项目目录中

  1. 编译

当翻译内容完成后需点击【编译】,即将数据保存到项目中,点击后方可后续操作,例如【预览】、【构建发布】等

  1. 预览

用户编译完指定语言后,点击预览功能即可在编辑器中看到该语言的效果

构建发布

当以上步骤完成后,即可进行最后一步——构建发布,将翻译的数据打包,具体操作如下:

  1. 在构建发布中勾选上需要打包语言、默认语言及备用语言:

打包语言:即项目中包含的语言数据

默认语言:即项目打开后默认的语言

备用语言:即项目打开后默认语言出现问题后使用的备用语言

  1. 当项目构建完成后,对应的语言包就会打包成功

24

label功能

除了上述功能外,我们提供了针对项目中的内容进行定制化翻译能力,即Localization Editor的label组件——L10nLabel:

11

其功能如下:

重置key

注释:点击并获得一个尚未被使用的新key

2

手动输入及更改key

注释:用户可以自由填写key,key只要不为空即可

3

快捷搜索key

注释:用户点击按钮后弹出搜索框,通过输入字符快速找到已经存在的key

4

点击即可开启搜索功能

5

通过快捷搜索可以找到正在使用的key

变体设置

注释:用户可以通过选择Count来使用哪种格式的变体

6

卸载数据

若想彻底卸载项目中所有Localization Editor数据,只需要在顶部栏【面板】下选择卸载数据即可。

25

补充资料

辅助工具

以下是一些辅助翻译工具,用户们可以看下,辅助提高工作效率

● Manipulating PO Files

● PO 格式编辑器 https://poedit.net/

● PO 格式工具箱 https://github.com/translate/translate

● 离线 translation memory 工具 OmegaT - The Free Translation Memory Tool - OmegaT

注意事项

  1. 目前资源的翻译功能存在限制,原文的资源要存放在高优先级的 bundle中,建议放在resources否则可能导致资源重定向失效。后续关于资源重定向引擎将有更进一步的优化

后续规划

后续我们将会开放以下的内容:

  1. 新增文件导入导出能力,文件格式将为.po、csv、xlsx,该功能将进一步提高翻译效率

  2. ICU的功能,该功能主要是将特殊符号、货币等进行自动化翻译

  3. 自动化检查功能,该功能主要是辅助用户进行自动化检查,提高工作效率

  4. 接入更多的外部翻译厂商API接口

除了上述功能外,如果有用户们还有其它相关功能需求可以在Cocos论坛中提出,我们将认真考虑
[/quote]

9赞

如果文字不是固定的,如何获取翻译呢

您是指配表的文字还是哪里的,能否举个例子

MARK L10N.

比如说同一个按钮,我要显示上阵/下阵/详情,根据操作情况显示,如果不用多个label,直接根据情况获取翻译设置string,那么这个翻译怎么获取. 或者说tip上的文字,怎么获取翻译

您可以尝试通过l10n.t去获取,详情可以参考公测帖中的API文档

为了方便大家使用L10n的API文档,特在此回复中把文档补充出来,如果各位在使用中有任何疑问或者建议可以在此帖中回复

Localization Editor Api





L10nManager

导入示例:


import l10n from 'db://localization-editor/core/L10nManager'

描述:

l10n以api的方式提供了在代码中翻译文本的能力


索引

构造函数

  • L10nManager private

全局变量

l10n

定义: const l10n: L10nManager


静态属性

LOCAL_STORAGE_LANGUAGE_KEY

定义: static LOCAL_STORAGE_LANGUAGE_KEY: string

描述: 当调用changeLanguage切换游戏语言时,将使用localStorage

存储所切换的目标语言标记,并且使用LOCAL_STORAGE_LANGUAGE_KEY作为localStorage的key

备注:

|默认值|localization-editor/language|

|—|---|


实例方法

config

定义: config(options: L10nOptions): void

描述: 用于配置l10n的某些设置,探索更多选项可以查看L10nOptions

用例:


l10n.config({

    // 用于在默认语言没有找到相应翻译时,以该值进行补充显示

    fallbackLanguage: 'zh-Hans-CN',

    // 如果不喜欢LOCAL_STORAGE_LANGUAGE_KEY的默认值,可以在此修改,但是需要确保在changeLanguage之前

    localStorageLanguageKey: 'localization-editor/langauge'

})


changeLanguage

定义: changeLanguage(language: Intl.BCP47LanguageTag): void

描述: 用于动态切换语言,请查看BCP47 Language Tag以获得更多信息

用例:


l10n.changeLanguage('zh-Hans-CN')

注意: 在调用此方法后,会自动重启游戏,请务必做好数据持久化工作


t

定义: t(key: L10nKey, options?: StandardOption): L10nValue

描述: 根据传入的L10nKey,返回当前语言数据中所对应的L10nValue,探索更多选项可以查看StandardOption

用例:


console.log(l10n.t('this_is_apple'))

// 这是一个苹果

注意: 语言数据需要配合Localization Editor插件在编译后生成


exists

定义: exists(key: L10nKey): boolean

描述: 返回是否存在key

用例:


console.log(l10n.exists('test_key'))


currentLanguage

定义: get currentLanguage(): Intl.BCP47LanguageTag

描述: 返回当前语言的BCP47 Language Tag

用例:


console.log(l10n.currentLanguage)

// 'zh-Hans-CN'


languages

定义: get languages(): readonly Intl.BCP47LanguageTag[]

描述: 返回当前可用语言的BCP47 Language Tag数组,可利用该方法作为切换语言下拉框的数据源

用例:


console.log(l10n.languages)

// ['zh-Hans-CN', 'en-US']


direction

定义: direction(language?: Intl.BCP47LanguageTag): TextInfoDirection

描述: 绝大多数语言都尊崇从左到右的阅读习惯,但某些语言却例外比如阿拉伯语,此方法可以得知所传入语言的TextInfoDirection

用例:


console.log(l10n.direction('ar'))

// 'rtl'


on

定义: on(event: L10nListenEvent, callback: (...args: any[]) => void)

描述: 用于注册l10nL10nListenEvent事件回调,比如languageChanged

用例:


l10n.on(L10nListenEvent.languageChanged, (...args: any[]) => {

    //在切换语言后的一些操作,某些数据可以放在这里持久化,之后便会重启整个游戏场景

})


off

定义: off(event: L10nListenEvent, callback: (...args: any[]) => void)

描述: 用于反注册l10nL10nListenEvent事件回调

请务必使on与off成对出现,确保正确的销毁无用数据


别名

| 别名 | 原类型 |

|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|

| L10nKey | string |

| L10nValue | string |

| TextInfoDirection | 'ltr' / 'rtl' |

| FallbackLanguage | string / readonly string[] / FallbackLanguageObjectList / ((language: Intl.BCP47LanguageTag) => string / readonly string[] / FallbackLanguageObjectList |


接口

L10nOptions

| 函数/变量名 | 类型 | 可选 |

|---------------------------|-------------------------------------|-----|

| fallbackLanguage | false / FallbackLanguage | 是 |

| localStorageLanguageKey | string | 是 |

| beforeTranslate | (key: L10nKey) => L10nValue | 是 |

| afterTranslate | (key: L10nKey) => L10nValue | 是 |

| returnNull | boolean | 是 |

| returnEmptyString | boolean | 是 |


ResourceList

| 函数/变量名 | 类型 | 可选 |

|--------------------|---------------------------|-----|

| defaultLanguage | Intl.BCP47LanguageTag | 是 |

| fallbackLanguage | Intl.BCP47LanguageTag | 是 |

| languages | Intl.BCP47LanguageTag[] | 否 |

ResourceBundle

| 函数/变量名 | 类型 | 可选 |

|-------------------------------------|---------------------------------|-----|

| [language: Intl.BCP47LanguageTag] | ResourceData | 否 |


ResourceData

| 函数/变量名 | 类型 | 可选 |

|-----------------------|---------------------------------|-----|

| [namespace: string] | ResourceItem | 否 |


ResourceItem

| 函数/变量名 | 类型 | 可选 |

|-----------------|-------|-----|

| [key: string] | any | 否 |


FallbackLanguageObjectList

| 函数/变量名 | 类型 | 可选 |

|----------------------|---------------------|-----|

| [language: string] | readonly string[] | 否 |


StandardOption

| 函数/变量名 | 类型 | 可选 |

|--------------------|---------------------------|-----|

| count | number | 是 |

| defaultValue | L10nValue | 是 |

| language | Intl.BCP47LanguageTag | 是 |

| fallbackLanguage | FallbackLanguage | 是 |


枚举

L10nListenEvent

| 函数/变量名 | 类型 |

|-------------------|-------------------|

| languageChanged | languageChanged |

| onMissingKey | missingKey |

感觉还是FairyGUI好用,切换语言分支,所见即所得,还可以根据不同分支,设置不同的排版之类

大佬们能不能关注下3D的开发呢,譬如我要在3D模型中创建血条文本,能否智能点儿,随意拖拽出文本模型呢,这种便捷操作很急切啊,而且应用场景贼多

您提到的问题将会在后续版本中得到改善,我们有规划后续解决这些操作不方便的问题,我先记录下,感谢反馈

感谢啊,我们因为没这功能,好多智能从需求上砍掉了,期待cocos越来越屌,来世还玩cocos

额,收集完毕之后,如果有不需要翻译的Label,比如纯数字,该怎么从本地开发语言的已填充里面去掉?手动去把该label的L10nLabel组件删掉?

目前未提供删除功能,后续我们会讨论是否增加删除功能。
只要不理会纯数字即可,不会造成使用障碍

删除功能很有必要啊。现在为了不增加额外的L10nLabel组件,只能手动一个个去挂载。
另外希望额外增加一个只读属性,能比较明确的让人知道是附加到哪个节点了。
还有,怎么动态挂载L10nLabel?我在某个label的脚本里写
import { L10nLabel } from ‘db://localization-editor/l10n’;
this.node.addComponent(L10nLabel);
会报错:没有与此调用匹配的重载。
第 1 个重载(共 2 个),“(classConstructor: _types_globals__Constructor): L10nLabel”,出现以下错误。
类型“typeof L10nLabel”的参数不能赋给类型“_types_globals__Constructor”的参数。
不可将“protected”构造函数类型分配给“public”构造函数类型。
第 2 个重载(共 2 个),“(className: string): Component”,出现以下错误。
类型“typeof L10nLabel”的参数不能赋给类型“string”的参数

我们验证一下该问题,稍后给你回复

这是因为目前设计上不建议运行时增加该组件,
如果有需要可以考虑直接调用 了 l10n.t 的方法
原因如下
L10nLabel 的两大作用:
1.在编辑器内扫描与统计的时候能够扫描出来。

2.调用 l10n.t 方法翻译文案

而第一个作用仅在开发时需要,有需要翻译的部分可以直接使用 l10n.t 方法进行翻译。
所以我们不建议运行时增加该组件。

可以描述一下为什么需要运行时增加该组件吗?

并没有需求,只是试一下。我用i18n也是不需要动态加它的label组件,动态文本直接用i18n.t()。
手动删除功能才是必要的。能让扫描生成的key存些实际意义也有些好处。没有手动删除功能,还不如i18n灵活,虽然用下来确实有亮点

这个L10n好像只考虑了那些固定不变的文本翻译,带参数的翻译应该怎么实现呢?

比如下面这种很正常的带参数的翻译需求,L10n 应该怎么使用呢?

zh-cn:玩家 ${0} 今天获得 ${1} 金币
en-us:Player ${0} gets ${1} gold today
ar:يحصل اللاعب ${0} على ${1} قطعة نقدية اليوم

我们原先实现的一个伪代码是

// 后面可以接任意参数,自动替换到里面的 ${0} ${1}
i18n.get("key", player_name, 100);

在 L10N 里面应该是怎么做呢?