TP

.NET - Globalizace a lokalizace aplikací (1.)

Ukázková aplikace

V následujících dvou článcích se podíváme na prostředky, které .NET poskytuje pro tvorbu globalizovatelných a lokalizovatelných aplikací. Globalizace - která je tématem této části - znamená, že vaše aplikace funguje korektně v libovolném prostředí (tedy i pod operačním systémem s jiným jazykem a lokálním nastavením) a také se podle tohoto nastavení chová.

Lokalizovatelnost aplikací (o které bude řeč v příštím článku) znamená, že aplikace má oddělené zdroje, které jsou závislé na jazyce od samotného kódu. Takovouto lokalizovatelnou aplikaci lze snadno lokalizovat, tedy doplnit o zdroje v dalším jazyce.

Více o těchto pojmech naleznete například v MSDN v sekci Planning World-Ready Applications [1].

Co se dočtete v této části tutoriálu

Objekty pro globalizaci

Pro používání objektů umožňujících tvorbu globalizovatelných aplikací budete potřebovat zejména jmenný prostor System.Globalization. Základním objektem umožňující zjišťování systémového nastavení je objekt CultureInfo. Tento objekt obsahuje všechno základní nastavení a obsahuje vlastnosti které vrací objekty s informacemi o dalších detailech nastavení, jako je například kalendář (vlastnost Calendar).

Instanci tohoto objektu s aktuálním nastavením lze získat pomocí staticke vlastnosti CultureInfo.CurrentCulture. Je také možno získat výchozí nastavení pro daný jazyk a zemi a to pomocí standardních kódů popisovaných v RFC specifikaci [2]. Ve zkratce tyto kódy vypadají takto xx-YY, kde xx určuje jazyk a YY určuje nastavení specifické země. Například kód pro češtinu je cs a pro české nastavení cs-CZ, angličtina používaná v USA má kód en-US a britské nastavení má en-GB. Kompletní seznam všech podporovaných nastavení naleznete v MSDN dokumentaci u popisu třídy CultureInfo [3].

Lokální nastavení

V následující ukázce se podíváme jak zle zjistit aktuální nastavení a jak lze získat všechna možná nastavení .NET Frameworku:

// budeme pracovat s objekty Thread a CultureInfo
using System.Globalization;
using System.Threading;
...

// zjisti vsechny mozna nastaveni
CultureInfo[] cultures=
  CultureInfo.GetCultures(CultureTypes.AllCultures);
			
// Vypise jmena vsech nastaveni
foreach(CultureInfo culture in cultures)
{
  Console.WriteLine(culture.DisplayName);
}

// Vypise aktualni nastaveni
CultureInfo current=Thread.CurrentThread.CurrentCulture;
Console.WriteLine(current.DisplayName);

Nastavení CurrentCulture je specifické pro každé vlákno, proto se pro zjišťování nastavení používá vlastnost Thread.CurrentThread, která vrací objekt aktuálního vlákna. Měnit nastavení lze opět pouze pro aktuální vlákno a to nastavením vlastnosti CurrentCulture. Při změně nastavení je ale potřeba používat pouze specifické nastavení (tedy například nelze použít informace s kódem cs, ale je potřeba i určení země, tedy cs-CZ). K tomuto účelu slouží metoda CreateSpecificCulture jak je vidět v následující ukázce:

// Vytvori specificke CultureInfo pro anglictinu
CultureInfo eng=CultureInfo.CreateSpecificCulture("en");
// Vypsat informace o CultureInfo
Console.WriteLine("{0} - {1}",eng.Name,eng.DisplayName);

// Nastavit aktualni culture na en-US
Thread.CurrentThread.CurrentCulture=eng;
Výstup programu bude:
en-US - English (United States)

Možné chyby

Při nastavování CurrentCulture dojde k výjimce pokud se pokusíte nastavit CultureInfo, které nepopisuje specifické nastavení. Také může dojít k chybě při nastavení jednoho z několka kódů, které jsou sice podporovány v .NET Frameworku, ale ne ve WinAPI a vzhledem k tomu, že toto volání vnitřně s WinAPI pracuje dojde k chybě (jedná se například o zh-CHT - Traditional Chinese).

Formátování dat

Pokud používáte metody ToString nebo například Double.Parse k převodu čísel a řetězců, automaticky se vždy použije aktuální nastavení. Pokud tedy na systému s českým nastavením převedete číslo s desetinnou částí na textový řetězec, dostanete desetinnou čárku a v anglickém nastavení dostanete desetinnou tečku. Při volání metody Parse se opět předpokládá, že předávaný řetězec bude v aktuálním nastavení. Toto nastavení lze obejít tak, že metodě jako druhý parametr předáte objekt CultureInfo, kterým se má metoda řídit. Tato pravidla platí také pro strukturu DateTime, pomocí které lze pracovat s časem.

// Vypise cislo PI ve francouzskem formatu
CultureInfo frCulture=CultureInfo.CreateSpecificCulture("fr");
string pi=Math.PI.ToString(frCulture);
Console.WriteLine(pi);

// .. a prevod retezce zpet na cislo
double dblPi=Double.Parse(pi,frCulture);

Další co .NET Framework umožňuje, je získání jmen měsíců nebo dnů v týdnu, takže pokud ve vaší aplikaci chcete zobrazovat například ovládací prvek DropDownList se seznamem měsíců, není potřeba tyto měsíce psát do kódu, ale lze je získat za běhu a to přímo v jazyce, který má uživatel nastavený v operačním systému.

// Naplni seznam monthList jmeny mesicu
DateTimeFormatInfo df=CurrentCulture.DateTimeFormat;
for(int i=0; i<12; i++)
{
  monthList.Items.Add(df.MonthNames[i]);
}

Neutrální formát

Pokud chcete ve vaší aplikaci ukládat data například do souboru tak, aby nebyla závislá na aktuálním nastavení můžete použít takzvanou invariant culture, která za všech podmínek popisuje stejné nastavení. K získání tohoto nastavení lze použít statickou vlastnost objektu CultureInfo a to InvariantCulture. V následující ukázce se podíváme, jak lze zapsat a následně načíst ze souboru náhodné číslo ve formátu nezávislém na nastavení (v tomto nastavní se desetinná čísla ukládají s tečkou).

using System.IO;
using System.Globalization;
...

// Ziska objekt popisujici nezavisle nastaveni
CultureInfo invariant=CultureInfo.InvariantCulture;
using(StreamWriter sw=new StreamWriter("C:\\test.txt"))
{
  // Prevede nahodne cislo na retezec v invariant formatu
  // a ulozi jej do souboru..
  Random rnd=new Random();
  string num=rnd.NextDouble().ToString(invariant);
  sw.WriteLine(num);
}

Načítání ze souboru vypadá velmi podobně:

using System.IO;
using System.Globalization;
...

// Ziska objekt popisujici nezavisle nastaveni
CultureInfo invariant=CultureInfo.InvariantCulture;
double num=0;
using(StreamReader sr=new StreamReader("C:\\test.txt"))
{
  // Prevede nacteny retezec na cislo
  string str=sr.ReadLine();
  num=Double.Parse(str,invariant);
}

// .. a vypise cislo ve formatu dle aktualniho nastaveni
Console.WriteLine(num.ToString());

Soubory na stažení a odkazy

Published: Wednesday, 6 July 2005, 12:44 AM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: