1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.language;
16  
17  import com.liferay.portal.kernel.exception.SystemException;
18  import com.liferay.portal.kernel.language.Language;
19  import com.liferay.portal.kernel.language.LanguageWrapper;
20  import com.liferay.portal.kernel.log.Log;
21  import com.liferay.portal.kernel.log.LogFactoryUtil;
22  import com.liferay.portal.kernel.util.GetterUtil;
23  import com.liferay.portal.kernel.util.JavaConstants;
24  import com.liferay.portal.kernel.util.LocaleUtil;
25  import com.liferay.portal.kernel.util.ParamUtil;
26  import com.liferay.portal.kernel.util.PropsKeys;
27  import com.liferay.portal.kernel.util.StringBundler;
28  import com.liferay.portal.kernel.util.StringPool;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.kernel.util.Time;
31  import com.liferay.portal.kernel.util.Validator;
32  import com.liferay.portal.model.CompanyConstants;
33  import com.liferay.portal.model.Portlet;
34  import com.liferay.portal.security.auth.CompanyThreadLocal;
35  import com.liferay.portal.service.PortletLocalServiceUtil;
36  import com.liferay.portal.theme.ThemeDisplay;
37  import com.liferay.portal.util.CookieKeys;
38  import com.liferay.portal.util.PortalUtil;
39  import com.liferay.portal.util.PortletKeys;
40  import com.liferay.portal.util.PrefsPropsUtil;
41  import com.liferay.portal.util.PropsValues;
42  import com.liferay.portal.util.WebKeys;
43  import com.liferay.portlet.PortletConfigFactory;
44  
45  import java.text.MessageFormat;
46  
47  import java.util.HashMap;
48  import java.util.HashSet;
49  import java.util.Locale;
50  import java.util.Map;
51  import java.util.MissingResourceException;
52  import java.util.ResourceBundle;
53  import java.util.Set;
54  import java.util.concurrent.ConcurrentHashMap;
55  
56  import javax.portlet.PortletConfig;
57  import javax.portlet.PortletRequest;
58  
59  import javax.servlet.http.Cookie;
60  import javax.servlet.http.HttpServletRequest;
61  import javax.servlet.http.HttpServletResponse;
62  import javax.servlet.jsp.PageContext;
63  
64  import org.apache.struts.taglib.TagUtils;
65  
66  /**
67   * <a href="LanguageImpl.java.html"><b><i>View Source</i></b></a>
68   *
69   * @author Brian Wing Shun Chan
70   * @author Andrius Vitkauskas
71   */
72  public class LanguageImpl implements Language {
73  
74      public String format(Locale locale, String pattern, Object argument) {
75          return format(locale, pattern, new Object[] {argument}, true);
76      }
77  
78      public String format(
79          Locale locale, String pattern, Object argument,
80          boolean translateArguments) {
81  
82          return format(
83              locale, pattern, new Object[] {argument}, translateArguments);
84      }
85  
86      public String format(Locale locale, String pattern, Object[] arguments) {
87          return format(locale, pattern, arguments, true);
88      }
89  
90      public String format(
91          Locale locale, String pattern, Object[] arguments,
92          boolean translateArguments) {
93  
94          String value = null;
95  
96          try {
97              pattern = get(locale, pattern);
98  
99              if (arguments != null) {
100                 pattern = _escapePattern(pattern);
101 
102                 Object[] formattedArguments = new Object[arguments.length];
103 
104                 for (int i = 0; i < arguments.length; i++) {
105                     if (translateArguments) {
106                         formattedArguments[i] = get(
107                             locale, arguments[i].toString());
108                     }
109                     else {
110                         formattedArguments[i] = arguments[i];
111                     }
112                 }
113 
114                 value = MessageFormat.format(pattern, formattedArguments);
115             }
116             else {
117                 value = pattern;
118             }
119         }
120         catch (Exception e) {
121             if (_log.isWarnEnabled()) {
122                 _log.warn(e, e);
123             }
124         }
125 
126         return value;
127     }
128 
129     public String format(
130         PageContext pageContext, String pattern, Object argument) {
131 
132         return format(pageContext, pattern, new Object[] {argument}, true);
133     }
134 
135     public String format(
136         PageContext pageContext, String pattern, Object argument,
137         boolean translateArguments) {
138 
139         return format(
140             pageContext, pattern, new Object[] {argument}, translateArguments);
141     }
142 
143     public String format(
144         PageContext pageContext, String pattern, Object[] arguments) {
145 
146         return format(pageContext, pattern, arguments, true);
147     }
148 
149     public String format(
150         PageContext pageContext, String pattern, Object[] arguments,
151         boolean translateArguments) {
152 
153         String value = null;
154 
155         try {
156             pattern = get(pageContext, pattern);
157 
158             if (arguments != null) {
159                 pattern = _escapePattern(pattern);
160 
161                 Object[] formattedArguments = new Object[arguments.length];
162 
163                 for (int i = 0; i < arguments.length; i++) {
164                     if (translateArguments) {
165                         formattedArguments[i] =
166                             get(pageContext, arguments[i].toString());
167                     }
168                     else {
169                         formattedArguments[i] = arguments[i];
170                     }
171                 }
172 
173                 value = MessageFormat.format(pattern, formattedArguments);
174             }
175             else {
176                 value = pattern;
177             }
178         }
179         catch (Exception e) {
180             if (_log.isWarnEnabled()) {
181                 _log.warn(e, e);
182             }
183         }
184 
185         return value;
186     }
187 
188     public String format(
189         PageContext pageContext, String pattern, LanguageWrapper argument) {
190 
191         return format(
192             pageContext, pattern, new LanguageWrapper[] {argument}, true);
193     }
194 
195     public String format(
196         PageContext pageContext, String pattern, LanguageWrapper argument,
197         boolean translateArguments) {
198 
199         return format(
200             pageContext, pattern, new LanguageWrapper[] {argument},
201             translateArguments);
202     }
203 
204     public String format(
205         PageContext pageContext, String pattern, LanguageWrapper[] arguments) {
206 
207         return format(pageContext, pattern, arguments, true);
208     }
209 
210     public String format(
211         PageContext pageContext, String pattern, LanguageWrapper[] arguments,
212         boolean translateArguments) {
213 
214         String value = null;
215 
216         try {
217             pattern = get(pageContext, pattern);
218 
219             if (arguments != null) {
220                 pattern = _escapePattern(pattern);
221 
222                 Object[] formattedArguments = new Object[arguments.length];
223 
224                 for (int i = 0; i < arguments.length; i++) {
225                     if (translateArguments) {
226                         formattedArguments[i] =
227                             arguments[i].getBefore() +
228                             get(pageContext, arguments[i].getText()) +
229                             arguments[i].getAfter();
230                     }
231                     else {
232                         formattedArguments[i] =
233                             arguments[i].getBefore() +
234                             arguments[i].getText() +
235                             arguments[i].getAfter();
236                     }
237                 }
238 
239                 value = MessageFormat.format(pattern, formattedArguments);
240             }
241             else {
242                 value = pattern;
243             }
244         }
245         catch (Exception e) {
246             if (_log.isWarnEnabled()) {
247                 _log.warn(e, e);
248             }
249         }
250 
251         return value;
252     }
253 
254     public void init() {
255         _instances.clear();
256     }
257 
258     public String get(Locale locale, String key) {
259         return get(locale, key, key);
260     }
261 
262     public String get(Locale locale, String key, String defaultValue) {
263         if (key == null) {
264             return null;
265         }
266 
267         String value = null;
268 
269         try {
270             if (LanguageResources.isInitialized()) {
271 
272                 // LEP-4505
273 
274                 ResourceBundle bundle = ResourceBundle.getBundle(
275                     "content/Language", locale);
276 
277                 value = bundle.getString(key);
278             }
279             else {
280                 value = LanguageResources.getMessage(locale, key);
281             }
282         }
283         catch (Exception e) {
284             if (_log.isWarnEnabled()) {
285                 _log.warn(e, e);
286             }
287         }
288 
289         if (value == null) {
290             value = defaultValue;
291         }
292 
293         return value;
294     }
295 
296     public String get(PageContext pageContext, String key) {
297         return get(pageContext, key, key);
298     }
299 
300     public String get(
301         PageContext pageContext, String key, String defaultValue) {
302 
303         HttpServletRequest request =
304             (HttpServletRequest)pageContext.getRequest();
305 
306         ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
307             WebKeys.THEME_DISPLAY);
308 
309         PortletConfig portletConfig = (PortletConfig)request.getAttribute(
310             JavaConstants.JAVAX_PORTLET_CONFIG);
311 
312         String value = null;
313 
314         if (themeDisplay != null) {
315             if ((portletConfig != null) && (key != null) &&
316                 (!key.endsWith(StringPool.CLOSE_BRACKET))) {
317 
318                 StringBundler sb = new StringBundler(4);
319 
320                 sb.append(key);
321                 sb.append(StringPool.OPEN_BRACKET);
322                 sb.append(portletConfig.getPortletName());
323                 sb.append(StringPool.CLOSE_BRACKET);
324 
325                 key = sb.toString();
326             }
327 
328             value = get(themeDisplay.getLocale(), key, defaultValue);
329 
330             if (((value == null) || (value.equals(defaultValue))) &&
331                 ((key != null) && (key.endsWith(StringPool.CLOSE_BRACKET)))) {
332 
333                 int pos = key.lastIndexOf(StringPool.OPEN_BRACKET);
334 
335                 if (pos != -1) {
336                     key = key.substring(0, pos);
337 
338                     value = get(themeDisplay.getLocale(), key, defaultValue);
339                 }
340             }
341 
342             // LEP-7292
343 
344             if ((value != null) && !value.equals(defaultValue)) {
345                 return value;
346             }
347         }
348 
349         if (key == null) {
350             return null;
351         }
352 
353         try {
354             value = TagUtils.getInstance().message(
355                 pageContext, null, null, key);
356         }
357         catch (Exception e) {
358             if (_log.isWarnEnabled()) {
359                 _log.warn(e);
360             }
361         }
362 
363         if ((value == null) || value.equals(defaultValue)) {
364 
365             // LEP-2849
366 
367             if (portletConfig != null) {
368                 Locale locale = request.getLocale();
369 
370                 ResourceBundle bundle = portletConfig.getResourceBundle(locale);
371 
372                 try {
373                     value = bundle.getString(key);
374                 }
375                 catch (MissingResourceException mre) {
376                 }
377 
378                 // LEP-7393
379 
380                 if (((value == null) || (value.equals(defaultValue))) &&
381                     (portletConfig.getPortletName().equals(
382                         PortletKeys.PORTLET_CONFIGURATION))) {
383 
384                     value = _getPortletConfigurationValue(pageContext, key);
385                 }
386             }
387         }
388 
389         if (value == null) {
390             value = defaultValue;
391         }
392 
393         return value;
394     }
395 
396     public Locale[] getAvailableLocales() {
397         return _getInstance()._locales;
398     }
399 
400     public String getCharset(Locale locale) {
401         return _getInstance()._getCharset(locale);
402     }
403 
404     public String getLanguageId(PortletRequest portletRequest) {
405         HttpServletRequest request = PortalUtil.getHttpServletRequest(
406             portletRequest);
407 
408         return getLanguageId(request);
409     }
410 
411     public String getLanguageId(HttpServletRequest request) {
412         String languageId = ParamUtil.getString(request, "languageId");
413 
414         if (Validator.isNotNull(languageId)) {
415             if (_localesMap.containsKey(languageId) ||
416                 _charEncodings.containsKey(languageId)) {
417 
418                 return languageId;
419             }
420         }
421 
422         Locale locale = PortalUtil.getLocale(request);
423 
424         return getLanguageId(locale);
425     }
426 
427     public String getLanguageId(Locale locale) {
428         return LocaleUtil.toLanguageId(locale);
429     }
430 
431     public Locale getLocale(String languageCode) {
432         return _getInstance()._getLocale(languageCode);
433     }
434 
435     public String getTimeDescription(
436         PageContext pageContext, Long milliseconds) {
437 
438         return getTimeDescription(pageContext, milliseconds.longValue());
439     }
440 
441     public String getTimeDescription(
442         PageContext pageContext, long milliseconds) {
443 
444         String desc = Time.getDescription(milliseconds);
445 
446         String value = null;
447 
448         try {
449             int pos = desc.indexOf(StringPool.SPACE);
450 
451             int x = GetterUtil.getInteger(desc.substring(0, pos));
452 
453             value =
454                 x + " " +
455                 get(
456                     pageContext,
457                     desc.substring(pos + 1, desc.length()).toLowerCase());
458         }
459         catch (Exception e) {
460             if (_log.isWarnEnabled()) {
461                 _log.warn(e, e);
462             }
463         }
464 
465         return value;
466     }
467 
468     public boolean isAvailableLocale(Locale locale) {
469         return _getInstance()._localesSet.contains(locale);
470     }
471 
472     public boolean isDuplicateLanguageCode(String languageCode) {
473         return _getInstance()._duplicateLanguageCodes.contains(languageCode);
474     }
475 
476     public void resetAvailableLocales(long companyId) {
477          _resetAvailableLocales(companyId);
478     }
479 
480     public void updateCookie(
481         HttpServletRequest request, HttpServletResponse response,
482         Locale locale) {
483 
484         String languageId = LocaleUtil.toLanguageId(locale);
485 
486         Cookie languageIdCookie = new Cookie(
487             CookieKeys.GUEST_LANGUAGE_ID, languageId);
488 
489         languageIdCookie.setPath(StringPool.SLASH);
490         languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
491 
492         CookieKeys.addCookie(request, response, languageIdCookie);
493     }
494 
495     private static LanguageImpl _getInstance() {
496         long companyId = CompanyThreadLocal.getCompanyId();
497 
498         LanguageImpl instance = _instances.get(companyId);
499 
500         if (instance == null) {
501             instance = new LanguageImpl(companyId);
502 
503             _instances.put(companyId, instance);
504         }
505 
506         return instance;
507     }
508 
509     private LanguageImpl() {
510         this(CompanyConstants.SYSTEM);
511     }
512 
513     private LanguageImpl(long companyId) {
514         String[] localesArray = PropsValues.LOCALES;
515 
516         if (companyId != CompanyConstants.SYSTEM) {
517             try {
518                 localesArray = PrefsPropsUtil.getStringArray(
519                     companyId, PropsKeys.LOCALES, StringPool.COMMA,
520                     PropsValues.LOCALES);
521             }
522             catch (SystemException se) {
523                 localesArray = PropsValues.LOCALES;
524             }
525         }
526 
527         _charEncodings = new HashMap<String, String>();
528         _duplicateLanguageCodes = new HashSet<String>();
529         _locales = new Locale[localesArray.length];
530         _localesMap = new HashMap<String, Locale>(localesArray.length);
531         _localesSet = new HashSet<Locale>(localesArray.length);
532 
533         for (int i = 0; i < localesArray.length; i++) {
534             String languageId = localesArray[i];
535 
536             int pos = languageId.indexOf(StringPool.UNDERLINE);
537 
538             String language = languageId.substring(0, pos);
539             //String country = languageId.substring(pos + 1);
540 
541             Locale locale = LocaleUtil.fromLanguageId(languageId);
542 
543             _charEncodings.put(locale.toString(), StringPool.UTF8);
544 
545             if (_localesMap.containsKey(language)) {
546                 _duplicateLanguageCodes.add(language);
547             }
548 
549             _locales[i] = locale;
550 
551             if (!_localesMap.containsKey(language)) {
552                 _localesMap.put(language, locale);
553             }
554 
555             _localesSet.add(locale);
556         }
557     }
558 
559     private String _escapePattern(String pattern) {
560         return StringUtil.replace(
561             pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
562     }
563 
564     private String _getCharset(Locale locale) {
565         return StringPool.UTF8;
566     }
567 
568     private Locale _getLocale(String languageCode) {
569         return _localesMap.get(languageCode);
570     }
571 
572     private String _getPortletConfigurationValue(
573         PageContext pageContext, String key) {
574 
575         String value = null;
576 
577         try {
578             HttpServletRequest request =
579                 (HttpServletRequest)pageContext.getRequest();
580 
581             String portletResource = ParamUtil.getString(
582                 request, "portletResource");
583 
584             long companyId = PortalUtil.getCompanyId(request);
585 
586             Portlet portlet = PortletLocalServiceUtil.getPortletById(
587                 companyId, portletResource);
588 
589             PortletConfig portletConfig = PortletConfigFactory.create(
590                 portlet, pageContext.getServletContext());
591 
592             Locale locale = request.getLocale();
593 
594             ResourceBundle bundle = portletConfig.getResourceBundle(locale);
595 
596             value = bundle.getString(key);
597         }
598         catch (Exception e) {
599             if (_log.isWarnEnabled()) {
600                 _log.warn(e, e);
601             }
602         }
603 
604         return value;
605     }
606 
607     private void _resetAvailableLocales(long companyId) {
608         _instances.remove(companyId);
609     }
610 
611     private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
612 
613     private static Map<Long, LanguageImpl> _instances =
614         new ConcurrentHashMap<Long, LanguageImpl>();
615 
616     private Map<String, String> _charEncodings;
617     private Set<String> _duplicateLanguageCodes;
618     private Locale[] _locales;
619     private Map<String, Locale> _localesMap;
620     private Set<Locale> _localesSet;
621 
622 }