@@ -13,11 +13,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
GNU General Public License for more details.
14
14
*/
15
15
16
-
16
+ # include < ctype.h >
17
17
#include " extdll_menu.h"
18
18
#include " BaseMenu.h"
19
19
#include " Utils.h"
20
20
#include " MenuStrings.h"
21
+ #include " unicode_strtools.h"
21
22
22
23
#define EMPTY_STRINGS_1 " "
23
24
#define EMPTY_STRINGS_2 EMPTY_STRINGS_1, EMPTY_STRINGS_1
@@ -27,6 +28,14 @@ GNU General Public License for more details.
27
28
#define EMPTY_STRINGS_50 EMPTY_STRINGS_20, EMPTY_STRINGS_20, EMPTY_STRINGS_10
28
29
#define EMPTY_STRINGS_100 EMPTY_STRINGS_50, EMPTY_STRINGS_50
29
30
31
+ #define HASH_SIZE 256 // 256 * 4 * 4 == 4096 bytes
32
+ static struct dictionary_t
33
+ {
34
+ const char *name;
35
+ const char *value;
36
+ dictionary_t *next;
37
+ } *hashed_cmds[HASH_SIZE];
38
+
30
39
const char *MenuStrings[IDS_LAST] =
31
40
{
32
41
EMPTY_STRINGS_100, // 0..9
@@ -79,7 +88,52 @@ EMPTY_STRINGS_50, // 540..589
79
88
EMPTY_STRINGS_10, // 590..599
80
89
};
81
90
82
- void UI_InitAliasStrings ( void )
91
+ /*
92
+ =================
93
+ Com_HashKey
94
+
95
+ returns hash key for string
96
+ =================
97
+ */
98
+ static uint Com_HashKey ( const char *string, uint hashSize )
99
+ {
100
+ uint i, hashKey = 0 ;
101
+
102
+ for ( i = 0 ; string[i]; i++ )
103
+ {
104
+ hashKey = (hashKey + i) * 37 + tolower ( string[i] );
105
+ }
106
+
107
+ return (hashKey % hashSize);
108
+ }
109
+
110
+ static inline dictionary_t *Dictionary_FindInBucket ( dictionary_t *bucket, const char *name )
111
+ {
112
+ dictionary_t *i = bucket;
113
+ for ( ; i && strcasecmp ( name, i->name ); // filter out
114
+ i = i->next );
115
+
116
+ return i;
117
+ }
118
+
119
+ static void Dictionary_Insert ( const char *name, const char *second )
120
+ {
121
+ uint hash = Com_HashKey ( name, HASH_SIZE );
122
+ dictionary_t *elem;
123
+
124
+ elem = new dictionary_t ;
125
+ elem->name = StringCopy (name);
126
+ elem->value = StringCopy (second);
127
+ elem->next = hashed_cmds[hash];
128
+ hashed_cmds[hash] = elem;
129
+ }
130
+
131
+ static inline dictionary_t *Dictionary_GetBucket ( const char *name )
132
+ {
133
+ return hashed_cmds[ Com_HashKey ( name, HASH_SIZE ) ];
134
+ }
135
+
136
+ static void UI_InitAliasStrings ( void )
83
137
{
84
138
char token[1024 ];
85
139
@@ -106,6 +160,137 @@ void UI_InitAliasStrings( void )
106
160
MenuStrings[IDS_MAIN_MULTIPLAYERHELP] = StringCopy ( token );
107
161
}
108
162
163
+ static void Localize_AddToDictionary ( const char *name, const char *lang )
164
+ {
165
+ char filename[64 ];
166
+ snprintf ( filename, sizeof ( filename ), " resource/%s_%s.txt" , name, lang );
167
+
168
+ int unicodeLength;
169
+ uchar16 *unicodeBuf = (uchar16*)EngFuncs::COM_LoadFile ( filename, &unicodeLength );
170
+
171
+ if ( unicodeBuf ) // no problem, so read it.
172
+ {
173
+ int ansiLength = unicodeLength / 2 ;
174
+ char *afile = new char [ansiLength]; // save original pointer, so we can free it later
175
+ char *pfile = afile;
176
+ char token[4096 ];
177
+ int i = 0 ;
178
+
179
+ Q_UTF16ToUTF8 ( unicodeBuf + 1 , afile, ansiLength, STRINGCONVERT_ASSERT_REPLACE );
180
+
181
+ pfile = EngFuncs::COM_ParseFile ( pfile, token );
182
+
183
+ if ( stricmp ( token, " lang" ))
184
+ {
185
+ Con_Printf ( " Localize_AddToDict( %s, %s ): invalid header, got %s" , name, lang, token );
186
+ goto error;
187
+ }
188
+
189
+ pfile = EngFuncs::COM_ParseFile ( pfile, token );
190
+
191
+ if ( strcmp ( token, " {" ))
192
+ {
193
+ Con_Printf ( " Localize_AddToDict( %s, %s ): want {, got %s" , name, lang, token );
194
+ goto error;
195
+ }
196
+
197
+ pfile = EngFuncs::COM_ParseFile ( pfile, token );
198
+
199
+ if ( stricmp ( token, " Language" ))
200
+ {
201
+ Con_Printf ( " Localize_AddToDict( %s, %s ): want Language, got %s" , name, lang, token );
202
+ goto error;
203
+ }
204
+
205
+ // skip language actual name
206
+ pfile = EngFuncs::COM_ParseFile ( pfile, token );
207
+
208
+ pfile = EngFuncs::COM_ParseFile ( pfile, token );
209
+
210
+ if ( stricmp ( token, " Tokens" ))
211
+ {
212
+ Con_Printf ( " Localize_AddToDict( %s, %s ): want Tokens, got %s" , name, lang, token );
213
+ goto error;
214
+ }
215
+
216
+ pfile = EngFuncs::COM_ParseFile ( pfile, token );
217
+
218
+ if ( strcmp ( token, " {" ))
219
+ {
220
+ Con_Printf ( " Localize_AddToDict( %s, %s ): want { after Tokens, got %s" , name, lang, token );
221
+ goto error;
222
+ }
223
+
224
+ while ( (pfile = EngFuncs::COM_ParseFile ( pfile, token )))
225
+ {
226
+ if ( !strcmp ( token, " }" ))
227
+ break ;
228
+
229
+ char szLocString[4096 ];
230
+ pfile = EngFuncs::COM_ParseFile ( pfile, szLocString );
231
+
232
+ if ( !strcmp ( szLocString, " }" ))
233
+ break ;
234
+
235
+
236
+ if ( pfile )
237
+ {
238
+ Dictionary_Insert ( token, szLocString );
239
+ i++;
240
+ }
241
+ }
242
+
243
+ Con_Printf ( " Localize_AddToDict: loaded %i words from %s\n " , i, filename );
244
+
245
+ error:
246
+ delete[] afile;
247
+
248
+ EngFuncs::COM_FreeFile ( unicodeBuf );
249
+ }
250
+ else
251
+ {
252
+ Con_Printf ( " Couldn't open file %s. Strings will not be localized!.\n " , filename );
253
+ }
254
+ }
255
+
256
+ static void Localize_Init ( void )
257
+ {
258
+ char gamedir[256 ];
259
+
260
+ EngFuncs::GetGameDir ( gamedir );
261
+
262
+ memset ( hashed_cmds, 0 , sizeof ( hashed_cmds ) );
263
+
264
+ // first is lowest in priority
265
+ if ( strcmp ( gamedir, " gameui" )) // just for case
266
+ Localize_AddToDictionary ( " gameui" , " english" );
267
+
268
+ Localize_AddToDictionary ( " valve" , " english" );
269
+
270
+ if ( strcmp ( gamedir, " valve" ))
271
+ Localize_AddToDictionary ( gamedir, " english" );
272
+ }
273
+
274
+ static void Localize_Free ( void )
275
+ {
276
+ for ( int i = 0 ; i < HASH_SIZE; i++ )
277
+ {
278
+ dictionary_t *base = hashed_cmds[i];
279
+ while ( base )
280
+ {
281
+ dictionary_t *next = base->next ;
282
+
283
+ delete [] base->value ;
284
+ delete [] base->name ;
285
+ delete base;
286
+
287
+ base = next;
288
+ }
289
+ }
290
+
291
+ return ;
292
+ }
293
+
109
294
void UI_LoadCustomStrings ( void )
110
295
{
111
296
char *afile = (char *)EngFuncs::COM_LoadFile ( " gfx/shell/strings.lst" , NULL );
@@ -114,6 +299,7 @@ void UI_LoadCustomStrings( void )
114
299
int string_num;
115
300
116
301
UI_InitAliasStrings ();
302
+ Localize_Init ();
117
303
118
304
if ( !afile )
119
305
return ;
@@ -131,10 +317,32 @@ void UI_LoadCustomStrings( void )
131
317
}
132
318
else continue ; // invalid declaration ?
133
319
134
- // parse new string
320
+ // parse new string
135
321
pfile = EngFuncs::COM_ParseFile ( pfile, token );
136
322
MenuStrings[string_num] = StringCopy ( token ); // replace default string with custom
137
323
}
138
324
139
325
EngFuncs::COM_FreeFile ( afile );
140
326
}
327
+
328
+ const char *L ( const char *szStr ) // L means Localize!
329
+ {
330
+ if ( szStr )
331
+ {
332
+ if ( *szStr == ' #' )
333
+ szStr++;
334
+
335
+ dictionary_t *base = Dictionary_GetBucket ( szStr );
336
+ dictionary_t *found = Dictionary_FindInBucket ( base, szStr );
337
+
338
+ if ( found )
339
+ return found->value ;
340
+ }
341
+
342
+ return szStr;
343
+ }
344
+
345
+ void UI_FreeCustomStrings ( void )
346
+ {
347
+ Localize_Free ();
348
+ }
0 commit comments