Wielojęzyczny program

0

Mam napisany pewien program ktory potrzebuje przetłumaczyc rozniez na angielski. Nie chce robic oddzielnego programu, tyle ze po angielsku, tylko jeden, dwujezyczny. Dodalem angielski w Project>languages>add, delphi dorzucilo mi do projektu kilkanascie plików i calkiem fajne narzedzie do tłumaczenia.

Teraz pytanie, jak zrealizowac przełączanie sie między językami w programie? Jak to tłumaczenie wykorzystac?

0
WombaT napisał(a)

Mam napisany pewien program ktory potrzebuje przetłumaczyc rozniez na angielski. Nie chce robic oddzielnego programu, tyle ze po angielsku, tylko jeden, dwujezyczny. Dodalem angielski w Project>languages>add, delphi dorzucilo mi do projektu kilkanascie plików i calkiem fajne narzedzie do tłumaczenia.

Teraz pytanie, jak zrealizowac przełączanie sie między językami w programie? Jak to tłumaczenie wykorzystac?

Otóż z tym jest pewien kłopot, bo owszem w Delphi jest ta opcja, ale służy ona do tłumaczenia zasobów, brak natomiast możliwości przełączania się między nimi w trkacie pracy programu, co więcej aby mieć inną wersję językową musisz rekompilować cały program z wybraną inną wersją językową.

Ja to zrobiłem nieco inaczej.

Stworzyłem sobie taką strukturę:

Załuszmy że mamy jedną formę na której jest menu:
[Plik {Nowy | Otwórz | Zapisz | Zapisz jako... | | Koniec}
Edycja {Cofnij | | Wytnij | Kopiuj | Wklej | Wyczyść | | Zaznacz wszystko}
Język {Polski | Angielski | Niemiecki}]
Do tego jest Memo i StatusBar na którym wyświetlane są podpowiedzi.

Type
 tLngItem = Record
  Caption : String;
  Hint : String;
 End;

 tLngFileMenu = Record
  File : tLngItem;
  New : tLngItem;
  Open : tLngItem;
  Save : tLngItem;
  SaveAs : tLngItem;
  Exit  : tLngItem;
 End;

 tLngEditMenu = Record
  Edit : tLngItem;
  Undo : tLngItem;
  Cut : tLngItem;
  Copy : tLngItem;
  Paste : tLngItem;
  Delete : tLngItem;
  SelectAll : tLngItem;
 End;

 tLngLanguageMenu = Record
  Language : tLngItem;
  Polish : tLngItem;
  English : tLngItem;
  German : tLngItem;
 End;

 tLanguage = Record
  File : tLngFileMenu;
  Edit : tLngEditMenu;
  Language : tLngLanguageMenu;
 End;

Var
 Language : Array [1..3] of tLanguage;

{teraz w procedurze TForm1.OnCreate przypisujesz wszystkim polom odpowiednie wartości (albo ręcznie albo z pliku typu  "File of tLanguage")}

{Tworzysz dodatkową procedurę dajmy na to:}
Procedure TForm1.SelectLng(LanguageNr : Byte); {od razu po wykonaniu tej procedury język zostanie zmieniony na wybrany (konkretnie wszystkie Captiony i Hinty wskazanych elementów na te z tablicy.) Można też bez tablicy, wtedy zmienna lokalna typu tLanguage, potem w zależności od parametru wczytanie odpowiedniego pliku "File of tLanguage" - np. Polish.lng i operacja, zresztą takie rozwiązanie ciągnie mniej pamięci, ale jest wolniejsze w praktyce}
 Begin
  With Language[LanguageNr] Do
   Begin
    File1.Caption:=File.File.Caption;
    File1.Hint:=File.File.Hint;
    New1.Caption:=File.New.Caption;
    {tak dla wszystkich}
   End;
 End; 

{Teraz pozostaje tylko:}
Procedure TForm1.Polish1.OnClick;
 Begin
  SelectLanguage(1);
 End;

Procedure TForm1.English1.OnClick;
 Begin
  SelectLanguage(2);
 End;

Procedure TForm1.German1.OnClick;
 Begin
  SelectLanguage(3);
 End;

{Jeszcze w TForm1.OnCreate możesz na końcu dać:
  (...) 
  SelectLanguage(1);
 End;
}

Wiem, że wymaga to trochę zachodu, ale dużo z tym kombinowałem i lepszego sposobu nie wymyśliłem (z tym, że u mnie jeszcze w pliku .ini zapisywał aktualny język i listę wszystkich zainstalowanych języków, czyli plików .lng, po czym odpowiednio modyfikował zawartość listy rozwijanej z językami do wyboru.)

0

zrobilem to po swojemu:

procedure Tfrejestr.open_lng;
begin
  lng:=tinifile.Create(extractfilepath(application.ExeName) + 'def.lng');
  case flogon.jakijez of
  0:  begin
        lng.Free;
        lng:=tinifile.Create(ExtractFilePath(Application.ExeName) + 'pol.lng');
      end; // case 0
  3:  begin
        lng.Free;
        lng:=tinifile.Create(ExtractFilePath(Application.ExeName) + 'eng.lng');
      end; // case 3
  end;
end;

procedure Tfrejestr.tlumacz;
var
  i:integer;
begin
try
  open_lng;
  for I := 0 to controlcount - 1 do
    begin
      if controls[i] is tbutton then
        tbutton(controls[i]).Caption:=lng.ReadString('tbutton',tbutton(controls[i]).Name,tbutton(controls[i]).Name)
      else if controls[i] is tlabelededit then
        tlabelededit(controls[i]).EditLabel.Caption:=lng.ReadString('tlabed',tlabelededit(controls[i]).Name,tlabelededit(controls[i]).Name)
      else if controls[i] is tcheckbox then
        tcheckbox(controls[i]).Caption:=lng.ReadString('tcheckbox',tcheckbox(controls[i]).Name,tcheckbox(controls[i]).Name)
      else if controls[i] is tlabel then
        tlabel(controls[i]).Caption:=lng.ReadString('tlabel',tlabel(controls[i]).Name,tlabel(controls[i]).Name)
    end;

    with podp do
    begin
      leimie:=lng.readstring('text','rej_himie','');
      lenick:=lng.readstring('text','rej_hnick','');
      leklan:=lng.readstring('text','rej_hklan','');
      legg:=lng.readstring('text','rej_hgg','');
      lemail:=lng.readstring('text','rej_hmail','');
      minfo:=lng.readstring('text','rej_hinfo','');
      gen:=lng.readstring('text','rej_hgen','');
      cbhts:=lng.ReadString('text','rej_hcbhts','');
    end;

finally
  lng.Free;
end;
end;

taki kod mam w oncreate danej formy, a to:

  for I := 0 to controlcount - 1 do
    begin
      if controls[i] is tbutton then
        tbutton(controls[i]).Caption:=lng.ReadString('tbutton',tbutton(controls[i]).Name,tbutton(controls[i]).Name)

.....

    end;

skacze po wszystkich obiektach, sprawdza typ i w przypadku odpowiedniego pobiera caption'a z pliku ini na podstawie nazwy obiektu. Ini wyglada tak:

[tbutton]
banuluj=Anuluj
bdzialaj=Rejestruj

analogicznie dla kazdego typu obiektu. A ten blok, gdzie tak troche "na chama" ładuje dane z ini, to ładowanie dłuższych opisów editów, labeli i przycisków ktore sie pojawiają po najechaniu myszką na dany obiekt.

i działa ;)

0

jak się to ma do cyrlicy, jak zapisać ?

0

http://www.subrip.fr.st/
Na tej stronie znajduje się program SubRip z dostępnymi źródłami, możesz kuknąć jak to jest tam rozwiązane.

0

Słabo programuję, więc podszedłbym do problemu bardziej po partyzancku :-)
Wszelkie teksty pisałbym w dwóch wersjach językowych i wyświetlał zależnie od wybranej wersji.

0

Rozwiązanie zasugerowane przez Młodego aby użyc kodu z SubRipa jest dobre. Jest tam moduł multilang.pas,
używany w unit1.pas i bodajże uconfig.pas. Jak dla prostej aplikacji to jest bardzo dobre rozwiązanie. Sam je
zastosowałem w jednym swoim programie. Bo robienie plików językowych w takiej postaci, jak na przykład w
Total Commanderze to trochę zabawy, a tak mamy proste Ini. Tylko nazwy identów i sekcji może nieco rażą.

1 użytkowników online, w tym zalogowanych: 0, gości: 1