gettext.pp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. Gettext interface to resourcestrings.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$MODE objfpc}
  13. {$H+}
  14. unit gettext;
  15. interface
  16. uses sysutils, classes;
  17. const
  18. MOFileHeaderMagic = $950412de;
  19. type
  20. TMOFileHeader = packed record
  21. magic: LongWord; // MOFileHeaderMagic
  22. revision: LongWord; // 0
  23. nstrings: LongWord; // Number of string pairs
  24. OrigTabOffset: LongWord; // Offset of original string offset table
  25. TransTabOffset: LongWord; // Offset of translated string offset table
  26. HashTabSize: LongWord; // Size of hashing table
  27. HashTabOffset: LongWord; // Offset of first hashing table entry
  28. end;
  29. TMOStringInfo = packed record
  30. length: LongWord;
  31. offset: LongWord;
  32. end;
  33. TMOStringTable = array[LongWord] of TMOStringInfo;
  34. PMOStringTable = ^TMOStringTable;
  35. TLongWordArray = array[LongWord] of LongWord;
  36. PLongWordArray = ^TLongWordArray;
  37. TPCharArray = array[LongWord] of PChar;
  38. PPCharArray = ^TPCharArray;
  39. TMOFile = class
  40. protected
  41. HashTableSize: LongWord;
  42. HashTable: PLongWordArray;
  43. OrigTable, TranslTable: PMOStringTable;
  44. OrigStrings, TranslStrings: PPCharArray;
  45. public
  46. constructor Create(AFilename: String);
  47. constructor Create(AStream: TStream);
  48. function Translate(AOrig: PChar; ALen: Integer; AHash: LongWord): String;
  49. function Translate(AOrig: String; AHash: LongWord): String;
  50. function Translate(AOrig: String): String;
  51. end;
  52. EMOFileError = class(Exception)
  53. end;
  54. procedure TranslateResourceStrings(AFile: TMOFile);
  55. procedure TranslateResourceStrings(AFilename: String);
  56. implementation
  57. uses dos;
  58. constructor TMOFile.Create(AStream: TStream);
  59. var
  60. header: TMOFileHeader;
  61. i: Integer;
  62. s: String;
  63. begin
  64. inherited Create;
  65. AStream.Read(header, Sizeof(header));
  66. if header.magic <> MOFileHeaderMagic then
  67. raise EMOFileError.Create('Invalid magic - not a MO file?');
  68. { WriteLn('Revision: ', header.revision);
  69. WriteLn('# of strings: ', header.nstrings);
  70. WriteLn('OrigTabOffset: ', header.OrigTabOffset);
  71. WriteLn('TransTabOffset: ', header.TransTabOffset);
  72. WriteLn('# of hashcodes: ', header.HashTabSize);
  73. WriteLn('HashTabOffset: ', header.HashTabOffset);
  74. }
  75. GetMem(OrigTable, header.nstrings * SizeOf(TMOStringInfo));
  76. GetMem(TranslTable, header.nstrings * SizeOf(TMOStringInfo));
  77. GetMem(OrigStrings, header.nstrings * SizeOf(PChar));
  78. GetMem(TranslStrings, header.nstrings * SizeOf(PChar));
  79. AStream.Position := header.OrigTabOffset;
  80. AStream.Read(OrigTable^, header.nstrings * SizeOf(TMOStringInfo));
  81. AStream.Position := header.TransTabOffset;
  82. AStream.Read(TranslTable^, header.nstrings * SizeOf(TMOStringInfo));
  83. // Read strings
  84. for i := 0 to header.nstrings - 1 do begin
  85. AStream.Position := OrigTable^[i].offset;
  86. SetLength(s, OrigTable^[i].length);
  87. AStream.Read(s[1], OrigTable^[i].length);
  88. OrigStrings^[i] := StrNew(PChar(s));
  89. end;
  90. for i := 0 to header.nstrings - 1 do begin
  91. AStream.Position := TranslTable^[i].offset;
  92. SetLength(s, TranslTable^[i].length);
  93. AStream.Read(s[1], TranslTable^[i].length);
  94. TranslStrings^[i] := StrNew(PChar(s));
  95. end;
  96. // Read hashing table
  97. HashTableSize := header.HashTabSize;
  98. GetMem(HashTable, 4 * HashTableSize);
  99. AStream.Position := header.HashTabOffset;
  100. AStream.Read(HashTable^, 4 * HashTableSize);
  101. end;
  102. constructor TMOFile.Create(AFilename: String);
  103. var
  104. f: TStream;
  105. begin
  106. f := TFileStream.Create(AFilename, fmOpenRead);
  107. try
  108. Self.Create(f);
  109. finally
  110. f.Free;
  111. end;
  112. end;
  113. function TMOFile.Translate(AOrig: PChar; ALen: Integer; AHash: LongWord): String;
  114. var
  115. idx, incr, nstr: LongWord;
  116. begin
  117. idx := AHash mod HashTableSize;
  118. incr := 1 + (AHash mod (HashTableSize - 2));
  119. while True do begin
  120. nstr := HashTable^[idx];
  121. if nstr = 0 then begin
  122. Result := '';
  123. exit;
  124. end;
  125. if (OrigTable^[nstr - 1].length = ALen) and
  126. (StrComp(OrigStrings^[nstr - 1], AOrig) = 0) then begin
  127. Result := TranslStrings^[nstr - 1];
  128. exit;
  129. end;
  130. if idx >= HashTableSize - incr then
  131. Dec(idx, HashTableSize - incr)
  132. else
  133. Inc(idx, incr);
  134. end;
  135. end;
  136. function TMOFile.Translate(AOrig: String; AHash: LongWord): String;
  137. begin
  138. Result := Translate(PChar(AOrig), Length(AOrig), AHash);
  139. end;
  140. function TMOFile.Translate(AOrig: String): String;
  141. begin
  142. Result := Translate(AOrig, Hash(AOrig));
  143. end;
  144. // -------------------------------------------------------
  145. // Resourcestring translation procedures
  146. // -------------------------------------------------------
  147. {
  148. Define USEITERATOR if you want to translate the strings using
  149. the SetResourceStrings call. This is not recommended for this
  150. particular iplementation, since we must pass through a global
  151. variable TheFile : TMOFile. However that works too.
  152. }
  153. {$ifdef USEITERATOR}
  154. Var
  155. Thefile : TMOFile;
  156. Function Translate (Name,Value : AnsiString; Hash : Longint) : AnsiString;
  157. begin
  158. Result:=TheFile.Translate(Value,Hash);
  159. end;
  160. procedure TranslateResourceStrings(AFile: TMOFile);
  161. var
  162. i,j : Integer;
  163. s : String;
  164. begin
  165. TheFile:=AFile;
  166. SetResourceStrings(@Translate);
  167. end;
  168. {$else}
  169. procedure TranslateResourceStrings(AFile: TMOFile);
  170. var
  171. i,j,count : Integer;
  172. s : String;
  173. begin
  174. For I:=0 to ResourceStringTableCount-1 do
  175. begin
  176. Count:=ResourceStringCount(I);
  177. For J:=0 to Count-1 do
  178. begin
  179. S:=AFile.Translate(GetResourceStringDefaultValue(I,J),
  180. GetResourceStringHash(I,J));
  181. if S <> '' then
  182. SetResourceStringValue(I,J,S);
  183. end;
  184. end;
  185. end;
  186. {$endif}
  187. procedure TranslateResourceStrings(AFilename: String);
  188. var
  189. mo: TMOFile;
  190. lang: String;
  191. begin
  192. lang := Copy(GetEnv('LANG'), 1, 2);
  193. try
  194. mo := TMOFile.Create(Format(AFilename, [lang]));
  195. TranslateResourceStrings(mo);
  196. mo.Free;
  197. except
  198. on e: Exception do;
  199. end;
  200. end;
  201. end.
  202. {
  203. $Log$
  204. Revision 1.8 2000-01-07 01:24:33 peter
  205. * updated copyright to 2000
  206. Revision 1.7 2000/01/06 01:20:33 peter
  207. * moved out of packages/ back to topdir
  208. Revision 1.1 2000/01/03 19:33:07 peter
  209. * moved to packages dir
  210. Revision 1.5 1999/10/15 19:42:18 michael
  211. hash is available in tables
  212. Revision 1.4 1999/08/28 13:35:16 michael
  213. * Uses now hash function of objpas
  214. Revision 1.3 1999/08/27 15:53:36 michael
  215. + Adapted to new resourcestring mechanism. Uses objpas interface only
  216. Revision 1.2 1999/08/26 11:05:15 peter
  217. * updated for new resourcestrings
  218. Revision 1.1 1999/08/04 11:31:09 michael
  219. * Added gettext
  220. Revision 1.1 1999/07/25 16:23:31 michael
  221. + Initial implementation from Sebastian Guenther
  222. }