Lokalizacja gotowej aplikacji ASP .NET MVC
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
Darek Tarczyński
24 Feb 09 at 15:21
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.
Bartłomiej Szafko
24 Feb 09 at 22:49
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
dario-g
26 Feb 09 at 18:35
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.
)