Vývojářský blog Jaromíra Nechanického

Tisk článku Tisk článku

Tvorba lokalizovatelné aplikace

[Zpět na blog]

Datum: 10. 10. 2009 23:39       Autor: Jaromír Nechanický       Zobrazeno: 3041x


Zajisté jste již také narazili na problém, kdy potřebujete Vaši aplikaci přeložit do cizího jazyka. “Ideálním” a bohužel velmi častým případem je, když si na to šéf vzpomene až po dokončení celé aplikace, jejíž návrh s touto možností samozřejmě nepočítal. A i kdyby to bylo v původních požadavcích, používání resources pro texty GUI při vývoji je velmi nepohodlné. Naštěstí má Visual Studio prostředky, jak nám náležitě ulehčit život.

Mějme klasickou již hotovou aplikaci. U formuláře, který chcete nastavit jako lokalizovatelný dejte jeho vlastnosti a najdete položku “Localizable”. Tu nastavte na True.

image

Nyní si všimněte, že VS vygenerovalo soubor $název formu$.resx.

image

V tomto souboru jsou extrahovány veškeré textové řetězce z GUI formuláře. Podíváte-li se na obsah tohoto souboru, uvidíte, že navíc obsahuje i informace o nastavení všech komponent (zobrazíte kliknutím na “Strings” a vyberte Other). Nyní přidáme resource soubor pro češtinu. Klikněte na “add new item” a zde v kategorii general vybereme resource file. Resource soubor musíte pojmenovat $název formu$.$culture$.resx. Například pro můj Form1 a češtinu bude jméno Form1.cs.resx. Do tohoto souboru nakopírujte texty z původního resource souboru.

Tip: pokud si nepamatujete/neznáte názvy jednotlivých kultur, spusťte v PowerShellu příkaz “[Globalization.CultureInfo]::GetCultures([Globalization.CultureTypes]::NeutralCultures)”

Nyní je nejvyšší čas odeslat soubor překladatelce. Formát resx je sice jednoduché XML, ze kterého by každý programátor/administrátor byl nadšen.

 <?xml version="1.0" encoding="utf-8"?>
<
root>
<!--

Microsoft ResX Schema

Version 2.0

The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.

Example:

... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>

There are any number of "resheader" rows that contain simple
name/value pairs.

Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.

The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:

Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.

mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<
xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<
xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<
xsd:element name="root" msdata:IsDataSet="true">
<
xsd:complexType>
<
xsd:choice maxOccurs="unbounded">
<
xsd:element name="metadata">
<
xsd:complexType>
<
xsd:sequence>
<
xsd:element name="value" type="xsd:string" minOccurs="0" />
</
xsd:sequence>
<
xsd:attribute name="name" use="required" type="xsd:string" />
<
xsd:attribute name="type" type="xsd:string" />
<
xsd:attribute name="mimetype" type="xsd:string" />
<
xsd:attribute ref="xml:space" />
</
xsd:complexType>
</
xsd:element>
<
xsd:element name="assembly">
<
xsd:complexType>
<
xsd:attribute name="alias" type="xsd:string" />
<
xsd:attribute name="name" type="xsd:string" />
</
xsd:complexType>
</
xsd:element>
<
xsd:element name="data">
<
xsd:complexType>
<
xsd:sequence>
<
xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<
xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</
xsd:sequence>
<
xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<
xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<
xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<
xsd:attribute ref="xml:space" />
</
xsd:complexType>
</
xsd:element>
<
xsd:element name="resheader">
<
xsd:complexType>
<
xsd:sequence>
<
xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</
xsd:sequence>
<
xsd:attribute name="name" type="xsd:string" use="required" />
</
xsd:complexType>
</
xsd:element>
</
xsd:choice>
</
xsd:complexType>
</
xsd:element>
</
xsd:schema>
<
resheader name="resmimetype">
<
value>text/microsoft-resx</value>
</
resheader>
<
resheader name="version">
<
value>2.0</value>
</
resheader>
<
resheader name="reader">
<
value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</
resheader>
<
resheader name="writer">
<
value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</
resheader>
<
data name="$this.Text" xml:space="preserve">
<
value>Form1</value>
</
data>
<
data name="&gt;&gt;$this.Name" xml:space="preserve">
<
value>Form1</value>
</
data>
<
data name="&gt;&gt;$this.Type" xml:space="preserve">
<
value>System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</
data>
<
data name="&gt;&gt;button1.Name" xml:space="preserve">
<
value>button1</value>
</
data>
<
data name="&gt;&gt;button1.Parent" xml:space="preserve">
<
value>$this</value>
</
data>
<
data name="&gt;&gt;button1.Type" xml:space="preserve">
<
value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</
data>
<
data name="&gt;&gt;button1.ZOrder" xml:space="preserve">
<
value>0</value>
</
data>
<
data name="button1.Text" xml:space="preserve">
<
value>Ahoj svete</value>
</
data>
</
root>

Bohužel většina lidí mimo obor naše nadšení nesdílí. Zde přichází ke slovu utilita ResGen.exe (distribuovaná s VS, případně Windows SDK), která umí toto XML konvertovat na textový soubor a naopak.

Spustíme příkaz “resgen Form1.cs.resx Form1.cs.txt”. Vygenerovaný textový soubor je podstatně přijatelnější pro další (neprogramové) zpracování. Změníme v něm potřebné texty například na anglické a opět spustíme “resgen Form1.cs.txt Form1.en.resx”.

Nyní ve Visual Studiu zvolíme “add existing item” a najdeme náš nový soubor s resources. Spustíte-li aplikaci, jakoby se nic nestalo. Ovšem přidáte-li do konstruktoru před “InitializeComponent()” tento řádek kódu:

Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo("en-US");

Nyní se aplikoval soubor s angličtinou. .NET se tedy automaticky podívá na nastavení aplikace (jaká je nastavená kultura při spuštění) a podle toho zvolí nejvhodnější soubor s texty. Pokud není specifický soubor pro danou zemi, použije se defaultní (Form1.resx).

Podíváme-li se k výslednému exe souboru aplikace, uvidíme, že zde přibyly nové složky. Tyto složky je třeba distribuovat spolu s aplikací, protože v nich jsou uloženy lokalizované texty.


> Na začátek

 

Hodnocení:

Hlasů: 9
Zvolte své hodnocení

Jaromír Nechanický


RSS Feed RSS Feed

Diskuse

1 

Lokalizace

Datum: 11.10.2009 0:16
Autor: Ondřej Linhart
Hodnocení autora: 1132
Příspěvků: 2389
Ještě jsem neviděl nikoho, kdo by lokalizaci formulářů prováděl takto nehorázně. Příslušné resource soubory se automaticky vytvoří při výběru jazyka formuláře (vlastnost Language) a nic není třeba přidávat ručně. Kromě toho není v článku ani zmínka o neutrální kultuře, což je škoda, protože to je jedna ze základních věcí která ovlivňuje chování lokalizované aplikace.
 
           [Odpovědět]
 
Hodnocení: -3 Čekejte, prosím...

Re: Lokalizace

Datum: 11.10.2009 19:18
Autor: Jaromír Nechanický
Hodnocení autora: 4
Příspěvků: 5
Je to asi věc názoru. Mě přijde naprosto nevhodné Vaše řešení a to z jednoho prostého důvodu: nedá se rozumě automatizovat. U každého formuláře bych totiž musel naklikat všechny možné jazyky, kdežto u ručního přidávání stačí toto provést pouze pro základní jazyk a o zbytek se postará najatá překladatelka v kombinaci s několika řádky v PowerShellu. Vaše řešení mi připadá lepší pro malé aplikace, ovšem u čehokoliv většího bych si odrovnal zápěstí :-)
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: Lokalizace

Datum: 11.10.2009 20:07
Autor: Ondřej Linhart
Hodnocení autora: 1132
Příspěvků: 2389
Člověče co to plácáte za nesmysly?! Jaká automatizace? Kliknete pouze tolikrát, do kolika jazyků chcete lokalizovat, kdežto ve vašem případě budete kromě ručního přidávání příslušných ResX souborů také pokaždé kopírovat jejich obsah. O tom co dostane překladatelka to je už jiná kapitola. A jestli pro takto triviální úlohy používáte PowerShell tak to je tedy k pousmání. Moje řešení je běžně používané a doporučované pro jakoukoliv lokalizaci.
 
           [Odpovědět]
 
Hodnocení: -2 Čekejte, prosím...

Re: Lokalizace

Datum: 11.10.2009 20:26
Autor: Tomáš Herceg
Hodnocení autora: 1660
Příspěvků: 3533
Až budete lokalizovat aplikaci se 150 okny do šesti jazyků, tak už to smysl má.
 
           [Odpovědět]
 
Hodnocení: 2 Čekejte, prosím...

Re: Lokalizace

Datum: 11.10.2009 20:27
Autor: Jaromír Nechanický
Hodnocení autora: 4
Příspěvků: 5
Ano kliknete pouze tolikrát, kolik potřebujete jazyků a pro každý formulář. Zároveň nevím, jak Vám, ale mne VS nevygeneruje nic, dokud se nějaký text nezmění, což znamená, že musím zároveň přepsat kus textu (toto chování může být způsobeno nastavením VS, nepátral jsem). Počty jsou nyní již jednoduché:
Aplikace má 15 formulářů, chci to přeložit do 3 jazyků, včetně základního. To Vám dělá 15*3 a k tomu ještě změna alespoň jediného textu (pokud potom obsah budete kopírovat stejně jako já, případně vyplňovat ručně, protože do těchto souborů se promítne pouze změněný text).
V mém řešení stačí pouze všem formulářům nastavit Localizable (15 kliknutí) a poté rozkopírovat příslušný textový soubor a jen ho přejmenovat (jeden PS command). Překladatelka přeloží a opět jedním PS commandem uděláte ze souborů resx, které třemi kliky přidáte do projektu (všechny). Myslím, že co do složitosti vedu ;-)

Nicméně rád se přiučím. Můžete mi prosím popsat, jak to u Vás funguje? Vytvořím tedy resx soubory pro všechny formy a všechny jazyky. V jakém formátu pak texty dáváte překladatelce a jak je poté dáváte do aplikace?
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: Lokalizace

Datum: 11.10.2009 20:44
Autor: Ondřej Linhart
Hodnocení autora: 1132
Příspěvků: 2389
Překladatelka není potřeba (není nic horšího než nechat si externě překládat odborné věci), texty se lokalizují přímo ve Visual Studiu v příslušném ResX souboru.
 
           [Odpovědět]
 
Hodnocení: -4 Čekejte, prosím...

Re: Lokalizace

Datum: 12.10.2009 10:30
Autor: Michal Augustýn
Hodnocení autora: 20
Příspěvků: 37
Cože, překladatelka není potřeba? To je opravdu úlet. Vy jste možná dokonalý a umíte perfenktně všechny jazyky světa, ale běžné to rozhodně není ;-)
Článek se mi moc líbí!
 
           [Odpovědět]
 
Hodnocení: 3 Čekejte, prosím...

Re: Lokalizace

Datum: 12.10.2009 12:05
Autor: Ondřej Linhart
Hodnocení autora: 1132
Příspěvků: 2389
Všechny jazyky světa rozhodně nejsou potřeba. Běžně se překládá pouze do angličtiny, maximálně do němčiny. Pokud někdo není úplný dement a nemá problémy se čtením odborné anglické literatury, MSDN a podobně, tak uživatelské rozhraní je schopen si bez problémů přeložit sám. Překládáte snad román nebo co?! Překladatelce bych svěřil možná tak nápovědu a dokumentaci.
 
           [Odpovědět]
 
Hodnocení: -5 Čekejte, prosím...

Re: Lokalizace

Datum: 12.10.2009 13:05
Autor: Michal Augustýn
Hodnocení autora: 20
Příspěvků: 37
Aha, tak pokud pro Vás existují jen čeština, angličtina a němčina, tak se opravdu nemá cenu s Vámi dohadovat...
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: Lokalizace

Datum: 12.10.2009 13:37
Autor: Ondřej Linhart
Hodnocení autora: 1132
Příspěvků: 2389
Aha, a pro kolik jazyků se lokalizují vaše aplikace? Nemyslím nějaké plácání webových stránek, ale klasické desktopové aplikace... Probuďte se prosím.
 
           [Odpovědět]
 
Hodnocení: -5 Čekejte, prosím...

Re: Lokalizace

Datum: 12.10.2009 16:15
Autor: Jaromír Nechanický
Hodnocení autora: 4
Příspěvků: 5
Co se mne a desktopových aplikací týče, tak například za poslední půl rok jsem krom AGJ, NJ a CZ (mimochodem i na NJ již potřebuji někoho, kdo to přeloží) lokalizoval do slovenštiny, polštiny a maďarštiny.
Opět se jedná o typ aplikace, kterou píšete. Je samozřejmé, že krabicovou distribuci malá firmička nebude lokalizovat jinam, než do AGJ. Ovšem pokud píšete aplikaci na zakázku, se kterou budou pracovat i lidé mající pouze ZŠ vzdělání, musí to být v jejich mateřštině. Navíc pokud Vám zákazník zaplatí několik set tisíc za aplikaci na zakázku, nemůžete mu říct, že v civilizovaných zemích se mluví anglicky a ať se to kouká naučit
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: Lokalizace

Datum: 12.10.2009 16:38
Autor: Michal Augustýn
Hodnocení autora: 20
Příspěvků: 37
Naše desktopová aplikace je lokalizovaná do 33 jazyků. Vy se probuďte, svět není jen o malých desktopových aplikacích na zakázku...
 
           [Odpovědět]
 
Hodnocení: 2 Čekejte, prosím...

Re: Lokalizace

Datum: 12.10.2009 17:46
Autor: Ondřej Linhart
Hodnocení autora: 1132
Příspěvků: 2389
Malé desktopové aplikace na zakázku sem furt cpete vy. Pracoval jsem na velmi rozsáhlém projektu (řádově rozsáhlejší aplikace než ubohý avast), který nebylo ani potřeba lokalizovat, takže velikost projektu rozhodně neznamená nutnou potřebu lokalizace.
 
           [Odpovědět]
 
Hodnocení: -4 Čekejte, prosím...

Re: Lokalizace

Datum: 13.11.2009 12:00
Autor: Tomáš Jecha
Hodnocení autora: 697
Příspěvků: 1285
Nejdříve jste napadal samotné řešení. Když bylo obhájeno, tak jste začal napadat důvod jeho použití. To jste argumentoval prakticky nulovou potřebou lokalizovat, což bylo nesmyslně obhájeno tím, že na projektu, který jste dělal lokalizace potřeba není (resp nikdo ji nevyžadoval / nechtěl zaplatit). A nakonec jste skončil u napadnutí Avastu.
 
           [Odpovědět]
 
Hodnocení: -1 Čekejte, prosím...

Re: Lokalizace

Datum: 13.11.2009 14:26
Autor: Michal Augustýn
Hodnocení autora: 20
Příspěvků: 37
Aneb kdo chce psa bít, hůl si vždy najde :)
 
           [Odpovědět]
 
Hodnocení: 3 Čekejte, prosím...

Re: Lokalizace

Datum: 2.1.2010 21:00
Autor: neregistrovaný (78.102.236.137)
Hodnocení autora: není
Příspěvků: 0
Článek je sice pěkný, ale bohužel velmi často není potřeba překládat jen Formy, ale i ostatní věci, ketré na formuláři nejsou, přesto je třeba je mít v daném jazyku (např. MsgBox, ToolBar, atd.) Tam tento způsob použitelný není, docela jsem se s tím trápil, než jsem přišel na to, jak to ve VB.NET udělat. Možná by se to někomu hodilo, kdyby to tu pro ostatní bylo autorem taky ukázáno.
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: Lokalizace

Datum: 3.7.2010 13:17
Autor: Ondřej Linhart
Hodnocení autora: 1132
Příspěvků: 2389
Proboha co je to za nesmysly?!
 
           [Odpovědět]
 
Hodnocení: -5 Čekejte, prosím...
1 
 

VBNET.CZ | © 2007 Tomáš Herceg, Tomáš Jecha | Kopírování a přejímání jakéhokoliv obsahu z tohoto webu je bez písemného svolení autorů zakázáno.