给大家分享我的I18解决方案

给大家分享我的I18解决方案

最近在做多语言相关,本来是想打算用官方的I18插件来做.但是发现不满足需求,所以自己写了套I18的处理方案.

官方I18插件存在的问题:

1 不分包.官方的做法是把每种语言的资源都绑定上去,那么一种语言就会多一套资源.运行加载的时候就会把所有语言的资源都加载起来.如果资源多,那么加载量就会很大.运行过程中其实只需要一种语言资源,其他语言用不到,没必要都加载起来.
2 没有处理代码指定的资源.有些时候会动态切换资源,比如编辑器中绑定一堆SpriteFrame数组,运行的时候根据需求更换SpriteFrame. 由于SpriteFrame已经绑定好了,如果要做多语言,需要额外代码处理.

我的需求:

1 每种语言做一个语言bundle,运行时按照需要的语言加载bundle
2 代码指定SpriteFrame不需要额外处理也能达到多语言切换效果
3 不仅仅是Label/RichTxt Sprite, 还需要支持字体,Spine, 声音 总之所有跟多语言相关的都需要支持

我的解决办法:

1 一种语言一个bundle
2 所有语言的资源路径和名字一致(所有多语言名字唯一,方便工具自动化)
3 需要用到多语言的地方绑定一个组件,组件上记录资源路径
4 加载场景 预制体的时候 一并加载需要用到的多语言资源

我的方案

以下是我的方案:以中文/英文为例

目录:

中文为默认语言放到 assets/resources/CN 不为bundle
英文放到 assets/EN 并且为bundle

核心组件:

I18Cmpt: I18组件,记录资源路径,切换语言后自动刷新(目前支持Label,RichTxt,Sprite,Spine)
I18Font: I18字体,记录资源路径,切换语言后自动更换字体
I18PreUrl: I18预加载URL,主要记录某个Node会用到的所有资源路径(排除I18Cmpt上的路径)
I18Mgr: 负责管理多语言资源,切换语言,预加载/加载资源
TxtMgr 文本管理
image

核心接口

I18Mgr.ts
changeBundle:切换语言
preloadScene:预加载
loadScene:加载场景
getRes:根据url获得当前语言的资源

I18SpriteTool.ts
changeI18SpriteFrame:更改spriteFrame
changeSpriteFrame:更改spriteFrame

TxtMgr.ts
getTxt:根据key获得文本,支持通配符

具体操作

1 I18Cmpt组件
给所有需要用到多语言的地方绑定I18Cmpt
比如Label/RichText Sprite Spine
Label记录文本的key,其他资源记录路径
image

2 字体 I18Font
操作同上

3 给所有的scene和prefab的第一个node添加I18PreUrl(预加载时用),如果资源没有预加载,那么在切换语言的时候或者显示的时候,I18Cmpt需要等待资源加载完成后刷新,在这期间会存在闪烁现象.
image

4 所有加载场景的地方使用I18Mgr的preloadScene和loadScene进行替换

5 所有代码指定SpriteFrame的地方使用I18SpriteTool.changeI18SpriteFrame进行替换

效果展示

[上传不了视频,就不展示了,大家项目自己运行吧]

理论存在 实践开始 !!!

我不会傻傻的手动去执行上面的绑定操作的(项目已经上线,增发多语言版本)!!!
我自己写了个工具集合
image

工具配置:run.js

_artPath			美术资源绝对路径
_projectAssetsPath	项目assets绝对路径
_defaultLanguageDir	默认语言目录,相对路径
_languageDir		目标语言目录
_allLanguageDir		项目中所有语言目录(排除默认语言)
_i18CmptType		I18组件的type(项目中具体值)
_i18PrelaodType		项目中I18Pre组件的type(项目中具体值)

[Label自动添加I18Cmpt]

命令:node run.js AddI18Label

执行过程:
1 读取txt文本
2 修改编辑器中带中文的Label
	如果有i18组件,则检查i18上key对应的文本内容,并更新Label上的string
	如果没有i18组件,则自动添加
	如果txt没有对应文本,则自动生成 key:文本 key自增
	将文本的key记录到i18组件上	
3 写出txt文本
	如果旧的 key:文本 没用使用过,则不会被保存
注意事项
仅对中文生效
会更新Label上的string内容
也会根据使用情况调整key
因为涉及到其他语言,仅在第一次运行

[自动导入多语言资源]

比如项目中默认是中文,现在要添加英文.现在美术给了一部分英文资源.那么根据英文资源自动导入.找到项目中使用的中文的资源,放到中文目录. 英文资源放入英文bundle
命令:node run.js ImportTexture

执行过程:
1 读取美术多语言资源,得到文件列表
2 通过1得到列表,找到项目中对应的文件uuid
3 修改项目中使用到多语言资源的场景和prefab
	如果没有i18组件,则自动添加
	将资源路径记录到i18组件
4 移动文件
	将美术资源放入到项目中多语言目录
	将项目中的资源移动到默认语言目录
注意事项
运行前项目先备份
多语言资源名字要和默认语言资源名字一致
执行后打开creator刷新保存项目
	注意检查场景文件和预制体修改日志
	----------modify scene and prefab in project----------		
可能存在多语言美术资源,但项目中没有
	这种情况未处理,注意检查输出
	----------no deal art res----------		
所有资源名要唯一
	目前工具不支持 同名文件

[转换图片格式]

图片类型由texture转换为sprite-frame
图片放入到文件夹后,类型默认是texture,不转换成sprite-frame的话,加载不了.(坑!!!)
命令:node run.js Texture2Sprite “D:/Test/assets/EN/”

执行过程:
1 读取多语言目录
2 查找.png.meta 修改类型
注意事项
[导入多语言资源]后不可立即执行[转换图片格式]
[导入多语言资源]执行后,需要打开Creator生成meta,然后可执行此功能

[添加I18PreUrl]

命令:node run.js AddI18Pre “D:/Test/assets/” “D:/Test/assets/resources/CN/”

执行过程:
1 找到所有的scene和prefab文件
2 找到CN所有资源的url
3 查找scene和prefab中使用到CN资源的uuid
	如果i18Cmpt已经使用,则排除
4 给scene和prefab的第一个Node添加I18Pre组件
注意事项:
运行前项目先备份
运行后打开Creator保存
	修改日志
	-------modify file list-------

骚操作 [手动狗头]

原本项目中默认语言是中文,发印尼,印尼主要是印尼语,几乎用不到中文.
所以我就想要不干脆把默认语言整成印尼语,中文作为语言包.
于是乎我就写了一个更改资源引用的工具.
命令:node run.js ChangeBundle “D:/Test/assets/” “D:/Test/assets/resources/CN/” “D:/Test/assets/EN/”

执行过程:
1 读取默认bundle里的资源UUID
2 读取目标bundle里的资源UUID
3 读取项目中对默认bundle里资源的引用
4 将项目中对默认bundle里的资源引用指向目标bundle的资源
5 将Label/RichTxt的内容重新指向目标bundle的文本(仅对中文生效)
6 更改默认bundle和目标bundle的bundle属性
7 交换默认bundle和目标bundle的位置
注意事项:
运行前项目先备份
默认bundle可以是一个文件夹,也可以是一个bundle
默认bundle和目标bundle的资源名字要相同
默认bundle和目标bundle的资源要一一对应,目标bundle资源不可少于默认bundle
更改中文Label内容

替换资源后,Sprite的SizeMode会改为RAW
游戏运行时,I18Cmpt相关脚本更改spriteFrame时会改为TRIMMED

本工具运行后,记得更改I18Mgr的默认语言

工具集其他工具


检查README.txt

示例项目:
I18.zip (304.1 KB)

工具:
I18Tools.zip (160.3 KB) FileTools.zip (12.4 KB)

夸我!快!!!

16赞

牛逼666

:rofl:

太强了我的哥

creator版本:3.8.4
node 版本:v22.14.0

示例项目中忘记写 加载/预加载示例了 就是要把项目中加载场景的地方改成I18Mgr的preloadscene 和 loadscene 就行了.(主要是为了预加载多语言资源,没有这一步的话,I18Cmpt显示时要等资源下载,再刷新,会先看到中文,再看到英文)

太强了,mark下。
还在用2.4.x的i18n

卧槽,你是真正的大佬!!!

这实在是泰裤辣:kissing_heart:

这个做海外项目特别有用,值得学习

有占位符文本的那种也要挂i18组件吗

占位符文本,是需要代码手动控制的,所以不用挂载I18Cmpt

例如:
assets/CN/txt.json
{ “txt_115”: “正在加载 {1}%” }

assets/resources/EN/txt.json
{ “txt_115”: “loading {1}%” }

脚本:
this.txtProgress.string = txt( "txt_115", p );
txt是封装好的取文本接口,可传递多个参数

这样切换语言的时候是不是无法实时刷新

切换语言需要等待语言包下载完成.语言包下载完成后会通知i18cmpt组件更新,然后i18组件去拉自己需要的资源.
所以切换语言后不能立即刷新.切换语言后,建议做一个loading界面

我是说 用这种动态的旧没办法实时刷新了

如果切换的语言包在远端(非默认语言),就不能实时刷新.如果是本地语言包(默认语言),就可以立即刷新

动态没办法监听到吧

因为没有挂在这个脚本

语言包准备就绪后会发送事件 “I18BundleReady”,你自己监听这个事件然后做些处理

没办法搜到

I18 多语言接入

以默认英文(EN), 切换中文(CN)为例

代码引入

1 将I18脚本文件放入到assets/scrpits/

image

2 修改事件分发器

修改成对应的事件分发器,代码不报错即可

3 在启动场景的脚本里启动I18

收到事件”I18BundleReady”后再进行后续操作

二 新建语言目录

assets/CN/ 设置为bundle包

assets/resources/EN/ 非bundle包

三 多语言文本

1 让策划将多语言文本单独整理成StringUI.xlsx

image

注意事项:

行列,工具会固定位置读取

通配符为{1} {2} {3} …

文本中不可以有双引号,需要使用双引号由单引号替代,实际显示时代码会自动将单引号还原成双引号

2 配置好FileTools/LanguageJson.bat里的目录

运行LanguageJson.bat

运行之后在语言包下有txt.json文件

image
image

3 代码中使用txt获取文本

Old:

label.string = “加载进度” + v + “%”;

文本

assets/CN/txt.json

{ “txt_0”: “加载进度{1}%” }

assets/resources/EN/txt.json

{ “txt_0”: “Load {1}%” }

New:

label.string = txt( “txt_0”, v );

四 多语言图片

1 拿到i18Cmpt脚本的uuid

随便找个项目中的prefab

随便找个节点添加i18Cmpt组件

i18Cmpt的key填写test112233

保存

image

然后用记事本打开prefab文件查找”test112233”

image

这个”type”的值就是i18Cmpt组件的uuid, 记住这个值,还原prefab

2 配置工具运行环境

I18Tools/run.js
image

_artPath 是一个临时的多语言美术资源中转目录

_projectAssetsPath 项目assets目录

_i18CmptType 填写成上一步拿到的i18Cmpt的uuid

3 将美术资源存放到中转目录

注意:

中英文资源名字相同

资源名字在项目中唯一,如果不唯一,则修改资源名字

4 运行工具

node run.js ImportTexture

运行后

① 语言资源会自动归档到各自的语言包中

② 会给使用到资源的节点,自动添加i18Cmpt,自动填写资源路径

建议:

少量美术资源运行,一次导入一个界面的资源

注意查看运行日志

预加载

未避免切换语言时造成闪烁,需要将多语言资源进行预加载

1 有多语言的scene加载接口替换成I18Mgr.getInstance().loadScene

2 单独加载的prefab,在加载后调用I18Mgr.getInstance().loadResByPrefab

3 调用上述接口后I18Cmpt I18BtnUrl I18Fonts上的资源已自动预加载

4 指定资源预加载

某些资源由运行时代码更改,这些资源的预加载可以由I18PreUrl指定预加载

找到该资源使用的scene或者prefab,在第一个节点上添加I18PreUrl组件

image

六 I18Mgr部分接口简介

initDefaultLanguage 加载语言包,根据浏览器参数加载对应语言包

getCurrBundleName 当前语言包名称,可用于当前语言判定

getCurrBundle 获得当前的语言包的bundle

getRes 获得资源

preloadScene 场景预加载

loadScene 加载场景

loadResByNode 加载Node上使用到的多语言资源

loadResByPrefab 加载Prefab上使用到的多语言资源

loadResByUrls 加载指定多种资源

”I18BundleReady”:此事件表示语言包已就绪

七 一些注意事项

I18Cmpt.ts

如果该显示内容由代码控制,不要勾选Refresh

某些spriteFrame由运行时代码控制,比如更换spriteFrame,更换的地方替换为I18SpriteTool.changeI18SpriteFrame,此类节点切记不要勾选I18Cmpt的Refresh

I18BtnUrl.ts 用于处理多语言的按钮

I18Fonts.ts 用于处理Label的字体

项目中,请将资源类型默认设置为spriteFrame,如果切换语言后,图片未显示,则可能是资源类型不是spriteFrame导致

图片资源,为避免拉伸/变形等,语言包的资源加载后,Sprite.sizeMode会设置为RAW, sprite.trim会设置为false

浏览器参数:

CN:中文 EN:英文

默认英文,其他不支持的语言,使用默认语言

语言参数不区分大小写

多语言属性,暂不支持,考虑支持中

工具使用请查阅README.txt, 某些功能久远,请注意使用风险

I18Tools.zip (160.3 KB) FileTools.zip (34.6 KB) i18.zip (9.0 KB)