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