1
22
23 package com.liferay.util;
24
25 import com.liferay.portal.kernel.language.LanguageUtil;
26 import com.liferay.portal.kernel.log.Log;
27 import com.liferay.portal.kernel.log.LogFactoryUtil;
28 import com.liferay.portal.kernel.util.LocaleUtil;
29 import com.liferay.portal.kernel.util.ParamUtil;
30 import com.liferay.portal.kernel.util.StringPool;
31 import com.liferay.portal.kernel.util.StringUtil;
32 import com.liferay.portal.kernel.util.Tuple;
33 import com.liferay.portal.kernel.util.Validator;
34
35 import java.io.StringReader;
36 import java.io.StringWriter;
37
38 import java.util.HashMap;
39 import java.util.Locale;
40 import java.util.Map;
41
42 import javax.portlet.ActionRequest;
43 import javax.portlet.PortletPreferences;
44 import javax.portlet.PortletRequest;
45
46 import javax.xml.stream.XMLInputFactory;
47 import javax.xml.stream.XMLOutputFactory;
48 import javax.xml.stream.XMLStreamConstants;
49 import javax.xml.stream.XMLStreamException;
50 import javax.xml.stream.XMLStreamReader;
51 import javax.xml.stream.XMLStreamWriter;
52
53 import org.apache.commons.collections.map.ReferenceMap;
54
55
78 public class LocalizationUtil {
79
80 public static String[] getAvailableLocales(String xml) {
81 String attributeValue = _getRootAttribute(
82 xml, _AVAILABLE_LOCALES, StringPool.BLANK);
83
84 return StringUtil.split(attributeValue);
85 }
86
87 public static String getDefaultLocale(String xml) {
88 String defaultLanguageId = LocaleUtil.toLanguageId(
89 LocaleUtil.getDefault());
90
91 return _getRootAttribute(xml, _DEFAULT_LOCALE, defaultLanguageId);
92 }
93
94 public static String getLocalization(
95 String xml, String requestedLanguageId) {
96
97 return getLocalization(xml, requestedLanguageId, true);
98 }
99
100 public static String getLocalization(
101 String xml, String requestedLanguageId, boolean useDefault) {
102
103 String value = _getCachedValue(xml, requestedLanguageId, useDefault);
104
105 if (value != null) {
106 return value;
107 }
108 else {
109 value = StringPool.BLANK;
110 }
111
112 String systemDefaultLanguageId = LocaleUtil.toLanguageId(
113 LocaleUtil.getDefault());
114
115 String defaultValue = StringPool.BLANK;
116
117 if (!Validator.isXml(xml)) {
118 if (requestedLanguageId.equals(systemDefaultLanguageId)) {
119 value = xml;
120 }
121 else {
122 value = defaultValue;
123 }
124
125 _setCachedValue(xml, requestedLanguageId, useDefault, value);
126
127 return value;
128 }
129
130 XMLStreamReader reader = null;
131
132 try {
133 XMLInputFactory factory = XMLInputFactory.newInstance();
134
135 reader = factory.createXMLStreamReader(new StringReader(xml));
136
137 String defaultLanguageId = StringPool.BLANK;
138
139
141 if (reader.hasNext()) {
142 reader.nextTag();
143
144 defaultLanguageId = reader.getAttributeValue(
145 null, _DEFAULT_LOCALE);
146
147 if (Validator.isNull(defaultLanguageId)) {
148 defaultLanguageId = systemDefaultLanguageId;
149 }
150 }
151
152
154 while (reader.hasNext()) {
155 int event = reader.next();
156
157 if (event == XMLStreamConstants.START_ELEMENT) {
158 String languageId = reader.getAttributeValue(
159 null, _LANGUAGE_ID);
160
161 if (Validator.isNull(languageId)) {
162 languageId = defaultLanguageId;
163 }
164
165 if (languageId.equals(defaultLanguageId) ||
166 languageId.equals(requestedLanguageId)) {
167
168 while (reader.hasNext()) {
169 event = reader.next();
170
171 if (event == XMLStreamConstants.CHARACTERS ||
172 event == XMLStreamConstants.CDATA) {
173
174 String text = reader.getText();
175
176 if (languageId.equals(defaultLanguageId)) {
177 defaultValue = text;
178 }
179
180 if (languageId.equals(requestedLanguageId)) {
181 value = text;
182 }
183
184 break;
185 }
186 else if (event == XMLStreamConstants.END_ELEMENT) {
187 break;
188 }
189 }
190
191 if (Validator.isNotNull(value)) {
192 break;
193 }
194 }
195 }
196 else if (event == XMLStreamConstants.END_DOCUMENT) {
197 break;
198 }
199 }
200
201 if (useDefault && Validator.isNull(value)) {
202 value = defaultValue;
203 }
204 }
205 catch (Exception e) {
206 if (_log.isWarnEnabled()) {
207 _log.warn(e, e);
208 }
209 }
210 finally {
211 if (reader != null) {
212 try {
213 reader.close();
214 }
215 catch (Exception e) {
216 }
217 }
218 }
219
220 _setCachedValue(xml, requestedLanguageId, useDefault, value);
221
222 return value;
223 }
224
225 public static Map<Locale, String> getLocalizationMap(
226 PortletRequest portletRequest, String parameter) {
227
228 Locale[] locales = LanguageUtil.getAvailableLocales();
229
230 Map<Locale, String> map = new HashMap<Locale, String>();
231
232 for (Locale locale : locales) {
233 String languageId = LocaleUtil.toLanguageId(locale);
234
235 String localeParameter =
236 parameter + StringPool.UNDERLINE + languageId;
237
238 map.put(
239 locale, ParamUtil.getString(portletRequest, localeParameter));
240 }
241
242 return map;
243 }
244
245 public static Map<Locale, String> getLocalizationMap(String xml) {
246 Locale[] locales = LanguageUtil.getAvailableLocales();
247
248 Map<Locale, String> map = new HashMap<Locale, String>();
249
250 for (Locale locale : locales) {
251 String languageId = LocaleUtil.toLanguageId(locale);
252
253 map.put(locale, getLocalization(xml, languageId));
254 }
255
256 return map;
257 }
258
259
262 public static Map<Locale, String> getLocalizedParameter(
263 PortletRequest portletRequest, String parameter) {
264
265 return getLocalizationMap(portletRequest, parameter);
266 }
267
268 public static String getPreferencesValue(
269 PortletPreferences preferences, String key, String languageId) {
270
271 return getPreferencesValue(preferences, key, languageId, true);
272 }
273
274 public static String getPreferencesValue(
275 PortletPreferences preferences, String key, String languageId,
276 boolean useDefault) {
277
278 String localizedKey = _getPreferencesKey(key, languageId);
279
280 String value = preferences.getValue(localizedKey, StringPool.BLANK);
281
282 if (useDefault && Validator.isNull(value)) {
283 value = preferences.getValue(key, StringPool.BLANK);
284 }
285
286 return value;
287 }
288
289 public static String[] getPreferencesValues(
290 PortletPreferences preferences, String key, String languageId) {
291
292 return getPreferencesValues(preferences, key, languageId, true);
293 }
294
295 public static String[] getPreferencesValues(
296 PortletPreferences preferences, String key, String languageId,
297 boolean useDefault) {
298
299 String localizedKey = _getPreferencesKey(key, languageId);
300
301 String[] values = preferences.getValues(localizedKey, new String[0]);
302
303 if (useDefault && Validator.isNull(values)) {
304 values = preferences.getValues(key, new String[0]);
305 }
306
307 return values;
308 }
309
310 public static String removeLocalization(
311 String xml, String key, String requestedLanguageId) {
312
313 return removeLocalization(xml, key, requestedLanguageId, false);
314 }
315
316 public static String removeLocalization(
317 String xml, String key, String requestedLanguageId, boolean cdata) {
318
319 if (Validator.isNull(xml)) {
320 return StringPool.BLANK;
321 }
322
323 xml = _sanitizeXML(xml);
324
325 String systemDefaultLanguageId = LocaleUtil.toLanguageId(
326 LocaleUtil.getDefault());
327
328 XMLStreamReader reader = null;
329 XMLStreamWriter writer = null;
330
331 try {
332 XMLInputFactory inputFactory = XMLInputFactory.newInstance();
333
334 reader = inputFactory.createXMLStreamReader(new StringReader(xml));
335
336 String availableLocales = StringPool.BLANK;
337 String defaultLanguageId = StringPool.BLANK;
338
339
341 if (reader.hasNext()) {
342 reader.nextTag();
343
344 availableLocales = reader.getAttributeValue(
345 null, _AVAILABLE_LOCALES);
346 defaultLanguageId = reader.getAttributeValue(
347 null, _DEFAULT_LOCALE);
348
349 if (Validator.isNull(defaultLanguageId)) {
350 defaultLanguageId = systemDefaultLanguageId;
351 }
352 }
353
354 if ((availableLocales != null) &&
355 (availableLocales.indexOf(requestedLanguageId) != -1)) {
356
357 availableLocales = StringUtil.remove(
358 availableLocales, requestedLanguageId, StringPool.COMMA);
359
360 StringWriter sw = new StringWriter(xml.length());
361
362 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
363
364 writer = outputFactory.createXMLStreamWriter(sw);
365
366 writer.writeStartDocument();
367 writer.writeStartElement(_ROOT);
368 writer.writeAttribute(_AVAILABLE_LOCALES, availableLocales);
369 writer.writeAttribute(_DEFAULT_LOCALE, defaultLanguageId);
370
371 _copyNonExempt(
372 reader, writer, requestedLanguageId, defaultLanguageId,
373 cdata);
374
375 writer.writeEndElement();
376 writer.writeEndDocument();
377
378 writer.close();
379 writer = null;
380
381 xml = sw.toString();
382 }
383 }
384 catch (Exception e) {
385 if (_log.isWarnEnabled()) {
386 _log.warn(e, e);
387 }
388 }
389 finally {
390 if (reader != null) {
391 try {
392 reader.close();
393 }
394 catch (Exception e) {
395 }
396 }
397
398 if (writer != null) {
399 try {
400 writer.close();
401 }
402 catch (Exception e) {
403 }
404 }
405 }
406
407 return xml;
408 }
409
410 public static void setLocalizedPreferencesValues (
411 ActionRequest actionRequest, PortletPreferences preferences,
412 String parameter)
413 throws Exception {
414
415 Map<Locale, String> map = getLocalizedParameter(
416 actionRequest, parameter);
417
418 for (Locale locale : map.keySet()) {
419 String languageId = LocaleUtil.toLanguageId(locale);
420
421 String key = parameter + StringPool.UNDERLINE + languageId;
422 String value = map.get(locale);
423
424 preferences.setValue(key, value);
425 }
426 }
427
428 public static void setPreferencesValue(
429 PortletPreferences preferences, String key, String languageId,
430 String value)
431 throws Exception {
432
433 preferences.setValue(_getPreferencesKey(key, languageId), value);
434 }
435
436 public static void setPreferencesValues(
437 PortletPreferences preferences, String key, String languageId,
438 String[] values)
439 throws Exception {
440
441 preferences.setValues(_getPreferencesKey(key, languageId), values);
442 }
443
444 public static String updateLocalization(
445 String xml, String key, String value) {
446
447 String defaultLanguageId = LocaleUtil.toLanguageId(
448 LocaleUtil.getDefault());
449
450 return updateLocalization(
451 xml, key, value, defaultLanguageId, defaultLanguageId);
452 }
453
454 public static String updateLocalization(
455 String xml, String key, String value, String requestedLanguageId) {
456
457 String defaultLanguageId = LocaleUtil.toLanguageId(
458 LocaleUtil.getDefault());
459
460 return updateLocalization(
461 xml, key, value, requestedLanguageId, defaultLanguageId);
462 }
463
464 public static String updateLocalization(
465 String xml, String key, String value, String requestedLanguageId,
466 String defaultLanguageId) {
467
468 return updateLocalization(
469 xml, key, value, requestedLanguageId, defaultLanguageId, false);
470 }
471
472 public static String updateLocalization(
473 String xml, String key, String value, String requestedLanguageId,
474 String defaultLanguageId, boolean cdata) {
475
476 xml = _sanitizeXML(xml);
477
478 XMLStreamReader reader = null;
479 XMLStreamWriter writer = null;
480
481 try {
482 XMLInputFactory inputFactory = XMLInputFactory.newInstance();
483
484 reader = inputFactory.createXMLStreamReader(new StringReader(xml));
485
486 String availableLocales = StringPool.BLANK;
487
488
490 if (reader.hasNext()) {
491 reader.nextTag();
492
493 availableLocales = reader.getAttributeValue(
494 null, _AVAILABLE_LOCALES);
495
496 if (Validator.isNull(availableLocales)) {
497 availableLocales = defaultLanguageId;
498 }
499
500 if (availableLocales.indexOf(requestedLanguageId) == -1) {
501 availableLocales = StringUtil.add(
502 availableLocales, requestedLanguageId,
503 StringPool.COMMA);
504 }
505 }
506
507 StringWriter sw = new StringWriter(xml.length());
508
509 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
510
511 writer = outputFactory.createXMLStreamWriter(sw);
512
513 writer.writeStartDocument();
514 writer.writeStartElement(_ROOT);
515 writer.writeAttribute(_AVAILABLE_LOCALES, availableLocales);
516 writer.writeAttribute(_DEFAULT_LOCALE, defaultLanguageId);
517
518 _copyNonExempt(
519 reader, writer, requestedLanguageId, defaultLanguageId,
520 cdata);
521
522 if (cdata) {
523 writer.writeStartElement(key);
524 writer.writeAttribute(_LANGUAGE_ID, requestedLanguageId);
525 writer.writeCData(value);
526 writer.writeEndElement();
527 }
528 else {
529 writer.writeStartElement(key);
530 writer.writeAttribute(_LANGUAGE_ID, requestedLanguageId);
531 writer.writeCharacters(value);
532 writer.writeEndElement();
533 }
534
535 writer.writeEndElement();
536 writer.writeEndDocument();
537
538 writer.close();
539 writer = null;
540
541 xml = sw.toString();
542 }
543 catch (Exception e) {
544 if (_log.isWarnEnabled()) {
545 _log.warn(e, e);
546 }
547 }
548 finally {
549 if (reader != null) {
550 try {
551 reader.close();
552 }
553 catch (Exception e) {
554 }
555 }
556
557 if (writer != null) {
558 try {
559 writer.close();
560 }
561 catch (Exception e) {
562 }
563 }
564 }
565
566 return xml;
567 }
568
569 private static void _copyNonExempt(
570 XMLStreamReader reader, XMLStreamWriter writer,
571 String exemptLanguageId, String defaultLanguageId, boolean cdata)
572 throws XMLStreamException {
573
574 while (reader.hasNext()) {
575 int event = reader.next();
576
577 if (event == XMLStreamConstants.START_ELEMENT) {
578 String languageId = reader.getAttributeValue(
579 null, _LANGUAGE_ID);
580
581 if (Validator.isNull(languageId)) {
582 languageId = defaultLanguageId;
583 }
584
585 if (!languageId.equals(exemptLanguageId)) {
586 writer.writeStartElement(reader.getLocalName());
587 writer.writeAttribute(_LANGUAGE_ID, languageId);
588
589 while (reader.hasNext()) {
590 event = reader.next();
591
592 if (event == XMLStreamConstants.CHARACTERS ||
593 event == XMLStreamConstants.CDATA) {
594
595 String text = reader.getText();
596
597 if (cdata) {
598 writer.writeCData(text);
599 }
600 else {
601 writer.writeCharacters(reader.getText());
602 }
603
604 break;
605 }
606 else if (event == XMLStreamConstants.END_ELEMENT) {
607 break;
608 }
609 }
610
611 writer.writeEndElement();
612 }
613 }
614 else if (event == XMLStreamConstants.END_DOCUMENT) {
615 break;
616 }
617 }
618 }
619
620 private static String _getCachedValue(
621 String xml, String requestedLanguageId, boolean useDefault) {
622
623 String value = null;
624
625 Map<Tuple, String> valueMap = _cache.get(xml);
626
627 if (valueMap != null) {
628 Tuple subkey = new Tuple(useDefault, requestedLanguageId);
629
630 value = valueMap.get(subkey);
631 }
632
633 return value;
634 }
635
636 private static String _getPreferencesKey(String key, String languageId) {
637 String defaultLanguageId = LocaleUtil.toLanguageId(
638 LocaleUtil.getDefault());
639
640 if (!languageId.equals(defaultLanguageId)) {
641 key += StringPool.UNDERLINE + languageId;
642 }
643
644 return key;
645 }
646
647 private static String _getRootAttribute(
648 String xml, String name, String defaultValue) {
649
650 String value = null;
651
652 XMLStreamReader reader = null;
653
654 try {
655 XMLInputFactory factory = XMLInputFactory.newInstance();
656
657 reader = factory.createXMLStreamReader(new StringReader(xml));
658
659 if (reader.hasNext()) {
660 reader.nextTag();
661
662 value = reader.getAttributeValue(null, name);
663 }
664 }
665 catch (Exception e) {
666 if (_log.isWarnEnabled()) {
667 _log.warn(e, e);
668 }
669 }
670 finally {
671 if (reader != null) {
672 try {
673 reader.close();
674 }
675 catch (Exception e) {
676 }
677 }
678 }
679
680 if (Validator.isNull(value)) {
681 value = defaultValue;
682 }
683
684 return value;
685 }
686
687 private static String _sanitizeXML(String xml) {
688 if (Validator.isNull(xml) || (xml.indexOf("<root") == -1)) {
689 xml = _EMPTY_ROOT_NODE;
690 }
691
692 return xml;
693 }
694
695 private static void _setCachedValue(
696 String xml, String requestedLanguageId, boolean useDefault,
697 String value) {
698
699 if (Validator.isNotNull(xml) && !xml.equals(_EMPTY_ROOT_NODE)) {
700 synchronized (_cache) {
701 Map<Tuple, String> map = _cache.get(xml);
702
703 if (map == null) {
704 map = new HashMap<Tuple, String>();
705 }
706
707 Tuple subkey = new Tuple(useDefault, requestedLanguageId);
708
709 map.put(subkey, value);
710
711 _cache.put(xml, map);
712 }
713 }
714 }
715
716 private static final String _AVAILABLE_LOCALES = "available-locales";
717
718 private static final String _DEFAULT_LOCALE = "default-locale";
719
720 private static final String _EMPTY_ROOT_NODE = "<root />";
721
722 private static final String _LANGUAGE_ID = "language-id";
723
724 private static final String _ROOT = "root";
725
726 private static Log _log = LogFactoryUtil.getLog(LocalizationUtil.class);
727
728 private static Map<String, Map<Tuple, String>> _cache = new ReferenceMap(
729 ReferenceMap.SOFT, ReferenceMap.HARD);
730
731 }