Lokalizacja gotowej aplikacji ASP .NET MVC

image

No dobra, po godzinach też programuje, ale już dla przyjemności 😉 dlatego nikt mi za to nie płaci 😀

Sytuacja: gotowa aplikacja w ASP .NET MVC – język wszystkich komunikatów to angielski. Dodatkowo aplikacja nie była przystosowana w żaden sposób do lokalizacji. Można powiedzieć, że jest to typowa brownfield application.

Zadanie: spolszczyć całość aplikacji ? zachowując przy tym możliwość pokazania interfejsu użytkownika w pierwotnej wersji językowej.

Pierwsze koty za płoty ? rozwiązanie gorsze

Pierwsze rozwiązanie jakie przychodzi na myśl to ? tłumaczenie wszystkich tekstów z kontrolerów i modyfikacja widoków. Sposób słaby i nie pozwoli na pokazanie interfejsu w oryginalnym języku.

Drugie rozwiązanie ? lepsze

Kontrolery

Przeniesienie wszystkich stringów, które podlegają lokalizacji, z Controllerów do resourców w folderze App_LocalResources. Następnie trzeba stworzyć wersje resourców dla każdego języka.

Trzeba jeszcze wziąć pod uwagę, czy komunikaty są budowane za pomocą String.Format ? w moim wypadku tak na szczęście było.

Wyciąganie stringów do resourców ? to jest naprawdę mordercze zajęcie ? na szczęście po małym wyszukiwaniu znalazłem super wtyczkę do Resharpera ? RGreatEx. Wtyczka potrafi wyciągnąć stringi do resourców i w ich miejsce wstawić odpowiednie odwołania. Podobno potrafi także tłumaczyć za pomocą google translate, ale do automatycznego tłumaczenia jestem nastawiony sceptycznie.

Widoki

Zdublowanie plików widoków np About.aspx w wersji angielskiej ?> About.pl.aspx w wersji polskiej. Wiem, teoretycznie powinienem też wyciągnąć wszystkie stringi do lokalizacji, jednak(odstawiając na bok różne dogmaty) takie rozwiązanie wydało mi się bardzie sensowne. No dobra, teraz tylko sposób żeby ViewEngine w pierwszej kolejności wyszukał stronę About.pl.aspx, a dopiero w drugiej About.aspx. Okazuje się, że najlepiej w tym celu zrobić własny ViewEngine:

public class LocalizationViewEngine : WebFormViewEngine
    {
        public LocalizationViewEngine() : base()
        {
            ViewLocationFormats = AppendCulture(ViewLocationFormats);
            PartialViewLocationFormats = AppendCulture(PartialViewLocationFormats);
            MasterLocationFormats = AppendCulture(MasterLocationFormats);
        }

        private string [] AppendCulture(string[] arr)
        {
            List<string> ret = new List<string>();
            for (int i = 0; i < arr.Length; i++)
            {
                string s = arr[i];
                s = s.Replace(".aspx",
                              "." + Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName + ".aspx");
                s = s.Replace(".ascx",
                              "." + Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName + ".ascx");
                s = s.Replace(".master",
                              "." + Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName + ".master");
                ret.Insert(0, s);
            }
            ret.AddRange(arr);
            return ret.ToArray();
        }

Trzeba tylko jeszcze powiedzieć MVC, że używamy własnego silnika widoków w global.asax.cs:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new LocalizationViewEngine());

A w web.config zmienić ustawienia globalization:

<globalization
requestEncoding="utf-8"
responseEncoding="utf-8"
culture="en-US"
uiCulture="pl-PL"
/>

Teraz zostaje tylko nudna część tzn.: wygibasy lingwistyczne i tłumaczenie resource oraz widoków. Jak już jest wszystko wymyślone to średnio chce mi się odwalać czarną robotę ;P

3 thoughts on “Lokalizacja gotowej aplikacji ASP .NET MVC

  1. Hej! A czy nie lepiej użyć dyrektyw Resources:Strings po stronie widoku? Wtedy aplikacja tłumaczy się sama, skoro już masz tak, czy siak wszystkie stringi w resource-ach.

  2. Zastanawiałem się nad czymś takim, ale stwierdziłem, że pliki .aspx są już same takimi “jakby” resourcami. Poza tym nie mógłbym napisać własnego ViewEngine :p

  3. dario-g says:

    Ja zerwałem z ustrojstwem ASP.NET i stosuję własny sposób. Napisałem sobie własny mechanizm trzymający tłumaczenia w zewnętrznym pliku XML.

    Pisząc tekst w pliku View używam Extension method z mechanizmu translacji i wygląda to tak:

    “Ten tekst może być przetłumaczony”.Translate()

    Szczególnie przydatne przy dynamicznie dodawanych tłumaczeniach przez użytkowników końcowych. 🙂
    :))

Leave a Reply

Your email address will not be published. Required fields are marked *