1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.language;
16  
17  import com.liferay.portal.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.CharPool;
23  import com.liferay.portal.kernel.util.GetterUtil;
24  import com.liferay.portal.kernel.util.JavaConstants;
25  import com.liferay.portal.kernel.util.LocaleUtil;
26  import com.liferay.portal.kernel.util.ParamUtil;
27  import com.liferay.portal.kernel.util.PropsKeys;
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  /**
65   * <a href="LanguageImpl.java.html"><b><i>View Source</i></b></a>
66   *
67   * @author Brian Wing Shun Chan
68   * @author Andrius Vitkauskas
69   */
70  public class LanguageImpl implements Language {
71  
72      public String format(Locale locale, String pattern, Object argument) {
73          return format(locale, pattern, new Object[] {argument}, true);
74      }
75  
76      public String format(
77          Locale locale, String pattern, Object argument,
78          boolean translateArguments) {
79  
80          return format(
81              locale, pattern, new Object[] {argument}, translateArguments);
82      }
83  
84      public String format(Locale locale, String pattern, Object[] arguments) {
85          return format(locale, pattern, arguments, true);
86      }
87  
88      public String format(
89          Locale locale, String pattern, Object[] arguments,
90          boolean translateArguments) {
91  
92          if (PropsValues.TRANSLATIONS_DISABLED) {
93              return pattern;
94          }
95  
96          String value = null;
97  
98          try {
99              pattern = get(locale, pattern);
100 
101             if (arguments != null) {
102                 pattern = _escapePattern(pattern);
103 
104                 Object[] formattedArguments = new Object[arguments.length];
105 
106                 for (int i = 0; i < arguments.length; i++) {
107                     if (translateArguments) {
108                         formattedArguments[i] = get(
109                             locale, arguments[i].toString());
110                     }
111                     else {
112                         formattedArguments[i] = arguments[i];
113                     }
114                 }
115 
116                 value = MessageFormat.format(pattern, formattedArguments);
117             }
118             else {
119                 value = pattern;
120             }
121         }
122         catch (Exception e) {
123             if (_log.isWarnEnabled()) {
124                 _log.warn(e, e);
125             }
126         }
127 
128         return value;
129     }
130 
131     public String format(
132         PageContext pageContext, String pattern, Object argument) {
133 
134         return format(pageContext, pattern, new Object[] {argument}, true);
135     }
136 
137     public String format(
138         PageContext pageContext, String pattern, Object argument,
139         boolean translateArguments) {
140 
141         return format(
142             pageContext, pattern, new Object[] {argument}, translateArguments);
143     }
144 
145     public String format(
146         PageContext pageContext, String pattern, Object[] arguments) {
147 
148         return format(pageContext, pattern, arguments, true);
149     }
150 
151     public String format(
152         PageContext pageContext, String pattern, Object[] arguments,
153         boolean translateArguments) {
154 
155         if (PropsValues.TRANSLATIONS_DISABLED) {
156             return pattern;
157         }
158 
159         String value = null;
160 
161         try {
162             pattern = get(pageContext, pattern);
163 
164             if (arguments != null) {
165                 pattern = _escapePattern(pattern);
166 
167                 Object[] formattedArguments = new Object[arguments.length];
168 
169                 for (int i = 0; i < arguments.length; i++) {
170                     if (translateArguments) {
171                         formattedArguments[i] =
172                             get(pageContext, arguments[i].toString());
173                     }
174                     else {
175                         formattedArguments[i] = arguments[i];
176                     }
177                 }
178 
179                 value = MessageFormat.format(pattern, formattedArguments);
180             }
181             else {
182                 value = pattern;
183             }
184         }
185         catch (Exception e) {
186             if (_log.isWarnEnabled()) {
187                 _log.warn(e, e);
188             }
189         }
190 
191         return value;
192     }
193 
194     public String format(
195         PageContext pageContext, String pattern, LanguageWrapper argument) {
196 
197         return format(
198             pageContext, pattern, new LanguageWrapper[] {argument}, true);
199     }
200 
201     public String format(
202         PageContext pageContext, String pattern, LanguageWrapper argument,
203         boolean translateArguments) {
204 
205         return format(
206             pageContext, pattern, new LanguageWrapper[] {argument},
207             translateArguments);
208     }
209 
210     public String format(
211         PageContext pageContext, String pattern, LanguageWrapper[] arguments) {
212 
213         return format(pageContext, pattern, arguments, true);
214     }
215 
216     public String format(
217         PageContext pageContext, String pattern, LanguageWrapper[] arguments,
218         boolean translateArguments) {
219 
220         if (PropsValues.TRANSLATIONS_DISABLED) {
221             return pattern;
222         }
223 
224         String value = null;
225 
226         try {
227             pattern = get(pageContext, pattern);
228 
229             if (arguments != null) {
230                 pattern = _escapePattern(pattern);
231 
232                 Object[] formattedArguments = new Object[arguments.length];
233 
234                 for (int i = 0; i < arguments.length; i++) {
235                     if (translateArguments) {
236                         formattedArguments[i] =
237                             arguments[i].getBefore() +
238                             get(pageContext, arguments[i].getText()) +
239                             arguments[i].getAfter();
240                     }
241                     else {
242                         formattedArguments[i] =
243                             arguments[i].getBefore() +
244                             arguments[i].getText() +
245                             arguments[i].getAfter();
246                     }
247                 }
248 
249                 value = MessageFormat.format(pattern, formattedArguments);
250             }
251             else {
252                 value = pattern;
253             }
254         }
255         catch (Exception e) {
256             if (_log.isWarnEnabled()) {
257                 _log.warn(e, e);
258             }
259         }
260 
261         return value;
262     }
263 
264     public String format(
265         PortletConfig portletConfig, Locale locale, String pattern,
266         Object argument) {
267 
268         return format(
269         portletConfig, locale, pattern, new Object[] {argument}, true);
270     }
271 
272     public String format(
273         PortletConfig portletConfig, Locale locale, String pattern,
274         Object argument, boolean translateArguments) {
275 
276         return format(
277             portletConfig, locale, pattern, new Object[] {argument},
278             translateArguments);
279     }
280 
281     public String format(
282         PortletConfig portletConfig, Locale locale, String pattern,
283         Object[] arguments) {
284 
285         return format(portletConfig, locale, pattern, arguments, true);
286     }
287 
288     public String format(
289         PortletConfig portletConfig, Locale locale, String pattern,
290         Object[] arguments, boolean translateArguments) {
291 
292         if (PropsValues.TRANSLATIONS_DISABLED) {
293             return pattern;
294         }
295 
296         String value = null;
297 
298         try {
299             pattern = get(portletConfig, locale, pattern);
300 
301             if (arguments != null) {
302                 pattern = _escapePattern(pattern);
303 
304                 Object[] formattedArguments = new Object[arguments.length];
305 
306                 for (int i = 0; i < arguments.length; i++) {
307                     if (translateArguments) {
308                         formattedArguments[i] = get(
309                             locale, arguments[i].toString());
310                     }
311                     else {
312                         formattedArguments[i] = arguments[i];
313                     }
314                 }
315 
316                 value = MessageFormat.format(pattern, formattedArguments);
317             }
318             else {
319                 value = pattern;
320             }
321         }
322         catch (Exception e) {
323             if (_log.isWarnEnabled()) {
324                 _log.warn(e, e);
325             }
326         }
327 
328         return value;
329     }
330 
331     public void init() {
332         _instances.clear();
333     }
334 
335     public String get(Locale locale, String key) {
336         return get(locale, key, key);
337     }
338 
339     public String get(Locale locale, String key, String defaultValue) {
340         try {
341             return _get(null, null, locale, 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(PageContext pageContext, String key) {
353         return get(pageContext, key, key);
354     }
355 
356     public String get(
357         PageContext pageContext, String key, String defaultValue) {
358 
359         try {
360             return _get(pageContext, null, null, key, defaultValue);
361         }
362         catch (Exception e) {
363             if (_log.isWarnEnabled()) {
364                 _log.warn(e, e);
365             }
366 
367             return defaultValue;
368         }
369     }
370 
371     public String get(PortletConfig portletConfig, Locale locale, String key) {
372         return get(portletConfig, locale, key, key);
373     }
374 
375     public String get(
376         PortletConfig portletConfig, Locale locale, String key,
377         String defaultValue) {
378 
379         try {
380             return _get(null, portletConfig, locale, key, defaultValue);
381         }
382         catch (Exception e) {
383             if (_log.isWarnEnabled()) {
384                 _log.warn(e, e);
385             }
386 
387             return defaultValue;
388         }
389     }
390 
391     public Locale[] getAvailableLocales() {
392         return _getInstance()._locales;
393     }
394 
395     public String getCharset(Locale locale) {
396         return _getInstance()._getCharset(locale);
397     }
398 
399     public String getLanguageId(PortletRequest portletRequest) {
400         HttpServletRequest request = PortalUtil.getHttpServletRequest(
401             portletRequest);
402 
403         return getLanguageId(request);
404     }
405 
406     public String getLanguageId(HttpServletRequest request) {
407         String languageId = ParamUtil.getString(request, "languageId");
408 
409         if (Validator.isNotNull(languageId)) {
410             if (_localesMap.containsKey(languageId) ||
411                 _charEncodings.containsKey(languageId)) {
412 
413                 return languageId;
414             }
415         }
416 
417         Locale locale = PortalUtil.getLocale(request);
418 
419         return getLanguageId(locale);
420     }
421 
422     public String getLanguageId(Locale locale) {
423         return LocaleUtil.toLanguageId(locale);
424     }
425 
426     public Locale getLocale(String languageCode) {
427         return _getInstance()._getLocale(languageCode);
428     }
429 
430     public String getTimeDescription(
431         PageContext pageContext, Long milliseconds) {
432 
433         return getTimeDescription(pageContext, milliseconds.longValue());
434     }
435 
436     public String getTimeDescription(
437         PageContext pageContext, long milliseconds) {
438 
439         String desc = Time.getDescription(milliseconds);
440 
441         String value = null;
442 
443         try {
444             int pos = desc.indexOf(CharPool.SPACE);
445 
446             int x = GetterUtil.getInteger(desc.substring(0, pos));
447 
448             value =
449                 x + " " +
450                 get(
451                     pageContext,
452                     desc.substring(pos + 1, desc.length()).toLowerCase());
453         }
454         catch (Exception e) {
455             if (_log.isWarnEnabled()) {
456                 _log.warn(e, e);
457             }
458         }
459 
460         return value;
461     }
462 
463     public boolean isAvailableLocale(Locale locale) {
464         return _getInstance()._localesSet.contains(locale);
465     }
466 
467     public boolean isDuplicateLanguageCode(String languageCode) {
468         return _getInstance()._duplicateLanguageCodes.contains(languageCode);
469     }
470 
471     public void resetAvailableLocales(long companyId) {
472          _resetAvailableLocales(companyId);
473     }
474 
475     public void updateCookie(
476         HttpServletRequest request, HttpServletResponse response,
477         Locale locale) {
478 
479         String languageId = LocaleUtil.toLanguageId(locale);
480 
481         Cookie languageIdCookie = new Cookie(
482             CookieKeys.GUEST_LANGUAGE_ID, languageId);
483 
484         languageIdCookie.setPath(StringPool.SLASH);
485         languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
486 
487         CookieKeys.addCookie(request, response, languageIdCookie);
488     }
489 
490     private static LanguageImpl _getInstance() {
491         Long companyId = CompanyThreadLocal.getCompanyId();
492 
493         LanguageImpl instance = _instances.get(companyId);
494 
495         if (instance == null) {
496             instance = new LanguageImpl(companyId);
497 
498             _instances.put(companyId, instance);
499         }
500 
501         return instance;
502     }
503 
504     private LanguageImpl() {
505         this(CompanyConstants.SYSTEM);
506     }
507 
508     private LanguageImpl(long companyId) {
509         String[] localesArray = PropsValues.LOCALES;
510 
511         if (companyId != CompanyConstants.SYSTEM) {
512             try {
513                 localesArray = PrefsPropsUtil.getStringArray(
514                     companyId, PropsKeys.LOCALES, StringPool.COMMA,
515                     PropsValues.LOCALES);
516             }
517             catch (SystemException se) {
518                 localesArray = PropsValues.LOCALES;
519             }
520         }
521 
522         _charEncodings = new HashMap<String, String>();
523         _duplicateLanguageCodes = new HashSet<String>();
524         _locales = new Locale[localesArray.length];
525         _localesMap = new HashMap<String, Locale>(localesArray.length);
526         _localesSet = new HashSet<Locale>(localesArray.length);
527 
528         for (int i = 0; i < localesArray.length; i++) {
529             String languageId = localesArray[i];
530 
531             int pos = languageId.indexOf(CharPool.UNDERLINE);
532 
533             String language = languageId.substring(0, pos);
534             //String country = languageId.substring(pos + 1);
535 
536             Locale locale = LocaleUtil.fromLanguageId(languageId);
537 
538             _charEncodings.put(locale.toString(), StringPool.UTF8);
539 
540             if (_localesMap.containsKey(language)) {
541                 _duplicateLanguageCodes.add(language);
542             }
543 
544             _locales[i] = locale;
545 
546             if (!_localesMap.containsKey(language)) {
547                 _localesMap.put(language, locale);
548             }
549 
550             _localesSet.add(locale);
551         }
552     }
553 
554     private String _escapePattern(String pattern) {
555         return StringUtil.replace(
556             pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
557     }
558 
559     private String _get(
560             PageContext pageContext, PortletConfig portletConfig, Locale locale,
561             String key, String defaultValue)
562         throws Exception {
563 
564         if (PropsValues.TRANSLATIONS_DISABLED) {
565             return key;
566         }
567 
568         if (key == null) {
569             return null;
570         }
571 
572         String value = null;
573 
574         if (pageContext != null) {
575             HttpServletRequest request =
576                 (HttpServletRequest)pageContext.getRequest();
577 
578             ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
579                 WebKeys.THEME_DISPLAY);
580 
581             locale = themeDisplay.getLocale();
582 
583             portletConfig = (PortletConfig)request.getAttribute(
584                 JavaConstants.JAVAX_PORTLET_CONFIG);
585         }
586 
587         if (portletConfig != null) {
588             ResourceBundle resourceBundle = portletConfig.getResourceBundle(
589                 locale);
590 
591             try {
592                 value = resourceBundle.getString(key);
593             }
594             catch (MissingResourceException mre) {
595             }
596 
597             // LEP-7393
598 
599             if (((value == null) || (value.equals(defaultValue))) &&
600                 (portletConfig.getPortletName().equals(
601                     PortletKeys.PORTLET_CONFIGURATION))) {
602 
603                 try {
604                     value = _getPortletConfigurationValue(
605                         pageContext, locale, key);
606                 }
607                 catch (MissingResourceException mre) {
608                 }
609             }
610 
611             if (value != null) {
612                 value = LanguageResources.fixValue(value);
613             }
614         }
615 
616         if ((value == null) || value.equals(defaultValue)) {
617             value = LanguageResources.getMessage(locale, key);
618         }
619 
620         if ((value == null) || value.equals(defaultValue)) {
621             if (key.endsWith(StringPool.CLOSE_BRACKET)) {
622                 int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
623 
624                 if (pos != -1) {
625                     key = key.substring(0, pos);
626 
627                     return _get(
628                         pageContext, portletConfig, locale, key, defaultValue);
629                 }
630             }
631         }
632 
633         if (value == null) {
634             value = defaultValue;
635         }
636 
637         return value;
638     }
639 
640     private String _getCharset(Locale locale) {
641         return StringPool.UTF8;
642     }
643 
644     private Locale _getLocale(String languageCode) {
645         return _localesMap.get(languageCode);
646     }
647 
648     private String _getPortletConfigurationValue(
649             PageContext pageContext, Locale locale, String key)
650         throws Exception {
651 
652         if (PropsValues.TRANSLATIONS_DISABLED) {
653             return key;
654         }
655 
656         HttpServletRequest request =
657             (HttpServletRequest)pageContext.getRequest();
658 
659         String portletResource = ParamUtil.getString(
660             request, "portletResource");
661 
662         long companyId = PortalUtil.getCompanyId(request);
663 
664         Portlet portlet = PortletLocalServiceUtil.getPortletById(
665             companyId, portletResource);
666 
667         PortletConfig portletConfig = PortletConfigFactory.create(
668             portlet, pageContext.getServletContext());
669 
670         ResourceBundle resourceBundle = portletConfig.getResourceBundle(
671             locale);
672 
673         return resourceBundle.getString(key);
674     }
675 
676     private void _resetAvailableLocales(long companyId) {
677         _instances.remove(companyId);
678     }
679 
680     private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
681 
682     private static Map<Long, LanguageImpl> _instances =
683         new ConcurrentHashMap<Long, LanguageImpl>();
684 
685     private Map<String, String> _charEncodings;
686     private Set<String> _duplicateLanguageCodes;
687     private Locale[] _locales;
688     private Map<String, Locale> _localesMap;
689     private Set<Locale> _localesSet;
690 
691 }