1 (*
2  * Hedgewars, a free turn based strategy game
3  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *)
18 
19 {$INCLUDE "options.inc"}
20 
21 unit uLocale;
22 interface
23 uses uTypes;
24 
25 const MAX_EVENT_STRINGS = 255;
26 
27 procedure LoadLocale(FileName: shortstring);
GetEventStringnull28 function  GetEventString(e: TEventId): ansistring;
29 
Formatnull30 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: shortstring; argCount: Byte): shortstring;
Formatnull31 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: shortstring): shortstring;
Formatnull32 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8: shortstring): shortstring;
Formatnull33 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7: shortstring): shortstring;
Formatnull34 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6: shortstring): shortstring;
Formatnull35 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5: shortstring): shortstring;
Formatnull36 function Format(fmt: shortstring; arg1, arg2, arg3, arg4: shortstring): shortstring;
Formatnull37 function Format(fmt: shortstring; arg1, arg2, arg3: shortstring): shortstring;
Formatnull38 function Format(fmt: shortstring; arg1, arg2: shortstring): shortstring;
Formatnull39 function Format(fmt: shortstring; arg1: shortstring): shortstring;
FormatAnull40 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: ansistring; argCount: Byte): ansistring;
FormatAnull41 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: ansistring): ansistring;
FormatAnull42 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8: ansistring): ansistring;
FormatAnull43 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7: ansistring): ansistring;
FormatAnull44 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6: ansistring): ansistring;
FormatAnull45 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5: ansistring): ansistring;
FormatAnull46 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4: ansistring): ansistring;
FormatAnull47 function FormatA(fmt: ansistring; arg1, arg2, arg3: ansistring): ansistring;
FormatAnull48 function FormatA(fmt: ansistring; arg1, arg2: ansistring): ansistring;
FormatAnull49 function FormatA(fmt: ansistring; arg1: ansistring): ansistring;
50 
51 {$IFDEF HWLIBRARY}
52 procedure LoadLocaleWrapper(path: pchar; userpath: pchar; filename: pchar); cdecl; export;
53 {$ENDIF}
54 
55 implementation
56 uses SysUtils, uRandom, uUtils, uVariables, uDebug, uPhysFSLayer;
57 
58 var trevt: array[TEventId] of array [0..Pred(MAX_EVENT_STRINGS)] of ansistring;
59     trevt_n: array[TEventId] of integer;
60 
61 procedure LoadLocale(FileName: shortstring);
62 var s: ansistring;
63     f: pfsFile;
64     a, b, c: LongInt;
65     first: array[TEventId] of boolean;
66     e: TEventId;
67 begin
68 {- TODO: Add support for localized decimal separator in Pas2C -}
69 {$IFNDEF PAS2C}
70 lDecimalSeparator:= FormatSettings.DecimalSeparator;
71 {$ENDIF}
72 
73 for e:= Low(TEventId) to High(TEventId) do
74     first[e]:= true;
75 
76 f:= pfsOpenRead(FileName);
77 checkFails(f <> nil, 'Cannot load locale "' + FileName + '"', false);
78 
79 s:= '';
80 
81 if f <> nil then
82     begin
83     while not pfsEof(f) do
84         begin
85         pfsReadLnA(f, s);
86         if Length(s) = 0 then
87             continue;
88         if (s[1] < '0') or (s[1] > '9') then
89             continue;
90         checkFails(Length(s) > 6, 'Load locale: empty string', true);
91         {$IFNDEF PAS2C}
92         val(s[1]+s[2], a, c);
93         checkFails(c = 0, ansistring('Load locale: numbers should be two-digit: ') + s, true);
94         val(s[4]+s[5], b, c);
95         checkFails(c = 0, ansistring('Load locale: numbers should be two-digit: ') + s, true);
96         {$ELSE}
97         val(s[1]+s[2], a);
98         val(s[4]+s[5], b);
99         {$ENDIF}
100         checkFails(s[3] = ':', 'Load locale: ":" expected', true);
101         checkFails(s[6] = '=', 'Load locale: "=" expected', true);
102         if not allOK then exit;
103         Delete(s, 1, 6);
104         case a of
105             0: if (b >=0) and (b <= ord(High(TAmmoStrId))) then
106                 trammo[TAmmoStrId(b)]:= s;
107             1: if (b >=0) and (b <= ord(High(TMsgStrId))) then
108                 trmsg[TMsgStrId(b)]:= s;
109             2: if (b >=0) and (b <= ord(High(TEventId))) then
110                 begin
111                 checkFails(trevt_n[TEventId(b)] < MAX_EVENT_STRINGS, 'Too many event strings in ' + IntToStr(a) + ':' + IntToStr(b), false);
112                 if first[TEventId(b)] then
113                     begin
114                     trevt_n[TEventId(b)]:= 0;
115                     first[TEventId(b)]:= false;
116                     end;
117                 trevt[TEventId(b)][trevt_n[TEventId(b)]]:= s;
118                 inc(trevt_n[TEventId(b)]);
119                 end;
120             3: if (b >=0) and (b <= ord(High(TAmmoStrId))) then
121                 trammoc[TAmmoStrId(b)]:= s;
122             4: if (b >=0) and (b <= ord(High(TAmmoStrId))) then
123                 trammod[TAmmoStrId(b)]:= s;
124             5: if (b >=0) and (b <= ord(High(TGoalStrId))) then
125                 trgoal[TGoalStrId(b)]:= s;
126             6: if (b >=0) and (b <= ord(High(TCmdHelpStrId))) then
127                 trcmd[TCmdHelpStrId(b)]:= s;
128            end;
129        end;
130    pfsClose(f);
131    end;
132 end;
133 
GetEventStringnull134 function GetEventString(e: TEventId): ansistring;
135 begin
136     if trevt_n[e] = 0 then // no messages for this event type?
137         GetEventString:= '*missing translation*'
138     else
139         GetEventString:= trevt[e][GetRandom(trevt_n[e])]; // Pick a random message and return it
140 end;
141 
142 // Format the string fmt.
143 // Take a shortstring with placeholders %1, %2, %3, ... %9. and replace
144 // them with the corresponding elements of an array with up to
145 // argCount. ArgCount must not be larger than 9.
146 // Each placeholder must be used exactly once and numbers MUST NOT be
147 // skipped (e.g. using %1 and %3 but not %2.
Formatnull148 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: shortstring; argCount: Byte): shortstring;
149 var i, p: LongInt;
150 tempstr, curArg: shortstring;
151 begin
152 tempstr:= fmt;
153 for i:=0 to argCount - 1 do
154     begin
155         case i of
156             0: curArg:= arg1;
157             1: curArg:= arg2;
158             2: curArg:= arg3;
159             3: curArg:= arg4;
160             4: curArg:= arg5;
161             5: curArg:= arg6;
162             6: curArg:= arg7;
163             7: curArg:= arg8;
164             8: curArg:= arg9;
165         end;
166 
167         repeat
168         p:= Pos('%'+IntToStr(i+1), tempstr);
169         if (p <> 0) then
170             begin
171             delete(tempstr, p, 2);
172             insert(curArg, tempstr, p);
173             end;
174         until (p = 0);
175     end;
176 Format:= tempstr;
177 end;
178 
179 // Same as Format, but for ansistring
FormatAnull180 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: ansistring; argCount: Byte): ansistring;
181 var i, p: LongInt;
182 tempstr, curArg: ansistring;
183 begin
184 tempstr:= fmt;
185 for i:=0 to argCount - 1 do
186     begin
187         case i of
188             0: curArg:= arg1;
189             1: curArg:= arg2;
190             2: curArg:= arg3;
191             3: curArg:= arg4;
192             4: curArg:= arg5;
193             5: curArg:= arg6;
194             6: curArg:= arg7;
195             7: curArg:= arg8;
196             8: curArg:= arg9;
197         end;
198 
199         repeat
200         p:= Pos('%'+IntToStr(i+1), tempstr);
201         if (p <> 0) then
202             begin
203             delete(tempstr, p, 2);
204             insert(curArg, tempstr, p);
205             end;
206         until (p = 0);
207     end;
208 FormatA:= tempstr;
209 end;
210 
211 // The following functions are just shortcuts of Format/FormatA, with fewer argument counts
Formatnull212 function Format(fmt: shortstring; arg1: shortstring): shortstring;
213 begin
214     Format:= Format(fmt, arg1, '', '', '', '', '', '', '', '', 1);
215 end;
Formatnull216 function Format(fmt: shortstring; arg1, arg2: shortstring): shortstring;
217 begin
218     Format:= Format(fmt, arg1, arg2, '', '', '', '', '', '', '', 2);
219 end;
Formatnull220 function Format(fmt: shortstring; arg1, arg2, arg3: shortstring): shortstring;
221 begin
222     Format:= Format(fmt, arg1, arg2, arg3, '', '', '', '', '', '', 3);
223 end;
Formatnull224 function Format(fmt: shortstring; arg1, arg2, arg3, arg4: shortstring): shortstring;
225 begin
226     Format:= Format(fmt, arg1, arg2, arg3, arg4, '', '', '', '', '', 4);
227 end;
Formatnull228 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5: shortstring): shortstring;
229 begin
230     Format:= Format(fmt, arg1, arg2, arg3, arg4, arg5, '', '', '', '', 5);
231 end;
Formatnull232 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6: shortstring): shortstring;
233 begin
234     Format:= Format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, '', '', '', 6);
235 end;
Formatnull236 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7: shortstring): shortstring;
237 begin
238     Format:= Format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, '', '', 7);
239 end;
Formatnull240 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8: shortstring): shortstring;
241 begin
242     Format:= Format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, '', 8);
243 end;
Formatnull244 function Format(fmt: shortstring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: shortstring): shortstring;
245 begin
246     Format:= Format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, 9);
247 end;
248 
FormatAnull249 function FormatA(fmt: ansistring; arg1: ansistring): ansistring;
250 begin
251     FormatA:= FormatA(fmt, arg1, ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), 1);
252 end;
FormatAnull253 function FormatA(fmt: ansistring; arg1, arg2: ansistring): ansistring;
254 begin
255     FormatA:= FormatA(fmt, arg1, arg2, ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), 2);
256 end;
FormatAnull257 function FormatA(fmt: ansistring; arg1, arg2, arg3: ansistring): ansistring;
258 begin
259     FormatA:= FormatA(fmt, arg1, arg2, arg3, ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), 3);
260 end;
FormatAnull261 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4: ansistring): ansistring;
262 begin
263     FormatA:= FormatA(fmt, arg1, arg2, arg3, arg4, ansistring(''), ansistring(''), ansistring(''), ansistring(''), ansistring(''), 4);
264 end;
FormatAnull265 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5: ansistring): ansistring;
266 begin
267     FormatA:= FormatA(fmt, arg1, arg2, arg3, arg4, arg5, ansistring(''), ansistring(''), ansistring(''), ansistring(''), 5);
268 end;
FormatAnull269 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6: ansistring): ansistring;
270 begin
271     FormatA:= FormatA(fmt, arg1, arg2, arg3, arg4, arg5, arg6, ansistring(''), ansistring(''), ansistring(''), 6);
272 end;
FormatAnull273 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7: ansistring): ansistring;
274 begin
275     FormatA:= FormatA(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, ansistring(''), ansistring(''), 7);
276 end;
FormatAnull277 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8: ansistring): ansistring;
278 begin
279     FormatA:= FormatA(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, ansistring(''), 8);
280 end;
FormatAnull281 function FormatA(fmt: ansistring; arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9: ansistring): ansistring;
282 begin
283     FormatA:= FormatA(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, 9);
284 end;
285 
286 {$IFDEF HWLIBRARY}
287 procedure LoadLocaleWrapper(path: pchar; userpath: pchar; filename: pchar); cdecl; export;
288 begin
289     PathPrefix := Strpas(path);
290     UserPathPrefix := Strpas(userpath);
291 
292     //normally this var set in preInit of engine
293     allOK := true;
294 
295     uVariables.initModule;
296 
297     PathPrefix:= PathPrefix + #0;
298     UserPathPrefix:= UserPathPrefix + #0;
299     uPhysFSLayer.initModule(@PathPrefix[1], @UserPathPrefix[1]);
300     PathPrefix:= copy(PathPrefix, 1, length(PathPrefix) - 1);
301     UserPathPrefix:= copy(UserPathPrefix, 1, length(UserPathPrefix) - 1);
302 
303     LoadLocale(Strpas(filename));
304 
305     uPhysFSLayer.freeModule;
306     uVariables.freeModule;
307 end;
308 {$ENDIF}
309 
310 end.
311