2013-05-30 1 views
8

Я работаю над интернационализацией введенных пользователем данных в довольно большом клиенте/сервере (приложение HTTP (Hessian) используется для связи), которое хранится в базе данных. Пользователи могут выбирать язык, который они хотят видеть, и есть язык по умолчанию, который используется, когда перевода на запрошенный язык нет.Можно ли использовать ThreadLocal для хранения запрошенной локали?

В настоящее время класс данных может выглядеть следующим образом:

class MyDataClass { 
    private Long id; 
    private String someText; 
    /* getters and setters */ 
} 

После интернационализации она может выглядеть следующим образом:

class MyDataClass { 
    private Long id; 
    private Set<LocalizedStrings> localizedStrings; 
    /* getters and setters */ 
} 
class LocalizedStrings { 
    private Locale locale; 
    private String someText; 
    /* getters and setters */ 
} 

Конечно, это может быть интересно для создания делегата геттер в MyDataClass, который принимает уход за текстом в правильном регионе:

public String getSomeText(Locale locale) { 
    for(LocalizedString localized : localizedStrings) { 
    if (localized.getLocale().equals(locale)) { 
     return localized.getSomeText(); 
    } 
    } 
} 

В моей команде были некоторые проблемы, но о необходимости проходить локаль все время, пока они не достигнут класса данных. Так как все эти вещи происходят на сервере, и каждый запрос к серверу обрабатывается в специальной резьбе, некоторые люди предложили хранить запрашиваемую локаль в ThreadLocal объекта и создать обратный совместимый без аргументов поглотитель:

public String getSomeText() { 
    return getSomeText(myThreadLocalLocale.get()); 
} 

Затем ThreadLocal должен быть глобальной переменной (статической где-то), или ее нужно вводить в MyDataClass при каждом создании экземпляра (мы используем Spring, поэтому мы можем вставлять его, если мы сделаем наши классы данных весной управляемыми (что неправильно меня)).

Использование ThreadLocal для локали меня как-то не так. Я могу смутно утверждать, что мне не нравится невидимая магия в getter и зависимость от глобальной переменной (в классе данных!). Тем не менее, наличие «плохого чувства» об этом на самом деле не является хорошим способом спорить с моими коллегами об этом. Для того, чтобы помочь мне нужен ответ с одним из следующих способов:

  1. Скажите мне, что мое чувство отстоя и решение отлично подходит для причин X, Y и Z.
  2. Дайте мне несколько хороших Quotable аргументов я могу использовать для спорить с моими коллегами и рассказывать мне, как это сделать лучше всего (просто всегда обходите локаль вокруг или любую другую идею?)
+1

Почему вы используете набор для 'localizedStrings', а не карту? –

+0

Считаете ли вы использование Spring [LocaleContextHolder] (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/i18n/LocaleContextHolder.html). Его пружины имеют собственный способ хранения текущей локали (хранимой DispatcherServlet) для потока. – sbk

+0

Если объем вашей переменной локализации - это один поток, это кажется интеллектуальным (и простым) решением. Если вы решитесь на несколько потоков, то, очевидно, это требует чего-то большего. Если ваш API имеет информацию о локализации в каждом запросе, то это полностью действующее решение. KISS, это лучший аргумент, который вы можете сделать. –

ответ

1

Этот подход абсолютно применим. Например, Spring делает Locale доступным с использованием ThreadLocal через RequestContextListener и LocaleContextHolder.

Если вы создаете пользовательскую реализацию, убедитесь, что вы правильно обрабатываете ThreadLocal (set/remove).

1

Использование потока, локального, как вы описываете, является очень распространенным шаблоном в веб-приложениях. Смотрите этот класс в Spring API в качестве примера:

org.springframework.web.context.request.RequestContextHolder 

Используйте сервлетный фильтр (или аналогичный) к обеим установить локаль в потоке локальным, а затем очистить значение локало после того, как сервер закончил каждый запрос. Вместо того, чтобы вводить его в каждом месте, он используется, используя статический метод factory/accessor, аналогичный RequestContextHolder: RequestContextHolder.getRequestAttributes().

2

Хотя, обычной практикой я не люблю делать локализацию «глубокой» в приложении.

Intead этого:

public String getSomeText() { 
    return getSomeText(myThreadLocalLocale.get()); 
} 

Мы делаем это:

public LocalizableText getSomeText() { 
    return new LocalizableText(resourceBundle, "someText"); 
} 

А потом делать, например, в JSP или выходном слое:

<%= localizable.getString(locale) %> 

Сама логика является агностиком языка. У нас есть случаи, когда после некоторой обработки приложение отправляет результат по почте, регистрирует его и представляет его веб-пользователю на всех разных языках. Поэтому обработка вместе с формированием результата, а затем локализация должна быть отдельной.

0

ThreadLocal - плохая практика. Это глобальные переменные, и есть много статей о том, насколько это плохо, на любом языке. Тот факт, что Spring использует его, не оправдывает его использование. Мне нравится решение cruftex. Избегайте передачи данных через глобальные переменные.

Смежные вопросы