做多语言的时候用中文做KEY绝对是有100%的好处,如果用英文表示那么代码里面给文字赋值的地方全都是英文,写的代码多了以后维护起来就没有人能看懂了,或者看起来很费劲。
说说用中文做KEY的原理:Unity中给文字赋值的地方就两处, 一个是提前预制在UI Prefab上的文字,还有一个是写在代码里面的文字。那么在开发阶段我们在Prefab和代码里面直接就写中文,等项目后期通过工具把所有中文的地方全部提取出来。然后把提取出来的中文交给策划,让策划他们去翻译去,这样我们之前写的中文就是多语言的KEY,最终显示的界面上的文字是用这个中文KEY读表读出来的。
NGUI里所有的文字都是在UILabel中,可是我们要做图文混排,一般都是在UILabel上在拓展一个自己的脚本,用这个脚本在生成对应的UILabel和UISprite。这篇文章我就先以UILabel来说明原理。
1.遍历所有UIPrefab把包含UILabe(或者是你自己写的)组件找出来,并且把文字提取出来。
2.遍历所有的CS代码,把所有 StrUtil.GetText(“雨松MOMO\n我要换行“); 双引号中间的中文以及字符全部提取出来。
直接上思路代码。
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
using
UnityEngine
;
using
System
.
Collections
;
using
UnityEditor
;
using
System
.
Collections
.
Generic
;
using
System
.
IO
;
using
System
.
Text
;
using
System
.
Text
.
RegularExpressions
;
public
class
TestStart
:
Editor
{
//UIPrefab文件夹目录
private
static
string
UIPrefabPath
=
Application
.
dataPath
+
"/UI"
;
//脚本的文件夹目录
private
static
string
ScriptPath
=
Application
.
dataPath
+
"/Scripts"
;
//导出的中文KEY路径
private
static
string
OutPath
=
Application
.
dataPath
+
"/out.txt"
;
private
static
List
<
string
>
Localization
=
null
;
private
static
string
staticWriteText
=
""
;
[
MenuItem
(
"Tools/导出多语言"
)
]
static
void
ExportChinese
(
)
{
Localization
=
new
List
<
string
>
(
)
;
staticWriteText
=
""
;
//提取Prefab上的中文
staticWriteText
+=
"----------------Prefab----------------------\n"
;
LoadDiectoryPrefab
(
new
DirectoryInfo
(
UIPrefabPath
)
)
;
//提取CS中的中文
staticWriteText
+=
"----------------Script----------------------\n"
;
LoadDiectoryCS
(
new
DirectoryInfo
(
ScriptPath
)
)
;
//最终把提取的中文生成出来
string
textPath
=
OutPath
;
if
(
System
.
IO
.
File
.
Exists
(
textPath
)
)
{
File
.
Delete
(
textPath
)
;
}
using
(
StreamWriter
writer
=
new
StreamWriter
(
textPath
,
false
,
Encoding
.
UTF8
)
)
{
writer
.
Write
(
staticWriteText
)
;
}
AssetDatabase
.
Refresh
(
)
;
}
//递归所有UI Prefab
static
public
void
LoadDiectoryPrefab
(
DirectoryInfo
dictoryInfo
)
{
if
(
!
dictoryInfo
.
Exists
)
return
;
FileInfo
[
]
fileInfos
=
dictoryInfo
.
GetFiles
(
"*.prefab"
,
SearchOption
.
AllDirectories
)
;
foreach
(
FileInfo
files
in
fileInfos
)
{
string
path
=
files
.
FullName
;
string
assetPath
=
path
.
Substring
(
path
.
IndexOf
(
"Assets/"
)
)
;
GameObject
prefab
=
AssetDatabase
.
LoadAssetAtPath
(
assetPath
,
typeof
(
GameObject
)
)
as
GameObject
;
GameObject
instance
=
GameObject
.
Instantiate
(
prefab
)
as
GameObject
;
SearchPrefabString
(
instance
.
transform
)
;
GameObject
.
DestroyImmediate
(
instance
)
;
}
}
//递归所有C#代码
static
public
void
LoadDiectoryCS
(
DirectoryInfo
dictoryInfo
)
{
if
(
!
dictoryInfo
.
Exists
)
return
;
FileInfo
[
]
fileInfos
=
dictoryInfo
.
GetFiles
(
"*.cs"
,
SearchOption
.
AllDirectories
)
;
foreach
(
FileInfo
files
in
fileInfos
)
{
string
path
=
files
.
FullName
;
string
assetPath
=
path
.
Substring
(
path
.
IndexOf
(
"Assets/"
)
)
;
TextAsset
textAsset
=
AssetDatabase
.
LoadAssetAtPath
(
assetPath
,
typeof
(
TextAsset
)
)
as
TextAsset
;
string
text
=
textAsset
.
text
;
//用正则表达式把代码里面两种字符串中间的字符串提取出来。
Regex
reg
=
new
Regex
(
"StrUtil.GetText\\(\".*?\"");
MatchCollection mc = reg.Matches(text);
foreach(Match m in mc)
{
string format = m.Value;
format = format.Replace("
StrUtil
.
GetText
(
\"
","
");
format = format.Replace("
\"
","
");
if(!Localization.Contains(format) && !string.IsNullOrEmpty(format)){
Localization.Add(format);
staticWriteText+=format+"
\
n
";
}
}
}
}
//提取Prefab上的中文
static public void SearchPrefabString(Transform root)
{
foreach(Transform chind in root)
{
//因为这里是写例子,所以我用的是UILabel
//这里应该是写你用于图文混排的脚本。
UILabel label = chind.GetComponent<UILabel>();
if(label != null)
{
string text = label.text;
if(!Localization.Contains(text) && !string.IsNullOrEmpty(text)){
Localization.Add(text);
text = text.Replace("
\
n
",@"
\
n
");
staticWriteText+=text+"
\
n"
;
}
}
if
(
chind
.
childCount
>
0
)
SearchPrefabString
(
chind
)
;
}
}
}
|
比如这个是个简单界面上赋值的代码。用StrUtil.GetText()去取中文,StrUtiL类是我们自己写的。
StrUtiL类里面去处理Key从本地数据表里中替换对应多语言显示的文字。
使用工具代码提取,最终将所有多语言中文的地方提取在txt里面。
最后就是让策划拿着生成出来的中文KEY在Excel表里,给出对应的翻译文字。
还有一个重要的知识点就是换行问题,可能你在Prefab上进行的换行的操作,但是\n并不是字符串,所以我们要把\n转成”\n”字符串写进去。
text.Replace(“\n”,@”\n”);
反过来在读取表的时候还是需要再把”\n”字符串转成\n换行符
text.Replace(@”\n”,”\n”);
这样就没问题了。策划也可以直接在数据表里填写\n来进行换行了。
最后的思考
1.开发的过程中可能要修改代码或者要加新功能删功能,所以我们要把差异性的中文Key提取出来,也就是把新增加的KEY 或者 新删除的KEY列举出来。因为没有变化的就不需要策划重新翻译了。
2.最好能直接帮策划生成Excel文件,Windows上很容易,但是MAC就不行。我知道怎么在Mac上读取excel文件,但是我不知道在mac上怎么生成Excel有哪位大神知道还请告知一下我。要能生成.xlsx的那种,谢谢啦。
3.因为要做图文混排,所以UILabel我已经不直接使用了,而是又写了一个类去管理UILable和UISprite, 其实就是根据XML或者JSON 一类的描述符去动态生成UILable和UISprite在帮它的动态的算坐标,算间距 一类的。因为你的中文KEY需要传参数 比如 “我叫{0}我今年{1}大了” 一类的字符串,所以还是在写一个方法。
最后是本文的下载地址,其实本文主要还是提供一个思路。 如果你有对多语言更好的建议,或者是办法,欢迎在下面给我留言,谢谢。
http://pan.baidu.com/s/1pJmGbzl
- 本文固定链接: http://www.xuanyusong.com/archives/2987
- 转载: 雨松MOMO 2014年07月23日 于 雨松MOMO程序研究院 发表