001    /**
002     * Copyright (c) 2000-2010 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.GetterUtil;
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.StringPool;
028    import com.liferay.portal.kernel.util.StringUtil;
029    import com.liferay.portal.kernel.util.Time;
030    import com.liferay.portal.kernel.util.Validator;
031    import com.liferay.portal.model.CompanyConstants;
032    import com.liferay.portal.model.Portlet;
033    import com.liferay.portal.security.auth.CompanyThreadLocal;
034    import com.liferay.portal.service.PortletLocalServiceUtil;
035    import com.liferay.portal.theme.ThemeDisplay;
036    import com.liferay.portal.util.CookieKeys;
037    import com.liferay.portal.util.PortalUtil;
038    import com.liferay.portal.util.PortletKeys;
039    import com.liferay.portal.util.PrefsPropsUtil;
040    import com.liferay.portal.util.PropsValues;
041    import com.liferay.portal.util.WebKeys;
042    import com.liferay.portlet.PortletConfigFactoryUtil;
043    
044    import java.text.MessageFormat;
045    
046    import java.util.HashMap;
047    import java.util.HashSet;
048    import java.util.Locale;
049    import java.util.Map;
050    import java.util.MissingResourceException;
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                    String value = null;
090    
091                    try {
092                            pattern = get(locale, pattern);
093    
094                            if (arguments != null) {
095                                    pattern = _escapePattern(pattern);
096    
097                                    Object[] formattedArguments = new Object[arguments.length];
098    
099                                    for (int i = 0; i < arguments.length; i++) {
100                                            if (translateArguments) {
101                                                    formattedArguments[i] = get(
102                                                            locale, arguments[i].toString());
103                                            }
104                                            else {
105                                                    formattedArguments[i] = arguments[i];
106                                            }
107                                    }
108    
109                                    value = MessageFormat.format(pattern, formattedArguments);
110                            }
111                            else {
112                                    value = pattern;
113                            }
114                    }
115                    catch (Exception e) {
116                            if (_log.isWarnEnabled()) {
117                                    _log.warn(e, e);
118                            }
119                    }
120    
121                    return value;
122            }
123    
124            public String format(
125                    PageContext pageContext, String pattern, Object argument) {
126    
127                    return format(pageContext, pattern, new Object[] {argument}, true);
128            }
129    
130            public String format(
131                    PageContext pageContext, String pattern, Object argument,
132                    boolean translateArguments) {
133    
134                    return format(
135                            pageContext, pattern, new Object[] {argument}, translateArguments);
136            }
137    
138            public String format(
139                    PageContext pageContext, String pattern, Object[] arguments) {
140    
141                    return format(pageContext, pattern, arguments, true);
142            }
143    
144            public String format(
145                    PageContext pageContext, String pattern, Object[] arguments,
146                    boolean translateArguments) {
147    
148                    String value = null;
149    
150                    try {
151                            pattern = get(pageContext, pattern);
152    
153                            if (arguments != null) {
154                                    pattern = _escapePattern(pattern);
155    
156                                    Object[] formattedArguments = new Object[arguments.length];
157    
158                                    for (int i = 0; i < arguments.length; i++) {
159                                            if (translateArguments) {
160                                                    formattedArguments[i] =
161                                                            get(pageContext, arguments[i].toString());
162                                            }
163                                            else {
164                                                    formattedArguments[i] = arguments[i];
165                                            }
166                                    }
167    
168                                    value = MessageFormat.format(pattern, formattedArguments);
169                            }
170                            else {
171                                    value = pattern;
172                            }
173                    }
174                    catch (Exception e) {
175                            if (_log.isWarnEnabled()) {
176                                    _log.warn(e, e);
177                            }
178                    }
179    
180                    return value;
181            }
182    
183            public String format(
184                    PageContext pageContext, String pattern, LanguageWrapper argument) {
185    
186                    return format(
187                            pageContext, pattern, new LanguageWrapper[] {argument}, true);
188            }
189    
190            public String format(
191                    PageContext pageContext, String pattern, LanguageWrapper argument,
192                    boolean translateArguments) {
193    
194                    return format(
195                            pageContext, pattern, new LanguageWrapper[] {argument},
196                            translateArguments);
197            }
198    
199            public String format(
200                    PageContext pageContext, String pattern, LanguageWrapper[] arguments) {
201    
202                    return format(pageContext, pattern, arguments, true);
203            }
204    
205            public String format(
206                    PageContext pageContext, String pattern, LanguageWrapper[] arguments,
207                    boolean translateArguments) {
208    
209                    String value = null;
210    
211                    try {
212                            pattern = get(pageContext, pattern);
213    
214                            if (arguments != null) {
215                                    pattern = _escapePattern(pattern);
216    
217                                    Object[] formattedArguments = new Object[arguments.length];
218    
219                                    for (int i = 0; i < arguments.length; i++) {
220                                            if (translateArguments) {
221                                                    formattedArguments[i] =
222                                                            arguments[i].getBefore() +
223                                                            get(pageContext, arguments[i].getText()) +
224                                                            arguments[i].getAfter();
225                                            }
226                                            else {
227                                                    formattedArguments[i] =
228                                                            arguments[i].getBefore() +
229                                                            arguments[i].getText() +
230                                                            arguments[i].getAfter();
231                                            }
232                                    }
233    
234                                    value = MessageFormat.format(pattern, formattedArguments);
235                            }
236                            else {
237                                    value = pattern;
238                            }
239                    }
240                    catch (Exception e) {
241                            if (_log.isWarnEnabled()) {
242                                    _log.warn(e, e);
243                            }
244                    }
245    
246                    return value;
247            }
248    
249            public String format(
250                    PortletConfig portletConfig, Locale locale, String pattern,
251                    Object argument) {
252    
253                    return format(
254                    portletConfig, locale, pattern, new Object[] {argument}, true);
255            }
256    
257            public String format(
258                    PortletConfig portletConfig, Locale locale, String pattern,
259                    Object argument, boolean translateArguments) {
260    
261                    return format(
262                            portletConfig, locale, pattern, new Object[] {argument},
263                            translateArguments);
264            }
265    
266            public String format(
267                    PortletConfig portletConfig, Locale locale, String pattern,
268                    Object[] arguments) {
269    
270                    return format(portletConfig, locale, pattern, arguments, true);
271            }
272    
273            public String format(
274                    PortletConfig portletConfig, Locale locale, String pattern,
275                    Object[] arguments, boolean translateArguments) {
276    
277                    String value = null;
278    
279                    try {
280                            pattern = get(portletConfig, locale, pattern);
281    
282                            if (arguments != null) {
283                                    pattern = _escapePattern(pattern);
284    
285                                    Object[] formattedArguments = new Object[arguments.length];
286    
287                                    for (int i = 0; i < arguments.length; i++) {
288                                            if (translateArguments) {
289                                                    formattedArguments[i] = get(
290                                                            locale, arguments[i].toString());
291                                            }
292                                            else {
293                                                    formattedArguments[i] = arguments[i];
294                                            }
295                                    }
296    
297                                    value = MessageFormat.format(pattern, formattedArguments);
298                            }
299                            else {
300                                    value = pattern;
301                            }
302                    }
303                    catch (Exception e) {
304                            if (_log.isWarnEnabled()) {
305                                    _log.warn(e, e);
306                            }
307                    }
308    
309                    return value;
310            }
311    
312            public void init() {
313                    _instances.clear();
314            }
315    
316            public String get(Locale locale, String key) {
317                    return get(locale, key, key);
318            }
319    
320            public String get(Locale locale, String key, String defaultValue) {
321                    try {
322                            return _get(null, null, locale, key, defaultValue);
323                    }
324                    catch (Exception e) {
325                            if (_log.isWarnEnabled()) {
326                                    _log.warn(e, e);
327                            }
328    
329                            return defaultValue;
330                    }
331            }
332    
333            public String get(PageContext pageContext, String key) {
334                    return get(pageContext, key, key);
335            }
336    
337            public String get(
338                    PageContext pageContext, String key, String defaultValue) {
339    
340                    try {
341                            return _get(pageContext, null, null, key, defaultValue);
342                    }
343                    catch (Exception e) {
344                            if (_log.isWarnEnabled()) {
345                                    _log.warn(e, e);
346                            }
347    
348                            return defaultValue;
349                    }
350            }
351    
352            public String get(PortletConfig portletConfig, Locale locale, String key) {
353                    return get(portletConfig, locale, key, key);
354            }
355    
356            public String get(
357                    PortletConfig portletConfig, Locale locale, String key,
358                    String defaultValue) {
359    
360                    try {
361                            return _get(null, portletConfig, locale, key, defaultValue);
362                    }
363                    catch (Exception e) {
364                            if (_log.isWarnEnabled()) {
365                                    _log.warn(e, e);
366                            }
367    
368                            return defaultValue;
369                    }
370            }
371    
372            public Locale[] getAvailableLocales() {
373                    return _getInstance()._locales;
374            }
375    
376            public String getCharset(Locale locale) {
377                    return _getInstance()._getCharset(locale);
378            }
379    
380            public String getLanguageId(PortletRequest portletRequest) {
381                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
382                            portletRequest);
383    
384                    return getLanguageId(request);
385            }
386    
387            public String getLanguageId(HttpServletRequest request) {
388                    String languageId = ParamUtil.getString(request, "languageId");
389    
390                    if (Validator.isNotNull(languageId)) {
391                            if (_localesMap.containsKey(languageId) ||
392                                    _charEncodings.containsKey(languageId)) {
393    
394                                    return languageId;
395                            }
396                    }
397    
398                    Locale locale = PortalUtil.getLocale(request);
399    
400                    return getLanguageId(locale);
401            }
402    
403            public String getLanguageId(Locale locale) {
404                    return LocaleUtil.toLanguageId(locale);
405            }
406    
407            public Locale getLocale(String languageCode) {
408                    return _getInstance()._getLocale(languageCode);
409            }
410    
411            public String getTimeDescription(
412                    PageContext pageContext, Long milliseconds) {
413    
414                    return getTimeDescription(pageContext, milliseconds.longValue());
415            }
416    
417            public String getTimeDescription(
418                    PageContext pageContext, long milliseconds) {
419    
420                    String desc = Time.getDescription(milliseconds);
421    
422                    String value = null;
423    
424                    try {
425                            int pos = desc.indexOf(StringPool.SPACE);
426    
427                            int x = GetterUtil.getInteger(desc.substring(0, pos));
428    
429                            value =
430                                    x + " " +
431                                    get(
432                                            pageContext,
433                                            desc.substring(pos + 1, desc.length()).toLowerCase());
434                    }
435                    catch (Exception e) {
436                            if (_log.isWarnEnabled()) {
437                                    _log.warn(e, e);
438                            }
439                    }
440    
441                    return value;
442            }
443    
444            public boolean isAvailableLocale(Locale locale) {
445                    return _getInstance()._localesSet.contains(locale);
446            }
447    
448            public boolean isDuplicateLanguageCode(String languageCode) {
449                    return _getInstance()._duplicateLanguageCodes.contains(languageCode);
450            }
451    
452            public void resetAvailableLocales(long companyId) {
453                     _resetAvailableLocales(companyId);
454            }
455    
456            public void updateCookie(
457                    HttpServletRequest request, HttpServletResponse response,
458                    Locale locale) {
459    
460                    String languageId = LocaleUtil.toLanguageId(locale);
461    
462                    Cookie languageIdCookie = new Cookie(
463                            CookieKeys.GUEST_LANGUAGE_ID, languageId);
464    
465                    languageIdCookie.setPath(StringPool.SLASH);
466                    languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
467    
468                    CookieKeys.addCookie(request, response, languageIdCookie);
469            }
470    
471            private static LanguageImpl _getInstance() {
472                    long companyId = CompanyThreadLocal.getCompanyId();
473    
474                    LanguageImpl instance = _instances.get(companyId);
475    
476                    if (instance == null) {
477                            instance = new LanguageImpl(companyId);
478    
479                            _instances.put(companyId, instance);
480                    }
481    
482                    return instance;
483            }
484    
485            private LanguageImpl() {
486                    this(CompanyConstants.SYSTEM);
487            }
488    
489            private LanguageImpl(long companyId) {
490                    String[] localesArray = PropsValues.LOCALES;
491    
492                    if (companyId != CompanyConstants.SYSTEM) {
493                            try {
494                                    localesArray = PrefsPropsUtil.getStringArray(
495                                            companyId, PropsKeys.LOCALES, StringPool.COMMA,
496                                            PropsValues.LOCALES);
497                            }
498                            catch (SystemException se) {
499                                    localesArray = PropsValues.LOCALES;
500                            }
501                    }
502    
503                    _charEncodings = new HashMap<String, String>();
504                    _duplicateLanguageCodes = new HashSet<String>();
505                    _locales = new Locale[localesArray.length];
506                    _localesMap = new HashMap<String, Locale>(localesArray.length);
507                    _localesSet = new HashSet<Locale>(localesArray.length);
508    
509                    for (int i = 0; i < localesArray.length; i++) {
510                            String languageId = localesArray[i];
511    
512                            int pos = languageId.indexOf(StringPool.UNDERLINE);
513    
514                            String language = languageId.substring(0, pos);
515                            //String country = languageId.substring(pos + 1);
516    
517                            Locale locale = LocaleUtil.fromLanguageId(languageId);
518    
519                            _charEncodings.put(locale.toString(), StringPool.UTF8);
520    
521                            if (_localesMap.containsKey(language)) {
522                                    _duplicateLanguageCodes.add(language);
523                            }
524    
525                            _locales[i] = locale;
526    
527                            if (!_localesMap.containsKey(language)) {
528                                    _localesMap.put(language, locale);
529                            }
530    
531                            _localesSet.add(locale);
532                    }
533            }
534    
535            private String _escapePattern(String pattern) {
536                    return StringUtil.replace(
537                            pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
538            }
539    
540            private String _get(
541                            PageContext pageContext, PortletConfig portletConfig, Locale locale,
542                            String key, String defaultValue)
543                    throws Exception {
544    
545                    if (key == null) {
546                            return null;
547                    }
548    
549                    String value = null;
550    
551                    if (pageContext != null) {
552                            HttpServletRequest request =
553                                    (HttpServletRequest)pageContext.getRequest();
554    
555                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
556                                    WebKeys.THEME_DISPLAY);
557    
558                            locale = themeDisplay.getLocale();
559    
560                            portletConfig = (PortletConfig)request.getAttribute(
561                                    JavaConstants.JAVAX_PORTLET_CONFIG);
562                    }
563    
564                    if (portletConfig != null) {
565                            ResourceBundle resourceBundle = portletConfig.getResourceBundle(
566                                    locale);
567    
568                            try {
569                                    value = resourceBundle.getString(key);
570                            }
571                            catch (MissingResourceException mre) {
572                            }
573    
574                            // LEP-7393
575    
576                            if (((value == null) || (value.equals(defaultValue))) &&
577                                    (portletConfig.getPortletName().equals(
578                                            PortletKeys.PORTLET_CONFIGURATION))) {
579    
580                                    try {
581                                            value = _getPortletConfigurationValue(
582                                                    pageContext, locale, key);
583                                    }
584                                    catch (MissingResourceException mre) {
585                                    }
586                            }
587                    }
588    
589                    if ((value == null) || value.equals(defaultValue)) {
590                            value = LanguageResources.getMessage(locale, key);
591                    }
592    
593                    if ((value == null) || value.equals(defaultValue)) {
594                            if (key.endsWith(StringPool.CLOSE_BRACKET)) {
595                                    int pos = key.lastIndexOf(StringPool.OPEN_BRACKET);
596    
597                                    if (pos != -1) {
598                                            key = key.substring(0, pos);
599    
600                                            return _get(
601                                                    pageContext, portletConfig, locale, key, defaultValue);
602                                    }
603                            }
604                    }
605    
606                    if (value == null) {
607                            value = defaultValue;
608                    }
609    
610                    return value;
611            }
612    
613            private String _getCharset(Locale locale) {
614                    return StringPool.UTF8;
615            }
616    
617            private Locale _getLocale(String languageCode) {
618                    return _localesMap.get(languageCode);
619            }
620    
621            private String _getPortletConfigurationValue(
622                            PageContext pageContext, Locale locale, String key)
623                    throws Exception {
624    
625                    HttpServletRequest request =
626                            (HttpServletRequest)pageContext.getRequest();
627    
628                    String portletResource = ParamUtil.getString(
629                            request, "portletResource");
630    
631                    long companyId = PortalUtil.getCompanyId(request);
632    
633                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
634                            companyId, portletResource);
635    
636                    PortletConfig portletConfig = PortletConfigFactoryUtil.create(
637                            portlet, pageContext.getServletContext());
638    
639                    ResourceBundle resourceBundle = portletConfig.getResourceBundle(
640                            locale);
641    
642                    return resourceBundle.getString(key);
643            }
644    
645            private void _resetAvailableLocales(long companyId) {
646                    _instances.remove(companyId);
647            }
648    
649            private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
650    
651            private static Map<Long, LanguageImpl> _instances =
652                    new ConcurrentHashMap<Long, LanguageImpl>();
653    
654            private Map<String, String> _charEncodings;
655            private Set<String> _duplicateLanguageCodes;
656            private Locale[] _locales;
657            private Map<String, Locale> _localesMap;
658            private Set<Locale> _localesSet;
659    
660    }