В JSF - Получение локали клиента (для отображения времени в часовом поясе браузера) - PullRequest
12 голосов
/ 22 декабря 2011

Я пишу веб-приложение в JSF 2.0, которое отображает метки времени как часть информации для пользователя.Я бы хотел, чтобы пользователь видел временные метки, локализованные по их местоположению (локаль браузера).

Пока что, что бы я ни делал, временные метки всегда будут отображаться локализованными в часовом поясе сервера.Я попытался получить локаль с помощью следующих методов:

Locale browserLocale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

или

Locale browserLocale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();

Оба вернули локаль сервера.

Затем я использую объект локали с SimpleDateFormatдля печати меток времени.

Использую ли я правильный API?
Я где-то читал, что для получения часового пояса браузера нужно использовать код на стороне клиента (Javascript).Это верно?Как бы вы это сделали?

Спасибо 'n' Advance.

ОБНОВЛЕНИЕ найдено этот (jsTimezoneDetect) код JavaScript.Но я все еще не уверен, как перевести часовой пояс в Java Locale Object

Ответы [ 6 ]

27 голосов
/ 23 декабря 2011

Вы, вероятно, должны использовать встроенный тег форматирования вместо SimpleDateFormat.Ваш вопрос подразумевает, что вы хотите показывать дату и время международному пользователю, и в этом случае вам действительно следует использовать локальный формат пользователя (они, как вы знаете, имеют тенденцию к различию).

В случае часового пояса он имеетНичего общего с интернационализацией и локализацией, то есть в США есть несколько часовых поясов.Здесь вы можете использовать два подхода:

  1. Сохранять информацию о часовом поясе в профиле пользователя (если он у вас есть).Это самый простой способ, позволяющий использовать встроенный тег <f:convertDateTime>.

  2. Получение информации о часовом поясе из веб-браузера.Вы можете получить его через запрос Ajax, как в примере с Беном.Технически вы также можете использовать тег <f:convertDateTime> здесь.

  3. Вы можете отправлять временные метки в формате UTC в каком-либо общепринятом, не зависящем от локали (или инвариантном, если хотите) формате, проанализируйте его вна стороне клиента для создания объекта даты и формата JavaScript для локали с помощью Globalize .

Ниже будут приведены некоторые примеры, но позвольте мне сначала кое-что объяснить.

Locale browserLocale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

Это будет отображать языковой стандарт веб-браузера (но не часовой пояс, поскольку не языковой стандарт).Он фактически прочитает содержимое заголовка HTTP Accept-Language и выберет наилучшую возможную локаль.Если это не работает для вас, пожалуйста, убедитесь, что вы правильно установили поддерживаемые локали в вашем faces-config.xml.Под лучшим возможным языком я понимаю, что он будет пытаться использовать наиболее предпочтительный язык пользователя (если это поддерживается вашим приложением), затем второе место и так далее.Если ни один из языковых стандартов не поддерживается, он будет возвращаться к стандартным языкам вашего приложения (опять же, faces-config.xml должен иметь этот параметр) или к стандартному языку сервера, если этот параметр отсутствует (или, по крайней мере, я так думаю, этоиз имеет смысл).

Locale browserLocale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();

Этот даст вам верхнюю локаль из заголовка Accept-Language.Пожалуйста, проверьте настройки вашего веб-браузера - почти невозможно , чтобы он мог предоставить вам языковой стандарт сервера, если они не совпадают с настройками вашего веб-браузера.Это может дать вам настройки сервера по умолчанию тогда и только тогда, когда ни одна из локалей веб-браузера не поддерживается JVM (что кажется немного маловероятным).

Кстати.FacesContext.getCurrentInstance().getExternalContext().getRequestLocales() даст вам Итератор, чтобы вы могли вручную перебирать список Locales в заголовке Accept-Language.Это просто для того, чтобы вы знали, что вы, вероятно, не должны его использовать (UIViewRoot действительно достаточно).

Теперь предположим, что у вас есть некоторый компонент с профилем пользователя и метод, который даст вам часовой пояс.Этот метод лучше, чем Ajax-вызов, в том смысле, что два разных часовых пояса могут иметь одинаковое смещение UTC, но переключать летнее время на другую дату (другими словами, некоторые временные метки будут напечатаны неправильно).В любом случае, в таком случае вы можете отформатировать свою метку времени следующим образом (дата также получена из некоторого компонента):

<h:outputText value="#{someBean.timestamp}">
  <f:convertDateTime type="both" dateStyle="default" timeStyle="default" timeZone="#{userProfile.timeZone}" />
</h:outputtext>

Теперь позвольте мне объяснить атрибуты:

  • type - что показывать, оба означают дату и время
  • dateStyle - стиль даты (из короткого, среднего, длинного, полного, по умолчанию).Вы должны действительно использовать значение по умолчанию здесь, так как это будет использовать наиболее подходящий формат для каждого Locale
  • timeStyle - аналогично стилю даты, но для временной части
  • timeZone - принимает смещение UTC (так что вы нене нужно ничего преобразовывать) или имя часового пояса (например, America / Los_Angeles).

По умолчанию тег будет использовать текущее представление Locale, поэтому вам не нужно беспокоиться об этой части, особенно есливы правильно настроили поддержку Locale.

Объединить ее с Ajax (см. ответ Бена) было бы достаточно легко (я думаю).

Я также упомянул, что вы можете записывать инвариантные даты, анализировать ихна стороне клиента, а затем отформатируйте их с помощью Globalize.Предполагая, что вы уже проанализировали дату (это зависит от представления, которое вы хотите использовать, поэтому я пропущу эту часть), это можно сделать так:

// you also have to assign the culture based on UIViewRoot locale and send it out with JavaScript
Globalize.culture(theLocale);
var formattedDateTime = Globalize.format(parsedDateTime, "f"); // this will use short date time format

В отличие от Java, у Globalize есть только короткие ("f") и длинные ("F") форматы даты и времени. Поэтому я решил использовать короткий.
Также имейте в виду, что культуры Globalize разделяются дефисом, а не подчеркиванием, поэтому вам нужен, например, «fr-CA», а не «fr_CA».
Пожалуйста, дайте мне знать, если вы хотите использовать этот метод и вам нужен более конкретный пример.

7 голосов
/ 22 декабря 2011

Преемник. Вот что я сделал:

Добавлено в JSF скрытое поле ввода, чтобы я мог отправлять значения JavaScript на сервер:

<h:form prependId="false">
    <h:inputText id="timezone_holder" value="#{bean.timezone}" styleClass="hide">
        <f:ajax listener="#{bean.timezoneChangedListener}"></f:ajax>
    </h:inputText>
</h:form>

Используя плагин выше, я запустил JavaScript код, который получил смещение браузера.

$(document).ready(function() {
    var timezone = jstz.determine_timezone();

    $("#timezone_holder").val(timezone.offset());
    $("#timezone_holder").change();
});

Когда вводится часовой пояс (инициируется из кода JavaScript выше), я запускаю этот код в eventListener:

String strFromJavaScript = getTimezone();
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext()
                .getRequest();
Locale browserLocale = request.getLocale();
TimeZone tz = TimeZone.getTimeZone("GMT" + strFromJavaScript);

// set time zone
SimpleDateFormat formatter = new SimpleDateFormat("MMM d, yyyy, HH:mm", browserLocale);
formatter.setTimeZone(tz);

Затем, когда мне нужно отформатировать дату, я использую средство форматирования даты, которое было создано выше.

2 голосов
/ 20 апреля 2013

Другим вариантом может быть создание файла cookie на Javascript, который выполняется, когда домашняя страница готова. После этого файл cookie будет существовать при каждом последующем запросе и будет доступен

Ваш Javascript может использовать jQuery и jsTimezoneDetect

    $(document).ready(function() {  
        setTimezoneCookie();
    });

    function setTimezoneCookie() {

        var timezone = jstz.determine().name();

        if (null == getCookie("timezoneCookie")) {
        document.cookie = "timezoneCookie=" + timezone;
        }
    }

    function getCookie(cookieName) {
        var cookieValue = document.cookie;
        var cookieStart = cookieValue.indexOf(" " + cookieName + "=");
        if (cookieStart == -1) {
            cookieStart = cookieValue.indexOf(cookieName + "=");
        }
        if (cookieStart == -1) {
            cookieValue = null;
        } else {
            cookieStart = cookieValue.indexOf("=", cookieStart) + 1;
            var cookieEnd = cookieValue.indexOf(";", cookieStart);
            if (cookieEnd == -1) {
                cookieEnd = cookieValue.length;
            }
            cookieValue = unescape(cookieValue.substring(cookieStart, cookieEnd));
        }
        return cookieValue;
    }

Ваш Facelet будет использовать значение куки, если оно существует:

<h:outputText value="#{bean.time}">
   <f:convertDateTime
       dateStyle="full"
       timeStyle="full"
       type="both"
       timeZone="#{cookie.timezoneCookie.value}">
   </f:convertDateTime>
</h:outputText>
2 голосов
/ 22 декабря 2011

Возможно, вы захотите попробовать jsTimezoneDetect для определения часового пояса на стороне клиента и отправки на сервер.

ОБНОВЛЕНИЕ: чтобы получить локаль пользователя, вы можете попробовать следующее:

HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
Locale locale = request.getLocale();

Возвращает перечисление объектов Locale, указывающее, в порядке убывания порядок, начиная с предпочтительного языка, языков, которые приемлемый для клиента на основе заголовка Accept-Language. Если клиентский запрос не предоставляет заголовок Accept-Language, этот метод возвращает перечисление, содержащее одну локаль, локаль по умолчанию для сервер.

0 голосов
/ 27 апреля 2012

Вы также можете использовать это прямо в коде JSF:

<script type="text/javascript">
        $(document).ready(function () {
            var timezone = jstz.determine_timezone();
            $("#timezone_holder").val(timezone.name()); //use TimeZone name instead of offset
            $("#timezone_holder").change();
        });
</script>

Затем вы можете повторно использовать имя времени в преобразователе JSF:

<f:convertDateTime pattern="dd.MM.yyyy HH:mm" timeZone="#{bean.timezone}" />
0 голосов
/ 22 декабря 2011

Если все, что вам нужно, это отображать отметки времени с местным временем пользователя, то вам не нужен объект Locale (необходимо добавить смещение часов пользователя по времени GMT + 0), Y Вам необходимо отправить значение timezone.offset () (из примера в ссылке) на сервер (вы можете сделать это, используя сообщение сервлета с параметром)

, а затем добавьте это смещение к объекту даты, созданному на вашем сервере (установите для вашего языка на сервере значение GMT ​​+ 00)

таким образом вы создадите метки времени с правильным временем пользователя, который вошел в ваше веб-приложение

(это то, что я сделал сам ...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...