.NET - Globalizace a lokalizace aplikací (2.)
Toto je druhá část tutoriálu, ve kteý se zabývá globalizovatelnými a lokalizovatelnými aplikacemi. V prvním díle jsem psal o globalizaci aplikací, což znamená že aplikace funguje korektně v libovolném prostředí a také se podle tohoto nastavení chová.
V tomto druhém díle se dočtete o tom jak vytvářet lokalizovatelné aplikace, které lze snadno překládat do různých jazyků (tedy lokalizovat), protože takovéto aplikace mají oddělené zdroje, které jsou závislé na jazyce od samotného kódu.
Více o probíraných tématech naleznete například v MSDN v sekci Planning World-Ready Applications [1].
Co se dočtete v této části tutoriálu
- Možné postupy při lokalizování webových aplikací
- Práce s resources pomocí třidy
ResourceManager - Lokalizace WinForms aplikací
Lokalizace webových aplikací
Při lokalizaci webových aplikací lze zvolit několik možných přístupů podle typu aplikace.
Pokud se jedná o aplikaci s větším množstvím statických textů, je nejjednodušší možností
zkopírovat aspx a ascx soubory s textovým obsahem do adresářů
podle jazyka a přeložit jejich obsah. Pokud je kód aplikace psán v codebehind souborech
a nejsou v nich žádné texty, není ani potřeba aby pro každý jazyk existovala webová
aplikace, protože stačí nechat zkompilovanou dll knihovnu v adresáři bin
a jednotlivé lokalizované stránky uložit například do adresářů en a cs.
Pokud se jedná o aplikaci kde nejsou příliš rozsáhlé texty, ale může být i velmi rozsáhlá
a komplikovaná je nejlepší možností uložení jazykově specifických zdrojů do takzvaných satellite
assemblies. Jedná se o dll soubory, které jsou uloženy v adresářové struktuře
určené jazyky v adresáři bin. K textům uloženým v těchto satellite assemblies
lze poté přistupovat pomocí objektu ResourceManager.
Detekce jazyka
Ať již ve vaší aplikaci zvolíte kterýkoliv z možných přístupů, budete potřebovat
detekovat jaký jazyk má uživatel nastaven jako výchozí. K tomu lze požít HTTP hlavičku
Accept-Languages (která by měla obsahovat uživatelem preferované jazyky).
V ASP.NET je možné tyto jazyky zjišťovat pomocí pole Request.UserLanguages,
které obsahuje kódy jednotlivých jazyků. Pokud chcete tedy ve vaší aplikaci rozlišit
české a ostatní uživatele, můžete toho dosáhnout následujícím kódem:
// Pokud ma uzivatel nastavenou cestinu.. foreach(string lang in Request.UserLanguages) { if (lang=="cs") { // .. provede se redirect na ceskou verzi Response.Redirect("cs/default.aspx"); return; } } // .. ostatnim uzivatelum se zobrazi anglicka Response.Redirect("en/default.aspx");
Pokud chcete tento příklad otestovat, tak ve všech prohlížečích naleznete někde v nastavení volbu jazyka. Internet Explorer přebírá toto nastavení z Windows, Firefox má po nainstalování nastavený jazyk na angličtinu (alespoň anglická verze).
Lokalizace pomocí resources
V následující části vytvoříme jednoduchý projekt na kterém se pokusím demonstrovat základní
postupy při tvorbě lokalizovatelných webových aplikací, které mají texty uložené v
resources. Visual studio umí vygenerovat satellite assemblies automaticky, pokud do projektu
přidáte soubor *.resx s textovými zdroji a jak jsem již zmiňoval lze k nim
přistupovat pomocí třidy ResourceManager. Vytváření resx souborů
není ve VS.Net 2003 příliš pohodlné a proto doporučuji například plugin Resource Editor (viz [2] ).
Nejprve do projektu přidáme soubory Texts.resx (výchozí jazyk) a Texts.cs.resx
(texty v českém jazyce). V následující ukázce se podíváme jak lze z těchto resource souborů
získat texty:
public string GetText(string key)
{
// 'LocalizationWeb' je vychozi namespace projektu
ResourceManager rm=new ResourceManager("LocalizationWeb.Texts",
System.Reflection.Assembly.GetExecutingAssembly());
// Pokud neni zadano jinak tak ResourceManager
// pouziva jazyk urceny v CurrentUICulture
// Zde se nastavi CurrentUICulture podle nastaveni uzivatele
Thread.CurrentThread.CurrentUICulture=
new CultureInfo(Request.UserLanguages[0]);
// .. zjistuje text se zadanym klicem
return rm.GetString(key);
}
Metoda GetString umožňuje jako druhý parametr předat objekt typu
CultureInfo kterým se bude řídit při hledání textu. Pokud zadáte například
en-US, tak se nejprve pokousí nalézt text, který byl zadán v souboru
Texts.en-US.resx, pokud neexistuje tak Texts.en.resx
a naposledy Texts.resx.
Protože toto načítání textů vyžaduje vytváření objektů a nějaké další
operace s nimi nebylo by příliš pohodlné opisovat tento kód pokaždé když potřebujete
načítat text z resources. Proto je dobré vytvořit si pomocnou třídu, která přístup
k resources zjednoduší. V ukázkové aplikaci (kterou naleznete ke stažení na
konci článku) jednu takovou naleznete. Navíc je v ní ještě implementována
možnost změnit jazyk (toto nastavení se ukládá do cookie a je testováno
dříve než se jazyk načte z Request.UserLanguages).
Další velké usnadnění, které umožní snadno vkládat texty z resources do
aspx stránek je vytvořit si následující bázovou stránku a od ní
podědit všechny stránky v projektu:
// Bazova stranka umoznujici pristup k resources public class ResPage : System.Web.UI.Page { // Metoda pro nacitani resources - viz predchozi priklad protected string GetText(string key) { // ... } }
Tato bázová třída vám totiž umožní vkládat texty z resources do stránky takto:
<%@@ Page language="c#" Inherits="LocalizationWeb.ResPage" %> <html> <body> <h1><%=GetText("pageHeader") %></h1> </body> </html>
V přiložené ukázce jsou všechny soubory s přeloženými texty (resx) součástí
projektu a to není nejlepší řešení pokud potřebujete podporu pro další jayzky přidávat
bez překompilování projektu. Lokalizované texty lze ukládat i mimo projekt, ale není to
úplně snadné. Pro více informací se můžete podívat na článek, který k tomuto tématu vyšel
na serveru Interval.cz (viz [3] ).
Lokalizace WinForms aplikací
Lokalizace WinForms aplikací je jednodušší díky zabudované podpoře ve VisualStudiu.Net.
Designer ve kterém se tvoří návrh formulářů totiž umožňuje ukládat automaticky hodnoty
vlastností, které se v něm nastavují do resources (resx souborů), které
se dále zkompilují do satellite assemblies obdobně jako tomu bylo v předcházejícím
příkladu u webových aplikací. Pokud tedy vytvoříte WinForms aplikaci a chcete přeložit
formulář do jiného jazyka stačí ve vlastnostech formuláře nastavit Localizable
na hodnotu true. Poté můžete zvolit jazyk (Language)
a pokud poté provedete nějaké změny (například změnu textu), tak se změny uloží
pouze pro právě vybraný jazyk.


Na obrázku vlevo je naznačeno jak umožnit formuláři aby byl lokalizovatelný. Na obrázku
v pravo je poté vidět jakou strukturu resource soubourů Visual Studio vytváří. V souboru
MainForm.resx je výchozí nastavení (které se použije pro všechny jazyky pro
které neexistuje specifický resx soubor). V MainForm.cs.resx a
MainForm.en.resx jsou uloženy změny, které byly provedeny v době, kdy byla
vybrána jako jazyk čeština (respektive angličtina).
Pokud se podíváte do vygenerovaného zdrojového kódu, naleznete přibližně toto (bez připsaných komentářů):
private void InitializeComponent()
{
// Zde se vytvori resource manager pro formular MainForm
System.Resources.ResourceManager resources=
new System.Resources.ResourceManager(typeof(MainForm));
// ... vytvareni ovladacich prvku ...// Lokalizovane vlastnosti se nacitaji z resources
this.label1.Enabled = ((bool)(resources.GetObject("label1.Enabled")));
this.label1.Font = ((System.Drawing.Font)(resources.GetObject("label1.Font")));
this.label1.Text = resources.GetString("label1.Text");
// ...
}

Lokalizace tedy používá již známý objekt ResourceManager.
Nejedná se tedy o nic tajemného, ale je to velmi přijemné zjdednodušení práce.
Pokud ve vaší aplikaci potřebujete načítat nějaké další texty (například
chybová hlášení), můžete postupovat stejně jako u webových aplikací tak, že
přidáte další resx soubor (a jeho jazykové mutace) ve kterém budete
ukládat vaše texty.
Na obrázku v pravo vidíte, jak se ukázková aplikace zobrazí ve dvou různých jazycích.
Abych mohl takvýto screenshot pořídit přidal jsem do aplikace ještě možnost změnit
před spuštěním jazyk. Stejně jako u webových aplikací i zde načítá objekt
ResourceManager data z resources podle nastavení CurrentUICulture.
Můžete tedy ve vaší aplikaci měnit CurrentUICulture a tak změnit jazyk
ve kterém se aplikace spustí. Tuto změnu je ale potřeba provést před tím, než se
spustí metoda InitializeComponent, tj. v metodě Main
před voláním Application.Run:
static void Main()
{
// Umozni uzivateli zmenit jazyk..
DialogResult ret=MessageBox.Show(
"Click 'Yes' if you want to run english version of application.\n"+
"Kliknete na 'Ne' pokud chcete spustit ceskou verzi aplikace.\n"+
"Pokud kliknete na 'Cancel' pouzije se aktualni nastaveni",
"Localization",MessageBoxButtons.YesNoCancel);
if (ret==DialogResult.Yes)
{
// zmenime CurrentUICulture na anglictinu
Thread.CurrentThread.CurrentUICulture=
CultureInfo.CreateSpecificCulture("en");
}
else if (ret==DialogResult.No)
{
// zmenime CurrentUICulture na cestinu
Thread.CurrentThread.CurrentUICulture=
CultureInfo.CreateSpecificCulture("cs");
}
// a spustit aplikaci v danem jazyce..
Application.Run(new MainForm());
}
Soubory na stažení a odkazy
- [1] Overview of Globalization and Localization [^] - MSDN
- [2] Resource Editor for VS.NET 2003 [^] - CodeProject.com a novější verze [^] - Weblog autora
- [3] Vícejazyčné aplikace a autodetekce preferovaného jazyka v ASP.NET [^] - Interval.cz