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))
143 let arrow_add_variable
146 let x = Obj.magic x in
147 let y = Obj.magic y in
148 (Obj.magic (x :: y) : ('a -> 'b) arrow)
154 let value_to_text (expected_type : 'a arrow) v =
155 let s = value_to_string v in
156 let expected_type = Obj.magic expected_type in
157 let format_type = type_format s in
158 if format_type = expected_type then
159 (Obj.magic s : ('a, unit, string) format) else
160 failwith "Bad format"
162 let text_to_value v =
163 let v = Obj.magic v in
166 let text_option (expected_type : 'a arrow)
168 define_option_class "Text"
169 (value_to_text expected_type)
172 let gettext v = Printf.sprintf !!v
174 let buftext buf (v : ('a, Buffer.t, unit) format Options.option_record) =
175 Printf.bprintf buf !!v
178 let int x = arrow_add_variable (Obj.magic Type_int : int variable) x
179 let char x = arrow_add_variable (Obj.magic Type_char : char variable) x
180 let string x = arrow_add_variable (Obj.magic Type_string : string variable) x
181 let float x = arrow_add_variable (Obj.magic Type_float : float variable) x
182 let bool x = arrow_add_variable (Obj.magic Type_bool : bool variable) x
183 let int32 x = arrow_add_variable (Obj.magic Type_int32 : int32 variable) x
184 let int64 x = arrow_add_variable (Obj.magic Type_int64 : int64 variable) x
185 let nativeint x = arrow_add_variable (Obj.magic Type_nativeint : nativeint variable) x
186 let format = (Obj.magic [] : string arrow)
187 let bformat = (Obj.magic [] : unit arrow)
188 let option = text_option
189 let boption x = (Obj.magic text_option) x
193 (********* Some tests ************)
196 let option_file = create_options_file "test.ini"
198 let nshared = define_option option_file
199 ["nshared"] "Text for Nshared option"
201 (T.int (T.int32 T.format)))
208 save_with_help option_file
211 lprint_string (Printf.sprintf !! nshared 23 (Int32.one));
219 let strings = Hashtbl.create 1111
220 let next_slot = ref 0
221 let translation = ref [||]
222 let verified = ref [||]
223 let default = ref [||]
224 let requests = ref [||]
225 let strings_file = ref None
227 let strings_file_error = ref false
228 let save_strings_file = ref false
230 let no_translation = " "
231 let modules = Hashtbl.create 11
233 let register modname x =
235 Hashtbl.find strings x
238 (* lprintf "New message [%s]\n" x; *)
239 save_strings_file := true;
241 if !next_slot = Array.length !translation then begin
243 (* lprintf "Incrementing size\n"; *)
244 let new_array = Array.make (2 * !next_slot+ 1) false
246 Array.blit !verified 0 new_array 0 !next_slot;
247 verified := new_array;
249 let new_array = Array.make (2 * !next_slot+ 1) no_translation
251 Array.blit !translation 0 new_array 0 !next_slot;
252 translation := new_array;
254 let new_array = Array.make (2 * !next_slot+ 1) 0
256 Array.blit !requests 0 new_array 0 !next_slot;
257 requests := new_array;
259 let new_array = Array.make (2 * !next_slot+ 1) no_translation
261 Array.blit !default 0 new_array 0 !next_slot;
262 default := new_array;
265 let index = !next_slot in
266 let m = { name = x ; index = index } in
268 let names = Hashtbl.find modules modname in
269 names := index :: !names
271 Hashtbl.add modules modname (ref [index]));
272 Hashtbl.add strings x m;
274 !default.(index ) <- x;
277 let translate modname s t =
278 if t <> "" && t <> s then
280 (* lprintf "Register\n"; *)
281 let m = register modname s in
282 (* lprintf "Translation: %s = %s\n" s t; *)
283 save_strings_file := true;
284 !translation.(m.index) <- t
288 let y = (Obj.magic x : string) in
289 Obj.magic (register y : string message)
291 let s_ x = register x
295 let verify index translated =
296 let index_type = type_format !default.(index) in
297 let translated_type = type_format translated in
298 if index_type = translated_type then begin
299 !verified.(index) <- true;
302 lprintf_nl "Bad format for %s\n" translated;
303 save_strings_file := true;
304 !translation.(index) <- no_translation;
308 let ss_ modname (x : string) = register modname x
310 let index = m.index in
311 !requests.(index) <- !requests.(index) + 1;
312 let translation = !translation.(index) in
313 let s= if translation == no_translation then
320 let _s modname (x : string) = _ss (ss_ modname x)
322 let bb_ : string -> ('a, 'b, 'c, 'd) format4 -> ('a, 'b, 'c, 'd) format4 _string = fun modname -> Obj.magic (ss_ modname)
323 let _bb : ('a, 'b, 'c, 'd) format4 _string -> ('a, 'b, 'c, 'd) format4 = fun m ->
324 let index = m.index in
325 !requests.(index) <- !requests.(index) + 1;
326 let translation = !translation.(index) in
327 let s= if translation == no_translation then
330 if !verified.(index) || verify index translation then
332 else !default.(index)
336 let _b modname x = _bb (bb_ modname x)
339 let save_strings () =
340 match !strings_file with
343 if !save_strings_file && not !strings_file_error then
345 Unix2.tryopen_write filename (fun oc ->
347 Hashtbl.iter (fun modname names ->
349 Printf.fprintf oc "(************************************)\n";
350 Printf.fprintf oc " module \"%s\"\n" (String.escaped modname);
351 Printf.fprintf oc "(************************************)\n\n";
356 Printf.fprintf oc "\"%s\" = \"%s\"\n\n"
357 (String.escaped !default.(i))
359 (if !translation.(i) != no_translation then
368 save_strings_file := false)
370 lprintf_nl "save_strings: Error %s"
371 (Printexc2.to_string e)
374 let lexer = make_lexer [ "=" ; "module" ]
376 let current_modname = ref ""
378 let rec parse_file = (parser
379 | [< 'String s0; 'Kwd "="; 'String s1; strm >] ->
380 (* lprintf "trans\n"; *)
381 translate !current_modname s0 s1; parse_file strm
382 | [< 'Kwd "module"; 'String modname; strm >] ->
383 current_modname := modname;
385 | [< >] -> (* lprintf "done\n" *) ())
387 let set_strings_file filename =
391 with _ -> (Charset.Locale.default_language ^ "_" ^ Charset.Locale.locale_string)
393 Printf.sprintf "%s.%s" filename extension
396 (match !strings_file with Some _ -> ()
398 Pervasives.at_exit (fun _ -> try save_strings () with _ -> ()));
399 strings_file := Some filename;
401 (* If the file exists, load it. Check that '%' formats are the same
402 in the default and in the translation. *)
403 (*lprintf "Loading...\n"; *)
405 Unix2.tryopen_read filename (fun ic ->
406 lprintf_nl "Loading language resource %s" filename;
407 let s = Stream.of_channel ic in
409 let stream = lexer s in
411 current_modname := "general";
414 strings_file_error := true;
415 lprintf_nl "set_strings_file: Exception %s in %s at pos %d"
416 (Printexc2.to_string e) filename (Stream.count s))
418 save_strings_file := true);
424 let file = Sys.getenv "GETTEXT_FILE" in
425 let ext = Sys.getenv "LANG" in
426 let f1 = Printf.sprintf "%s.en" file in
427 let f2 = Printf.sprintf "%s.%s" file ext in
428 let strings = Hashtbl.create 111 in
430 let translate1 s0 s1 =
431 lprintf_nl "translate0 %s" s0;
432 Hashtbl.add strings s0 s1
436 let rec parse_file = (parser
437 | [< 'Ident s0; 'Kwd "="; s1 = parse_next; strm >] ->
438 translate1 s0 s1; parse_file strm
439 | [< >] -> (* lprintf "done\n" *) ())
441 and parse_next = parser
442 | [< 'Ident s1 >] -> s1
443 | [< 'String s1 >] -> s1
447 Unix2.tryopen_read f1(fun ic ->
448 let s = Stream.of_channel ic in
450 let stream = lexer s in
454 strings_file_error := true;
455 lprintf_nl "set_strings_file: Exception %s in %s at pos %d"
456 (Printexc2.to_string e) f1 (Stream.count s))
458 save_strings_file := true;
459 lprintf_nl "set_strings_file: no message file found. Creating one");
461 let translate2 s0 s1 =
463 lprintf_nl "translate2 %s" s0;
464 let s0 = Hashtbl.find strings s0 in
465 translate "Former Translation" s0 s1
466 with _ -> lprintf_nl "No translation for %s" s0
469 let rec parse_file = (parser
470 | [< 'Ident s0; 'Kwd "="; s1 = parse_next; strm >] ->
471 translate2 s0 s1; parse_file strm
472 | [< >] -> (* lprintf "done\n" *) ())
474 and parse_next = parser
475 | [< 'Ident s1 >] -> s1
476 | [< 'String s1 >] -> s1
480 Unix2.tryopen_read f2 (fun ic ->
481 let s = Stream.of_channel ic in
483 let stream = lexer s in
487 strings_file_error := true;
488 lprintf_nl "set_strings_file: Exception %s in %s at pos %d"
489 (Printexc2.to_string e) f2 (Stream.count s))
491 save_strings_file := true;
492 lprintf_nl "set_strings_file: no message file found. Creating one"