CnLangUtils.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  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 CnLangUtils;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:CnPack 多语包
  24. * 单元名称:多语工具类单元
  25. * 单元作者:CnPack开发组 刘啸 (liuxiao@cnpack.org)
  26. * 备 注:该单元定义了多语工具类
  27. * 开发平台:PWin2000 + Delphi 5.0
  28. * 兼容测试:PWin9X/2000/XP + Delphi 5/6/7
  29. * 本 地 化:该单元中的字符串均符合本地化处理方式
  30. * 单元标识:$Id$
  31. * 修改记录:2006.10.12 V1.0
  32. * 创建单元,实现功能
  33. ================================================================================
  34. |</PRE>}
  35. interface
  36. {$I CnPack.inc}
  37. uses
  38. SysUtils, SysConst, Classes, Windows;
  39. type
  40. { TCnLangStringExtractor }
  41. TLangTransFilter = (tfFont, tfCaption, tfCategory, tfHelpKeyword, tfHint,
  42. tfText, tfImeName, tfTitle, tfDefaultExt, tfFilter, tfInitialDir,
  43. tfSubItemsText, tfOthers);
  44. TLangTransFilterSet = set of TLangTransFilter;
  45. TCnLangStringExtractor = class
  46. private
  47. FFilterOptions: TLangTransFilterSet;
  48. protected
  49. procedure GetObjectStrings(AOwner: TComponent; AObject: TObject; Strings: TStrings;
  50. const BaseName: string; SkipEmptyStr: Boolean);
  51. procedure GetRecurComponentStrings(AOwner: TComponent; AComponent: TComponent;
  52. AList: TList; Strings: TStrings; const BaseName: string; SkipEmptyStr: Boolean); virtual;
  53. {* 递归获得一 Component 以及其子 Component 的字串 }
  54. procedure GetRecurObjectStrings(AOwner: TComponent; AObject: TObject; AList: TList;
  55. Strings: TStrings; const BaseName: string; SkipEmptyStr: Boolean); virtual;
  56. {* 递归获得一 Object 属性以及其子属性对象的字串 }
  57. public
  58. constructor Create;
  59. {* 取得一个窗体上所有字符串}
  60. procedure GetFormStrings(AForm: TComponent; Strings: TStrings; SkipEmptyStr: Boolean = False);
  61. {* 获得一 Form 上的所有字串 }
  62. procedure GetComponentStrings(AComponent: TComponent; Strings: TStrings;
  63. const BaseName: string = ''; SkipEmptyStr: Boolean = False);
  64. {* 获得一 Component 的所有字串 }
  65. procedure SetFilterOptions(const AFilterOptions: TLangTransFilterSet);
  66. {* 设置过滤 *}
  67. end;
  68. {* 从 SysUtils 的 TLanguages 移植而来但修正了 DEP 错误的语言列表类}
  69. TCnLanguages = class(TObject)
  70. private
  71. FSysLangs: array of TLangRec;
  72. function LocalesCallback(LocaleID: PChar): Integer; stdcall;
  73. function GetExt(Index: Integer): string;
  74. function GetID(Index: Integer): string;
  75. function GetLCID(Index: Integer): LCID;
  76. function GetName(Index: Integer): string;
  77. function GetNameFromLocaleID(ID: LCID): string;
  78. function GetNameFromLCID(const ID: string): string;
  79. function GetCount: integer;
  80. public
  81. constructor Create;
  82. destructor Destroy; override;
  83. function IndexOf(ID: LCID): Integer;
  84. property Count: Integer read GetCount;
  85. property Name[Index: Integer]: string read GetName;
  86. property NameFromLocaleID[ID: LCID]: string read GetNameFromLocaleID;
  87. property NameFromLCID[const ID: string]: string read GetNameFromLCID;
  88. property ID[Index: Integer]: string read GetID;
  89. property LocaleID[Index: Integer]: LCID read GetLCID;
  90. property Ext[Index: Integer]: string read GetExt;
  91. end;
  92. function CnLanguages: TCnLanguages;
  93. {* 返回全局的 CnLanguages 列表类}
  94. implementation
  95. uses
  96. {$IFDEF COMPILER6_UP}Variants, {$ENDIF}
  97. Forms, Dialogs, Graphics, Menus, Grids, ComCtrls, Controls, ExtCtrls,
  98. ToolWin, ActnList, ImgList, TypInfo, StdCtrls, CnCommon, CnIniStrUtils,
  99. Clipbrd, CnLangMgr, CnClasses, CnLangConsts, CnLangStorage;
  100. const
  101. THUNK_SIZE = 4096; // x86 页大小
  102. var
  103. FLanguages: TCnLanguages;
  104. FTempLanguages: TCnLanguages = nil;
  105. function EnumLocalesCallback(LocaleID: PChar): Integer; stdcall;
  106. begin
  107. Result := FTempLanguages.LocalesCallback(LocaleID);
  108. end;
  109. { TCnLanguages }
  110. function GetLocaleDataW(ID: LCID; Flag: DWORD): string;
  111. var
  112. Buffer: array[0..1023] of WideChar;
  113. begin
  114. Buffer[0] := #0;
  115. GetLocaleInfoW(ID, Flag, Buffer, SizeOf(Buffer) div 2);
  116. Result := Buffer;
  117. end;
  118. function GetLocaleDataA(ID: LCID; Flag: DWORD): string;
  119. var
  120. Buffer: array[0..1023] of AnsiChar;
  121. begin
  122. Buffer[0] := #0;
  123. SetString(Result, Buffer, GetLocaleInfoA(ID, Flag, Buffer, SizeOf(Buffer)) - 1);
  124. end;
  125. function TCnLanguages.LocalesCallback(LocaleID: PChar): Integer; stdcall;
  126. var
  127. AID: LCID;
  128. ShortLangName: string;
  129. GetLocaleDataProc: function (ID: LCID; Flag: DWORD): string;
  130. begin
  131. if Win32Platform = VER_PLATFORM_WIN32_NT then
  132. GetLocaleDataProc := @GetLocaleDataW
  133. else
  134. GetLocaleDataProc := @GetLocaleDataA;
  135. AID := StrToInt('$' + Copy(LocaleID, 5, 4));
  136. ShortLangName := GetLocaleDataProc(AID, LOCALE_SABBREVLANGNAME);
  137. if ShortLangName <> '' then
  138. begin
  139. SetLength(FSysLangs, Length(FSysLangs) + 1);
  140. with FSysLangs[High(FSysLangs)] do
  141. begin
  142. FName := GetLocaleDataProc(AID, LOCALE_SLANGUAGE);
  143. FLCID := AID;
  144. FExt := ShortLangName;
  145. end;
  146. end;
  147. Result := 1;
  148. end;
  149. constructor TCnLanguages.Create;
  150. begin
  151. inherited Create;
  152. FTempLanguages := Self;
  153. EnumSystemLocales(@EnumLocalesCallback, LCID_SUPPORTED);
  154. end;
  155. destructor TCnLanguages.Destroy;
  156. begin
  157. inherited;
  158. end;
  159. function TCnLanguages.GetCount: Integer;
  160. begin
  161. Result := High(FSysLangs) + 1;
  162. end;
  163. function TCnLanguages.GetExt(Index: Integer): string;
  164. begin
  165. Result := FSysLangs[Index].FExt;
  166. end;
  167. function TCnLanguages.GetID(Index: Integer): string;
  168. begin
  169. Result := HexDisplayPrefix + IntToHex(FSysLangs[Index].FLCID, 8);
  170. end;
  171. function TCnLanguages.GetLCID(Index: Integer): LCID;
  172. begin
  173. Result := FSysLangs[Index].FLCID;
  174. end;
  175. function TCnLanguages.GetName(Index: Integer): string;
  176. begin
  177. Result := FSysLangs[Index].FName;
  178. end;
  179. function TCnLanguages.GetNameFromLocaleID(ID: LCID): string;
  180. var
  181. Index: Integer;
  182. begin
  183. Index := IndexOf(ID);
  184. if Index <> - 1 then Result := Name[Index];
  185. if Result = '' then Result := SUnknown;
  186. end;
  187. function TCnLanguages.GetNameFromLCID(const ID: string): string;
  188. begin
  189. Result := NameFromLocaleID[StrToIntDef(ID, 0)];
  190. end;
  191. function TCnLanguages.IndexOf(ID: LCID): Integer;
  192. begin
  193. for Result := Low(FSysLangs) to High(FSysLangs) do
  194. if FSysLangs[Result].FLCID = ID then Exit;
  195. Result := -1;
  196. end;
  197. function CnLanguages: TCnLanguages;
  198. begin
  199. if FLanguages = nil then
  200. FLanguages := TCnLanguages.Create;
  201. Result := FLanguages;
  202. end;
  203. { TCnLangStringExtractor }
  204. constructor TCnLangStringExtractor.Create;
  205. begin
  206. SetFilterOptions([]);
  207. end;
  208. procedure TCnLangStringExtractor.GetComponentStrings(AComponent: TComponent;
  209. Strings: TStrings; const BaseName: string; SkipEmptyStr: Boolean);
  210. var
  211. AList: TList;
  212. begin
  213. if (Strings <> nil) and (AComponent.ComponentCount > 0) then
  214. begin
  215. AList := TList.Create;
  216. try
  217. if AComponent.Owner = nil then
  218. GetRecurComponentStrings(AComponent, AComponent, AList, Strings, BaseName, SkipEmptyStr)
  219. else
  220. GetRecurComponentStrings(nil, AComponent, AList, Strings, BaseName, SkipEmptyStr)
  221. finally
  222. AList.Free;
  223. end;
  224. end
  225. else
  226. GetObjectStrings(nil, AComponent, Strings, BaseName, SkipEmptyStr);
  227. end;
  228. procedure TCnLangStringExtractor.GetFormStrings(AForm: TComponent;
  229. Strings: TStrings; SkipEmptyStr: Boolean);
  230. begin
  231. GetComponentStrings(AForm, Strings, AForm.ClassName, SkipEmptyStr);
  232. end;
  233. procedure TCnLangStringExtractor.GetObjectStrings(AOwner: TComponent;
  234. AObject: TObject; Strings: TStrings; const BaseName: string; SkipEmptyStr: Boolean);
  235. var
  236. AList: TList;
  237. begin
  238. AList := TList.Create;
  239. try
  240. GetRecurObjectStrings(AOwner, AObject, AList, Strings, BaseName, SkipEmptyStr);
  241. finally
  242. AList.Free;
  243. end;
  244. end;
  245. procedure TCnLangStringExtractor.GetRecurComponentStrings(AOwner: TComponent;
  246. AComponent: TComponent; AList: TList; Strings: TStrings; const BaseName: string;
  247. SkipEmptyStr: Boolean);
  248. var
  249. I: Integer;
  250. T: TComponent;
  251. begin
  252. if (AComponent <> nil) and (AList <> nil) and (AList.IndexOf(AComponent) = -1) then
  253. begin
  254. GetRecurObjectStrings(AOwner, AComponent, AList, Strings, BaseName, SkipEmptyStr);
  255. for I := 0 to AComponent.ComponentCount - 1 do
  256. begin
  257. T := AComponent.Components[I];
  258. if AComponent is TCustomForm then
  259. GetRecurComponentStrings(AOwner, T, AList, Strings, BaseName, SkipEmptyStr)
  260. else
  261. GetRecurComponentStrings(AOwner, T, AList, Strings, BaseName + DefDelimeter + AComponent.Name, SkipEmptyStr);
  262. end;
  263. end;
  264. end;
  265. procedure TCnLangStringExtractor.GetRecurObjectStrings(AOwner: TComponent;
  266. AObject: TObject; AList: TList; Strings: TStrings; const BaseName: string;
  267. SkipEmptyStr: Boolean);
  268. var
  269. i: Integer;
  270. APropName, APropValue, AStr: string;
  271. APropType: TTypeKind;
  272. Data: PTypeData;
  273. ActionObj, SubObj: TObject;
  274. AItem: TCollectionItem;
  275. AListItem: TListItem;
  276. ATreeNode: TTreeNode;
  277. IsForm: Boolean;
  278. NeedIgnoreAction: Boolean;
  279. ActionCaption, ActionHint: string;
  280. Info: PPropInfo;
  281. begin
  282. if (AObject <> nil) and (AList <> nil) and (AList.IndexOf(AObject) = -1) then
  283. begin
  284. AList.Add(AObject);
  285. // 避免传入一些野了的 AObject 导致死循环,曾在 IDE 内部出现过
  286. try
  287. if AObject.ClassType = AObject.ClassParent then
  288. Exit;
  289. if (AObject.ClassParent <> nil) and (AObject.ClassParent.ClassParent = AObject.ClassType) then
  290. Exit;
  291. except
  292. Exit;
  293. end;
  294. if (AObject is TCnCustomLangStorage) or (AObject is TCnCustomLangStorage)
  295. or ((AObject is TComponent) and ((AObject as TComponent).Name = '')) then
  296. Exit;
  297. if (AObject is TStrings) then // Strings的对象直接加入其 Text 属性。
  298. begin
  299. if not (tfText in FFilterOptions) then
  300. Exit;
  301. AStr := 'Text';
  302. if BaseName <> '' then
  303. AStr := BaseName + DefDelimeter + AStr;
  304. if not SkipEmptyStr or ((AObject as TStrings).Text <> '') then
  305. Strings.Add(AStr + DefEqual + StringReplace((AObject as TStrings).Text,
  306. SCnCRLF, SCnBR, [rfReplaceAll, rfIgnoreCase]));
  307. Exit;
  308. end
  309. else if (AObject is TCollection) then // TCollection 对象遍历其 Item
  310. begin
  311. for i := 0 to (AObject as TCollection).Count - 1 do
  312. begin
  313. AItem := (AObject as TCollection).Items[i];
  314. if BaseName <> '' then
  315. GetRecurObjectStrings(AOwner, AItem, AList, Strings, BaseName + DefDelimeter
  316. + 'Item' + InttoStr(i), SkipEmptyStr)
  317. else
  318. GetRecurObjectStrings(AOwner, AItem, AList, Strings, 'Item' + InttoStr(i), SkipEmptyStr);
  319. end;
  320. end
  321. // ListView 在需要时遍历其 Item
  322. else if CnLanguageManager.TranslateListItem and (AObject is TListView) then
  323. begin
  324. for i := 0 to (AObject as TListView).Items.Count - 1 do
  325. begin
  326. AListItem := (AObject as TListView).Items[i];
  327. if BaseName <> '' then
  328. GetRecurObjectStrings(AOwner, AListItem, AList, Strings, BaseName + DefDelimeter
  329. + TComponent(AObject).Name + DefDelimeter + 'ListItem' + InttoStr(i), SkipEmptyStr)
  330. else
  331. GetRecurObjectStrings(AOwner, AListItem, AList, Strings,
  332. TComponent(AObject).Name + DefDelimeter + 'ListItem' + InttoStr(i), SkipEmptyStr);
  333. end;
  334. end
  335. // 是 ListItem 时处理其 Caption 属性和 SubItems 属性
  336. else if CnLanguageManager.TranslateListItem and (AObject is TListItem) then
  337. begin
  338. if (tfCaption in FFilterOptions) then
  339. begin
  340. AStr := 'Caption';
  341. if BaseName <> '' then
  342. AStr := BaseName + DefDelimeter + AStr;
  343. if not SkipEmptyStr or ((AObject as TListItem).Caption <> '') then
  344. Strings.Add(AStr + DefEqual + (AObject as TListItem).Caption);
  345. end;
  346. if (tfSubItemsText in FFilterOptions) then
  347. begin
  348. AStr := 'SubItems.Text';
  349. if BaseName <> '' then
  350. AStr := BaseName + DefDelimeter + AStr;
  351. if not SkipEmptyStr or ((AObject as TListItem).SubItems.Text <> '') then
  352. Strings.Add(AStr + DefEqual + (AObject as TListItem).SubItems.Text);
  353. end;
  354. Exit;
  355. end
  356. // TreeView 在需要时遍历其 Item
  357. else if CnLanguageManager.TranslateTreeNode and (AObject is TTreeView) then
  358. begin
  359. for i := 0 to (AObject as TTreeView).Items.Count - 1 do
  360. begin
  361. ATreeNode := (AObject as TTreeView).Items[i];
  362. if BaseName <> '' then
  363. GetRecurObjectStrings(AOwner, ATreeNode, AList, Strings, BaseName + DefDelimeter
  364. + TComponent(AObject).Name + DefDelimeter + 'TreeNode' + InttoStr(i), SkipEmptyStr)
  365. else
  366. GetRecurObjectStrings(AOwner, ATreeNode, AList, Strings,
  367. TComponent(AObject).Name + DefDelimeter + 'TreeNode' + InttoStr(i), SkipEmptyStr);
  368. end;
  369. end
  370. // 是 TreeNode 时处理其 Text 属性
  371. else if CnLanguageManager.TranslateTreeNode and (AObject is TTreeNode) then
  372. begin
  373. if not (tfText in FFilterOptions) then
  374. Exit;
  375. AStr := 'Text';
  376. if BaseName <> '' then
  377. AStr := BaseName + DefDelimeter + AStr;
  378. if not SkipEmptyStr or ((AObject as TTreeNode).Text <> '') then
  379. Strings.Add(AStr + DefEqual + (AObject as TTreeNode).Text);
  380. Exit;
  381. end;
  382. IsForm := (AObject is TCustomForm); // or (AObject is TCustomFrame);
  383. // if IsForm then IsForm := (AObject as TWinControl).Parent = nil;
  384. try
  385. Data := GetTypeData(AObject.Classinfo);
  386. except
  387. Exit; // TChartSeriesList 会在此处出错,不得不抓住屏蔽
  388. end;
  389. NeedIgnoreAction := False;
  390. if CnLanguageManager.IgnoreAction then
  391. begin
  392. // 查找是否有 Action 属性,看是否 nil
  393. for I := 0 to Data^.PropCount - 1 do
  394. begin
  395. APropName := GetPropName(AObject, I);
  396. if (PropType(AObject, APropName) = tkClass) and (APropName = 'Action') then
  397. begin
  398. // 存在 Action 属性,为tkClass
  399. ActionObj := GetObjectProp(AObject, APropName);
  400. if (ActionObj <> nil) and (ActionObj is TCustomAction)then
  401. begin
  402. // 有 Action 属性不为 nil 的,需要记录 Caption 和 Hint 供比较
  403. NeedIgnoreAction := True;
  404. ActionCaption := (ActionObj as TCustomAction).Caption;
  405. ActionHint := (ActionObj as TCustomAction).Hint;
  406. Break;
  407. end;
  408. end;
  409. end;
  410. end;
  411. for I := 0 to Data^.PropCount - 1 do
  412. begin
  413. APropName := GetPropName(AObject, I);
  414. // 不翻译 TComponent 的 Name 属性
  415. if (AObject is TComponent) and (APropName = 'Name') then
  416. Continue;
  417. // 不翻译 TCnComponent 的 About 属性
  418. if (AObject is TCnComponent) and (APropName = 'About') then
  419. Continue;
  420. APropType := PropType(AObject, APropName);
  421. if (APropType in [tkString, tkLString, tkWString //, tkWChar
  422. {$IFDEF UNICODE_STRING}, tkUString{$ENDIF}]) then
  423. begin
  424. try
  425. APropValue := VartoStr(GetPropValue(AObject, APropName));
  426. except
  427. // 部分 OLE 等组件获取 WideString 属性时出错,加个屏蔽
  428. Continue;
  429. end;
  430. if NeedIgnoreAction then
  431. begin
  432. if (APropName = 'Caption') and (ActionCaption = APropValue) then
  433. Continue
  434. else if (APropName = 'Hint') and (ActionHint = APropValue) then
  435. Continue;
  436. end;
  437. Info := GetPropInfo(AObject, APropName);
  438. if (Info <> nil) and (Info^.SetProc = nil) then // 只读不能写的,躲开
  439. Continue;
  440. // 处理过滤条件
  441. if (APropName = 'Caption') then
  442. begin
  443. if not (tfCaption in FFilterOptions) then
  444. begin
  445. Continue;
  446. end;
  447. end
  448. else if (APropName = 'Category') then
  449. begin
  450. if not (tfCategory in FFilterOptions) then
  451. begin
  452. Continue;
  453. end;
  454. end
  455. else if (APropName = 'HelpKeyword') then
  456. begin
  457. if not (tfHelpKeyword in FFilterOptions) then
  458. begin
  459. Continue;
  460. end;
  461. end
  462. else if (APropName = 'Hint') then
  463. begin
  464. if not (tfHint in FFilterOptions) then
  465. begin
  466. Continue;
  467. end;
  468. end
  469. else if (APropName = 'ImeName') then
  470. begin
  471. if not (tfImeName in FFilterOptions) then
  472. begin
  473. Continue;
  474. end;
  475. end
  476. else if (APropName = 'Title') then
  477. begin
  478. if not (tfTitle in FFilterOptions) then
  479. begin
  480. Continue;
  481. end;
  482. end
  483. else if (APropName = 'DefaultExt') then
  484. begin
  485. if not (tfDefaultExt in FFilterOptions) then
  486. begin
  487. Continue;
  488. end;
  489. end
  490. else if (APropName = 'Filter') then
  491. begin
  492. if not (tfFilter in FFilterOptions) then
  493. begin
  494. Continue;
  495. end;
  496. end
  497. else if (APropName = 'InitialDir') then
  498. begin
  499. if not (tfInitialDir in FFilterOptions) then
  500. begin
  501. Continue;
  502. end;
  503. end
  504. else if not (tfOthers in FFilterOptions) then
  505. begin
  506. Continue;
  507. end;
  508. if IsForm then
  509. AStr := AObject.ClassName + DefDelimeter + APropName
  510. else if AObject is TComponent then
  511. AStr := TComponent(AObject).Name + DefDelimeter + APropName
  512. else
  513. AStr := APropName;
  514. if (BaseName <> '') and not IsForm then
  515. AStr := BaseName + DefDelimeter + AStr;
  516. if not SkipEmptyStr or (APropValue <> '') then
  517. Strings.Add(AStr + DefEqual + APropValue);
  518. end
  519. else if APropType = tkClass then
  520. begin
  521. SubObj := GetObjectProp(AObject, APropName);
  522. if (SubObj is TComponent) and (AOwner <> nil) and
  523. ((SubObj as TComponent).Owner = AOwner) then
  524. begin
  525. // 子对象是窗体的直系组件时,不在这里翻译
  526. end
  527. else if AObject is TComponent then
  528. begin
  529. if AList.IndexOf(SubObj) = -1 then
  530. begin
  531. if (AObject is TControl) and (SubObj is TFont) and (APropName = 'Font') then
  532. begin
  533. if (tfFont in FFilterOptions) then
  534. if not IsParentFont(AObject as TControl) then // 不使用 ParentFont 时存字体
  535. begin
  536. if not IsForm then
  537. AStr := TComponent(AObject).Name + DefDelimeter + SCnControlFont
  538. else
  539. AStr := SCnControlFont;
  540. if BaseName <> '' then
  541. AStr := BaseName + DefDelimeter + AStr;
  542. AList.Add(SubObj);
  543. Strings.Add(AStr + DefEqual + FontToStringEx(SubObj as TFont,
  544. GetParentFont(AObject as TComponent)));
  545. end;
  546. end // 不按常规处理 TControl的字体
  547. else if CnLanguageManager.TranslateOtherFont and (SubObj is TFont) then
  548. begin
  549. if (tfFont in FFilterOptions) then
  550. begin
  551. if not IsForm then
  552. AStr := TComponent(AObject).Name + DefDelimeter +
  553. SystemNamePrefix + APropName
  554. else
  555. AStr := SystemNamePrefix + APropName;
  556. if BaseName <> '' then
  557. AStr := BaseName + DefDelimeter + AStr;
  558. AList.Add(SubObj);
  559. Strings.Add(AStr + DefEqual + FontToStringEx(SubObj as TFont,
  560. GetParentFont(AObject as TComponent)));
  561. end;
  562. end
  563. else if not (SubObj is TComponent) or ((SubObj as TComponent).Owner = nil) then
  564. begin
  565. if IsForm then
  566. GetRecurObjectStrings(AOwner, SubObj, AList, Strings,
  567. TComponent(AObject).ClassName + DefDelimeter + APropName, SkipEmptyStr)
  568. else if (InheritsFromClassName(AObject, 'TNotebook') or InheritsFromClassName(AObject, 'TTabbedNotebook'))
  569. and (APropName = 'Pages') then
  570. // 不获取 TNotebook/TTabbedNotebook 的 Pages 属性,以免出现翻译后页面内容丢失。
  571. else
  572. GetRecurObjectStrings(AOwner, SubObj, AList, Strings, BaseName +
  573. DefDelimeter + TComponent(AObject).Name + DefDelimeter + APropName, SkipEmptyStr);
  574. end;
  575. end;
  576. end
  577. else
  578. begin
  579. GetRecurObjectStrings(AOwner, SubObj, AList, Strings,
  580. BaseName + DefDelimeter + APropName, SkipEmptyStr);
  581. end;
  582. end;
  583. end;
  584. end;
  585. end;
  586. procedure TCnLangStringExtractor.SetFilterOptions(
  587. const AFilterOptions: TLangTransFilterSet);
  588. begin
  589. if AFilterOptions = [] then
  590. begin
  591. Include(FFilterOptions, tfFont);
  592. Include(FFilterOptions, tfCaption);
  593. Include(FFilterOptions, tfCategory);
  594. Include(FFilterOptions, tfHelpKeyword);
  595. Include(FFilterOptions, tfHint);
  596. Include(FFilterOptions, tfText);
  597. Include(FFilterOptions, tfImeName);
  598. Include(FFilterOptions, tfTitle);
  599. Include(FFilterOptions, tfDefaultExt);
  600. Include(FFilterOptions, tfFilter);
  601. Include(FFilterOptions, tfInitialDir);
  602. Include(FFilterOptions, tfSubItemsText);
  603. Include(FFilterOptions, tfOthers);
  604. end
  605. else
  606. FFilterOptions := AFilterOptions;
  607. end;
  608. initialization
  609. finalization
  610. if FLanguages <> nil then
  611. FreeAndNil(FLanguages);
  612. end.