I2 Localization插件官方有2种添加Source的方法,一种是在Resources文件夹下放I2Languages.asset文件,另一种是在场景中添加Source组件,使得翻译数据跟着场景加载和卸载。
这容易让人产生一个误会就是可以把Source放在预制里,再把预制放在场景中实现复用。而官方并没有推荐这个做法。这个做法不但不推荐,而且还有可能造成错误结果。
通过调试代码发现这样做插件会重复加载Source,也就是场景加载了一次,预制也加载了一次。重复的Source如果不进行任何修改的话不会有什么错误,但是一旦涉及修改问题就会变得很麻烦,因为你修改的Source和显示文字所使用的Source可能不是同一个。
举一个非常具体的例子:
创建一个预制,名为“SourceInProject”,添加Source并添加一个Term,名为“Term001”,文字为“Text001”。
把这个预制放在场景中,改名为“SourceInScene”
随便添加一个Text
添加Localize组件,选择刚刚添加的Term
此时翻译已经显示出来
我们可以在LocalizationManager_Sources.cs的RegisterSceneSources()方法下打断点看到它是怎么加载Source的。这里的问题是它调用的是Resources.FindObjectsOfTypeAll()方法,该方法可以获取项目内的和场景内的所有组件。
可以看到它已经加载了3个Source,其中一个是I2Languages.asset上的Source,可以不用管它。另外两个就是上文所说的重复加载的Source,一个名为SourceInProject,一个名为SourceInScene。正常来讲应该只加载SourceInScene的,可是I2 Localization插件就是这么特别,可能为的是在非运行时也能编辑和使用预制里的数据。
可以写一段测试代码测试修改Term的情况
using I2.Loc;
using UnityEngine;
public class TestI2Localization : MonoBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
var source = LocalizationManager.Sources[1];
var termData = source.GetTermData("Term001");
termData.Languages[0] = "Text002";
}
if (Input.GetKeyDown(KeyCode.B))
{
var source = LocalizationManager.Sources[2];
var termData = source.GetTermData("Term001");
termData.Languages[0] = "Text003";
}
}
}
按了键盘上的A键之后,它修改了SourceInProject
SourceInProject的Term001的文字已经被修改成了Text002,修改成功了。
场景里的Text也同时被修改了
按了键盘上的B键之后,它修改了SourceInScene
SourceInScene的Term001的文字已经被修改成了Text003
但是场景里的Text并未被修改,还是Text002
不要以为它会先搜索预制的Source再搜索场景的Source,这个顺序是不确定的,再实验一两次就会发现Sources[1]对应的是SourceInScene,反过来了。
总结
I2 Localization插件加载Source的逻辑决定了它不支持把Source放在预制里,再把预制放在场景里的这种做法。这样做一是会造成数据的冗余,二是修改Term数据时如果使用LocalizationManager.Sources数组的话就要格外小心。正确的做法是,如果数据是跟着场景加载卸载的,就只在场景里添加Source;如果数据是一直使用的,就放在预制里就行了,它一样会加载的。
你问为什么不使用I2Lanugages.asset?因为它是固定在Resources文件夹里的,不能热更新。