2017-06-06 15 views
3

私は自分のクラスを作成してandroid/ios appの翻訳を管理しています。私は以下のコードを説明しますが、それはかなり簡単で短いです。Delphi TStringList Findメソッドが項目を見つけることができません

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を返します。最後にlocalizeメソッドを使って私の翻訳を取得します。


私はいつもエラー'Locale not found'を取得します。何か案が?私はこれを発見したデバッガの使用:

enter image description here

FLocaleListしてアイテムを持っていますが、私はこれをテストしていると私は、私は(私は検索機能を使用)ライン71上の何かを間違ってやっていることと思います。インデックスを間違って渡していますか?

+0

ではなく.Findのあなたが.IndexOfを試してみてくださいように思える... –

+0

検索は、ソートされたリストで動作します - 私はあなたがやっていることを確認するものではありません。 IndexOfを使用するか、リストを最初にソートします。 – Jason

+0

この質問の範囲外です。あなたのクラスに2つの用語を混ぜているようです。ロケールと言語コード(またはID)。ロケールと呼ぶものは、通常、言語コード(またはID)と呼ばれます。ロケールは言語の特定のサブクラス(例えば、世界の特定の地域で使用される)であり、例えば、「en」、「it」などである。英語の場合は英国の英語( 'en-gb')、アメリカの英語(' en-us')などです。テキストを翻訳するときは、まず特定の方言(ロケール)、そうでない場合は、その言語に共通のものを使用してください。 – Victoria

答えて

9

コードロジックが後方にあります。 Find()は、一致するものが見つかるとTrueを返し、そうでない場合はFalseを返します。 がFalseを返した場合はItems[]にアクセスし、Trueを返す場合は例外を発生します。あなたのif文でnotを削除する必要があります、

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'に追加し、そのIDを探して 'FLanguagesList'をループするか、2)' TObjectList'の代わりに 'FLictionaryList'を' TDictionary <文字列、TLanguage> 'に変更します。 –

+0

入力いただきありがとうございます、私はあなたの考えが私よりも理にかなっていると思います。 –

関連する問題