fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
3 minut

Ustawianie kultury aplikacji na podstawie preferencji przeglądarki


16.05.2011

Wielojęzyczność aplikacji www można rozwiązać na kilka sposobów. Jedne strony mają rysuneczki flag symbolizujących język, w jakim chcemy widzieć teksty (i nie tylko) i pamiętają to w cookie. Inne pozwalają to ustawić w profilu użytkownika i pamiętają ustawienie w bazie.

Ostatnio pisałem rozwiązanie, które ustawia odpowiednią kulturę aplikacji na podstawie informacji wysyłanych przez przeglądarkę podczas żądania. Sam szkielet rozwiązania jest banalny:

  1:  public static class CultureUtils
  2:  {
  3:      public static void SetCurrentThreadCultureToBrowserPreferences()
  4:      {
  5:          var langs = HttpContext.Current.Request.UserLanguages;
  6:  
  7:          CultureInfo userCulture = CultureInfo.GetCultureInfo(langs[0]);
  8:  
  9:          Thread.CurrentThread.CurrentCulture = userCulture;
 10:          Thread.CurrentThread.CurrentUICulture = userCulture;
 11:      }
 12:  }

Pobieramy język wybrany jako pierwszy w ustawieniach przeglądarki… i już.

Jednak podczas działania aplikacji raz po raz coś zaczęło się wywalać. Problemem okazał się POST wysyłany przez flashowy uploadify – takie żądanie nie wysyłało UserLanguages. Więc pierwsza modyfikacja…

  1:  public static void SetCurrentThreadCultureToBrowserPreferences()
  2:  {
  3:      var langs = HttpContext.Current.Request.UserLanguages;
  4:  
  5:      if (langs != null)
  6:      {
  7:          CultureInfo userCulture = CultureInfo.GetCultureInfo(langs[0]);
  8:  
  9:          //....

Nie trwało jednak długo, zanim znalazłem kolejny problem. Otóż w przeglądarce użytkownik może przecież wybrać tzw “neutral culture”, czyli kulturę nie określającą regionu, do którego się odnosi (więcej info w MSDN). Przy próbie ustawienia takiej kultury jako UICulture dostajemy wyjątek:

Culture ‘en’ is a neutral culture. It cannot be used in formatting and parsing and therefore cannot be set as the thread’s current culture

I słusznie…

Niektóre aplikacje mogłyby sobie pozwolić na wyświetlenie w tym momencie komunikatu “wybierz w przeglądarce ‘specific’ culture”. Jest jedno ALE… nie we wszystkich przeglądarkach da się to zrobić! Na przykład domyślnie w FF 4.0 nie ma kultury “pl-PL”, jest tylko “pl”. Wymaganie od użytkownika żeby sam definiował nową kulturę na poziomie przeglądarki to trochę przegięcie.

Wystarczyło jednak kilka chwil zastanowienia i taką sytuację rozwiązałem w następujący sposób:

  1:  public static class CultureUtils
  2:  {
  3:      private static readonly CultureInfo[] _allCultures = CultureInfo.GetCultures(CultureTypes.FrameworkCultures);
  4:  
  5:      public static void SetCurrentThreadCultureToBrowserPreferences()
  6:      {
  7:          var langs = HttpContext.Current.Request.UserLanguages;
  8:  
  9:          if (langs != null)
 10:          {
 11:              CultureInfo userCulture = CultureInfo.GetCultureInfo(langs[0]);
 12:              if (userCulture.IsNeutralCulture)
 13:              {
 14:                  // browser sent neutral culture that cannot be used for parsing and formatting
 15:                  // using first non-neutral culture inheriting from this culture
 16:                  userCulture = _allCultures.Where(x => x.Parent.LCID == userCulture.LCID)
 17:                      .First();
 18:              }
 19:              Thread.CurrentThread.CurrentCulture = userCulture;
 20:              Thread.CurrentThread.CurrentUICulture = userCulture;
 21:          }
 22:      }
 23:  }

Po prostu w przypadku otrzymania neutralnej kultury wyszukuję pierwszą lepszą kulturę specific będącą jej dzieckiem. A że nie znalazłem innego sposobu niż ten przedstawiony wyżej, to zostawiam go tu ku pamięci.

0 0 votes
Article Rating
10 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Łukasz K.
12 years ago

Krótki, rzeczowy wpis – na pewno się przyda – dzięki

marek
12 years ago

Hej,

nie tylko user może wyłączyć domyślny język przeglądarki, googlebot pewnie też nie ma ustawionego domyślnego języka ;)

Sądzę, że warto także sprawdzić czy HttpContext.Current nie jest przypadkiem null, tak dla pewności.
Inna rzecz to podejżewam, że nie masz testu na ten kod ;)

Pozdrawiam,
Marek

procent
12 years ago

marek,
To prawda, na pewno w niektórych sytuacjach trzeba do tego coś dopisać. Akurat aplikacja w której zastosowałem powyższy kod nie jest wystawiana publicznie, więc google (czy cokolwiek innego poza przeglądarką) mnie nie interesuje.

A co do testu – to prawda, nie mam i w obecnej postaci raczej ciężko byłoby takowy dopisać. Ale ten kod ma pokazać technikę ustawiania kultury aplikacji na podstawie danych z przeglądarki, a nie testowania aplikacji webowych:).
Jakbym dorzucił tu przekazywanie kontekstu w parametrze konstruktora to trzeba by było dodatkowo napisać skąd instancja tej klasy się bierze, gdzie wpiąć kontener DI, jaki to ma wpływ na ControllerFactory i wiele innych rzeczy, o których tutaj pisać nie chciałem.

Michal
Michal
12 years ago

Czy był jakiś konkretny powód, dla którego nie chciałeś wykorzystać <globalization /> z web.config (http://msdn.microsoft.com/en-us/library/hy4kkhe0(v=VS.90).aspx)? Dla każdej neutral culture przypisanej do CurrentUICulture asp.net sam wybierze pierwszy specific culture i przypisze do CurrentCulture.

procent
12 years ago

Michal,
Ustawiając to w web.config decyduję się na jedną stałą kulturę… czy czegoś nie wiem?

Michal
Michal
12 years ago

procent,

Można go ustawić tak: <globalization culture="auto" uiCulture="auto"/> i wtedy pobierze sobie to z przeglądarki użytkownika. Moim zdaniem zadziała to dokładnie tak jak Twój kod, czyli odpowiednio pominie netural-culture dla CurrentCulture.

xRidx
xRidx
12 years ago

Można go ustawić tak: <globalization culture="auto" uiCulture="auto"/>
Chyba nawet z tego skorzystać ,niż powyższej klasy ,gdyż można łatwo podczepić
culture z web.config np.pod scriptmenagera ustawiając
EnableScriptGlobalization="true" EnableScriptLocalization="true"

procent
12 years ago

Michal, xRidx,
Dzięki za info, nie zdawałem sobie z tego sprawy. Jeśli tak jest to faktycznie lepiej skorzystać z auto niż z tego co napisałem:)

endrju
endrju
12 years ago

Ja to tak ogólnie nigdy nie zmuszam użytkowników do danego języka, zdarza się, że pod ręką jest przeglądarka z innym domyślnym językiem niż pożądany albo ktoś po prostu woli przeglądać w innym języku, tak więc zawsze dorzucam te flagi języka, tak na wszelki wypadek, lepsze to niż przełączać priorytety kultury w przeglądarce, przynajmniej dla użytkownika końcowego.

procent
12 years ago

endrju,
Tak jak napisałem nie jest to aplikacja publiczna i było to konkretne "feature request" od klienta. W aplikacji publicznej z pewnością znalazłby się inny mechanizm do tego.

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Książka

Zobacz również