package org.sigmah.server.util; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.sigmah.shared.Cookies; import org.sigmah.shared.Language; /** * <b>Server-side</b> utility class for {@link Language} enum. * * @author Denis Colliot (dcolliot@ideia.fr) * @see org.sigmah.shared.Language */ public final class Languages { /** * <p> * Default language. * </p> * <p> * This default value is set <em>only</em> when user has no cookie <b>and</b> no available language can be detected * from HTTP request header. * </p> * <p> * This default value should match the <b>fallback</b> {@code locale} property's value set into {@code Sigmah.gwt.xml} * module file: * * <pre> * <set-property-fallback name="locale" value="<b><u>en</u></b>" /> * </pre> * * </p> */ public static final Language DEFAULT_LANGUAGE = Language.EN; /** * HTTP request {@code Accept-Language} header name. */ private static final String ACCEPT_LANGUAGE_HEADER = "Accept-Language"; /** * <p> * Gets the current user {@link Language}. * </p> * <p> * The method follows this pattern: * <ol> * <li>Determines language instance from language cookie in {@code request}. If cookie is missing or does not * reference a valid available language, method attempts rule #2.</li> * <li>Determines language instance from {@code request} headers ; see * {@code http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4}. If language cannot be determined from * request headers, method applies rule #3.</li> * <li><em>Last resort (should most-likely never happen):</em> returns a default locale ; see * {@link #DEFAULT_LANGUAGE}.</li> * </ol> * </p> * * @param request * The HTTP request. * @return The current user {@link Language}. If no language can be determined from {@code request}, the method * returns a default value (never returns {@code null}). */ public static Language getLanguage(final HttpServletRequest request) { // Attempt to retrieve locale from cookies. final Cookie[] cookies = request != null ? request.getCookies() : null; if (cookies != null) { for (final Cookie cookie : cookies) { if (Cookies.LANGUAGE_COOKIE.equals(cookie.getName())) { final Language language = Language.fromString(cookie.getValue()); if (language != null) { return language; } break; } } } // Attempt to retrieve locale from request headers. final String acceptLanguageHeader = request != null ? request.getHeader(ACCEPT_LANGUAGE_HEADER) : null; if (StringUtils.isNotBlank(acceptLanguageHeader)) { for (final String acceptLanguageToken : acceptLanguageHeader.split(",|;|-|_")) { if (acceptLanguageToken.contains("=")) { continue; // Not a valid language token. } final Language language = Language.fromString(acceptLanguageToken); if (language != null) { return language; } } } // Last resort: default value. return DEFAULT_LANGUAGE; } /** * Returns the given {@code language} or default language if {@code null}. * Ensures that a valid language is always returned. * * @param language * The language instance. * @return The given {@code language} or default language if {@code null} (never returns {@code null}). * @see Languages#DEFAULT_LANGUAGE */ public static final Language notNull(final Language language) { return language != null ? language : DEFAULT_LANGUAGE; } /** * Returns the given {@code language} corresponding file suffix. * * <pre> * getFileSuffix(EN, null) → "" (<em>Special case for default language</em>) * getFileSuffix(FR, null) → "_fr" * getFileSuffix(ES, null) → "_es" * getFileSuffix(EN, ".properties") → ".properties" (<em>Special case for default language</em>) * getFileSuffix(FR, ".properties") → "_fr.properties" * getFileSuffix(ES, ".properties") → "_es.properties" * </pre> * * @param language * The language instance, may be {@code null}. * @param extension * (optional) The file extension to append at the end of the suffix. Should contain the extension separator. * @return The given {@code language} corresponding file suffix or empty if default language, never {@code null}. */ public static final String getFileSuffix(final Language language, final String extension) { if (notNull(language) == DEFAULT_LANGUAGE) { // FIXME REMOVE THIS BLOCK IF "_en" I18N FILES ARE RESTORED return "" + StringUtils.trimToEmpty(extension); } return '_' + notNull(language).getLocale() + StringUtils.trimToEmpty(extension); } /** * Utility class constructor (unused). */ private Languages() { // Only provides static methods. } }