2017-06-06 47 views
3

我寫我自己的類來管理Android/iOS應用程序的翻譯和我產生了這個代碼。我將解釋下面的代碼,但它非常簡單和簡短。德爾福的TStringList查找方法無法找到項目

unit Localization; 

interface 

uses 
System.Classes, System.SysUtils, Generics.Collections, Vcl.Dialogs; 

//this class represents a single language (Italian, French, German...) 
type 
TLanguage = class 
    private 
    FTranslationList: TDictionary<string, string>; 
    function localize(const aWordId: string): string; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    //methods 
    procedure addWord(const aIndex, aWord: string); 
    procedure removeWord(const aIndex: string); 
end; 

//this is a "container", it gathers all the languages in one place 
type 
TLocalization = class 
    private 
    FLanguagesList: TObjectList<TLanguage>; 
    FLocaleList: TStringList; 
    function getLang(Index: string): TLanguage; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    //methods 
    function localize(const aLocaleId: string; const aIndex: string): string; 
    procedure addLanguage(const localeId: string); 
    //property to manage the languages 
    property Locale[Index: string]: TLanguage read getLang; 
    property langCount: integer read getCount; 
end; 

implementation 

{ TLocalization } 

{ add a new language to the class. } 
{the localeId is a symbol like 'it' that represents the Italian language} 
procedure TLocalization.addLanguage(const localeId: string); 
begin 
//add the language to the languages container 
FLanguagesList.Add(TLanguage.Create); 
//add the representation of the language. 
FLocaleList.Add(localeId); 
end; 

constructor TLocalization.Create; 
begin 
FLanguagesList := TObjectList<TLanguage>.Create; 
FLocaleList := TStringList.Create; 
end; 

destructor TLocalization.Destroy; 
begin 
FLanguagesList.Free; 
FLocaleList.Free; 
inherited; 
end; 

//ERROR HERE 
function TLocalization.getLang(Index: string): TLanguage; 
var i: integer; 
begin 

{ I search the locale id (for example 'it') if it's in the list. } 
{ if it's in the list, I return the respective TLanguage object} 
if not(FLocaleList.Find(Index, i)) then 
    Result := FLanguagesList.Items[i] 
else 
    raise Exception.Create('Locale not found'); 

end; 

function TLocalization.localize(const aLocaleId, aIndex: string): string; 
var k: integer; 
begin 

k := 0; 

if not(FLocaleList.Find(aLocaleId, k)) then 
    raise Exception.Create('Locale not found.'); 

//ho trovato il locale, adesso basta cercare la parola 
Result := FLanguagesList.Items[k].localize(aIndex); 

end; 

{ TLanguage } 

procedure TLanguage.addWord(const aIndex, aWord: string); 
begin 
FTranslationList.Add(aIndex, aWord); 
end; 

constructor TLanguage.Create; 
begin 
FTranslationList := TDictionary<string, string>.Create; 
end; 

destructor TLanguage.Destroy; 
begin 
FTranslationList.Free; 
inherited; 
end; 

function TLanguage.localize(const aWordId: string): string; 
begin 

try 
    Result := FTranslationList.Items[aWordId]; 
except 
    Result := 'Not found.'; 
end; 

end; 

procedure TLanguage.removeWord(const aIndex: string); 
begin 
FTranslationList.Remove(aIndex); 
end; 

end. 

以上被用作代碼如下:

var a: TLocalization; 
begin 
    a := TLocalization.Create; 

    a.addLanguage('it'); 
    a.addLanguage('cse'); 
    a.Locale['it'].addWord('test', 'Ciao mondo!'); 
    a.Locale['cse'].addWord('test', 'fadfa ea!'); 

    ButtonSomething.Text := a.localize('it', test); 

end; 

TLocalization類完成所有工作。正如你所看到的,我創建了變量a,然後我添加一個語言到這個類(這是使用字典/字符串列表在內部管理的)。

我可以使用Locale[Index: string]屬性訪問我已添加的語言,該屬性返回一個TLanguage,該類用於指示單個lang。在本地化方法的最後,我得到了我的翻譯。


奇怪的是,我總是得到錯誤'Locale not found'。任何想法?使用我發現這個調試器:

enter image description here

FLocaleList有項目,但我已經測試了這一點,我想我做錯了什麼上線71(在這裏我使用查找功能)。我是否錯過了索引?

+0

好像不是.Find你應該嘗試.IndexOf ... –

+0

查找工作與排序名單 - 我不知道你在做什麼。使用IndexOf或首先對列表進行排序。 – Jason

+0

在這個問題的範圍之外 - 看起來你在課堂上混合了兩個術語。區域設置和語言代碼(或ID)。你所說的區域設置通常被稱爲語言代碼(或ID),例如, 'en','it'等,而區域設置是語言的特定子類(用於世界的特定區域),例如,對於英語,它可以是英式英語('en-gb'),美式英語('en-us')等。因此,在翻譯文本時,首先檢查文本是否僅存在於特定方言),如果不是,請使用該語言的通用語言。 – Victoria

回答

9

你的代碼邏輯是倒退。 Find()如果找到匹配則返回True,否則返回False。如果Find()返回False,則正在訪問Items[],如果返回True則引發異常。您需要刪除notif聲明:

function TLocalization.getLang(Index: string): TLanguage; 
var 
    i: integer; 
begin 
    { I search the locale id (for example 'it') if it's in the list. } 
    { if it's in the list, I return the respective TLanguage object} 
    if FLocaleList.Find(Index, i) then // <-- HERE 
    Result := FLanguagesList.Items[i] 
    else 
    raise Exception.Create('Locale not found'); 
end; 

但是,更重要的是,Find() documentation說:

注:僅使用Find與有序列表。對於未排序的列表,請使用IndexOf方法。

您的列表未排序,因爲Sorted屬性默認爲false。因此,使用IndexOf()代替:

function TLocalization.getLang(Index: string): TLanguage; 
var 
    i: integer; 
begin 
    { I search the locale id (for example 'it') if it's in the list. } 
    { if it's in the list, I return the respective TLanguage object} 
    i := FLocaleList.IndexOf(Index); 
    if i <> -1 then 
    Result := FLanguagesList.Items[i] 
    else 
    raise Exception.Create('Locale not found'); 
end; 
+0

非常感謝,我的班現在在這種情況下完美工作 –

+3

,我根本不會使用'TStringList'。如果出現問題,就很容易讓FLanguagesList和FLocaleList不同步。我要麼1)添加一個'LocaleID'成員到'TLanguage',然後通過'FLanguagesList'查找該ID,或者2)將'FLanguagesList'更改爲'TDictionary '而不是'TObjectList' –

+0

感謝您的意見,我想您的想法比我更有意義。 –