13. díl - Multilingual (vícejazyková) aplikace

C# .NET Pro pokročilé Instant Messenger Multilingual (vícejazyková) aplikace

Vyzkoušel jsem několik způsobů na překlad aplikace. Každý z nich má nějaké výhody a nevýhody. Zkoušel jsem překlad načítaný ze souboru. Lze lehko modifikovat a uživatel si tak může nadefinovat lehce i vlastní jazyk. Ovšem překlad v aplikaci se pak řeší strašně. Poté jsem zkoušel pomocí ***.resx** metodou projetí všech komponent a najítí k jejich vlastnostem (tooltip, text) odpovídající překlad. Nejvíce se mi však osvědčila metoda, kterou si nyní ukážeme a to vytvoření si onech *.resx souborů pro jednotlivé jazyky. A data z nich budeme získávat pomocí metoda Translate, která vyhledá zadaný výraz v souboru a vrátí jeho překlad. Lze takto skládat jednoduše věty a na použití je to velmi jednoduché. V *.resx souboru je vlastně XML, kde jsou uložený jednotlivé hodnoty.

Do Properties jsem si přidal složku Strings v níž jsem si vytvořil soubor s resources _default.resx (default se jmenovat nemůže, bže je to klíčové slovo). Teď přichází ta nejhnusnější část. A to přepsat sem všechny stringy. Ovšem lze si to zjednodušit. Projet všechny komponenty foreach (Control c in Controls) a pokud je to třeba Label c is Label (některé komponenty nemají vlastnost text) a jeho Text má nějakou hodnotu !String.IsNullOrEmpty(c.Text) tak si ji uložím do souboru. Když si otevřete onen soubor _default.resx a sjedete dolů uvidíte jak se to tam generuje:

<data name="hello" xml:space="preserve">
    <value>Ahoj</value>
</data>

Takže můžete udělat toto:

foreach (Control c in Controls)
{
        if ((c is Label) && (!String.IsNullOrEmpty(c.text)))
        {
                sw.WriteLine("<data name=\"" + c.Name + "\" xml:space=\"preserve\">\r\n"
                                                + "<value>" + c.Text + "</value>\r\n"
                                        + "</data>"
                                        );
        }
}

Pak to jen přidáte do souboru uložíte a VS si to načte => pohodička. Pak už soubor jen zduplikujete pojmenujete například cs-CZ.resx a změníte hodnoty na jejich český ekvivalent.

V aplikaci si vytvoříte nějaký ComboBox a do něj si přidáte třeba:

English
Česky

Takto by mohla vypadat třída LangManager:

public static class LangManager
{

Do listu Languages si dáme podporované jazyky, ve stejném pořadí jako jsou v ComboBoxu

        public static List<string> Languages = new List<string>() { "en-GB", "cs-CZ" };

        public static string currentCulture;
        public static System.Resources.ResourceManager strings;

        public static void SetLangFromFile()
        {
                string culture = null;
                if (File.Exists(Global.appDataFolder + "lang.ini"))
                {
                        using (StreamReader sr = new StreamReader(Global.appDataFolder + "lang.ini", Encoding.UTF8))
                        {
                                culture = sr.ReadLine();
                        }
                }
                SetLanguage(culture);
        }

        public static void SaveLangToFile(string culture)
        {
                using (StreamWriter sw = new StreamWriter(Global.appDataFolder + "lang.ini", false, Encoding.UTF8))
                {
                        sw.WriteLine(culture);
                }
        }

        public static void SetLanguage(string culture)
        {
                if (culture == "cs-CZ")
                {
                        Thread.CurrentThread.CurrentCulture = new CultureInfo("cs-CZ");
                        strings = Properties.Strings.cs_CZ.ResourceManager;
                        currentCulture = "cs-CZ";
                }
                else
                {
                        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");
                        strings = Properties.Strings._default.ResourceManager;
                        currentCulture = "en-GB";
                }
        }

        public static string Translate(string name)
        {
                if (strings == null)
                        SetLanguage(null);

                return strings.GetString(name);
        }
}

Při nastavování vybraného jazyka:

languageSelector.SelectedIndex = Global.LangManager.Languages.IndexOf(Global.LangManager.currentCulture);

Ukládání vybraného jazyka:

string culture = "en-GB";
if (languageSelector.SelectedIndex != -1)
        culture = Global.LangManager.Languages[languageSelector.SelectedIndex];

if (Global.LangManager.currentCulture != culture)
{
        Global.LangManager.SaveLangToFile(culture);
        Global.LangManager.SetLanguage(culture);
        Global.OpenForms.mainForm.TranslateForm();
}

Zde je vidět, jak pošéfit překlad za běhu aplikace. Prostě si uděláte nějakou metodu, která přeloží formulář a zavoláte ji.

No a pak už jen voláte nameTB.Text = LangManager.Translate("name");


 

  Aktivity (1)

Článek pro vás napsal David Jančík [sczdavos]
Avatar
Autor je vášnivý programátor v .NET C# a PHP. Nezná slovo "nelze", nebojí se zkoušet nepoznané a pronikat do nových technologií.

Jak se ti líbí článek?
Celkem (1 hlasů) :
55555


 



 

 

Komentáře

Avatar
Kit
Redaktor
Avatar
Kit:

Skládat XML pomocí WriteLine mi připadá poněkud nešikovné. Co třeba použít DOM?

Odpovědět  +1 15.1.2013 17:15
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Kit:

Další možností je XmlWriter nebo XmlTextWriter.

Odpovědět 15.1.2013 17:41
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Odpovídá na Kit
David Jančík [sczdavos]:

Aha, už chápu to nasměrování na XmlWriter :D
To je jen pro takové rychlé vygenerování, v aplikaci to pak nikde nejni, je to jen na jedno použití, jen vygeneruju potřebná data a kód smažu.
Chápu, že ty by jsi to stihnul vygenerovat s elegancí za polovic času :D A doufám, že pro tento jednorázový účel mi XML způsob jakým s ním pracuji odpustí. :O

Odpovědět 15.1.2013 19:02
Čím více času dostaneš, tím méně ho máš.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Jančík [sczdavos]
Kit:

Myslím si, že hlavní výhodou generování XML pomocí XmlWriter a podobných je menší riziko výstupu nevalidního dokumentu. Tyto generátory se často starají i o entity a správnou deklaraci v hlavičce. U drobných dokumentů je to však jedno.

Jenom jsem nikde v dokumentaci XmlWriteru nenašel ani zmínku o atributech a přitom jsem si jist, že to umí.

Odpovědět 16.1.2013 8:31
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 4 zpráv z 4.