Aplikacje wielojęzykowe

Jako, że aktualnie pracuję w firmie, która posiada swoje oddziały w Polsce i na Ukrainie, interfejs aplikacji nad którymi pracuję musi być tłumaczony minimum na te dwa języki. Domyślnie interfejs aplikacji jest tworzony w języku angielskim a następnie tłumaczony na pozostałe języki.

W dzisiejszym wpisie, chcę Wam pokazać jak szybko napisać aplikację wielojęzykową. Sposób który zaprezentuję, może być zastosowany do aplikacji dowolnego typu (desktop, webowe itd) oraz bez względu na język w którym aplikacja jest/będzie pisana. Na potrzeby tego wpisu zastosowałem „znacznie” uproszczoną wersję standardu GNU GETTEXT. Nie chcę się tutaj wdawać w szczegóły dotyczące tego standardu. Chętnym poszerzenia swojej wiedzy proponuję zajrzeć tutaj. Wspomnę tylko, że zastosowanie plików tekstowych do tłumaczenia aplikacji niesie ze sobą kilka korzyści. Np. w przeciwieństwie do standardu tłumaczeń domyślnego dla .NET czyli w plikach zasobów / dll, pliki tekstowe można wykorzystać w dowolnym systemie operacyjnym (Windows/Linux/MacOsX) a osoby tłumaczące mogą korzystać ze zwykłych edytorów tekstowych bez ingerencji w kod.

Całość opiera się na schemacie klucz-wartość, gdzie kluczem jest fraza oryginalna natomiast wartością jest fraza przetłumaczona. W celu uproszczenia przyjmę zasadę, że tłumaczenia będą zapisane w pliku tekstowym z kodowaniem UTF8, który będzie miał poniższą strukturę (para linii oryginał + tłumaczenie):
tekst_oryginalny_1
tekst_przetłumaczony_1
tekst_oryginalny_2
tekst_przetłumaczony_2

tekst_oryginalny_n
tekst_oryginalny_n

Wszystkie pliki tłumaczeń będą przechowywane w podkatalogu Translations naszej aplikacji i będą miały nazwy w postaci język.lang (np. Polish.lang). Dodatkowo w tym folderze będziemy przechowywali pliki z flagą dla określonego państwa, a każdy z nich będzie miał nazwę w postaci język.png (np. Polish.png). Aplikacja będzie na starcie ładować listę tłumaczeń znajdujących się w w/w podkatalogu i uzupełniała menu wyboru języka. Język aplikacji można zmienić w trakcie jej działania bez konieczności restartu.

Cały mechanizm tłumaczenia oprzemy na jednej klasie statycznej (ze względu na to, że chcemy mieć dostęp do tłumaczeń z poziomu całej aplikacji), którą nazwiemy I18N. Klasa ta będzie po prostu opakowaniem dla słownika (Dictionary<string, string>), w którym będziemy przechowywali nasze oryginały i tłumaczenia. Poniżej źródło:

public static class I18N
{
    private static Dictionary<string, string> _messages = new Dictionary<string, string>();

    public static string __(string originalText)
    {
        if (!string.IsNullOrEmpty(originalText))
        {
            if (_messages.ContainsKey(originalText))
            {
                if (!string.IsNullOrEmpty(_messages[originalText]))
                {
                    originalText = _messages[originalText].ToString();
                }
            }
        }
        return originalText;
    }

    public static void Clear()
    {
        _messages.Clear();
    }

    public static void Write(string original, string translated, bool update)
    {
        if (_messages.ContainsKey(original) && update)
        {
            _messages[original] = translated;
        }
        else
        {
            _messages.Add(original, translated);
        }
    }

    public static bool Load(string fileName, bool append, bool update)
    {
        bool isLoaded = false;
        if (File.Exists(fileName))
        {
            if (!append)
            {
                Clear();
            }

            using (var reader = new StreamReader(fileName, Encoding.UTF8))
            {
                while (!reader.EndOfStream)
                {
                    string original = reader.ReadLine();
                    string translated = reader.ReadLine();
                    Write(original, translated, update);
                }
            }
            return true;
        }
        return isLoaded;
    }
}

Jak widać, w klasie mamy jedynie cztery metody:

public static bool Load(string fileName, bool append, bool update)

ładuje wskazany plik do słownika umożliwiając dołączenie nowych tłumaczeń oraz zastąpienie aktualnych tłumaczeń na nowe

public static void Clear()

usuwa wszystkie aktualne tłumaczenia za słownika

public static void Write(string original, string translated, bool update)

dopisuje do słownika nową frazę lub aktualizuje już istniejącą

public static string __(string originalText)

zwraca przetłumaczoną frazę lub tekst oryginalny jeśli tłumaczenie nie istnieje w słowniku.

Po załadowaniu pliku tłumaczeń możemy z dowolnego miejsca programu wywołać tłumaczenie:

I18N.__("tekst oryginalny");

Uprzedzam, że jeśli stosujemy formatowanie stringów np. string.Format(„formatowany ciąg znaków {0}”, zmienna); należy najpierw dokonać tłumaczenia a dopiero potem sformatować wyjściowy tekst:

string.Format(I18N.__("formatowany ciąg znaków {0}"), zmienna);

zamiast:

I18N.__(string.Format("formatowany ciąg znaków {0}", zmienna));

Własny system tłumaczeń można znacznie bardziej rozbudować, np. o obsługę tłumaczeń pluginów aplikacji, obsługę różnych struktur plików tekstowych itd… Ale to wychodzi już poza ramy tego wpisu.

Kończąc ten post, życzę przyjemnej pracy z internacjonalizacją własnych aplikacji 🙂

Przykładowa aplikacja nie robiąca nic poza wykorzystaniem klasy I18N jest do pobrania poniżej.

Aplikacja wielojęzykowa
Aplikacja wielojęzykowa
MultiLingualApp.zip
51.0 KiB
Pobrano 71 razy
Szczegóły...

Tagi:, , , ,

Nie ma jeszcze komentarzy.

Dodaj komentarz

Uzupełnij * Time limit is exhausted. Please reload the CAPTCHA.