TEngine--Localization模块

Localization模块

TEngine的本地化模块使用的是I2Localization插件实现的(注意该插件为付费插件),可以先看这个插件的文档YouTube视频

通过学习该插件,发现本地化配置是通过ScriptableObject或Prefab来实现的。但是这里面又有一些问题,如果要热更本地化配置,ScriptableObject不容易热更,因为插件内部定义了该文件。用Prefab来配置又会有无法获取当前设备语言等一些小问题。所以TE框架采用了在运行时创建配置对象的方法来完善插件并且统一了管理。

TE里配置本地化模块只需添加在Assets/Editor/I2Localization/I2Languages.asset里配置好的CSV文件。
本地化配置

本地化运行时截图

注:为防止I2Localization插件的install链接失效,可以用下面的文件来复制,并重命名至WebServices

1
2
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
/*                  I2 Google Web Service

This is an script used by I2 Localization and I2 Data to access your spreadsheets
without storing the username/password in the app.

By using this Web Service, the plugin is able to access the spreadsheets even after
the game is deployed and running on the device. So, if you make any modification to
your data, the games will automatically update without building it again.

***************************************************************************************

Follow this steps to Install the Web Service.
If you find any issue, here is a step by step guide:
(also, here is a video showing the steps https://www.youtube.com/watch?v=t-7jx_i1IdM)

First: Set a password to prevent others from changing your locazation data
Just change the value of the variable LocalizationPassword in the next line.
****************************************************************************************/

var LocalizationPassword = "change_this"; // Only change this password if you are in I2L v2.8.7b3 or higher
// When password is "change_this" it gets ignored and any password works

/***************************************************************************************
Now follow this steps to Deploy the WebService:

1- On the menu, select "Deploy" and then "New Deployment"

2- In the window that opens
- In "Execute app as:" select "me(your email)"
- In "Who has access to the app:" select "any one, even anonymous"

3- In the new window that opens, Copy the URL at "Current Web App URL".
That URL will have the format: https://script.google.com/macros/s/XXXXXXXXX/exec

3.1- Depending on your account type, you may get a warning from google saying:
"This app isn't verified"
In that case, click "Show advanced" and then "Go to Copy of I2GoogleWebServiceV5 (unsafe)"
Then grant the webservice permisions (i.e. to create/modify spreadsheets files)

4- In the menu, select "Run" and then "DoGet"

4.1- (If a dialog is shown) Authorize the script to access your spreadsheets and file date data

5- Paste the URL from step 3 in the "Web Service URL" on the Unity Editor



***************************************************************************************/
var LocalizationPrefix = "I2Loc";

function GetVersion()
{
return 5;
}

function doGet(e)
{
var result;
var action;

if (e===undefined || e.parameters.action==undefined)
action = "Ping";
else
action = e.parameters.action.toString();

if (LocalizationPassword!="change_this" && (action=="GetSpreadsheetList" || action=="NewSpreadsheet" || action=="SetLanguageSource") &&
e!==undefined && e.parameters.password!=LocalizationPassword)
{
return ContentService.createTextOutput("Wrong Password").setMimeType(ContentService.MimeType.TEXT);
}

//Logger.log(action);
switch( action)
{
case "Ping" : var result = {}; result["script_version"]=GetVersion(); break;

case "GetSpreadsheetList": result = doGetSpreadsheetList(e); break;

case "GetLanguageSource": return ContentService.createTextOutput(doGetLanguageSource(e)).setMimeType(ContentService.MimeType.TEXT);

case "NewSpreadsheet": result = doCreateSpreadsheet(e); break;

case "Translate" : return ContentService.createTextOutput(doTranslate(e)).setMimeType(ContentService.MimeType.TEXT);

case "SetLanguageSource" : result = doSetLanguageSource(e); break;

default: result = "unknown action";
}

var JsonValue = JSON.stringify(result);

return ContentService.createTextOutput(JsonValue.toString()).setMimeType(ContentService.MimeType.JSON);
}

function doPost(e)
{
return doGet(e);
}
1
2
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
function testGetSource()
{
var res = doGetLanguageSource()
Logger.log(res);
}

function doGetLanguageSource(e)
{
var key;
var version;
//Logger.log("start");

if (e===undefined || e.parameters===undefined || e.parameters.key===undefined)
id = "1nNwzZkSK-olYxOzmqY-pBQFx-PpsdFTXh-daUUN2tMA";
else
id = e.parameters.key;

if (e===undefined || e.parameters===undefined || e.parameters.version===undefined)
version = -1;
else
version = e.parameters.version;

var currentVersion = getFileLastUpdateTime(id);

if (currentVersion <= version)
return "";

var spreadsheet = SpreadsheetApp.openById(id);
if (spreadsheet===null) return "";

if (spreadsheet.getName().indexOf(LocalizationPrefix)!=0)
return "";

var results = "version="+currentVersion+",script_version="+ GetVersion()+",";
if (e!=undefined && e.parameters!=undefined && e.parameters.justcheck=="true")
{
return results;
}

var sheets = spreadsheet.getSheets();
for (var i=0; i<sheets.length; ++i)
{
var sheetName = sheets[i].getName();
if (StartsWith(sheetName, "~"))
continue;
results+="[i2category]"+sheetName+"[/i2category]";
results+= SheetToCSV(sheets[i])+"[/i2csv]";
}
//Logger.log(results);
return results;
}

function SheetToCSV(sheet)
{
// This represents ALL the data
var range = sheet.getDataRange();
var values = range.getValues();
//var formulas = range.getFormulas();

// In the new format, the Type and Description comes from the notes
// this section reconstructs those columns before sending the CSV
if (values[0][1] != "Type")
{
var notes = range.getNotes();

values[0][0] = "Description";
values[0].unshift("Keys","Type");

for (var i=1; i<values.length; ++i)
{
var note = notes[i][0];
var key = values[i][0];
if (note.indexOf("Type:")==0)
{
var iLineEnd = note.indexOf("\n");
if (iLineEnd<0) iLineEnd = note.length;
var type = note.substr(5, iLineEnd-5);
var desc = note.substr(iLineEnd+1);
if (type[0]==' ') type = type.substr(1, type.length-1);
values[i][0] = desc;
values[i].unshift(key, type);
}
else
{
values[i][0] = note;
values[i].unshift(key, "");
}
}
}

// Remove any column that starts with ~
for (var i=values[0].length-1; i>2; i--)
{
if (StartsWith(values[0][i], "~"))
{
for (var j = 0; j < values.length; j++)
values[j].splice(i,1);
}
}

// Remove any row that starts with ~
for (var i=values.length-1; i>0; i--)
{
if (StartsWith(values[i][0], "~"))
values.splice(i,1);
}


for (var i = 0; i < values.length; i++)
values[i] = values[i].join("[*]");
var row = values.join("[ln]");

return row;
}

function getFileLastUpdateTime(id)
{
try
{
var file = DriveApp.getFileById(id);
if (file===null)
return 0;

var date = file.getLastUpdated();// this is not very accurate
return date.getTime();
}
catch (e)
{
}

/*try // this method is more accurate but requires user to enable Drive SDK on their developer console
{
var revisions = Drive.Revisions.list(id);
Logger.log(JSON.stringify(revisions));
if (revisions && revisions.items && revisions.items.length > 0)
{
var lastRevision = revisions.items.length-1;
var lastModified = new Date(revisions.items[lastRevision].modifiedDate);
return lastModified.getTime();
}
}
catch (e)
{
Logger.log(e);
}*/

return 0;
}
1
2
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
function doSetLanguageSource(e)
{
//var id = "1nNwzZkSK-olYxOzmqY-pBQFx-PpsdFTXh-daUUN2tMA";
var id = e.parameters.key.toString();

var spreadsheet = SpreadsheetApp.openById(id);
if (spreadsheet===null) return false;

if (spreadsheet.getName().indexOf(LocalizationPrefix)!=0)
return false;

//var updateMode = "AddNewTerms";//"Replace";
//var CSVstring = "Category<I2Loc>Key[*]Type[*]Desc[*]English[*]Spanish[*]Arabic[*]$TestLang[ln]Term2[*]Text[*][*]Anotherthis is'frank' hey [font] and [/final] more <tag></tag> text 524[*]Anotherthis is'frank' hey [font] and [/final] more <tag></tag> text 524[*]Anotherthis is'frank' hey [font] and [/final] more <tag></tag> text 524[*]Anotherthis is'frank' hey [font] and [/final] more <tag></tag> text524<I2Loc>Default<I2Loc>Key[*]Type[*]Desc[*]English[*]Spanish[*]Arabic[*]$TestLang[ln]Term1[*]Text[*][*]My text524[*]My text524[*]My text524[*]My text524[ln]Term4[*]Text[*][*]''SpecialCases[*]'''SpecialCases'[*]''SpecialCases'[*]'=SpecialCases";
//var CSVstring = "Default<I2Loc>Key[*]Type[*]Desc[*]English[*]French[*]German[*]Spanish[*]Japanese[*]Korean[*]Portuguese (Brazil)[*]Russian[*]Italian[*]Chinese (Simplified)[ln]TestPhrase1[*]Text[*][*]T1-This is English (update)[*]T1-This is French[*]T1-This is German[*]''T1-This is Spanish[*]'=T1-This is Japanese[*]T1-This is Korean[*]T1-This is Portuguese[*]T1-This is Russian[*]T1-This is Italian[*]T1-This is Chinese[ln]Amaranth-Regular[*]Text[*][*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[ln]_CurrentLanguageLocalizedName[*]Text[*][*]English[*]Français[*]Deutsch[*]Español[*]日本語[*]한국어[*]Português[*]Русский[*]Italiano[*]中文[ln]Test3[*]Text[*][*]T3-En[*]T3-Fr[*]T3-Gr[*]T3-Es[*]T3-Ja[*]T3-Ko[*]T3-Pr[*]T3-Ru[*]T3-It[*]T3-Cn[ln]NewKey1[*]Text[*][*]New1_English[*]New1_French[*]New1_German[*]New1_Spanish[*]New1_Japanese[*]New1_Korean[*]New1_Portuguese (Brazil)[*]New1_Russian[*]New1_Italian[*]New1_Chinese (Simplified)<I2Loc>Quests<I2Loc>Key[*]Type[*]Desc[*]English[*]French[*]German[*]Spanish[*]Japanese[*]Korean[*]Portuguese (Brazil)[*]Russian[*]Italian[*]Chinese (Simplified)[ln]Quest1[*]Text[*][*]quest1-English[*]quest1-French[*]quest1-German[*]quest1-Spanish[*]quest1-Japanese[*]quest1-Korean[*]quest1-Portuguese[*]quest1-Russian[*]quest1-Italian[*]quest1-Chinese[ln]Quest2[*]Text[*][*]quest2-English[*]quest2-French[*]quest2-German[*]quest2-Spanish[*]quest2-Japanese[*]quest2-Korean[*]quest2-Portuguese (Brazil)[*]quest2-Russian[*]quest2-Italian[*]quest2-Chinese (Simplified)";

var updateMode = e.parameters.updateMode.toString();
var CSVstring = e.parameters.data.toString();




var lines = CSVstring.split("<I2Loc>");

for (var i=0; i<lines.length; i+=2)
CSVtoSheet(lines[i], lines[i+1], spreadsheet, updateMode);

if (updateMode=="Replace")
{
// Remove non existent categories
var sheets = spreadsheet.getSheets();
for (var i=sheets.length-1; i>=0; --i)
if (!ContainsCSV(lines, sheets[i].getName()))
spreadsheet.deleteSheet(sheets[i]);
}

return true;
}

function ContainsCSV( lines, category )
{
for (var i=0; i<lines.length; i+=2)
if (lines[i]==category)
return true;
return false;
}

function CSVtoSheet(sheetname, CSVstring, spreadsheet, updateMode)
{
var sheet = spreadsheet.getSheetByName(sheetname);
if (sheet===null)
sheet = spreadsheet.insertSheet(sheetname);

var csv = ParseI2CSV(CSVstring);

if (updateMode=="Replace")
{
sheet.clear();
}
else
RemoveOldHeaders(sheet);

var range = sheet.getDataRange();
var rangeData = range.getValues();
var notes = range.getNotes();

//--[ Combine Languages ]---
var languages = [];
for (var i=1; i<rangeData[0].length; ++i)
languages.push(rangeData[0][i]);

for (var i=3; i<csv[0].length; ++i)
{
var index = LanguageIndex(languages, csv[0][i]);
if (index<0)
languages.push(csv[0][i]);
}

//--[Add new languages to the existing data]---

for (var i=0; i<rangeData.length; ++i)
{
for (var j=rangeData[i].length; j<languages.length+1; ++j)
rangeData[i].push("");
notes[i].length = rangeData[i].length;

for (var j=0; j<notes[i].length; ++j)
notes[i][j] = "";
}
rangeData[0][0] = "Keys";
for (var i=0; i<languages.length; ++i)
rangeData[0][i+1] = languages[i];

//--[ Add/Update the terms in the CSV array ]------
for (var i=1; i<csv.length; i++)
{
var index = TermIndex(rangeData, csv[i][0]);
var termData;

if (index<0)
{
termData = [csv[i][0]];//, csv[i][1], csv[i][2]];
termData.length = rangeData[0].length;

for (var j=0; j<languages.length; ++j)
termData[j+1] = "";

rangeData.push(termData);
notes.push([]);
index=rangeData.length-1;
}
else
{
termData = rangeData[index];
if (updateMode == "AddNewTerms") // This term already exist and we only want to Add New terms
{
// Fix any value that has a Prefix Character (') or (=)
for (var j=1; j<termData.length; ++j)
{
var ss=termData[j].toString();
if (ss.length>1 && (ss[0]=='\'' || ss[0]=='='))
termData[j] = "'" + termData[j];
}
continue;
}
}

for (var j=3; j<csv[i].length; ++j)
{
var idx = 1+LanguageIndex(languages, csv[0][j]);
var val = csv[i][j];
termData[idx] = val;//(StartsWith(val, "[i2auto]") ? "" : val);
}

notes[index].length = rangeData[index].length;
for (var j=1; j<notes[index].length; ++j)
notes[index][j] = "";
notes[index][0] = GetCellNote(csv[i][1], csv[i][2]);
}

var range = sheet.getRange(1,1, rangeData.length, rangeData[0].length);

range.setValues(rangeData);
range.setNotes(notes);

SetupSheetFormat( sheet, range );
//SetupAutoTranslated( range, rangeData, languages, csv );
}

function RemoveOldHeaders( sheet )
{
var range = sheet.getDataRange();
var rangeData = range.getValues();
if (rangeData.length==0 || rangeData[0].length<3 || rangeData[0][1]!="Type" || rangeData[0][2]!="Description")
return;

var notes = range.getNotes();
for (var i=1; i<rangeData.length; ++i)
if (notes[i][0]=="")
notes[i][0] = GetCellNote( rangeData[i][1], rangeData[i][2] );

range.setNotes(notes);
sheet.deleteColumns(2, 2);
}

function LanguageIndex( languages, languageName )
{
for (var i=0; i<languages.length; ++i)
if (languages[i] == languageName)
return i;
return -1;
}

function TermIndex( data, termName )
{
for (var i=1; i<data.length; ++i)
if (data[i][0] == termName && data[i][0]!="")
return i;
return -1;
}

function GetCellNote( mType, mDesc )
{
var note = "";
if (mType!="" && mType!="Text")
note = "Type:"+mType;

if (mDesc!="")
note += (note!="" ? "\n"+mDesc : mDesc);
return note;
}

function MyTest()
{
var spreadsheet = SpreadsheetApp.openById("1-ypADjz2_09_SJwV0hjq6Mn7o1f1XlaAQB0HZRovuwY");
if (spreadsheet===null) return false;

//var I2CSVstring = "Key[*]Type[*]Desc[*]English[*]Spanish[ln]Texto de ejemplo[*]Text[*]cc[*]Texto de ejemplo[*][ln]Abajo[*]Text[*][*]Down1[*]Abajo[ln]Ar[*]Text[*][*]Up[*]Arriba[ln]";
//var CSVstring = "Default=Keys,Type,Description,English,Spanish\nTexto de ejemplo,bb,cc,Texto de ejemplo,[i2auto]Texto de EJEMPLO\nAbajo,,,[i2auto]Down,[i2auto]Abajo\nAr,,,[i2auto]Above,Arriba\n"
var I2CSVstring = "Default<I2Loc>Key[*]Type[*]Desc[*]English[*]French[*]German[*]Spanish[*]Japanese[*]Korean[*]Portuguese (Brazil)[*]Russian[*]Italian[*]Chinese (Simplified)[ln]TestPhrase1[*]Text[*][*]T1-This is English (update)[*]T1-This is French[*]T1-This is German[*]T1-This is Spanish[*]T1-This is Japanese[*]T1-This is Korean[*]T1-This is Portuguese[*]T1-This is Russian[*]T1-This is Italian[*]T1-This is Chinese[ln]Amaranth-Regular[*]Text[*][*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[*]Amaranth-Regular[ln]_CurrentLanguageLocalizedName[*]Text[*][*]English[*]Français[*]Deutsch[*]Español[*]日本語[*]한국어[*]Português[*]Русский[*]Italiano[*]中文[ln]Test3[*]Text[*][*]T3-En[*]T3-Fr[*]T3-Gr[*]T3-Es[*]T3-Ja[*]T3-Ko[*]T3-Pr[*]T3-Ru[*]T3-It[*]T3-Cn[ln]NewKey1[*]Text[*][*]New1_English[*]New1_French[*]New1_German[*]New1_Spanish[*]New1_Japanese[*]New1_Korean[*]New1_Portuguese (Brazil)[*]New1_Russian[*]New1_Italian[*]New1_Chinese (Simplified)<I2Loc>Quests<I2Loc>Key[*]Type[*]Desc[*]English[*]French[*]German[*]Spanish[*]Japanese[*]Korean[*]Portuguese (Brazil)[*]Russian[*]Italian[*]Chinese (Simplified)[ln]Quest1[*]Text[*][*]quest1-English[*]quest1-French[*]quest1-German[*]quest1-Spanish[*]quest1-Japanese[*]quest1-Korean[*]quest1-Portuguese[*]quest1-Russian[*]quest1-Italian[*]quest1-Chinese[ln]Quest2[*]Text[*][*]quest2-English[*]quest2-French[*]quest2-German[*]quest2-Spanish[*]quest2-Japanese[*]quest2-Korean[*]quest2-Portuguese (Brazil)[*]quest2-Russian[*]quest2-Italian[*]quest2-Chinese (Simplified)";
//var I2CSVstring = "Key[*]Type[*]Desc[*]English US [en-US][*]French CAN[*]German[*]Italian[*]Portuguese (Brazil)[*]Russian[*]Spanish[*]Polish[ln]Award_Name_Audience[*]Text[*][*]Audience[*][*]Publikum[*]Pubblico[*]Plateia[*]Зритель[*]Audiencia[*]Publiczność[ln]Award_Name_Steadfast[*]Text[*][*]Steadfast[*]Résolu[*]Resolut[*]Deciso[*]Inabalável[*]Стоик[*]Firme[*]Niezłomny[ln]Award_Name_Lethal[*]Text[*][*]Lethal[*]Mortel[*]Tödlich[*]Letale[*]Letal[*]Убийца[*]Letal[*]Śmiertelny[ln]Award_Name_Fleet[*]Text[*][*]Fleet[*]Rapide[*]Schnell[*]Veloce[*]Pé de vento[*]Ловкач[*]Veloz[*]Flota[ln]Award_Name_Greedy[*]Text[*][*]Greedy[*]Avare[*]Gierig[*]Avido[*]Ganancioso[*]Жадина[*]Materialista[*]Chciwy[ln]Award_Name_Hot Temper[*]Text[*][*]Hot Temper[*]Tempérament Fort[*]Temperamentvoll[*]Irascibile[*]Pavio curto[*]Сорвиголова[*]Temperamental[*]Gorący temperament[ln]Award_Name_Cautious[*]Text[*][*]Cautious[*]Prudent[*]Vorsichtig[*]Prudente[*]Cuidadoso[*]Скромник[*]Prudente[*]Ostrożny[ln]Award_Name_Efficient[*]Text[*][*]Efficient[*]Efficace[*]Effizient[*]Efficiente[*]Eficiente[*]Мастер[*]Eficiente[*]Wydajny[ln]Award_Name_Champion[*]Text[*][*]Champion[*]Champion[*]Ass[*]Asso[*]Campeão[*]Победитель[*]As[*]Mistrz[ln]Award_Name_Fragile[*]Text[*][*]Fragile[*]Fragile[*]Zerbrechlich[*]Fragile[*]Frágil[*]Хлюпик[*]Frágil[*]Kruchy[ln]Award_Name_Most Helpful[*]Text[*][*]Most Helpful[*]Serviable[*]Hilfreich[*]Servizievole[*]Grande auxílio[*]Доброе сердце[*]Más Servicial[*]najbardziej pomocne[ln]Award_Name_Impatient[*]Text[*][*]Impatient[*]Impatient[*]Ungeduldig[*]Impaziente[*]Impaciente[*]Торопыга[*]Impaciente[*]Jestem cierpliwy[ln]Award_Name_Intrusive[*]Text[*][*]Intrusive[*]Intrusif[*]Aufdringlich[*]Invadente[*]Intruso[*]Забияка[*]Metomentodo[*]Natrętny[ln]Award_Name_Outspoken[*]Text[*][*]Outspoken[*]Franc[*]Freimütig[*]Franco[*]Tagarela[*]Краснобай[*]Cotorra[*]Szczery[ln]Award_Name_Obstinate[*]Text[*][*]Obstinate[*]Obstiné[*]Stur[*]Ostinato[*]Obstinado[*]Упрямец[*]Cabezota[*]Uparty[ln]Award_Name_Pacifist[*]Text[*][*]Pacifist[*]Pacifiste[*]Pazifist[*]Pacifista[*]Pacífico[*]Пацифист[*]Pacifista[*]Pacyfista[ln]Award_Name_Push Over[*]Text[*][*]Push Over[*]Frêle[*]Schwächling[*]Debole[*]Pressionado[*]Тряпка[*]Endeble[*]Wywracać pchnięciem[ln]Award_Name_Rampager[*]Text[*][*]Rampager[*]Ravageur[*]Wüter[*]Furioso[*]Vândalo[*]Вандал[*]Apisonadora[*]Rampager[ln]Award_Name_Most Skilled[*]Text[*][*]Most Skilled[*]Le plus habile[*]Am geschicktesten[*]Abilissimo[*]Habilidoso[*]Умелец[*]Más Hábil[*]najbardziej wykwalifikowanych[ln]Award_Name_Rowdy[*]Text[*][*]Rowdy[*]Désobéissant[*]Schläger[*]Turbolento[*]Arruaceiro[*]Буян[*]Bullebulle[*]Hałaśliwy[ln]";

Logger.log("start");
Logger.log( ParseI2CSV(I2CSVstring));
//CSVtoSheet("Default", I2CSVstring, spreadsheet, "Replace") ;
//CSVtoSheet("Default", I2CSVstring, spreadsheet, "Replace") ;
//CSVtoSheet("Default", I2CSVstring, spreadsheet, "Replace") ;
//CSVtoSheet("Default", I2CSVstring, spreadsheet, "Replace") ;
//CSVtoSheet("Default", I2CSVstring, spreadsheet, "Replace") ;
Logger.log("done");
}

function SetupSheetFormat( sheet, range )
{
sheet.clearFormats();
range.clearDataValidations();

//-- COLORS ------------------------
range.setBackground("white");
sheet.getRange(1, 1, 1, sheet.getLastColumn()).setBackground("#e6b8af");
if (sheet.getLastRow()>1)
sheet.getRange(2, 1, sheet.getLastRow()-1, 1).setBackground("#c9daf8");

//-- LAYOUT ------------------------
sheet.setFrozenColumns(1);
sheet.setFrozenRows(1);

//sheet.autoResizeColumn(1);
//if (sheet.getColumnWidth(1)>150) sheet.setColumnWidth(1, 150);
}

function SetupAutoTranslated( range, values, languages, csv )
{
var backgrounds = range.getBackgrounds();
for (var r=1; r<values.length; ++r)
for (var c=1; c<values[r].length; ++c)
if (values[r][c]==="" && (csv[r][1]=="" || csv[r][1]=="Text"))
{
SetAutoTranslateCell(values, r, c, languages);
backgrounds[r][c] = "#f0f0f0";
}
range.setBackgrounds( backgrounds );
range.setValues( values );
}

function SetAutoTranslateCell( values, r, c, languages )
{
var code = "auto";
var term = values[0];
var fc = 0;
for (var cc=1; cc<values[r].length; ++cc)
if (cc!=c && values[r][cc]!="")
{
term = values[r][cc];
fc = cc;
code = GetLangCode( languages[fc-1] );
break;
}

var targetCell = GetCellName(fc,r);
values[r][c] = '=GOOGLETRANSLATE('+targetCell+';"'+code+'";"'+GetLangCode( languages[c-1] )+'")';
}


function GetCellName( c, r )
{
return ("ABCDEFGHIJKLMNOPQRSTUVWXYZ")[c] + (r+1);
}

function GetLangCode( lan )
{
if (lan==undefined) return "auto";
if (lan.toLowerCase().indexOf("afrikaans")>=0) return "af";
if (lan.toLowerCase().indexOf("albanian")>=0) return "sq";
if (lan.toLowerCase().indexOf("arabic")>=0) return "ar";
if (lan.toLowerCase().indexOf("azerbaijani")>=0) return "az";
if (lan.toLowerCase().indexOf("basque")>=0) return "eu";
if (lan.toLowerCase().indexOf("bengali")>=0) return "bn";
if (lan.toLowerCase().indexOf("belarusian")>=0) return "be";
if (lan.toLowerCase().indexOf("bulgarian")>=0) return "bg";
if (lan.toLowerCase().indexOf("catalan")>=0) return "ca";
if (lan.toLowerCase().indexOf("simplified")>=0) return "zh-cn";
if (lan.toLowerCase().indexOf("traditional")>=0) return "zh-tw";
if (lan.toLowerCase().indexOf("chinese")>=0) return "zh-cn";
if (lan.toLowerCase().indexOf("croatian")>=0) return "hr";
if (lan.toLowerCase().indexOf("czech")>=0) return "cs";
if (lan.toLowerCase().indexOf("danish")>=0) return "da";
if (lan.toLowerCase().indexOf("dutch")>=0) return "nl";
if (lan.toLowerCase().indexOf("english")>=0) return "en";
if (lan.toLowerCase().indexOf("esperanto")>=0) return "eo";
if (lan.toLowerCase().indexOf("estonian")>=0) return "et";
if (lan.toLowerCase().indexOf("filipino")>=0) return "tl";
if (lan.toLowerCase().indexOf("finnish")>=0) return "fi";
if (lan.toLowerCase().indexOf("french")>=0) return "fr";
if (lan.toLowerCase().indexOf("galician")>=0) return "gl";
if (lan.toLowerCase().indexOf("georgian")>=0) return "ka";
if (lan.toLowerCase().indexOf("german")>=0) return "de";
if (lan.toLowerCase().indexOf("greek")>=0) return "el";
if (lan.toLowerCase().indexOf("gujarati")>=0) return "gu";
if (lan.toLowerCase().indexOf("haitian")>=0) return "ht";
if (lan.toLowerCase().indexOf("hebrew")>=0) return "iw";
if (lan.toLowerCase().indexOf("hindi")>=0) return "hi";
if (lan.toLowerCase().indexOf("hungarian")>=0) return "hu";
if (lan.toLowerCase().indexOf("icelandic")>=0) return "is";
if (lan.toLowerCase().indexOf("indonesian")>=0) return "id";
if (lan.toLowerCase().indexOf("irish")>=0) return "ga";
if (lan.toLowerCase().indexOf("italian")>=0) return "it";
if (lan.toLowerCase().indexOf("japanese")>=0) return "ja";
if (lan.toLowerCase().indexOf("kannada")>=0) return "kn";
if (lan.toLowerCase().indexOf("korean")>=0) return "ko";
if (lan.toLowerCase().indexOf("latin")>=0) return "la";
if (lan.toLowerCase().indexOf("latvian")>=0) return "lv";
if (lan.toLowerCase().indexOf("lithuanian")>=0) return "lt";
if (lan.toLowerCase().indexOf("macedonian")>=0) return "mk";
if (lan.toLowerCase().indexOf("malay")>=0) return "ms";
if (lan.toLowerCase().indexOf("maltese")>=0) return "mt";
if (lan.toLowerCase().indexOf("norwegian")>=0) return "no";
if (lan.toLowerCase().indexOf("persian")>=0) return "fa";
if (lan.toLowerCase().indexOf("polish")>=0) return "pl";
if (lan.toLowerCase().indexOf("portuguese")>=0) return "pt";
if (lan.toLowerCase().indexOf("romanian")>=0) return "ro";
if (lan.toLowerCase().indexOf("russian")>=0) return "ru";
if (lan.toLowerCase().indexOf("serbian")>=0) return "sr";
if (lan.toLowerCase().indexOf("slovak")>=0) return "sk";
if (lan.toLowerCase().indexOf("slovenian")>=0) return "sl";
if (lan.toLowerCase().indexOf("spanish")>=0) return "es";
if (lan.toLowerCase().indexOf("swahili")>=0) return "sw";
if (lan.toLowerCase().indexOf("swedish")>=0) return "sv";
if (lan.toLowerCase().indexOf("tamil")>=0) return "ta";
if (lan.toLowerCase().indexOf("telugu")>=0) return "te";
if (lan.toLowerCase().indexOf("thai")>=0) return "th";
if (lan.toLowerCase().indexOf("turkish")>=0) return "tr";
if (lan.toLowerCase().indexOf("ukrainian")>=0) return "uk";
if (lan.toLowerCase().indexOf("urdu")>=0) return "ur";
if (lan.toLowerCase().indexOf("vietnamese")>=0) return "vi";
if (lan.toLowerCase().indexOf("welsh")>=0) return "cy";
if (lan.toLowerCase().indexOf("yiddish")>=0) return "yi";
return "auto";
}

function StartsWith( text, tag )
{
if (typeof text !== 'string')
return false;

if (text.length < tag.length)
return false;

return (text.substr(0, tag.length) == tag);
}


1
2
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
function doGetSpreadsheetList()
{
var result = {};
var Spreadsheets = DriveApp.getFilesByType(MimeType.GOOGLE_SHEETS);

while (Spreadsheets.hasNext())
{
var file = Spreadsheets.next();
var SpreadSheetName = file.getName();

if (SpreadSheetName.indexOf(LocalizationPrefix)==0)
{
result[SpreadSheetName] = file.getId();
}
}
return result;
}

function doCreateSpreadsheet(e)
{
var name = e.parameters.name.toString();
if (name.indexOf(LocalizationPrefix)!=0)
name = LocalizationPrefix + " " + name;

var ssNew = SpreadsheetApp.create(name);
var sheet = ssNew.getActiveSheet();

sheet.setName("Default");

CSVtoSheet("Default", "Key,Type,Desc,English", ssNew, "Replace");

var result = {};
result["name"] = name;
result["id"] = ssNew.getId();
result["script_version"]=GetVersion();

return result;
}


function BasicEncriptation( data, password )
{
data = "[Header]" + data;
var s = "";
for (var i=0; i<data.length; ++i)
{
s += String.fromCharCode(data.charCodeAt(i) + password.charCodeAt(i % password.length));
}
return s;
}

function BasicDeEncriptation( data, password )
{
var s = "";
for (var i=0; i<data.length; ++i)
s += String.fromCharCode(data.charCodeAt(i) - password.charCodeAt(i % password.length));

if (s.substr(0, "[Header]".length) != "[Header]")
return null;

return s.substr("[Header]".length);
}
1
2
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
function ParseCSV( Line )
{
var iStart = 0;
var CSV = [];

while (iStart < Line.length)
{
var list = [];

var TextLength = Line.length;
var iWordStart = iStart;
var InsideQuote = false;

while (iStart < TextLength)
{
var c = Line[iStart];

if (InsideQuote)
{
if (c=='"') //--[ Look for Quote End ]------------
{
if (iStart+1 >= TextLength || Line[iStart+1] != '"') //-- Single Quote: Quotation Ends
{
InsideQuote = false;
}
else
if (iStart+2 < TextLength && Line[iStart+2]=='"') //-- Tripple Quotes: Quotation ends
{
InsideQuote = false;
iStart+=2;
}
else
iStart++; // Skip Double Quotes
}
}

else //-----[ Separators ]----------------------

if (c=='\n' || c==',')
{
list.push( AddCSVtoken(Line, iStart, iWordStart) );
iWordStart = iStart+1;

if (c=='\n') // Stop the row on line breaks
{
iStart++;
break;
}
}

else //--------[ Start Quote ]--------------------

if (c=='"')
InsideQuote = true;

iStart++;
}
if (iStart>iWordStart)
{
list.push( AddCSVtoken(Line, iStart, iWordStart) );
iWordStart = iStart+1;
}

CSV.push( list );
}
return CSV;
}

function AddCSVtoken( Line, iEnd, iWordStart)
{
var Text = Line.substr(iWordStart, iEnd-iWordStart);

Text = Text.replace(/""/gi, '"' );
if (Text.length>1 && Text[0]=='"' && Text[Text.length-1]=='"')
Text = Text.substr(1, Text.length-2 );

return Text;
}

function ParseI2CSV( Line )
{
var lines = Line.split("[ln]");
for (var i=0; i<lines.length; ++i)
lines[i] = lines[i].split("[*]");
return lines;
}
1
2
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
114
115
116
117
118
function testTranslate()
{
var e = "en:tr=bet";
var result = myTranslate(e);
Logger.log(result);
}
function doTranslate(e)
{
if (e===undefined || e.parameters==undefined || e.parameters.list==undefined)
e = "es:en=El jugador no tiene puntos<I2Loc>en:ru=another <I2Loc>en:ru=otro mas<I2Loc>en:ru=last one"
//e = "auto:es=This is a text";
//e = "en:es,fr=This is a text<I2Loc>en:es,ko=THIS IS ANOTHER TEXT";
else
e = e.parameters.list.toString();

return myTranslate(e);
}

function myTranslate(e)
{
var result = "";
var lines = e.split("<I2Loc>");
//var count=0;
//for (var m=0; m<30; ++m)
for (var i=0; i<lines.length; i++)
{
if (i>0)
result += "<I2Loc>";
var line = lines[i];
var textIdx = line.indexOf("=");
var text = line.substr(textIdx+1);

var baseLangIdx = line.indexOf(":");
var baseLang = line.substr(0, baseLangIdx);
if (baseLang == "auto") baseLang = "";

var targetLangLine = line.substr(baseLangIdx+1, textIdx-baseLangIdx-1);
var targetLangs = targetLangLine.split(",");

//result += text;

//var translation = []
for (var t=0; t<targetLangs.length; t++)
{
var translated = LanguageApp.translate(text, baseLang, targetLangs[t]);
translated = fixCase(text, translated);

if (t>0) result += "<i2>";
result += translated;

//count++;
//if (count>=90)
//{
// count = 0;
// Utilities.sleep(2000);
//}
//translation.push( fixCase(text, translated) );
//Logger.log(targetLangs[i] + "=" +translation[t]);
}
}
//Logger.log(LanguageApp.translate("El jugador no tiene puntos.", "es", "EN"));
//Logger.log(result);
return result;
}

function fixCase( original, translated )
{
/*if (original == original.toUpperCase())
return translated.toUpperCase();

if (original == original.toLowerCase())
return translated.toLowerCase();
*/
if (original == toTitleCase(original))
return toTitleCase(translated);

/*if (original == toUpperFirst(original))
return toUpperFirst(translated);*/

return translated;
}

function toUpperFirst(str)
{
return str.toLowerCase().replace(/(^[a-z]|\. [a-z]|\.\n[a-z])/g,
function($1){
return $1.toUpperCase();
}
);
}

function toTitleCase( str )
{
return str.toLowerCase().replace(/(^[a-z]| [a-z]|-[a-z])/g,
function($1){
return $1.toUpperCase();
}
);
}

function testURL()
{
var options =
{
"langpair" : "en|es",
"text" : "hello%20world",
"vi" : "c",
"hl" : "en",
"submit" : "Translate"
};
var url1 = "https://translate.google.com/?hl=en&vi=c&ie=UTF8&oe=UTF8&text=hello+world#en/es/my%20hello%20world";

var response = UrlFetchApp.fetch(url1/*"http://www.google.com/translate_t", options*/);
Logger.log(response.getContentText().indexOf("mundo"));
var result = "";
Logger.log(result);
}

将他们粘贴并重新命名


TEngine--Localization模块
https://www.liu2dream.fun/post/TEngine--Localization模块/
作者
刘老师 MrLiu
发布于
2024年12月11日
许可协议