CnIniLangFileStorage.pas 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2016 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnIniLangFileStorage;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:CnPack 多语包
  24. * 单元名称:Ini 多语存储组件单元
  25. * 单元作者:CnPack开发组
  26. * 备 注:该单元实现了 Ini 多语存储组件类,内部使用了 HashMap
  27. * 开发平台:PWin2000 + Delphi 5.0
  28. * 兼容测试:PWin9X/2000/XP + Delphi 5/6/7
  29. * 本 地 化:该单元中的字符串均符合本地化处理方式
  30. * 单元标识:$Id$
  31. * 修改记录:2008.11.19 V1.1
  32. * Efeis 修正 Ini 载入出错的问题
  33. * 2003.08.20 V1.0
  34. * 创建单元,实现功能
  35. ================================================================================
  36. |</PRE>}
  37. interface
  38. {$I CnPack.inc}
  39. uses
  40. SysUtils, Classes, IniFiles, Dialogs, FileCtrl, CnCommon,
  41. CnConsts, CnIniStrUtils, CnWideStrings, CnLangStorage, CnHashLangStorage;
  42. const
  43. SCnGlobalSectionName = SystemNamePrefix + 'Global';
  44. SCnStringsSectionName = SystemNamePrefix + 'Strings';
  45. type
  46. TCnCustomIniLangFileStorage = class(TCnCustomHashLangStorage)
  47. private
  48. FIniFile: TIniFile;
  49. protected
  50. procedure InternalInit; override;
  51. procedure CreateCurrentLanguage; override;
  52. procedure InitFromAFile(const AFileName: WideString); override;
  53. procedure GetComponentInfo(var AName, Author, Email, Comment: string); override;
  54. public
  55. constructor Create(AOwner: TComponent); override;
  56. destructor Destroy; override;
  57. class function GetLanguageFileExt: WideString; override;
  58. {* 返回多语言文件的扩展名.INI }
  59. function IsLanguageFile(const FileName: WideString): Boolean; override;
  60. {* 判断一文件是否合法的语言文件 }
  61. function LoadCurrentLanguage: Boolean; override;
  62. {* 从 Ini 文件中载入当前语言条目,为翻译字串做准备 }
  63. procedure SaveCurrentLanguage; override;
  64. {* 保存当前语言文件 }
  65. published
  66. property StorageMode;
  67. {* 多语文件存储模式,按目录存储还是按文件存储 }
  68. property LanguagePath;
  69. {* 语言文件存储的统一路径 }
  70. property FileName;
  71. {* 按文件存储时的统一多语文件名 }
  72. property Languages;
  73. {* 语言对象列表 }
  74. property AutoDetect;
  75. {* LanguagePath 改变时是否自动检测语言 }
  76. end;
  77. TCnIniLangFileStorage = class(TCnCustomIniLangFileStorage)
  78. end;
  79. implementation
  80. uses
  81. CnLangConsts;
  82. { TCnCustomIniLangFileStorage}
  83. constructor TCnCustomIniLangFileStorage.Create(AOwner: TComponent);
  84. begin
  85. inherited;
  86. end;
  87. destructor TCnCustomIniLangFileStorage.Destroy;
  88. begin
  89. if Assigned(FIniFile) then
  90. FreeAndNil(FIniFile);
  91. inherited;
  92. end;
  93. procedure TCnCustomIniLangFileStorage.CreateCurrentLanguage;
  94. begin
  95. end;
  96. class function TCnCustomIniLangFileStorage.GetLanguageFileExt: WideString;
  97. begin
  98. Result := '.ini';
  99. end;
  100. procedure TCnCustomIniLangFileStorage.InternalInit;
  101. begin
  102. inherited;
  103. end;
  104. function TCnCustomIniLangFileStorage.IsLanguageFile(const FileName: WideString): Boolean;
  105. var
  106. IniFile: TIniFile;
  107. begin
  108. Result := True;
  109. IniFile := TIniFile.Create(FileName);
  110. try
  111. if not IniFile.SectionExists(SCnGlobalSectionName) then
  112. Result := False
  113. else if not IniFile.ValueExists(SCnGlobalSectionName, SystemNamePrefix
  114. + SCnLanguageID) then
  115. Result := False;
  116. finally
  117. IniFile.Free;
  118. end;
  119. end;
  120. function TCnCustomIniLangFileStorage.LoadCurrentLanguage: Boolean;
  121. var
  122. S: string;
  123. Sections, Lines: TStrings;
  124. I, J: Integer;
  125. begin
  126. Result := True;
  127. if Assigned(FIniFile) then
  128. FreeAndNil(FIniFile);
  129. //Added by Efeis on 2008-11-18 没有这行会出错,在父类中的过程有这行,应该需要初始化一下的
  130. InitHashMap;
  131. try
  132. // 设计期如果被赋值了设计期文件存储的目录,则存到此目录下
  133. if (csDesigning in ComponentState) and (LanguagePath = '') and (DesignLangPath <> '') then
  134. S := IncludeTrailingBackslash(DesignLangPath) + GetCurrentLanguageFileName
  135. else
  136. S := IncludeTrailingBackslash(LanguagePath) + GetCurrentLanguageFileName;
  137. if not ForceDirectories(_CnExtractFilePath(S)) then
  138. raise ELanguageStorageError.Create(SCnCanNotCreateDir + _CnExtractFilePath(S));
  139. FIniFile := TIniFile.Create(S);
  140. Sections := TStringList.Create;
  141. Lines := TStringList.Create;
  142. FIniFile.ReadSections(Sections);
  143. try
  144. for I := 0 to Sections.Count - 1 do
  145. begin
  146. if (Sections[I] = SCnGlobalSectionName) or
  147. (Sections[I] = SCnStringsSectionName) then // 是内部保留区或常量区
  148. begin
  149. FIniFile.ReadSection(Sections[I], Lines);
  150. for J := 0 to Lines.Count - 1 do
  151. begin
  152. //Modified by Efeis on 2008-11-18 原作者将ReadSection理解错了吧,且程序也受父类写法的影响
  153. AddStringToHashMap(Lines[J], FIniFile.ReadString(Sections[I], Lines[J], ''));
  154. end;
  155. end
  156. else // 是普通窗体的
  157. begin
  158. FIniFile.ReadSection(Sections[I], Lines);
  159. for J := 0 to Lines.Count - 1 do
  160. begin
  161. //Modified by Efeis on 2008-11-18 同上,对ReadSection的错误理解及IniFile的使用问题
  162. AddStringToHashMap(Sections[I] + DefDelimeter + Lines[J], FIniFile.ReadString(Sections[I], Lines[J], ''));
  163. end;
  164. end;
  165. end;
  166. finally
  167. Sections.Free;
  168. Lines.Free;
  169. end;
  170. except
  171. Result := False;
  172. end;
  173. end;
  174. procedure TCnCustomIniLangFileStorage.SaveCurrentLanguage;
  175. var
  176. Sections, List: TStringList;
  177. Key, Value, Sec: WideString;
  178. I, EPos: Integer;
  179. begin
  180. if Assigned(FIniFile) then
  181. begin
  182. Sections := TStringList.Create;
  183. try
  184. FIniFile.ReadSections(Sections);
  185. for I := 0 to Sections.Count - 1 do
  186. FIniFile.EraseSection(Sections[I]);
  187. finally
  188. Sections.Free;
  189. end;
  190. List := TStringList.Create;
  191. HashMap.StartEnum;
  192. while HashMap.GetNext(Key, Value) do
  193. List.Add(Key + DefEqual + Value);
  194. List.Sort;
  195. for I := 0 to List.Count - 1 do
  196. begin
  197. if Pos(SystemNamePrefix, List[I]) = 1 then // 判断第一个是不是感叹号
  198. begin
  199. Sec := SCnGlobalSectionName;
  200. end
  201. else // 再判断有无点号
  202. begin
  203. EPos := Pos(DefDelimeter, List[I]);
  204. if EPos > 0 then // 有点号,取出第一个点号前的做 Section 名字
  205. begin
  206. Sec := Copy(List[I], 1, EPos - 1);
  207. List[I] := Copy(List[I], EPos + 1, MaxInt);
  208. end
  209. else
  210. Sec := SCnStringsSectionName; // 无点号,是字符串
  211. end;
  212. // 拆分
  213. EPos := Pos(DefEqual, List[I]);
  214. if EPos > 0 then // 有等号
  215. begin
  216. Key := Copy(List[I], 1, EPos - 1);
  217. Value := Copy(List[I], EPos + 1, MaxInt);
  218. end
  219. else
  220. begin
  221. Key := List[I];
  222. Value := '';
  223. end;
  224. FIniFile.WriteString(Sec, Key, Value);
  225. end;
  226. FIniFile.UpdateFile;
  227. end;
  228. end;
  229. procedure TCnCustomIniLangFileStorage.InitFromAFile(const AFileName: WideString);
  230. begin
  231. // 从一语言文件读入语言内容
  232. if Assigned(FIniFile) then
  233. FreeAndNil(FIniFile);
  234. with Languages.Add do
  235. begin
  236. LanguageFileName := _CnExtractFileName(_CnChangeFileExt(AFileName, ''));
  237. FIniFile := TIniFile.Create(AFileName);
  238. try
  239. LanguageID := StrToIntDef(FIniFile.ReadString(SCnGlobalSectionName, SystemNamePrefix + SCnLanguageID, ''), 0);
  240. except
  241. LanguageID := 0;
  242. end;
  243. if LanguageID <> 0 then
  244. begin
  245. LanguageName := FIniFile.ReadString(SCnGlobalSectionName, SystemNamePrefix + SCnLanguageName, '');
  246. Author := FIniFile.ReadString(SCnGlobalSectionName, SystemNamePrefix + SCnAuthor, '');
  247. AuthorEmail := FIniFile.ReadString(SCnGlobalSectionName, SystemNamePrefix + SCnAuthorEmail, '');
  248. if FIniFile.ReadString(SCnGlobalSectionName, SystemNamePrefix + SCnDefaultFont, '') <> '' then
  249. StringToFont(FIniFile.ReadString(SCnGlobalSectionName, SystemNamePrefix + SCnDefaultFont, ''), DefaultFont);
  250. end
  251. else
  252. begin
  253. Self.FCurrentLanguageIndex := -1;
  254. Languages.Delete(Index);
  255. end;
  256. end;
  257. end;
  258. procedure TCnCustomIniLangFileStorage.GetComponentInfo(var AName, Author,
  259. Email, Comment: string);
  260. begin
  261. AName := SCnIniLangStorageName;
  262. Author := SCnPack_LiuXiao;
  263. Email := SCnPack_LiuXiaoEmail;
  264. Comment := SCnIniLangStorageComment;
  265. end;
  266. end.