001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.language;
016    
017    import com.liferay.portal.kernel.exception.SystemException;
018    import com.liferay.portal.kernel.language.Language;
019    import com.liferay.portal.kernel.language.LanguageWrapper;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.CharPool;
023    import com.liferay.portal.kernel.util.JavaConstants;
024    import com.liferay.portal.kernel.util.LocaleUtil;
025    import com.liferay.portal.kernel.util.ParamUtil;
026    import com.liferay.portal.kernel.util.PropsKeys;
027    import com.liferay.portal.kernel.util.ResourceBundleUtil;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.Time;
031    import com.liferay.portal.kernel.util.Validator;
032    import com.liferay.portal.model.CompanyConstants;
033    import com.liferay.portal.model.Portlet;
034    import com.liferay.portal.security.auth.CompanyThreadLocal;
035    import com.liferay.portal.service.PortletLocalServiceUtil;
036    import com.liferay.portal.theme.ThemeDisplay;
037    import com.liferay.portal.util.CookieKeys;
038    import com.liferay.portal.util.PortalUtil;
039    import com.liferay.portal.util.PortletKeys;
040    import com.liferay.portal.util.PrefsPropsUtil;
041    import com.liferay.portal.util.PropsValues;
042    import com.liferay.portal.util.WebKeys;
043    import com.liferay.portlet.PortletConfigFactoryUtil;
044    
045    import java.text.MessageFormat;
046    
047    import java.util.HashMap;
048    import java.util.HashSet;
049    import java.util.Locale;
050    import java.util.Map;
051    import java.util.ResourceBundle;
052    import java.util.Set;
053    import java.util.concurrent.ConcurrentHashMap;
054    
055    import javax.portlet.PortletConfig;
056    import javax.portlet.PortletRequest;
057    
058    import javax.servlet.http.Cookie;
059    import javax.servlet.http.HttpServletRequest;
060    import javax.servlet.http.HttpServletResponse;
061    import javax.servlet.jsp.PageContext;
062    
063    /**
064     * @author Brian Wing Shun Chan
065     * @author Andrius Vitkauskas
066     */
067    public class LanguageImpl implements Language {
068    
069            public String format(Locale locale, String pattern, Object argument) {
070                    return format(locale, pattern, new Object[] {argument}, true);
071            }
072    
073            public String format(
074                    Locale locale, String pattern, Object argument,
075                    boolean translateArguments) {
076    
077                    return format(
078                            locale, pattern, new Object[] {argument}, translateArguments);
079            }
080    
081            public String format(Locale locale, String pattern, Object[] arguments) {
082                    return format(locale, pattern, arguments, true);
083            }
084    
085            public String format(
086                    Locale locale, String pattern, Object[] arguments,
087                    boolean translateArguments) {
088    
089                    if (PropsValues.TRANSLATIONS_DISABLED) {
090                            return pattern;
091                    }
092    
093                    String value = null;
094    
095                    try {
096                            pattern = get(locale, pattern);
097    
098                            if ((arguments != null) && (arguments.length > 0)) {
099                                    pattern = _escapePattern(pattern);
100    
101                                    Object[] formattedArguments = new Object[arguments.length];
102    
103                                    for (int i = 0; i < arguments.length; i++) {
104                                            if (translateArguments) {
105                                                    formattedArguments[i] = get(
106                                                            locale, arguments[i].toString());
107                                            }
108                                            else {
109                                                    formattedArguments[i] = arguments[i];
110                                            }
111                                    }
112    
113                                    value = MessageFormat.format(pattern, formattedArguments);
114                            }
115                            else {
116                                    value = pattern;
117                            }
118                    }
119                    catch (Exception e) {
120                            if (_log.isWarnEnabled()) {
121                                    _log.warn(e, e);
122                            }
123                    }
124    
125                    return value;
126            }
127    
128            public String format(
129                    PageContext pageContext, String pattern, LanguageWrapper argument) {
130    
131                    return format(
132                            pageContext, pattern, new LanguageWrapper[] {argument}, true);
133            }
134    
135            public String format(
136                    PageContext pageContext, String pattern, LanguageWrapper argument,
137                    boolean translateArguments) {
138    
139                    return format(
140                            pageContext, pattern, new LanguageWrapper[] {argument},
141                            translateArguments);
142            }
143    
144            public String format(
145                    PageContext pageContext, String pattern, LanguageWrapper[] arguments) {
146    
147                    return format(pageContext, pattern, arguments, true);
148            }
149    
150            public String format(
151                    PageContext pageContext, String pattern, LanguageWrapper[] arguments,
152                    boolean translateArguments) {
153    
154                    if (PropsValues.TRANSLATIONS_DISABLED) {
155                            return pattern;
156                    }
157    
158                    String value = null;
159    
160                    try {
161                            pattern = get(pageContext, pattern);
162    
163                            if ((arguments != null) && (arguments.length > 0)) {
164                                    pattern = _escapePattern(pattern);
165    
166                                    Object[] formattedArguments = new Object[arguments.length];
167    
168                                    for (int i = 0; i < arguments.length; i++) {
169                                            if (translateArguments) {
170                                                    formattedArguments[i] =
171                                                            arguments[i].getBefore() +
172                                                            get(pageContext, arguments[i].getText()) +
173                                                            arguments[i].getAfter();
174                                            }
175                                            else {
176                                                    formattedArguments[i] =
177                                                            arguments[i].getBefore() +
178                                                            arguments[i].getText() +
179                                                            arguments[i].getAfter();
180                                            }
181                                    }
182    
183                                    value = MessageFormat.format(pattern, formattedArguments);
184                            }
185                            else {
186                                    value = pattern;
187                            }
188                    }
189                    catch (Exception e) {
190                            if (_log.isWarnEnabled()) {
191                                    _log.warn(e, e);
192                            }
193                    }
194    
195                    return value;
196            }
197    
198            public String format(
199                    PageContext pageContext, String pattern, Object argument) {
200    
201                    return format(pageContext, pattern, new Object[] {argument}, true);
202            }
203    
204            public String format(
205                    PageContext pageContext, String pattern, Object argument,
206                    boolean translateArguments) {
207    
208                    return format(
209                            pageContext, pattern, new Object[] {argument}, translateArguments);
210            }
211    
212            public String format(
213                    PageContext pageContext, String pattern, Object[] arguments) {
214    
215                    return format(pageContext, pattern, arguments, true);
216            }
217    
218            public String format(
219                    PageContext pageContext, String pattern, Object[] arguments,
220                    boolean translateArguments) {
221    
222                    if (PropsValues.TRANSLATIONS_DISABLED) {
223                            return pattern;
224                    }
225    
226                    String value = null;
227    
228                    try {
229                            pattern = get(pageContext, pattern);
230    
231                            if ((arguments != null) && (arguments.length > 0)) {
232                                    pattern = _escapePattern(pattern);
233    
234                                    Object[] formattedArguments = new Object[arguments.length];
235    
236                                    for (int i = 0; i < arguments.length; i++) {
237                                            if (translateArguments) {
238                                                    formattedArguments[i] = get(
239                                                            pageContext, arguments[i].toString());
240                                            }
241                                            else {
242                                                    formattedArguments[i] = arguments[i];
243                                            }
244                                    }
245    
246                                    value = MessageFormat.format(pattern, formattedArguments);
247                            }
248                            else {
249                                    value = pattern;
250                            }
251                    }
252                    catch (Exception e) {
253                            if (_log.isWarnEnabled()) {
254                                    _log.warn(e, e);
255                            }
256                    }
257    
258                    return value;
259            }
260    
261            public String format(
262                    PortletConfig portletConfig, Locale locale, String pattern,
263                    Object argument) {
264    
265                    return format(
266                    portletConfig, locale, pattern, new Object[] {argument}, true);
267            }
268    
269            public String format(
270                    PortletConfig portletConfig, Locale locale, String pattern,
271                    Object argument, boolean translateArguments) {
272    
273                    return format(
274                            portletConfig, locale, pattern, new Object[] {argument},
275                            translateArguments);
276            }
277    
278            public String format(
279                    PortletConfig portletConfig, Locale locale, String pattern,
280                    Object[] arguments) {
281    
282                    return format(portletConfig, locale, pattern, arguments, true);
283            }
284    
285            public String format(
286                    PortletConfig portletConfig, Locale locale, String pattern,
287                    Object[] arguments, boolean translateArguments) {
288    
289                    if (PropsValues.TRANSLATIONS_DISABLED) {
290                            return pattern;
291                    }
292    
293                    String value = null;
294    
295                    try {
296                            pattern = get(portletConfig, locale, pattern);
297    
298                            if ((arguments != null) && (arguments.length > 0)) {
299                                    pattern = _escapePattern(pattern);
300    
301                                    Object[] formattedArguments = new Object[arguments.length];
302    
303                                    for (int i = 0; i < arguments.length; i++) {
304                                            if (translateArguments) {
305                                                    formattedArguments[i] = get(
306                                                            locale, arguments[i].toString());
307                                            }
308                                            else {
309                                                    formattedArguments[i] = arguments[i];
310                                            }
311                                    }
312    
313                                    value = MessageFormat.format(pattern, formattedArguments);
314                            }
315                            else {
316                                    value = pattern;
317                            }
318                    }
319                    catch (Exception e) {
320                            if (_log.isWarnEnabled()) {
321                                    _log.warn(e, e);
322                            }
323                    }
324    
325                    return value;
326            }
327    
328            public String get(Locale locale, String key) {
329                    return get(locale, key, key);
330            }
331    
332            public String get(Locale locale, String key, String defaultValue) {
333                    if (PropsValues.TRANSLATIONS_DISABLED) {
334                            return key;
335                    }
336    
337                    if (key == null) {
338                            return null;
339                    }
340    
341                    String value = LanguageResources.getMessage(locale, key);
342    
343                    while ((value == null) || value.equals(defaultValue)) {
344                            if ((key.length() > 0) &&
345                                    (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
346    
347                                    int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
348    
349                                    if (pos != -1) {
350                                            key = key.substring(0, pos);
351    
352                                            value = LanguageResources.getMessage(locale, key);
353    
354                                            continue;
355                                    }
356                            }
357    
358                            break;
359                    }
360    
361                    if (value == null) {
362                            value = defaultValue;
363                    }
364    
365                    return value;
366            }
367    
368            public String get(PageContext pageContext, String key) {
369                    return get(pageContext, key, key);
370            }
371    
372            public String get(
373                    PageContext pageContext, String key, String defaultValue) {
374    
375                    try {
376                            return _get(pageContext, null, null, key, defaultValue);
377                    }
378                    catch (Exception e) {
379                            if (_log.isWarnEnabled()) {
380                                    _log.warn(e, e);
381                            }
382    
383                            return defaultValue;
384                    }
385            }
386    
387            public String get(PortletConfig portletConfig, Locale locale, String key) {
388                    return get(portletConfig, locale, key, key);
389            }
390    
391            public String get(
392                    PortletConfig portletConfig, Locale locale, String key,
393                    String defaultValue) {
394    
395                    try {
396                            return _get(null, portletConfig, locale, key, defaultValue);
397                    }
398                    catch (Exception e) {
399                            if (_log.isWarnEnabled()) {
400                                    _log.warn(e, e);
401                            }
402    
403                            return defaultValue;
404                    }
405            }
406    
407            public Locale[] getAvailableLocales() {
408                    return _getInstance()._locales;
409            }
410    
411            public String getCharset(Locale locale) {
412                    return _getInstance()._getCharset(locale);
413            }
414    
415            public String getLanguageId(HttpServletRequest request) {
416                    String languageId = ParamUtil.getString(request, "languageId");
417    
418                    if (Validator.isNotNull(languageId)) {
419                            if (_localesMap.containsKey(languageId) ||
420                                    _charEncodings.containsKey(languageId)) {
421    
422                                    return languageId;
423                            }
424                    }
425    
426                    Locale locale = PortalUtil.getLocale(request);
427    
428                    return getLanguageId(locale);
429            }
430    
431            public String getLanguageId(Locale locale) {
432                    return LocaleUtil.toLanguageId(locale);
433            }
434    
435            public String getLanguageId(PortletRequest portletRequest) {
436                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
437                            portletRequest);
438    
439                    return getLanguageId(request);
440            }
441    
442            public Locale getLocale(String languageCode) {
443                    return _getInstance()._getLocale(languageCode);
444            }
445    
446            public String getTimeDescription(
447                    PageContext pageContext, long milliseconds) {
448    
449                    return getTimeDescription(pageContext, milliseconds, false);
450            }
451    
452            public String getTimeDescription(
453                    PageContext pageContext, long milliseconds, boolean approximate) {
454    
455                    String description = Time.getDescription(milliseconds, approximate);
456    
457                    String value = null;
458    
459                    try {
460                            int pos = description.indexOf(CharPool.SPACE);
461    
462                            String x = description.substring(0, pos);
463    
464                            value = x.concat(StringPool.SPACE).concat(
465                                    get(
466                                            pageContext,
467                                            description.substring(
468                                                    pos + 1, description.length()).toLowerCase()));
469                    }
470                    catch (Exception e) {
471                            if (_log.isWarnEnabled()) {
472                                    _log.warn(e, e);
473                            }
474                    }
475    
476                    return value;
477            }
478    
479            public String getTimeDescription(
480                    PageContext pageContext, Long milliseconds) {
481    
482                    return getTimeDescription(pageContext, milliseconds.longValue());
483            }
484    
485            public void init() {
486                    _instances.clear();
487            }
488    
489            public boolean isAvailableLocale(Locale locale) {
490                    return _getInstance()._localesSet.contains(locale);
491            }
492    
493            public boolean isBetaLocale(Locale locale) {
494                    return _getInstance()._localesBetaSet.contains(locale);
495            }
496    
497            public boolean isDuplicateLanguageCode(String languageCode) {
498                    return _getInstance()._duplicateLanguageCodes.contains(languageCode);
499            }
500    
501            public void resetAvailableLocales(long companyId) {
502                     _resetAvailableLocales(companyId);
503            }
504    
505            public void updateCookie(
506                    HttpServletRequest request, HttpServletResponse response,
507                    Locale locale) {
508    
509                    String languageId = LocaleUtil.toLanguageId(locale);
510    
511                    Cookie languageIdCookie = new Cookie(
512                            CookieKeys.GUEST_LANGUAGE_ID, languageId);
513    
514                    languageIdCookie.setPath(StringPool.SLASH);
515                    languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
516    
517                    CookieKeys.addCookie(request, response, languageIdCookie);
518            }
519    
520            private static LanguageImpl _getInstance() {
521                    Long companyId = CompanyThreadLocal.getCompanyId();
522    
523                    LanguageImpl instance = _instances.get(companyId);
524    
525                    if (instance == null) {
526                            instance = new LanguageImpl(companyId);
527    
528                            _instances.put(companyId, instance);
529                    }
530    
531                    return instance;
532            }
533    
534            private LanguageImpl() {
535                    this(CompanyConstants.SYSTEM);
536            }
537    
538            private LanguageImpl(long companyId) {
539                    String[] localesArray = PropsValues.LOCALES;
540    
541                    if (companyId != CompanyConstants.SYSTEM) {
542                            try {
543                                    localesArray = PrefsPropsUtil.getStringArray(
544                                            companyId, PropsKeys.LOCALES, StringPool.COMMA,
545                                            PropsValues.LOCALES);
546                            }
547                            catch (SystemException se) {
548                                    localesArray = PropsValues.LOCALES;
549                            }
550                    }
551    
552                    _charEncodings = new HashMap<String, String>();
553                    _duplicateLanguageCodes = new HashSet<String>();
554                    _locales = new Locale[localesArray.length];
555                    _localesMap = new HashMap<String, Locale>(localesArray.length);
556                    _localesSet = new HashSet<Locale>(localesArray.length);
557    
558                    for (int i = 0; i < localesArray.length; i++) {
559                            String languageId = localesArray[i];
560    
561                            Locale locale = LocaleUtil.fromLanguageId(languageId);
562    
563                            _charEncodings.put(locale.toString(), StringPool.UTF8);
564    
565                            String language = languageId;
566    
567                            int pos = languageId.indexOf(CharPool.UNDERLINE);
568    
569                            if (pos > 0) {
570                                    language = languageId.substring(0, pos);
571                            }
572    
573                            if (_localesMap.containsKey(language)) {
574                                    _duplicateLanguageCodes.add(language);
575                            }
576    
577                            _locales[i] = locale;
578    
579                            if (!_localesMap.containsKey(language)) {
580                                    _localesMap.put(language, locale);
581                            }
582    
583                            _localesSet.add(locale);
584                    }
585    
586                    String[] localesBetaArray = PropsValues.LOCALES_BETA;
587    
588                    _localesBetaSet = new HashSet<Locale>(localesBetaArray.length);
589    
590                    for (String languageId : localesBetaArray) {
591                            Locale locale = LocaleUtil.fromLanguageId(languageId);
592    
593                            _localesBetaSet.add(locale);
594                    }
595            }
596    
597            private String _escapePattern(String pattern) {
598                    return StringUtil.replace(
599                            pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
600            }
601    
602            private String _get(
603                            PageContext pageContext, PortletConfig portletConfig, Locale locale,
604                            String key, String defaultValue)
605                    throws Exception {
606    
607                    if (PropsValues.TRANSLATIONS_DISABLED) {
608                            return key;
609                    }
610    
611                    if (key == null) {
612                            return null;
613                    }
614    
615                    String value = null;
616    
617                    if (pageContext != null) {
618                            HttpServletRequest request =
619                                    (HttpServletRequest)pageContext.getRequest();
620    
621                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
622                                    WebKeys.THEME_DISPLAY);
623    
624                            locale = themeDisplay.getLocale();
625    
626                            portletConfig = (PortletConfig)request.getAttribute(
627                                    JavaConstants.JAVAX_PORTLET_CONFIG);
628                    }
629    
630                    if (portletConfig != null) {
631                            ResourceBundle resourceBundle = portletConfig.getResourceBundle(
632                                    locale);
633    
634                            value = ResourceBundleUtil.getString(resourceBundle, key);
635    
636                            // LEP-7393
637    
638                            String portletName = portletConfig.getPortletName();
639    
640                            if (((value == null) || (value.equals(defaultValue))) &&
641                                    (portletName.equals(PortletKeys.PORTLET_CONFIGURATION))) {
642    
643                                    value = _getPortletConfigurationValue(pageContext, locale, key);
644                            }
645    
646                            if (value != null) {
647                                    value = LanguageResources.fixValue(value);
648                            }
649                    }
650    
651                    if ((value == null) || value.equals(defaultValue)) {
652                            value = LanguageResources.getMessage(locale, key);
653                    }
654    
655                    if ((value == null) || value.equals(defaultValue)) {
656                            if ((key.length() > 0) &&
657                                    (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
658    
659                                    int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
660    
661                                    if (pos != -1) {
662                                            key = key.substring(0, pos);
663    
664                                            return _get(
665                                                    pageContext, portletConfig, locale, key, defaultValue);
666                                    }
667                            }
668                    }
669    
670                    if ((value == null) || value.equals(key)) {
671                            value = defaultValue;
672                    }
673    
674                    return value;
675            }
676    
677            private String _getCharset(Locale locale) {
678                    return StringPool.UTF8;
679            }
680    
681            private Locale _getLocale(String languageCode) {
682                    return _localesMap.get(languageCode);
683            }
684    
685            private String _getPortletConfigurationValue(
686                            PageContext pageContext, Locale locale, String key)
687                    throws Exception {
688    
689                    if (PropsValues.TRANSLATIONS_DISABLED) {
690                            return key;
691                    }
692    
693                    HttpServletRequest request =
694                            (HttpServletRequest)pageContext.getRequest();
695    
696                    String portletResource = ParamUtil.getString(
697                            request, "portletResource");
698    
699                    long companyId = PortalUtil.getCompanyId(request);
700    
701                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
702                            companyId, portletResource);
703    
704                    PortletConfig portletConfig = PortletConfigFactoryUtil.create(
705                            portlet, pageContext.getServletContext());
706    
707                    ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
708    
709                    return ResourceBundleUtil.getString(resourceBundle, key);
710            }
711    
712            private void _resetAvailableLocales(long companyId) {
713                    _instances.remove(companyId);
714            }
715    
716            private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
717    
718            private static Map<Long, LanguageImpl> _instances =
719                    new ConcurrentHashMap<Long, LanguageImpl>();
720    
721            private Map<String, String> _charEncodings;
722            private Set<String> _duplicateLanguageCodes;
723            private Locale[] _locales;
724            private Set<Locale> _localesBetaSet;
725            private Map<String, Locale> _localesMap;
726            private Set<Locale> _localesSet;
727    
728    }