1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
3 This file is part of mldonkey.
5 mldonkey 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; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 let log_prefix = "[Gettext]"
26 lprintf_nl2 log_prefix fmt
29 lprintf2 log_prefix fmt
41 let ty_arrow x y = x :: y
43 (* Taken from ocaml-3.04, typing/typecore.ml *)
46 let len = String.length fmt in
48 failwith (Printf.sprintf "Incomplete format %s" (String.sub fmt i (len - i)))
51 failwith (Printf.sprintf "Bad format %s" (String.sub fmt i (j - i + 1)))
55 let rec scan_format i =
56 if i >= len then ty_result else
58 | '%' -> scan_flags i (i+1)
59 | _ -> scan_format (i+1)
61 if j >= len then incomplete i else
63 | '#' | '0' | '-' | ' ' | '+' -> scan_flags i (j+1)
66 if j >= len then incomplete i else
68 | '*' -> ty_arrow Type_int (scan_dot i (j+1))
69 | '.' -> scan_precision i (j+1)
70 | _ -> scan_fixed_width i j
71 and scan_fixed_width i j =
72 if j >= len then incomplete i else
74 | '0' .. '9' | '-' | '+' -> scan_fixed_width i (j+1)
75 | '.' -> scan_precision i (j+1)
76 | _ -> scan_conversion i j
78 if j >= len then incomplete i else
80 | '.' -> scan_precision i (j+1)
81 | _ -> scan_conversion i j
82 and scan_precision i j =
83 if j >= len then incomplete i else
85 | '*' -> ty_arrow Type_int (scan_conversion i (j+1))
86 | _ -> scan_fixed_precision i j
87 and scan_fixed_precision i j =
88 if j >= len then incomplete i else
90 | '0' .. '9' | '-' | '+' -> scan_fixed_precision i (j+1)
91 | _ -> scan_conversion i j
92 and scan_conversion i j =
93 if j >= len then incomplete i else
95 | '%' -> scan_format (j+1)
97 ty_arrow Type_string (scan_format (j+1))
99 ty_arrow Type_char (scan_format (j+1))
100 | 'd' | 'i' | 'o' | 'x' | 'X' | 'u' | 'N' ->
101 ty_arrow Type_int (scan_format (j+1))
102 | 'f' | 'e' | 'E' | 'g' | 'G' ->
103 ty_arrow Type_float (scan_format (j+1))
105 ty_arrow Type_bool (scan_format (j+1))
111 if j+1 >= len then incomplete i else begin
113 | 'd' | 'i' | 'o' | 'x' | 'X' | 'u' ->
114 ty_arrow Type_int32 (scan_format (j+2))
119 if j+1 >= len then incomplete i else begin
121 | 'd' | 'i' | 'o' | 'x' | 'X' | 'u' ->
122 ty_arrow Type_nativeint (scan_format (j+2))
127 if j+1 >= len then incomplete i else begin
129 | 'd' | 'i' | 'o' | 'x' | 'X' | 'u' ->
130 ty_arrow Type_int64 (scan_format (j+2))
144 let strings = Hashtbl.create 1111
145 let next_slot = ref 0
146 let translation = ref [||]
147 let verified = ref [||]
148 let default = ref [||]
149 let requests = ref [||]
150 let strings_file = ref None
152 let strings_file_error = ref false
153 let save_strings_file = ref false
155 let no_translation = " "
156 let modules = Hashtbl.create 11
158 let register modname x =
160 Hashtbl.find strings x
163 (* lprintf "New message [%s]\n" x; *)
164 save_strings_file := true;
166 if !next_slot = Array.length !translation then begin
168 (* lprintf "Incrementing size\n"; *)
169 let new_array = Array.create (2 * !next_slot+ 1) false
171 Array.blit !verified 0 new_array 0 !next_slot;
172 verified := new_array;
174 let new_array = Array.create (2 * !next_slot+ 1) no_translation
176 Array.blit !translation 0 new_array 0 !next_slot;
177 translation := new_array;
179 let new_array = Array.create (2 * !next_slot+ 1) 0
181 Array.blit !requests 0 new_array 0 !next_slot;
182 requests := new_array;
184 let new_array = Array.create (2 * !next_slot+ 1) no_translation
186 Array.blit !default 0 new_array 0 !next_slot;
187 default := new_array;
190 let index = !next_slot in
191 let m = { name = x ; index = index } in
193 let names = Hashtbl.find modules modname in
194 names := index :: !names
196 Hashtbl.add modules modname (ref [index]));
197 Hashtbl.add strings x m;
199 !default.(index ) <- x;
202 let translate modname s t =
203 if t <> "" && t <> s then
205 (* lprintf "Register\n"; *)
206 let m = register modname s in
207 (* lprintf "Translation: %s = %s\n" s t; *)
208 save_strings_file := true;
209 !translation.(m.index) <- t
212 let verify index translated =
213 let index_type = type_format !default.(index) in
214 let translated_type = type_format translated in
215 if index_type = translated_type then begin
216 !verified.(index) <- true;
219 lprintf_nl "Bad format for %s\n" translated;
220 save_strings_file := true;
221 !translation.(index) <- no_translation;
225 let ss_ : string -> string -> string _string = register
226 let _ss : string _string -> string = fun m ->
227 let index = m.index in
228 !requests.(index) <- !requests.(index) + 1;
229 let translation = !translation.(index) in
230 let s= if translation == no_translation then
237 let _s modname (x : string) = _ss (ss_ modname x)
239 let bb_ : string -> ('a, 'b, 'c, 'd) format4 -> ('a, 'b, 'c, 'd) format4 _string = fun modname -> Obj.magic (ss_ modname)
240 let _bb : ('a, 'b, 'c, 'd) format4 _string -> ('a, 'b, 'c, 'd) format4 = fun m ->
241 let index = m.index in
242 !requests.(index) <- !requests.(index) + 1;
243 let translation = !translation.(index) in
244 let s= if translation == no_translation then
247 if !verified.(index) || verify index translation then
249 else !default.(index)
253 let _b modname x = _bb (bb_ modname x)
255 let save_strings () =
256 match !strings_file with
259 if !save_strings_file && not !strings_file_error then
261 Unix2.tryopen_write filename (fun oc ->
263 Hashtbl.iter (fun modname names ->
265 Printf.fprintf oc "(************************************)\n";
266 Printf.fprintf oc " module \"%s\"\n" (String.escaped modname);
267 Printf.fprintf oc "(************************************)\n\n";
272 Printf.fprintf oc "\"%s\" = \"%s\"\n\n"
273 (String.escaped !default.(i))
275 (if !translation.(i) != no_translation then
284 save_strings_file := false)
286 lprintf_nl "save_strings: Error %s"
287 (Printexc2.to_string e)
290 let lexer = make_lexer [ "=" ; "module" ]
292 let current_modname = ref ""
294 let rec parse_file = (parser
295 | [< 'String s0; 'Kwd "="; 'String s1; strm >] ->
296 (* lprintf "trans\n"; *)
297 translate !current_modname s0 s1; parse_file strm
298 | [< 'Kwd "module"; 'String modname; strm >] ->
299 current_modname := modname;
301 | [< >] -> (* lprintf "done\n" *) ())
303 let set_strings_file filename =
307 with _ -> (Charset.Locale.default_language ^ "_" ^ Charset.Locale.locale_string)
309 Printf.sprintf "%s.%s" filename extension
312 (match !strings_file with Some _ -> ()
314 Pervasives.at_exit (fun _ -> try save_strings () with _ -> ()));
315 strings_file := Some filename;
317 (* If the file exists, load it. Check that '%' formats are the same
318 in the default and in the translation. *)
319 (*lprintf "Loading...\n"; *)
321 Unix2.tryopen_read filename (fun ic ->
322 lprintf_nl "Loading language resource %s" filename;
323 let s = Stream.of_channel ic in
325 let stream = lexer s in
327 current_modname := "general";
330 strings_file_error := true;
331 lprintf_nl "set_strings_file: Exception %s in %s at pos %d"
332 (Printexc2.to_string e) filename (Stream.count s))
334 save_strings_file := true);
340 let file = Sys.getenv "GETTEXT_FILE" in
341 let ext = Sys.getenv "LANG" in
342 let f1 = Printf.sprintf "%s.en" file in
343 let f2 = Printf.sprintf "%s.%s" file ext in
344 let strings = Hashtbl.create 111 in
346 let translate1 s0 s1 =
347 lprintf_nl "translate0 %s" s0;
348 Hashtbl.add strings s0 s1
352 let rec parse_file = (parser
353 | [< 'Ident s0; 'Kwd "="; s1 = parse_next; strm >] ->
354 translate1 s0 s1; parse_file strm
355 | [< >] -> (* lprintf "done\n" *) ())
357 and parse_next = parser
358 | [< 'Ident s1 >] -> s1
359 | [< 'String s1 >] -> s1
363 Unix2.tryopen_read f1(fun ic ->
364 let s = Stream.of_channel ic in
366 let stream = lexer s in
370 strings_file_error := true;
371 lprintf_nl "set_strings_file: Exception %s in %s at pos %d"
372 (Printexc2.to_string e) f1 (Stream.count s))
374 save_strings_file := true;
375 lprintf_nl "set_strings_file: no message file found. Creating one");
377 let translate2 s0 s1 =
379 lprintf_nl "translate2 %s" s0;
380 let s0 = Hashtbl.find strings s0 in
381 translate "Former Translation" s0 s1
382 with _ -> lprintf_nl "No translation for %s" s0
385 let rec parse_file = (parser
386 | [< 'Ident s0; 'Kwd "="; s1 = parse_next; strm >] ->
387 translate2 s0 s1; parse_file strm
388 | [< >] -> (* lprintf "done\n" *) ())
390 and parse_next = parser
391 | [< 'Ident s1 >] -> s1
392 | [< 'String s1 >] -> s1
396 Unix2.tryopen_read f2 (fun ic ->
397 let s = Stream.of_channel ic in
399 let stream = lexer s in
403 strings_file_error := true;
404 lprintf_nl "set_strings_file: Exception %s in %s at pos %d"
405 (Printexc2.to_string e) f2 (Stream.count s))
407 save_strings_file := true;
408 lprintf_nl "set_strings_file: no message file found. Creating one"