[ milan_sr @ 03.11.2011. 18:02 ] @
Imam zadatak uraditi neku aplikaciju ali ta aplikacija da ima mogucnost promenu jezika (pr. Menu->Jezik->SR, MKD, EN). Jer moze neka solucija kako to da odradim, dali da ima neki ini fajl gde pise koji jezik treba da podigne (pri startovanje app) pa u zavisnost od toga od drugi ini fajl da ocitava svaki "caption" elementa unutar aplikacije. Pri prvo podizanje programa bi imo da izabere koji jezik zeli, onda svako drugo podizanje preograma pravicu sporedbu jezika pri zadnje otvaranje i zatvaranje applikacije...Valjda ovo nije najbolje resenje :) Ako ima neka bolja ideja. Hvala
[ Mihajlo Cvetanović @ 03.11.2011. 18:53 ] @
Jedan problem je gde čuvati informaciju o jeziku apikacije. Ovo je sitan problem. Može .ini fajl, može registry (moj omiljen), može čak i baza (ako u bazi već čuvaš i neke druge stvari).

Drugi problem je kako u birati različite jezike ako već imaš informaciju o jeziku. Ovo je malo veći problem. Prva stvar koja apsolutno olakšava rešenje problema je da aplikacija bude Unicode. Dalje, u Visual C++ okruženju (sa ili bez MFC-a) možeš da imaš takozvane resursne DLL-ove (resource DLL). Ovi DLL-ovi nemaju ni jednu funkciju, ali zato imaju string tabele, prozore, menije, ikone, i sve ostalo. Možeš za svaki jezik da napraviš jedan DLL, i na početku rada učitaš željeni DLL i ostatku programa kažeš da za sve što im treba od resursa vide u tom DLL-u.

Drugo rešenje bi bilo da imaš nekakav xml fajl za svaki jezik, i da u celom programu u letu radiš čitanje stringova iz odgovarajućeg fajla, i zamenu default teksta u prozorim i menijima. Morao bi u prozorima da zauzmeš više mesta za sve labele, za slučaj da na nekom jeziku neka labela zauzima više mesta. Ja nikad nisam ovako radio, ali tako je sad popularno u svetu.
[ X Files @ 03.11.2011. 18:56 ] @
Pogledaj i ovu temu, ako se ne varam, koristiš BCB:
http://www.elitesecurity.org/t302421-Visejezicni-program-kako

[ milan_sr @ 03.11.2011. 20:03 ] @
Ovaj kod (X Files sto je dao) je dosta dobar (bar tako se meni cini) podesi ti keybord, code page za zeljeni jezik i na sve elemente promeni napise...samo imam jedan nejasan deo koda

Code:

// MyStrings.rh                                                              
#define   IDS_CANCEL             27114 

// Strings.rc                                                            
#pragma code_page(1252) 
#include "MyStrings.rh" 

STRINGTABLE 
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 
BEGIN 
  IDS_CANCEL, "Cancel" 
END 

STRINGTABLE 
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT 
BEGIN 
  IDS_CANCEL, "Zrusit" 
END 


Sada nisam toliko uputen bar nisam to jos izucio/cuo :S MyString.rh je? (Samo fajl u koi definisem sve "objekte"? ili) Isto tako String.rc to je neki resource fajl ili? u njega ukljucim MyString...Ako moze samo malo objasnenja ili tekst negde da procitam sto je to ustvari. Hvala

@mihajlo
Kako birati, po default ce se startuje sa nekim jezikom, onda biras to sto tebi odgovara i opet stavis u rg...svako sledece startovanje samo gledas koi je jezik i spored toga citas i reg :D (ako si na to mislio) :D Hvala vam na brzom odgovoru
[ Mihajlo Cvetanović @ 03.11.2011. 20:47 ] @
Ne znam Borland tako da ne vredi da ti odgovaram.
[ X Files @ 04.11.2011. 06:45 ] @
Citat:
MyString.rh je?

MyString.rh je obican tekstualni fajl, u kome se definise identifikator stringa i jedinstveni broj.

Citat:
Isto tako String.rc to je neki resource fajl ili?

String.rc je klasican resursni fajl, koji u nasem primeru sadrzi uglavnom sadrzaj stringova, definisanih preko identifikatora. Ovaj fajl treba DODATI U PROJEKAT (Add to Project).


Pokušaću da ti uradim jedan test primer u vezi ovoga, samo da pronađem makar malo vremena...
[ X Files @ 04.11.2011. 09:03 ] @
--- RSTRINGS.RH (tekstualni fajl, sam ga kreiras) ---
Code:

#define IDS_FORM1    10000
#define IDS_BUTTON1  10001 
#define IDS_LABEL1   10002


--- RSTRINGS.RC (tekstualni fajl, sam ga kreiras i DODAJES u projekat) ---
Code:

#pragma code_page(1252)
#include "RStrings.RH"

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
BEGIN
  IDS_FORM1,   "My form"
  IDS_BUTTON1, "My button"
  IDS_LABEL1,  "My label"
END

STRINGTABLE
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
BEGIN
  IDS_FORM1,   "Moja forma"
  IDS_BUTTON1, "Moj taster"
  IDS_LABEL1,  "Moj natpis"
END


--- PROJECT1.INI (tekstualni fajl za cuvanje informacije o izabranom jeziku, ne moras da pravis, bice autokreiran) ---
Code:

[Language]
ID=1


--- UNIT1.H (ovo je generisano u IDE-u, uz izmene koje sam uoci)---
Code:

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <IniFiles.hpp>

//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TButton *Button1;
        TLabel *Label1;
        void __fastcall Button1Click(TObject *Sender);
private:    // User declarations
        TIniFile *pIniFile;
        int IDLanguage;
        void PromeniJezik();

public:        // User declarations
        __fastcall TForm1(TComponent* Owner);
        __fastcall ~TForm1();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif



--- UNIT1.CPP ---
Code:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "RStrings.RH"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
    try
    {
        pIniFile = new TIniFile( ChangeFileExt( ParamStr(0), ".ini" ) );
        IDLanguage = pIniFile->ReadInteger( "Language", "ID", 0 );
    }
    catch ( const Exception &e )
    {
        IDLanguage = 0;
    }

    if ( pIniFile )
        delete pIniFile;

    PromeniJezik();
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
    try
    {
        pIniFile = new TIniFile( ChangeFileExt( ParamStr(0), ".ini" ) );
        pIniFile->WriteInteger( "Language", "ID", IDLanguage );
    }
    catch ( const Exception &e )
    {
        // ...
    }
    if ( pIniFile )
        delete pIniFile;

}
//---------------------------------------------------------------------------
static const TFontCharset CodepageToCharset( unsigned int cp )
{
   CHARSETINFO csi;

   if ( (cp == 0) || (!TranslateCharsetInfo( (unsigned long *)cp, &csi, TCI_SRCCODEPAGE )) )
   {
     return OEM_CHARSET;
   }
   return (TFontCharset)csi.ciCharset;
}
//---------------------------------------------------------------------------
static AnsiString InternalLoadStr( int ErrorCode )
{
   const int MaxResourceBufferSize = 4096;  // maximum resource string length is 4095 bytes
   char string[MaxResourceBufferSize];
   LoadString( GetModuleHandle(0), ErrorCode, string, MaxResourceBufferSize );
   return AnsiString( string );
}
//---------------------------------------------------------------------------
void TForm1::PromeniJezik()
{
    int CP;
    if ( IDLanguage == 0 )
    {
       SetThreadLocale( 0x0409 );  // U.S. English
       CP = 1250;
    }
    else
    {
       SetThreadLocale( 0x0405 );  // Czech local
       CP = 1252;
    }

    Form1->Font->Charset = CodepageToCharset( CP );
    Form1->Caption = InternalLoadStr( IDS_FORM1 );

    Button1->Font->Charset = CodepageToCharset( CP );
    Button1->Caption = InternalLoadStr( IDS_BUTTON1 );

    Label1->Font->Charset = CodepageToCharset( CP );
    Label1->Caption = InternalLoadStr( IDS_LABEL1 );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    if ( IDLanguage == 1 )
        IDLanguage = 0;
    else
        IDLanguage = 1;

    PromeniJezik();
}
//---------------------------------------------------------------------------



E sad, tragedija je da ja tebe savetujem da radis ovako, kako je proizvodjac softvera i predvideo, a ja sam ne radim ovako :) Osnovna anomalija ovakvog koda je hardcode-iranost prevoda, tj nemogucnost dodavanja novog jezika BEZ rekompajliranja koda.

Tvoja kreativnost se sada moze ogledati u smestanju prevoda u neke zasebne fajlove i sl.

Za sada, poneta ovog koda je da vidis:
- kako se cuvaju konfiguraciona podesavanja u INI fajlovima. Slicno je i za Regystry.
- Kako se menja jezik

[ Nedeljko @ 04.11.2011. 10:28 ] @
Off topic:

Qt ima alat Qt Linguist za jednostavno pravljenje prevoda (pravljen za prevodioce koji nisu programeri) koji nisu hardkodovani.
[ milan_sr @ 04.11.2011. 12:16 ] @
Razgledao sam kod, od ujutru par puta sam piso (dok si postiro kod) kod i nekako slabo. Sad mi je jasno kako to uradito recimo samo sa ini fajlovima, ali sada me nervira sto ovaj kod kod mene ne funkcionise t.e neizvrsava se. Uvek "otvara" LANG_ENGLISH idetifikator i kad je ID=0 i kad je ID=1. A i kad promenim drugi idetifikator (tacnije LANG_MACEDONIAN) daje mi error na njega...sve sam odradio kako u kodu?
[ X Files @ 04.11.2011. 12:29 ] @
Stvarno ne znam o čemu se radi. Kod sam probao i radio je, mada ga nisam detaljnije testirao. Pamtio je promenu i startovao se onako kako je poslednji put podešeno. Sada ne mogu da ti ga pošaljem u celosti, jer nisam trenutno na računaru na kome sam ga uradio.

Što se tiče ćirilice (LANG_MACEDONIAN), pokušaj neku drugu, možda Rusku varijantu...

Pretpostavljam da su ovi fajlovi odgovorni za jezičke konstante:
c:\Program Files\Borland\CBuilder6\Include\winnt.h
c:\Program Files\Borland\CBuilder6\Include\winnt.rh

Pokušaj da uključiš (include) nešto of ovoga ispod linije:
#include "RStrings.RH"
...ili jednostavno redefiniši (define) prema specifikaciji koja je u ovim fajlovima.
[ milan_sr @ 04.11.2011. 18:17 ] @
Sve sam probao i nikako da proradi :S. Bas me zanima ucemu je problem...evo prikacen projekt ali sve je isto :S
[ X Files @ 04.11.2011. 20:05 ] @
U pravu si, ovo ne radi na Win7!

Sada sam pogledao:

SetThreadLocale no longer changes GUI language in Vista
http://social.msdn.microsoft.c...c-900c-4c64-bdf8-fe94e46722e2/


Pokušaću da pronađem rešenje...

[ X Files @ 04.11.2011. 20:24 ] @
Ok, sve ovo je dokaz da treba ići ka novijim rešenjima što se tiče višejezičke podrške.

Kod koji sam inicijalno ostavio, radiće na XP-u, ali neće na novijim OS-ovima.


Da bi se to prevazišlo, jedno od rešenja je sledeće. Treba napraviti posebnu funkciju, koja će utvrditi tip OS-a, i prema tome reagovati:
Code:

void SetThreadLocalSettings(LANGID Language, LANGID SubLanguage)
{

   OSVERSIONINFOEX osver;
   ZeroMemory(&osver, sizeof(osver));
   osver.dwOSVersionInfoSize = sizeof(osver);

   GetVersionEx((OSVERSIONINFO *)&osver);


   if ( (osver.dwMajorVersion > 5))
   {
      typedef LANGID (WINAPI *FNSetThreadUILanguage)(LANGID wReserved);
      FNSetThreadUILanguage fnPtr = (FNSetThreadUILanguage)GetProcAddress(GetModuleHandle("kernel32.dll"),"SetThreadUILanguage");
      // ako ovo gore nece da se kompajlira, pokusaj ovako:
      // FNSetThreadUILanguage fnPtr = (FNSetThreadUILanguage)GetProcAddress(GetModuleHandle(_T("kernel32.dll")),"SetThreadUILanguage");

      if(fnPtr)
      { // vista or 2008
         LANGID langid = (*fnPtr)(Language);
      }
      else
      { // fallback for XP
         ::SetThreadLocale(MAKELCID(MAKELANGID(Language, SubLanguage), SORT_DEFAULT));
      }
   }
   else
   { //XP
      ::SetThreadLocale(MAKELCID(MAKELANGID(Language, SubLanguage), SORT_DEFAULT));
   }
}


... i zatim, umesto:
Citat:

Code:

    int CP;
     if ( IDLanguage == 0 )
     {
        SetThreadLocale( 0x0409 );  // U.S. English
        CP = 1250;
     }
     else
     {
        SetThreadLocale( 0x0405 );  // Czech local
        CP = 1252;
     }


Treba:
Code:

    int CP;
     if ( IDLanguage == 0 )
     {
        SetThreadLocalSettings( 0x0409, SUBLANG_ENGLISH_US );  // U.S. English
        CP = 1250;
     }
     else
     {
        SetThreadLocalSettings( 0x0405, SUBLANG_DEFAULT );  // Czech local
        CP = 1252;
     }

[ milan_sr @ 04.11.2011. 21:32 ] @
Ovo radi i to dobro, zadatak koi smo imali bio je nad 1000 objekta (button, panel, label i.t.d) da promenimo caption...ispisali smo oko 800. Od klika do izmene ne proge ni sekunda :)...e sada one funkcije sam razumeo, ali ova nemam pojma sta radi :)) Hvala ti X Files
[ milan_sr @ 04.11.2011. 22:19 ] @
Ali opet se vracam kod idetifikatora, javlja gresku kod ruskog, srpskog, makedonskog...pogledao sam winnt.h i winnt.rh i tamo su tako definisani a opet izadje error?

Code:

[BRCC32 Error] Strings.rc(13): Not a positive short integer
[ X Files @ 04.11.2011. 23:04 ] @
Dodaj:
#include "Winnt.RH"
... u RStrings.RC


Za "Serbian Latin":

--- RStrings.RC ---
Code:

#pragma code_page(1252)
#include "RStrings.RH"
#include "Winnt.RH"

 STRINGTABLE
 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 BEGIN
   IDS_FORM1,   "My form"
   IDS_BUTTON1, "My button"
   IDS_LABEL1,  "My label"
 END

 STRINGTABLE
 LANGUAGE LANG_SERBIAN, SUBLANG_SERBIAN_LATIN
 BEGIN
   IDS_FORM1,   "Moja forma"
   IDS_BUTTON1, "Moj taster"
   IDS_LABEL1,  "Moj natpis"
 END


--- UNIT1.CPP ---
Code:

// ...
     int CP;
     if ( IDLanguage == 0 )
     {
        SetThreadLocalSettings( 0x0409, SUBLANG_ENGLISH_US );  // U.S. English
        CP = 1250;
     }
     else
     {
        SetThreadLocalSettings( 0x081a, SUBLANG_DEFAULT );  // Serbian Latin
        CP = 1252;
     }

// ...
[ milan_sr @ 04.11.2011. 23:25 ] @
To sam vec odradio...samo trazim kako kirilicu da uklopim, idetifikator stavim code page za kirilicu je 1251 ama izlaze prasalnici :D trazicu gde je cakica :D
[ milan_sr @ 04.11.2011. 23:54 ] @
Zezao me je idetifikator za sublanguage...trebalo bi ovako da bude (ako nekom pocetniku kako mene zatreba) X Files hvala ti mnogo

--- RStrings.RC ---
Code:

#pragma code_page(1252)
#include "RStrings.RH"
#include "winnt.rh"

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
BEGIN
  IDS_FORM1,   "My form"
  IDS_BUTTON1, "My button"
  IDS_LABEL1,  "My label"
END

STRINGTABLE
LANGUAGE LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA
BEGIN
  IDS_FORM1,   "Moja Forma"
  IDS_BUTTON1, "Batonče"
  IDS_LABEL1,  "LjNjEЅŠЃŽZDžČЌ"
END


--- UNIT1.CPP ---
Code:

int CP;
    if ( IDLanguage == 0 )
    {
       SetThreadLocalSettings( 0x0409, SUBLANG_ENGLISH_US );  // U.S. English
       CP = 1250;
    }
    if ( IDLanguage == 1 )
    {
       SetThreadLocalSettings( 0x042F, SUBLANG_MACEDONIAN_MACEDONIA );  // MKD
       CP = 1251;
    }



[ X Files @ 05.11.2011. 10:23 ] @
Eto, lepo ako je proradilo.

Ipak, u perspektivi razmisli o tome da prevode držiš u sasvim zasebnim tekstualnim fajlovima, odvojenim od EXE-a ili DLL-a, tj. da budu "otvoreni" za editovanje spolja. Praksa je pokazala da je ovo praktičnije od rešenja koja se nude u okviru ekstenzija razvojnog okruženja. Na primer, pogledaj kako je to rešeno u ozbiljnijim softverima, tipa Total Commander-a...
[ milan_sr @ 05.11.2011. 11:09 ] @
Dok sam radio sa ovim kodom probo sam problem resiti sa ini, to mi je dobro ispalo, u jednim fajlom cuvam id jezika u drugi ini prevode i u zavisnost sta odberem to citam. E sada kod mene "current language for non-unicode programs" stoi MKD...nisam proverio da smenim to pa da vidim kako bi radilo onda. Sto sa ovim kodom sto si ti postirao to je zaobidjeno...
[ itf @ 05.11.2011. 14:59 ] @
Ja to vrlo jednostavno rješavam. Svi prijevodi su u bazi podataka u tablicama. Aplikacija tako automatski detektira koji jezici su dostupni i korisniku nudi jedan od prijevoda. Nove prijevode je samo potrebno dodati u bazu i odmah su dostupani aplikaciji bez ikakvog dodatnog kodiranja.
[ Nedeljko @ 06.11.2011. 10:40 ] @
Nedostatak tog rešenja je što moraš da vučeš bazu zbog jezika čak i ako ti nizašta drugo nije potrebna.
[ itf @ 06.11.2011. 10:43 ] @
Pa uvijek ionako vučem nekakve fajlove uz program. Barem zbog spremanja settingsa.
[ X Files @ 06.11.2011. 11:23 ] @
Problem sa više jezika u jednom fajlu (nebitno u kom obliku je fajl) je u tome što prevode ne može da ažurira/unapređuje više ljudi istovremeno i kad poželi, pogotovo kada dođu nove verzije softvera na red, a teško da sam autor softvera može da bude kompetentan za 10 jezika. Naravno, sve zavisi i od toga koliko je softver rasprostranjen, javan otvoren, ...

Po meni, najbolje je da svaki prevod bude u sopstvenom fajlu, a da postoji DEFAULT (osnovni) prevod, ka kome se svi ostali prevodi ravnaju. Najbolje je da je osnovni prevod na engleskom. Program lako može da enumeriše sve fajlove iz nekog foldera (npr, Translations) i da zna kojim jezicima raspolaže, to je najmanji problem.


Po meni, nije loše rešenje koje koristi softver Inno Setup kada su prevodi u pitanju. Sve je online, raspoloživo za unapređenja po želji. Imaju zvanične i nezvanične prevode, kao i ranije verzije prevoda. Svaki prevod ima glavnog autora. Ko god želi da doprinese, mora se javiti autoru. Postoji i alat koji olakšava prevođenje... itd.
[ itf @ 06.11.2011. 17:40 ] @
Baza (access) je više-klijentska tj. paralelno više ljudi može raditi na njoj.