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
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.
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
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. 馃檪
:))