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