internaţionalizarea

7
Internaţionalizarea aplicaţiilor Win32 folosind fişiere de resurse  Melinte Laurenţiu Ionuţ, master optimizare computaţională, an 1 LISA (Localization Industry Standard Association) defineşte internaţionalizarea ca fiind un proces de generalizare a unui produs ca sa accepte mai multe limbi şi convenţii culturale fără a fi nevoie de reproiectare. Internaţionalizarea are loc la nivelul proiectării  programului şi dezvoltării documentelor. In general, un produs este internaţionalizat in timpul ciclului de dezvoltare, apoi este localizat. Localizarea se refera la adaptarea unui produs pentru a fi potrivit din punct de vedere lingvistic si cultural, pentru o anumita ţară. Asta presupune de obicei traducere a textelor, schimbarea formatului datelor, numerelor, schimbarea orientării textului(pentru arabi), etc. Un aspect important al internaţionalizării este separarea textului de codul sursă. Textul care trebuie tradus se mută in fiş iere de resurse cu texte. Asta împiedică traducătorii să modifice codul su rsă din greşeală şi nu mai este nev oie să se recompile ze. Ca să poată afişa un set de caractere şi să suporte standarde locale specifice unei anumite ţări, un anumit set de caractere trebuie sa fie folosit. De exemplu ca un produs să  poate fie tradus în japoneză, trebuie să suporte caractere pe 2 octeţi(double-byte). Aceasta se poate realiza folosind suportul unicode pentru text. Internaţionalizarea nu se limitează la software. Suportul online şi documentarea, siturile web trebuie şi ele internaţionalizate. Pentru cei care scriu documentaţie aceasta se numeşte „scriere pentru audienţă globală”. Internaţionalizarea se prescurtează cu i18n, unde 18 reprezintă numărul de caractere intre i şi n în cuvântul internationalization. Localizarea se prescurtează l10n, după acelaşi model. Setul de caractere UNICODE Din 1950 pana in 1970 cele mai populare seturi de caractere au fost ASCII şi EBCDIC. Acestea erau folosite pe nişte terminale care se conectau la un mainframe şi nu ştiau decât să interpreteze codificarea unui număr într-un caracter care se afişa pe ecran. În 1980 au început să apară sisteme de operare cu mod grafic cum este Windows. Acestea  puteau să controleze afişarea fiecărui punct pe ecran, având astfel control deplin asupra caracterelor, nu cum depindea un mainframe de codificarea de la terminal. Prin combinarea cu tastaturi modificate pentru diferite limbi, s-a putut adapta un soft la fiecare limbă. Pentru că in ASCII se folosesc doar 7 biţi şi pot fi reprezentate 128 caractere, dintre care primele 32 sunt de control, IBM a creat noţiunea de code page sau set de caractere ASCII extins, adică setul ASCII la care se mai adaugă al 8-lea bit, pentru a coda 256 caractere, şi se renunţă la caracterele de control. Pentru fiecare limbă s-a creat un astfel de code page. Acestea au mers atâta timp cat un program folosea numai o limbă la un moment dat. IBM a creat un code page mai general numit CP850 care cuprindea caractere din mai multe limbi europene. Limbile asiatice au in schimb mii de caractere care nu au putut fi reprezentate prin seturi ASCII extinse. Ca să se poată reprezenta mai multe caractere s-a trecut la codificarea pe 16 biţi. Aşa a apă rut Unicode, care este şi el o formă extinsă de ASCII. In Unicode se pot reprezenta 65536 caractere. Cifrele se reprezintă în standard prin U+nnnn unde nnnn este un număr hexazecimal şi se numesc code point. Primele 256 de coduri sunt identice cu cele

Upload: laurentiumelinte

Post on 06-Apr-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Internaţionalizarea

8/2/2019 Internaţionalizarea

http://slidepdf.com/reader/full/internationalizarea 1/7

Internaţionalizarea aplicaţiilor Win32 folosind fişiere de resurse Melinte Laurenţiu Ionuţ, master optimizare computaţională, an 1

LISA (Localization Industry Standard Association) defineşte internaţionalizarea cafiind un proces de generalizare a unui produs ca sa accepte mai multe limbi şi convenţii

culturale fără a fi nevoie de reproiectare. Internaţionalizarea are loc la nivelul proiectării programului şi dezvoltării documentelor. In general, un produs este internaţionalizat intimpul ciclului de dezvoltare, apoi este localizat.

Localizarea se refera la adaptarea unui produs pentru a fi potrivit din punct devedere lingvistic si cultural, pentru o anumita ţară. Asta presupune de obicei traducereatextelor, schimbarea formatului datelor, numerelor, schimbarea orientării textului(pentruarabi), etc.

Un aspect important al internaţionalizării este separarea textului de codul sursă.Textul care trebuie tradus se mută in fişiere de resurse cu texte. Asta împiedică traducătoriisă modifice codul sursă din greşeală şi nu mai este nevoie să se recompileze.

Ca să poată afişa un set de caractere şi să suporte standarde locale specifice unei

anumite ţări, un anumit set de caractere trebuie sa fie folosit. De exemplu ca un produs să poate fie tradus în japoneză, trebuie să suporte caractere pe 2 octeţi(double-byte). Aceastase poate realiza folosind suportul unicode pentru text.

Internaţionalizarea nu se limitează la software. Suportul online şi documentarea,siturile web trebuie şi ele internaţionalizate. Pentru cei care scriu documentaţie aceasta senumeşte „scriere pentru audienţă globală”.

Internaţionalizarea se prescurtează cu i18n, unde 18 reprezintă numărul de caractereintre i şi n în cuvântul internationalization. Localizarea se prescurtează l10n, după acelaşimodel.

Setul de caractere UNICODE

Din 1950 pana in 1970 cele mai populare seturi de caractere au fost ASCII şiEBCDIC. Acestea erau folosite pe nişte terminale care se conectau la un mainframe şi nuştiau decât să interpreteze codificarea unui număr într-un caracter care se afişa pe ecran. În1980 au început să apară sisteme de operare cu mod grafic cum este Windows. Acestea puteau să controleze afişarea fiecărui punct pe ecran, având astfel control deplin asupracaracterelor, nu cum depindea un mainframe de codificarea de la terminal. Prin combinareacu tastaturi modificate pentru diferite limbi, s-a putut adapta un soft la fiecare limbă.

Pentru că in ASCII se folosesc doar 7 biţi şi pot fi reprezentate 128 caractere, dintrecare primele 32 sunt de control, IBM a creat noţiunea de code page sau set de caractereASCII extins, adică setul ASCII la care se mai adaugă al 8-lea bit, pentru a coda 256caractere, şi se renunţă la caracterele de control. Pentru fiecare limbă s-a creat un astfel de

code page. Acestea au mers atâta timp cat un program folosea numai o limbă la un momentdat. IBM a creat un code page mai general numit CP850 care cuprindea caractere din maimulte limbi europene. Limbile asiatice au in schimb mii de caractere care nu au putut fireprezentate prin seturi ASCII extinse.

Ca să se poată reprezenta mai multe caractere s-a trecut la codificarea pe 16 biţi.Aşa a apărut Unicode, care este şi el o formă extinsă de ASCII. In Unicode se potreprezenta 65536 caractere. Cifrele se reprezintă în standard prin U+nnnn unde nnnn esteun număr hexazecimal şi se numesc code point. Primele 256 de coduri sunt identice cu cele

Page 2: Internaţionalizarea

8/2/2019 Internaţionalizarea

http://slidepdf.com/reader/full/internationalizarea 2/7

din ISO-8859-1(code page ASCII - Latin 1 (ANSI)). Până acum au fost definite 38, 885caractere, in standardul Unicode 2.0, restul fiind lăsate libere în caz că va mai apărea ceva.Pentru că majoritatea caracterelor folosite din Unicode sunt cele de la început, cu primuloctet 0, a apărut diferite metode de codare, care să micşoreze numărul de octeţi folosiţi.Acestea se numesc Unicode Transformation Format (UTF). Cel mai folosit este UTF-8,unde pentru caracterele de la 0 la 256 se reprezintă doar primul octet, iar la celelalte se

folosesc codificări intre 2 şi 3 octeţi. Unicode suportă şi extindere la mai mult de 1 milionde caractere prin folosirea codurilor din U+D800 şi U+DFFF , care sunt caractere speciale, pentru extensie.

Setul de caractere Unicode in C şi C++

Pentru a reprezenta şiruri de caractere pe 2 octeţi se foloseşte prefixul L, iar ca tipde date pentru caracter pe 2 octeţi este wchar_t. Toate funcţiile folosite pentru manipulatşiruri de caractere din C au şi un corespondent Unicode. Acestea încep cu wcs în loc de str.Următoarea secvenţă de cod copiază un şir de caractere în format unicode.

#include <string.h>wchar_t A[] = L"xyz";

wchar_t B[4];wcscpy(B, A);

În C++ se foloseşte clasa wstring. Acelaşi cod, scris in C++:

#include <string>using namespace std;wstring A(L"xyz");wstring B;B = A;

Locales

Locale, în engleză, reprezintă un set de parametri care reprezintă o anumită limbă, oţară şi alte caracteristici speciale care ar putea să fie vizualizate într-o interfaţă a unui program. Nu se foloseşte termenul de limbă deoarece pentru o anumită ţară pot să fie maimulte limbi cum este de exemplu engleza canadiană şi franceza canadiană.

Setările specifice la un locale sunt:- Limba;- Formatul numerelor;- Formatul datei şi a timpului;- Formatul pentru monedă;- Zona de timp;- Corecţia de timp de vară şi iarnă;

- Tipul de tastatură;Aceste setări pot fi configurate în Windows din Control Panel > Regional and

Language Options.În Windows pentru a identifica un locale se foloseste un identificator numeric

(LCID, Locale Identifier), care este un număr pe 32 biţi, unde:- Biţii 1 – 9, 10 – 15 reprezintă limba primară şi limba secundară(se mai numesc

limbă şi sub-limbă). Acestea formează identificatorul de limbă (LANGID);

Page 3: Internaţionalizarea

8/2/2019 Internaţionalizarea

http://slidepdf.com/reader/full/internationalizarea 3/7

- Biţii de la 16 la 19 reprezintă identificatorul de sortare(SORTID), iar biţii de la20 la 23 versiunea de sortare.

- Biţii de la 24 la 31 nu sunt folosiţi.Sunt definite câteva macrouri pentru a lucra cu aceste constante:

LANGID lagid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK);LANGID xPrimary = PRIMARYLANGID(x);

LANGID xSecondary = SUBLANGID(x);LCID lcid = MAKELCID(langid, SORT_GERMAN_PHONE_BOOK);SORTID sortid = SORTIDFROMLCID(lcid);

LANG_NEUTRAL şi SUBLANG_NUETRAL defineşte un locale general, pentrucare nu se aplică reguli speciale. Există un locale implicit pentru sistem şi unul pentrufiecare user definite astfel:

#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT))

#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT))

Cu toate că se poate construi orice combinaţie de limbă, sub-limbă şi identificator de sortare, nu toate sunt valide.Constante locale pentru România sunt:LANG_ROMANIAN = 0x18Locale Identifier = 0x418 (Romanian)

Funcţii cu care se pot accesa LCID:ConvertDefaultLocale – converteşte o constantă care defineşte un locale implicit la unlocale real;EnumSystemLocales – enumerează toate setările locale suportate;GetSystemDefaultLangID, GetSystemDefaultLCID, GetUserDefaultLangID,GetUserDefaultLCID – returnează valororile implicite.

GetThreadLocale, SetThreadLocale – returnează/setază locale pentru un thread;IsValidLocale – spune dacă un locale este instalat şi/sau suportat;

Resurse Win32.

O resursă este un format care nu se execută , este folosit de aplicaţie şi se include înexecutabil în format binar, după linkare.

În Visual Studio se pot defini fişiere de resurse, în care se poate pune orice fişier multimedia, şiruri de caractere sau resurse care definesc dialoage. Acestea sunt în formattext şi au extensia .rc. Pentru a fi editat se selectează View Code la click dreapta pefişierul .rc, în Solution Explorer.

Visual Studio are încorporat un editor de resurse, care uşurează foarte mult lucrul

cu resurse. Voi exemplifica lucru cu acesta în Visual Studio 2008.Cu toate că editorul de resurse suportă formatul Unicode, fişierele .rc create deVisual Studio sunt în format ANSI, şi va apărea o problemă dacă se doreşte crearea deresurse în chineză de exemplu. Pentru a îl salva în format Unicode se deschide fişierul cuView Code, apoi se salvează de la meniul File > Save as…, unde se alege Save withEncoding…, ca în imaginea alăturată. Apoi se alege Unicode codepage 1200.

Page 4: Internaţionalizarea

8/2/2019 Internaţionalizarea

http://slidepdf.com/reader/full/internationalizarea 4/7

Fiecare resursă este identificată printr-un id numeric.Aceste id-uri sunt specificate cu #define într-un fişier numitde obicei resource.h. Id-urile sunt generate automat la inserarea unei resurse. Denumireaconstantei poate fi modificată de la fereastra de Properties al unele resurse şi din fereastra principală la resursele de tip şir de caractere.

Pentru a deschide editorul de resurse se dă

dublu click pe fişierul cu extensia .rc din SolutionExplorer. Va apare ceva asemănător cu ce e înimagine. Pentru a adăuga o resursă se dă clickdreapta pe fereastra editorului şi se alege Add >Resource, apoi se alege tipul de resursă dorită.

Resursele sunt grupate pe foldere. Fiecarefolder are un tip de resurse. Există cateva tipuristandard cum sunt: Accelerator, Bitmap, Cursor,Dialog, Html, Icon, Menu, String Table, Version.Pentru fiecare tip standard există o functie in API cucare se incarcă un anumit tip de resurse Câtevafuncţii sunt:

FindResource – caută o resursă de orice tip.Tipul este identificat printr-un şir de caractere.Pentru tipurile standard sunt definite constante, cumar fi RT_STRING pentru resursele tip şir decaractere. Se pot specifica şi tipuri definite de utilizator;

FindResourceEx – caută o resursă de orice tip, cu un anumit identificator delimbă(langid);

MAKEINTRESOURCE – macro care se foloseşte la generarea unui şir de caracterede la un id de resursă. Funcţia FindResource(Ex) primeşte un şir de caractere cu numeleresursei, dar este mai eficient să se folosească doar id-un numerice, ceea ce face şi VisualStudio cu editorul de resurse.

LoadResource – Încarcă resursa obţinută de la FindResource(Ex);LockResource – Obţine un pointer la memoria unde se află resursa, după ce a fost

încărcată cu LoadResource. Nu există o funcţie pentru unlock. Resursa se scoate dinmemorie când se eliberează modulul cu FreeLibrary();

Deci pentru a obţine o resursă de orice tip, se apelează FindResource(Ex) –>LoadResource -> LockResource. Din fericire sunt funcţii mult mai simplu de folosit, pentru tipurile standard de resurse. Acestea însă nu au variantă la care se poate specificaidentificatorul de limbă:

LoadString – încarcă un şir de caractere; Şirurile de caractere sunt grupate câte 10şi memorate într-un format mai special unde se specifică lungimea şirului la început, şi nuse pune caracterul 0 la sfârşit, decât dacă se află explicit în şir. O resursă de şir decaractere este deci alcătuită dintr-o zonă de memorie cu 10 şiruri de caractere cu lungimeala început pentru fiecare şir. Id-urile şirurilor de caractere grupate sunt consecutive, şi prindividerea la 10 se obţine id-ul resursei pentru a fi folosit cu FindResource; Se poate ca unid de şir de caractere să lipsească. În acest caz se va pune un şir de caractere de lungime 0.

LoadIcon – încarcă un icon;LoadMenu – încarcă un meniu;LoadCursor – încarcă un cursor;LoadBitmap – încarcă o imagine în format .bmp;

Page 5: Internaţionalizarea

8/2/2019 Internaţionalizarea

http://slidepdf.com/reader/full/internationalizarea 5/7

LoadAccelerators – încarcă o tabelă de acceleratori; Acceleratorii sunt acelecaractere subliniate la meniuri, cu care se poate activa un meniu dacă se apasă tastele ALT+ caracter.

Într-un fişier de resurse se poate specifica identificatorul de limba pentru o resursă.Pentru a îl modifica se face click dreapta pe resursă şi se alege Properties. În fereastra de

 proprietăţi se poate modifica limba. Se pot defini mai multeresurse cu acelaşi id şi de acelaşi tip, dar cu identificatori delimbă diferiţi. Funcţiile de încărcat resurse care nu primescidentificatorul de limbă ca parametru, îl folosesc pe cel setat pentru thread-ul în care e rulată funcţia. Acesta se setează cuSetThreadLocale. Dacă nu se găseşte o resursă exact cu id-ulde limbă dorit se face căutarea doar după id-ul de resursă şi sereturnează prima găsită. Cu toate că se poate folosi aceastăfuncţionalitate, de a scrie resursele pentru toate limbile înacelaşi fişier, nu este recomandat datorită unor modificărifăcute de la Windows 2000. Vezihttp://support.microsoft.com/default.aspx?scid=kb;en-us;300680. Metoda corectă este să sescrie resursele pentru o limbă de bază, să se compileze resursele în format binar, apoi cu un program de traducere specializat să se traducă fişierul binar de resurse şi pentru celelaltelimbi, obţinându-se câte un fişier binar cu resurse pentru fiecare limbă.

Fişiere dll de resurse

Pentru a separa resursele de codul executabil acestea se compilează separat, întru-nalt proiect, de tip .dll, care nu va conţine cod executabil. Pentru a face aceasta se procedează în felul următor:

1. Se creează o aplicaţie detip MFC Application;

2. Se alege la tip Dialog based, pentru a nu necomplica cu MVC;

3. Se lasă selectat UseUnicode Libraries;

4. Se selectează Finish;

Visual Sudio a creat un proiect cu un singur dialog cu 2 butoane Ok şi Cancel. Dialogul este

declarat în fişierul<numeprroiect>.rc.Creăm un nou proiect care

va conţine doar resursele.Pentru aceasta ne ducem la SolutionExplorer, dăm click dreapta pe numele soluţiei şi alegem Add > New Project... şi se alegeEmpty Project.

Page 6: Internaţionalizarea

8/2/2019 Internaţionalizarea

http://slidepdf.com/reader/full/internationalizarea 6/7

Denumirea proiectului se pune deobicei <numeproiect>.ui.Pentru că proiectul nu estecompilabil(îi trebuie unentry point, adică funcţia cu

care porneşte execuţia în program) se selecteazăProperties pe noul proiect şila Linker > Advanced sealege “No entry point”.

La General > ConfigurationType se alege DynamicLibrary(.dll).

Apoi se adaugă la proiect fişierul .rc din primul proiect. Când secompilează se va obţine undll doar cu resurse, fără codexecutabil. În proiectulexecutabil se lasă şi acoloresursele, pentru că se poateîntâmpla să nu se poatăîncărca fişierul de resurse.

Page 7: Internaţionalizarea

8/2/2019 Internaţionalizarea

http://slidepdf.com/reader/full/internationalizarea 7/7

Pentru a încărca modulul de resurse se foloseşte funcţia LoadLibrary, carereturnează o variabilă HMODULE(acelaşi lucru cu HINSTANCE) care apare la toatefuncţiile de încărcat resurse şi unde se poate folosi NULL pentru a încărca resursa dinmodulul principal, cu extensia .exe.

Aplicaţiile MFC au o metodă implementată în framework pentru a încărcamodule de resurse. Cu funcţia AfxSetResouceHandle se modifică o variabilă dintr-o clasă

internă care se foloseşte la toate funcţiile din framework pentru a încărca resursele. Pentrua obţine această variabilă se apelează AfxGetResourceHandle.Pentru a încărca şiruri de caractere în MFC se pot folosi funcţiile

CString::FormatString, care are variantă cu id de resursă şi funcţia CString::LoadStringcare are are 3 variante, prima doar cu id de resursă care foloseşte AfxGetResourceHandle, adoua care primeşte şi HINSTANCE pentru modul şi a treia care primeşte şi id de limbă.

Dacă aplicaţia conţine mai multe module cu cod executabil sau mai multethreaduri este bine să se evite folosirea funcţiei AfxSetResouceHandle, deoarece pot apăreaerori când nu este găsită o resursă (cel mai comun, resursele de dialoage). O metodăîntâlnită este să se ţină minte vechiul HISNTANCE, să se apeleze AfxSetResouceHandle,să se încarce resursele necesare, apoi să se restaureze HINSTANCE la dll-ul global deresurse cu AfxSetResouceHandle. Această metodă merge bine atât timp cât aplicaţia nu aremai multe threaduri. Cu toate că HINSTANCE pentru modulul global de resurse este setat pe modul, apar probleme când alt thread vrea să încarce o resursă tocmai când pe thread-ul principal s-a apelat AfxSetResouceHandle.Cel mai bine este să se facă o clasă pentru încărcat resursele dintr-un modul şi să seinstanţieze pentru fiecare modul de resurse încărcat. Încărcarea resurselor de tip dialog serealizează greu pentru dialoage. Pentru CDHtlmDialog se poate folosi protocolul res://.

Pentru încărcarea şi afişarea resurselor se folosesc 2 strategii.Prima este să se încarce resursele la iniţializarea aplicaţiei şi este mai simplă,

dezavantajul fiind că trebuie repornită aplicaţia pentru a schimba limba. Pentru ferestrelede tip dialog aceasta se face în funcţia OnInitDialog.

A doua este să se scrie o funcţie separată de încărcat şi afişat resursele. Pentruresurse de tip şiruri de caractere, meniuri, acceleratoare nu apar probleme, deoarece seapelează o funcţie de încărcat resursa doar. Dar pentru resurse de tip dialog este o problemădeoarece nu se poate reface un dialog fără să se piardă datele. Ar fi o soluţie dacă aplicaţiaare datele complet separate de interfaţă şi în orice moment se poate salva şi reface stareaaplicaţiei în funcţie de date.

Funcţia pentru modificat resurse se scrie pentru a fi apelată uşor ca un handler la unmesaj de fereastră înregistrat cu RegisterWindowMessage sau un mesaj custom definitca WM_USER + constantă. Dacă se nimereşte o constantă deja folosită apar  probleme, de aceea recomand metoda cu RegisterWindowMessage. În funcţia detratare a mesajului se va transmite mesajul de la o fereastră container cum este

fereastra de tip dialog, la toate ferestrele conţinute.Pentru mai multe informaţii despre internaţionalizare şi localizare vărecomand să citiţi carţile:

MS Press - International Programming for Microsoft Windows;Bert Esselink – A practical guide to localization;MS Press – Developing international software, Second Edition;