Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Lokalizacija projekta

[es] :: Pascal / Delphi / Kylix :: Lokalizacija projekta

[ Pregleda: 3235 | Odgovora: 6 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

reiser

Član broj: 7895
Poruke: 2314



+102 Profil

icon Lokalizacija projekta14.06.2011. u 00:34 - pre 156 meseci
Zapocinjem rad ne vecem projektu u Delphi 7, projekat treba da ima podrsku za vise jezika, pa me zanima na koji je nacin najbolje da to odradim, dok sam jos u ranoj fazi razvoja projekta ? Kontam da ce kasnije to biti skoro pa nemoguce ako ne pripremim projekat za lokalizacjiu vec sada. Jel postoje neke komponente za ovo ? Bilo kakvi hintovi su dobrodosli. Hvala :)
 
Odgovor na temu

Aleksandar Đokić

Član broj: 13478
Poruke: 4793
*.dynamic.isp.telekom.rs.



+638 Profil

icon Re: Lokalizacija projekta14.06.2011. u 18:57 - pre 156 meseci
kad nece iskusniji ajd ja da ti predlozim, jezicke postavke cuvas u .txt fajlu i pri form create ucitavas sve labele, buttone itd, to mozda moze i neki .ini da bude
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: Lokalizacija projekta14.06.2011. u 19:50 - pre 156 meseci
Sam Delphi ima alat za lokalizaciju mada mi se nikada nije dopao, imaš i neka gotova rešenja poput http://dxgettext.po.dk.
Ja sam to bio radio preko ovog unita, s tim što je on namenjen za unicode controle (TNT). Svakoj kontroli se dodeli jedinstveni tag i kasnije se u ini fajlovima (za svaki jezik po jedan), daju konkretni prevodi.

Prikačeni fajlovi
 
Odgovor na temu

rambo
Dejan Petković
Beograd

Član broj: 6095
Poruke: 190
*.dynamic.sbb.rs.



+6 Profil

icon Re: Lokalizacija projekta14.06.2011. u 19:58 - pre 156 meseci
Prvo, ako možeš, pređi na Delphi 2010 zbog Unicode podrške (naročito ako planiraš da podržavaš i ćirilicu i latinicu u istoj aplikaciji). To će ti uštedeti vreme i nećeš imati glavobolje kasnije.

Drugo, Delphi ima ITE (Integrated Translation Environment). Kada otvoriš projekat, pogledaj meni Project -> Languages.

Treće, ako baš insistiraš da ostaneš na Delphi 7, onda pogledaj dxGetText. Takođe, ne gine ti da koristiš TNT komponente jer jedino one podržavaju Unicode kako valja, ali je problem što se više ne održavaju, tj. kupio ih je TMS Software i integrisao u svoje proizvode. Može i dalje da se nađe negde arhiva sa originalnim komponentama, pa potraži malo.

Četvrto, postoji dosta komercijalnih paketa koji omogućavaju izradu višejezičkih aplikacija, pa pogledaj sledeće:

- tsiLang
- Localizer
- Multilizer
- Helicon Translator
- Sisulizer

Pogledaj i ove linkove, možda će te zanimati:

http://delphi.about.com/library/weekly/aa102400a.htm
http://delphi.about.com/od/objectpascalide/l/aa020502a.htm

Nadam se da sada imaš dovoljno informacija
"There is a theory which states that if ever anybody discovers exactly what the
Universe is for and why it is here, it will instantly disappear and be replaced by
something even more bizarre and inexplicable. There is another theory which states
that this has already happened."
-- Douglas Adams
 
Odgovor na temu

reiser

Član broj: 7895
Poruke: 2314



+102 Profil

icon Re: Lokalizacija projekta14.06.2011. u 21:23 - pre 156 meseci
Hvala lepo :)
 
Odgovor na temu

reiser

Član broj: 7895
Poruke: 2314



+102 Profil

icon Re: Lokalizacija projekta03.01.2012. u 01:59 - pre 149 meseci
Evo da se javim i kazem sta sam uradio, mozda ce nekome jos pomoci. Posto sam probao vecinu ovih gore alata i svi su mi delovali konfuzno / nisu radili ono sto ja hocu, napisao sam moju klasu za to. Klasa je smestena u jednom unitu - Localization.pas a dinamicki stringovi u drugom - LocalizationStr.pas.

Language fajl je u stvari .ini fajl koji se sastoji iz tri dela, info, data i strresources. U info idu razni podaci, ime autora, naziv jezika itd.

U data delu su imena komponenti i njihovi stringovi. Recimo, Form1.Label1 = LabelNaSrpskom. Prilikom lokalizacije, ucitavaju se svi stringovi iz ovog dela, nalazi komponenta sa ovim imenom na formi i ispituje da li komponenta ima Caption ili Text property. Ako postoji, setuje ga na ucitani string. Ako zelite da setujete hint komponente, ime komponente treba da pocne sa #. Dakle, za Label1, setovanje hinta bi izgledalo ovako: #Form1.Label1 = Hint Labele

strresources deo sadrzi tzv "dinamicke" stringovi. Oni se koriste kod objekta kod kojih je potrebno da se caption dinamicki menja, recimo ako zelite da u jednom labelu prikazete "Downloading file..." dok se fajl skida i "Download finished" kada se download zavrsi. Svaki string se smesta u LocalizationStr.pas kao promenljiva, i dodaje se sledeca linija u TLocalizer.LocalizeResourceStrings() funkciji koji taj string ucitava (recimo da se string promenljiva zove RS_AUTHENTICATING):

Code:
RS_AUTHENTICATING := PrepareString(INI.ReadString(SECTION, 'RS_AUTHENTICATING', RS_AUTHENTICATING));


Sa dinamickim stringovima je neophodno manuelno menjanje captiona naravno, recimo u OnDownloadBegin stavite Label1.Caption := RS_DOWNLOAD_BEGIN, u OnDownloadFinished stavite Label1.Caption := RS_DOWNLOAD_FINISHED


Localization.pas:

Code:

unit Localization;

interface

uses
  Classes;

type
  TLanguageInfo = record
                    Name        : String;
                    LocalName   : String;
                    CountryCode : String;
                    Author      : String;
                  end;
  {$M+}
  TLocalizer = class
               private
                 FLanguageFile      : String;
                 FLanguageList      : TStringList;
                 FLanguagesDir      : String;
                 FLanguagesFileMask : String;
               public
                 constructor Create(const ALanguagesDir : String = ''; const ALanguagesFilemask : String = '*.*');
                 destructor Destroy; override;

                 procedure Localize(const AComponent : TComponent);
                 procedure LocalizeResourceStrings;

                 procedure RefreshLanguageList;
                 function GetLanguageInfo(const ALanguageFile : String) : TLanguageInfo;
                 function FindLanguageByName(const ALanguageName : String; var AIndex : Integer) : Boolean;
               published
                 property LanguageFile : String read FLanguageFile write FLanguageFile;
                 property LanguageList : TStringList read FLanguageList;
                 property LanguagesDir : String read FLanguagesDir write FLanguagesDir;
               end;
  {$M-}


implementation

uses
  SysUtils, INIFiles, TypInfo, LocalizationStr;

constructor TLocalizer.Create(const ALanguagesDir : String = ''; const ALanguagesFilemask : String = '*.*');
begin
  FLanguageFile := '';
  FLanguagesDir := ALanguagesDir;
  FLanguagesFilemask := ALanguagesFilemask;

  FLanguageList := TStringList.Create;
  FLanguageList.Clear;
  FLanguageList.Sorted := TRUE;
  RefreshLanguageList;
end;

destructor TLocalizer.Destroy;
begin
  FLanguageList.Free;

  inherited;
end;

procedure TLocalizer.Localize(const AComponent : TComponent);
const
  DATASECTION = 'data';
var
  INI      : TMemINIFile;
  ident    : TStringList;
  values   : TStringList;
  objects  : TStringList;
  C1       : Integer;
  fcomp    : TComponent;
  PropInfo : PPropInfo;
  isHint   : Boolean;
  objStr   : String;
begin
  If Assigned(AComponent) Then
  Begin
    If FileExists(FLanguageFile) Then
    Begin
      INI := TMemINIFile.Create(FLanguageFile, TEncoding.UTF8);
      If INI.SectionExists(DATASECTION) Then
      Begin
        ident := TStringList.Create;
        values := TStringList.Create;
        INI.ReadSection(DATASECTION, ident);
        INI.ReadSectionValues(DATASECTION, values);
        For C1 := 0 to values.Count - 1 Do
          values.Strings[C1] := Trim(Copy(values.Strings[C1], Pos('=', values.Strings[C1]) + 1, Length(values.Strings[C1]) - Pos('=', values.Strings[C1])));

        objects := TStringList.Create;
        If ident.Count = values.Count Then
          For C1 := 0 to ident.Count - 1 Do
          Begin
            Split('.', ident.Strings[C1], objects);
            If objects.Count > 0 Then
            Begin
              objStr := objects.Strings[0];
              isHint := objStr[1] = '#';
              If isHint Then
                Delete(objStr, 1, 1);

              If LowerCase(objStr) = LowerCase(AComponent.Name) Then
              Begin
                objects.Delete(0);
                fcomp := AComponent;
                While (objects.Count > 0) and
                      (fcomp <> nil) Do
                Begin
                  fcomp := fcomp.FindComponent(objects.Strings[0]);
                  objects.Delete(0);
                End;
                If fcomp <> nil Then
                Begin
                  If isHint Then
                    PropInfo := GetPropInfo(fcomp, 'Hint')
                  else
                  Begin
                    PropInfo := GetPropInfo(fcomp, 'Caption');
                    If PropInfo = nil Then
                      PropInfo := GetPropInfo(fcomp, 'Text');
                  End;
                      
                  If PropInfo <> nil Then
                    SetStrProp(fcomp, PropInfo, PrepareString(values.Strings[C1]));
                End;
              End;  
            End;
          End;
        objects.Free;

        values.Free;
        ident.Free;
      End;
      INI.Free;
    End;
  End;
end;

procedure TLocalizer.LocalizeResourceStrings;
const
  SECTION = 'strresources';
var
  INI : TMemINIFile;
begin
  If FileExists(FLanguageFile) Then
  Begin
    INI := TMemINIFile.Create(FLanguageFile, TEncoding.UTF8);

    RS_AUTHENTICATING := PrepareString(INI.ReadString(SECTION, 'RS_AUTHENTICATING', RS_AUTHENTICATING));
    RS_RESPONSE_UNKNOWN := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_UNKNOWN', RS_RESPONSE_UNKNOWN));
    RS_RESPONSE_REGISTER_EMAIL_SENT := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_REGISTER_EMAIL_SENT', RS_RESPONSE_REGISTER_EMAIL_SENT));
    RS_RESPONSE_CHANNEL_ADDED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_CHANNEL_ADDED', RS_RESPONSE_CHANNEL_ADDED));
    RS_RESPONSE_CHANNEL_PASSWORD_CHANGED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_CHANNEL_PASSWORD_CHANGED', RS_RESPONSE_CHANNEL_PASSWORD_CHANGED));
    RS_RESPONSE_REQUEST_SENT := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_REQUEST_SENT', RS_RESPONSE_REQUEST_SENT));
    RS_RESPONSE_CONFIRMED_REQUEST := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_CONFIRMED_REQUEST', RS_RESPONSE_CONFIRMED_REQUEST));
    RS_RESPONSE_USER_UNBLOCKED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_USER_UNBLOCKED', RS_RESPONSE_USER_UNBLOCKED));
    RS_RESPONSE_USER_BLOCKED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_USER_BLOCKED', RS_RESPONSE_USER_BLOCKED));
    RS_RESPONSE_COULD_NOT_SEND_EMAIL := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_COULD_NOT_SEND_EMAIL', RS_RESPONSE_COULD_NOT_SEND_EMAIL));
    RS_RESPONSE_USERNAME_TAKEN := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_USERNAME_TAKEN', RS_RESPONSE_USERNAME_TAKEN));
    RS_RESPONSE_EMAIL_ALREADY_USED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_EMAIL_ALREADY_USED', RS_RESPONSE_EMAIL_ALREADY_USED));
    RS_RESPONSE_CAPTCHA_ERROR := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_CAPTCHA_ERROR', RS_RESPONSE_CAPTCHA_ERROR));
    RS_RESPONSE_REQ_LIMIT_REACHED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_REQ_LIMIT_REACHED', RS_RESPONSE_REQ_LIMIT_REACHED));
    RS_RESPONSE_INVALID_KEY := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_INVALID_KEY', RS_RESPONSE_INVALID_KEY));
    RS_RESPONSE_INVALID_USERNAME := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_INVALID_USERNAME', RS_RESPONSE_INVALID_USERNAME));
    RS_RESPONSE_ALREADY_A_FRIEND := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_ALREADY_A_FRIEND', RS_RESPONSE_ALREADY_A_FRIEND));
    RS_RESPONSE_INVALID_CONFIRMATION := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_INVALID_CONFIRMATION', RS_RESPONSE_INVALID_CONFIRMATION));
    RS_RESPONSE_INVALID_POSTS := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_INVALID_POSTS', RS_RESPONSE_INVALID_POSTS));
    RS_RESPONSE_INVALID_USER := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_INVALID_USER', RS_RESPONSE_INVALID_USER));
    RS_RESPONSE_NOT_CHANNEL_OWNER := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_NOT_CHANNEL_OWNER', RS_RESPONSE_NOT_CHANNEL_OWNER));
    RS_RESPONSE_INVALID_USERPASS := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_INVALID_USERPASS', RS_RESPONSE_INVALID_USERPASS));
    RS_RESPONSE_ALREADY_SENT_REQ := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_ALREADY_SENT_REQ', RS_RESPONSE_ALREADY_SENT_REQ));
    RS_RESPONSE_CHANNEL_RESERVED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_CHANNEL_RESERVED', RS_RESPONSE_CHANNEL_RESERVED));
    RS_RESPONSE_ACCOUNT_NOT_ACTIVATED := PrepareString(INI.ReadString(SECTION, 'RS_RESPONSE_ACCOUNT_NOT_ACTIVATED', RS_RESPONSE_ACCOUNT_NOT_ACTIVATED));
    RS_RUN_CLIENT_AS_ADMIN := PrepareString(INI.ReadString(SECTION, 'RS_RUN_CLIENT_AS_ADMIN', RS_RUN_CLIENT_AS_ADMIN));
    RS_CANNOT_CONNECT := PrepareString(INI.ReadString(SECTION, 'RS_CANNOT_CONNECT', RS_CANNOT_CONNECT));
    RS_WAITING_FOR_GAME := PrepareString(INI.ReadString(SECTION, 'RS_WAITING_FOR_GAME', RS_WAITING_FOR_GAME));
    RS_GAME_IN_PROGRESS := PrepareString(INI.ReadString(SECTION, 'RS_GAME_IN_PROGRESS', RS_GAME_IN_PROGRESS));
    RS_GAME_ENDED := PrepareString(INI.ReadString(SECTION, 'RS_GAME_ENDED', RS_GAME_ENDED));
    RS_WARDIALOG_TITLE := PrepareString(INI.ReadString(SECTION, 'RS_WARDIALOG_TITLE', RS_WARDIALOG_TITLE));
    RS_NO_RESPONSE_FROM_SERVER := PrepareString(INI.ReadString(SECTION, 'RS_NO_RESPONSE_FROM_SERVER', RS_NO_RESPONSE_FROM_SERVER));
    RS_GAME_PRECREEPS := PrepareString(INI.ReadString(SECTION, 'RS_GAME_PRECREEPS', RS_GAME_PRECREEPS));
    RS_DOWNLOAD_DOWNLOADING := PrepareString(INI.ReadString(SECTION, 'RS_DOWNLOAD_DOWNLOADING', RS_DOWNLOAD_DOWNLOADING));
    RS_WARCRAFT_REPLAY_NOT_ASSOCIATED := PrepareString(INI.ReadString(SECTION, 'RS_WARCRAFT_REPLAY_NOT_ASSOCIATED', RS_WARCRAFT_REPLAY_NOT_ASSOCIATED));
    RS_STARCRAFT_REPLAY_NOT_ASSOCIATED := PrepareString(INI.ReadString(SECTION, 'RS_STARCRAFT_REPLAY_NOT_ASSOCIATED', RS_STARCRAFT_REPLAY_NOT_ASSOCIATED));
    RS_INVALID_EMAIL := PrepareString(INI.ReadString(SECTION, 'RS_INVALID_EMAIL', RS_INVALID_EMAIL));
    RS_PASSWORD_MISMATCH := PrepareString(INI.ReadString(SECTION, 'RS_PASSWORD_MISMATCH', RS_PASSWORD_MISMATCH));
    RS_FILL_ALL_FIELDS := PrepareString(INI.ReadString(SECTION, 'RS_FILL_ALL_FIELDS', RS_FILL_ALL_FIELDS));
    RS_PASSWORD_TOO_SHORT := PrepareString(INI.ReadString(SECTION, 'RS_PASSWORD_TOO_SHORT', RS_PASSWORD_TOO_SHORT));
    RS_USERNAME_TOO_SHORT := PrepareString(INI.ReadString(SECTION, 'RS_USERNAME_TOO_SHORT', RS_USERNAME_TOO_SHORT));
    RS_CHECKING_FOR_UPDATES := PrepareString(INI.ReadString(SECTION, 'RS_CHECKING_FOR_UPDATES', RS_CHECKING_FOR_UPDATES));
    RS_REPLAY_DOWNLOADING := PrepareString(INI.ReadString(SECTION, 'RS_REPLAY_DOWNLOADING', RS_REPLAY_DOWNLOADING));
    RS_UPDATE_DOWNLOADING := PrepareString(INI.ReadString(SECTION, 'RS_UPDATE_DOWNLOADING', RS_UPDATE_DOWNLOADING));
    RS_AGREE_TO_TERMS := PrepareString(INI.ReadString(SECTION, 'RS_AGREE_TO_TERMS', RS_AGREE_TO_TERMS));

    INI.Free;
  End;
end;

function TLocalizer.GetLanguageInfo(const ALanguageFile : String) : TLanguageInfo;
var
  INI : TMemINIFile;
begin
  If FileExists(ALanguageFile) Then
  Begin
    INI := TMemINIFile.Create(ALanguageFile, TEncoding.UTF8);
    result.Name := INI.ReadString('info', 'LanguageName', '');
    result.LocalName := INI.ReadString('info', 'LocalLanguageName', '');
    result.CountryCode := INI.ReadString('info', 'CountryCode', '');
    result.Author := INI.ReadString('info', 'Author', '');
    INI.Free;
  End;
end;

procedure TLocalizer.RefreshLanguageList;
begin
  LanguageList.Clear;
  EnumerateFiles(FLanguagesDir, FLanguagesFilemask, TRUE, FLanguageList);
end;

function TLocalizer.FindLanguageByName(const ALanguageName : String; var AIndex : Integer) : Boolean;
var
  C1       : Integer;
  langInfo : TLanguageInfo;
begin
  result := FALSE;
  AIndex := -1;

  For C1 := 0 to FLanguageList.Count - 1 Do
  Begin
    langInfo := GetLanguageInfo(FLanguageList.Strings[C1]);
    If (langInfo.Name = ALanguageName) or
       (langInfo.LocalName = ALanguageName) Then
    Begin
      AIndex := C1;
      result := TRUE;
      Break;
    End;
  End;
end;

end.


Evo i raznih funkcija koje klasa koristi, a nema ih u samoj klasi. Ja ih pozivam iz drugog unita u kome smestam sve helper funkcije i koji sam includovao u klasu, ali je lakse da izvucem samo funkcije koje se koriste umesto da linkujem ceo unit:

Code:

function PrepareString(const AString : String) : String;
begin
  result := AString;
  result := StringReplace(result, '\n', #13#10, [rfReplaceAll]);
  result := StringReplace(result, '\_', ' ', [rfReplaceAll]);
end;

procedure Split(const ADelimiter : Char; const AInput : String; const AStrings : TStrings);
begin
  If Assigned(AStrings) Then
  Begin
    AStrings.Clear;
    AStrings.Delimiter := ADelimiter;
    AStrings.DelimitedText := AInput;
  End;
end;

function MatchStrings(const AStr1, AStr2 : String; const ACaseSensitive : Boolean) : Boolean;

  function MatchPattern(str1, str2 : PWideChar) : Boolean;
  begin
    If StrComp(str2, '*') = 0 Then
      result := TRUE
    else
      If (str1^ = #0) and
         (str2^ <> #0) Then
        result := FALSE
      else
        If str1^ = #0 Then
          result := TRUE
        else
          Case str2^ of
            '*': If MatchPattern(str1, @str2[1]) Then
                   result := TRUE
                 else
                   result := MatchPattern(@str1[1], str2);
            '?': result := MatchPattern(@str1[1], @str2[1]);
          else
            If str1^ = str2^ Then
              result := MatchPattern(@str1[1], @str2[1])
            else
              result := FALSE;
          end;
  end;

begin
  If ACaseSensitive Then
    result := MatchPattern(PWideChar(AStr1), PWideChar(AStr2)) or
              MatchPattern(PWideChar(AStr2), PWideChar(AStr1))
  else
    result := MatchPattern(PWideChar(LowerCase(AStr1)), PWideChar(LowerCase(AStr2))) or
              MatchPattern(PWideChar(LowerCase(AStr2)), PWideChar(LowerCase(AStr1)));
end;

function EnumerateFiles(const APath, AFilemask : String; const ASearchSubdirs : Boolean; var AFiles : TStringList) : Integer;
var
  SearchRec : TSearchRec;
  IsFound   : Boolean;
begin
  result := 0;
  IsFound := FindFirst(ITB(APath) + '*.*', faAnyFile, SearchRec) = 0;
  While IsFound Do
  Begin
    If (SearchRec.Name <> '.') and (SearchRec.Name <> '..') Then
    Begin
      If (ASearchSubdirs) and
         (SearchRec.Attr and faDirectory = faDirectory) Then
        Inc(result, EnumerateFiles(ITB(APath) + SearchRec.Name, AFilemask, ASearchSubdirs, AFiles))
      else
        If MatchStrings(ExtractFileExt(SearchRec.Name), AFilemask, FALSE) Then
        Begin
          AFiles.Add(ITB(APath) + SearchRec.Name);
          Inc(result);
        End;
    End;
    IsFound := FindNext(SearchRec) = 0;
  End;
  FindClose(SearchRec);
end;


Ovako bi izgledao LocalizationStr.pas:

Code:

unit LocalizationStr;

interface

var
  RS_AUTHENTICATING                    : String = 'Authenticating';
  RS_RESPONSE_UNKNOWN                  : String = 'Unknown response (%s%d)';
  RS_RESPONSE_REGISTER_EMAIL_SENT      : String = 'Registration successful! Please check your inbox for confirmation e-mail';
  RS_RESPONSE_CHANNEL_ADDED            : String = 'Channel added';
  RS_RESPONSE_CHANNEL_PASSWORD_CHANGED : String = 'Channel password changed';
  RS_RESPONSE_REQUEST_SENT             : String = 'Request sent';
  RS_RESPONSE_CONFIRMED_REQUEST        : String = 'Confirmed request';
  RS_RESPONSE_USER_UNBLOCKED           : String = 'Unblocked user';
  RS_RESPONSE_USER_BLOCKED             : String = 'User blocked';
  RS_RESPONSE_COULD_NOT_SEND_EMAIL     : String = 'Could not send an email';
  RS_RESPONSE_USERNAME_TAKEN           : String = 'Username already taken';
  RS_RESPONSE_EMAIL_ALREADY_USED       : String = 'E-Mail already in use';
  RS_RESPONSE_CAPTCHA_ERROR            : String = 'Invalid CAPTCHA';
  RS_RESPONSE_REQ_LIMIT_REACHED        : String = 'Request limit reached';
  RS_RESPONSE_INVALID_KEY              : String = 'Invalid key';
  RS_RESPONSE_INVALID_USERNAME         : String = 'Invalid username';
  RS_RESPONSE_ALREADY_A_FRIEND         : String = 'Already a friend';
  RS_RESPONSE_INVALID_CONFIRMATION     : String = 'Invalid confirmation';
  RS_RESPONSE_INVALID_POSTS            : String = 'Invalid posts';
  RS_RESPONSE_INVALID_USER             : String = 'Invalid user';
  RS_RESPONSE_NOT_CHANNEL_OWNER        : String = 'You''re not owner of the channel';
  RS_RESPONSE_INVALID_USERPASS         : String = 'Invalid username or password';
  RS_RESPONSE_ALREADY_SENT_REQ         : String = 'Request already sent';
  RS_BUTTON_REPAIR                     : String = 'Repair';
  RS_RESPONSE_CHANNEL_RESERVED         : String = 'Channel is reserved';
  RS_RESPONSE_ACCOUNT_NOT_ACTIVATED    : String = 'Account not activated\nPlease check your E-Mail inbox for activation mail';
  RS_RUN_CLIENT_AS_ADMIN               : String = 'Please run client as administrator\n(right click on client icon, then click on "Run as administrator")';
  RS_CANNOT_CONNECT                    : String = 'Cannot connect';
  RS_WAITING_FOR_GAME                  : String = 'Waiting for game...';
  RS_GAME_IN_PROGRESS                  : String = 'Game in progress...\n%.2d:%.2d';
  RS_GAME_ENDED                        : String = 'Game ended!';
  RS_WARDIALOG_TITLE                   : String = 'Please select Warcraft III executable file';
  RS_NO_RESPONSE_FROM_SERVER           : String = 'No response from server';
  RS_GAME_PRECREEPS                    : String = 'Game started!\n(preparing phase)';
  RS_DOWNLOAD_DOWNLOADING              : String = 'Downloading file...';
  RS_WARCRAFT_REPLAY_NOT_ASSOCIATED    : String = 'Replay file isnt associated with Warcraft III! This problem usually happens if you copied game files without installing them. Please reinstall the game.';
  RS_STARCRAFT_REPLAY_NOT_ASSOCIATED   : String = 'Replay file isnt associated with Starcraft II! This problem usually happens if you copied game files without installing them. Please reinstall the game.';
  RS_INVALID_EMAIL                     : String = 'Invalid E-Mail';
  RS_PASSWORD_MISMATCH                 : String = 'Passwords mismatch';
  RS_FILL_ALL_FIELDS                   : String = 'Please fill all fields';
  RS_PASSWORD_TOO_SHORT                : String = 'Password must be longer than %d characters';
  RS_USERNAME_TOO_SHORT                : String = 'Username must be longer than %d characters';
  RS_CHECKING_FOR_UPDATES              : String = 'Checking for updates...';
  RS_REPLAY_DOWNLOADING                : String = 'Downloading replay...';
  RS_UPDATE_DOWNLOADING                : String = 'Downloading update...';
  RS_AGREE_TO_TERMS                    : String = 'You must agree to user''s license agreements';

implementation

end.


Naravno, ovo je sve hardkodovano u programu, tj ako ne postoje language fajlovi, prikazace se ovi hardkodovani stringovi umesto praznih :)

I ovako bi na kraju trebao da izgleda language fajl za ovu klasu:

Code:

[info]
LanguageName = English
LocalLanguageName = English
CountryCode = GB
Author = Marko Paunovic ([email protected])

[data]
ComponentContainer.pmTrayShowClient = Show client
ComponentContainer.pmTraySettings = Settings
ComponentContainer.pmTrayLanguage = Language
ComponentContainer.pmTrayLogout = Logout
ComponentContainer.pmTrayExit = Exit

LoginWindow.frLogin.lbEMail = E-Mail
LoginWindow.frLogin.lbPassword = Password
LoginWindow.frLogin.chbRemember = Remember me
LoginWindow.frLogin.chbAutoLogin = Auto login
LoginWindow.frLogin.btLogin = Login
LoginWindow.frLogin.btRegister = Register
LoginWindow.frRegister.lbHeader = Become a member of Darer community!
LoginWindow.frRegister.lbEmail = E-Mail:
LoginWindow.frRegister.lbPassword = Password:
LoginWindow.frRegister.lbPasswordConfirm = Confirm password:
LoginWindow.frRegister.lbUsername = Username:
LoginWindow.frRegister.lbCountry = Country:
LoginWindow.frRegister.lbCAPTCHA = Security code:
LoginWindow.frRegister.btCancel = Cancel
LoginWindow.frRegister.btRegisterNow = Register now!
LoginWindow.frRegister.chbUserLicense = I agree to the user's
LoginWindow.frRegister.lbLicenseURL = license agreements

SettingsWindow = Settings
SettingsWindow.tsClient = \_\_Client
SettingsWindow.tsDota = \_\_DotA
SettingsWindow.btDetect = Detect
SettingsWindow.lbLanguage = Language
SettingsWindow.lbWarcraftPath = Warcraft III path
SettingsWindow.chbStartup = Startup with Windows
SettingsWindow.chbMinimizeOnLogin = Minimize on login
SettingsWindow.btOK = OK
SettingsWindow.btCancel = Cancel

MainWindow.pmExitButtonLogout = Logout
MainWindow.pmExitButtonExit = Exit

#MainWindow.btSettings = Settings
#MainWindow.btLogout = Logout

[strresources]
RS_RESPONSE_UNKNOWN                  = Unknown response (%s%d)
RS_RESPONSE_REGISTER_EMAIL_SENT      = Registration successful! Check your inbox for activation e-mail
RS_RESPONSE_COULD_NOT_SEND_EMAIL     = Could not send an email
RS_RESPONSE_USERNAME_TAKEN           = Username already taken
RS_RESPONSE_EMAIL_ALREADY_USED       = E-Mail already in use
RS_RESPONSE_CAPTCHA_ERROR            = Invalid CAPTCHA
RS_RESPONSE_REQ_LIMIT_REACHED        = Request limit reached
RS_RESPONSE_INVALID_KEY              = Invalid key
RS_RESPONSE_INVALID_USERNAME         = Invalid username
RS_RESPONSE_INVALID_CONFIRMATION     = Invalid confirmation
RS_RESPONSE_INVALID_POSTS            = Invalid posts
RS_RESPONSE_INVALID_USER             = Invalid user
RS_RESPONSE_INVALID_USERPASS         = Invalid username or password
RS_RESPONSE_ALREADY_SENT_REQ         = Request already sent
RS_RESPONSE_ACCOUNT_NOT_ACTIVATED    = Account not activated\nCheck your inbox for activation mail
RS_AUTHENTICATING                    = Authenticating...
RS_RUN_CLIENT_AS_ADMIN               = Please run client as administrator\n(right click on client icon > "Run as administrator")
RS_WAITING_FOR_GAME                  = Waiting for game...
RS_GAME_IN_PROGRESS                  = Game in progress...\n%.2d:%.2d
RS_GAME_ENDED                        = Game ended!
RS_WARDIALOG_TITLE                   = Select Warcraft III executable file
RS_NO_RESPONSE_FROM_SERVER           = No response from server
RS_GAME_PRECREEPS                    = Game in progress...\n(preparing phase)
RS_DOWNLOAD_DOWNLOADING              = Downloading file...
RS_WARCRAFT_REPLAY_NOT_ASSOCIATED    = Replay file isnt associated with Warcraft III! This problem usually happens if you copied game files without installing them. Please reinstall the game.
RS_STARCRAFT_REPLAY_NOT_ASSOCIATED   = Replay file isnt associated with Starcraft II! This problem usually happens if you copied game files without installing them. Please reinstall the game.
RS_INVALID_EMAIL                     = Invalid E-Mail
RS_PASSWORD_MISMATCH                 = Passwords mismatch
RS_FILL_ALL_FIELDS                   = Please fill all fields
RS_PASSWORD_TOO_SHORT                = Password must be longer than %d characters
RS_USERNAME_TOO_SHORT                = Username must be longer than %d characters
RS_CHECKING_FOR_UPDATES              = Checking for updates...
RS_AGREE_TO_TERMS                    = You must agree to user's license agreements


Eto, ako neko uspe da razume sve ovo, hteo bih da cujem misljenje, jer sam siguran da se nesto moze poboljsati :)

[Ovu poruku je menjao reiser dana 03.01.2012. u 03:10 GMT+1]
 
Odgovor na temu

tkaranovic
Tomislav Karanović
Beograd

Član broj: 220507
Poruke: 307



+18 Profil

icon Re: Lokalizacija projekta03.01.2012. u 10:06 - pre 149 meseci
Tako sam i ja radio, odnosno po imenu pronađem komponentu i zamenim hint ili caption.

Kod hinta ima dve začkoljice, hint koristi uspravnu crtu | za odvajanje... (videti u helpu čega) pa ako taj karakter treba da bude u hintu onda treba zameniti funkciju koja ima veze sa odvajanje koje radi taj karakter.
Isto tako ako treba više redova u hintu to treba posebno obraditi...

Onda kod comboboxa (i još nekih beše komponenti) treba posebno učitavati vrednosti...
 
Odgovor na temu

[es] :: Pascal / Delphi / Kylix :: Lokalizacija projekta

[ Pregleda: 3235 | Odgovora: 6 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.