001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.language;
016    
017    import com.liferay.portal.kernel.language.LanguageUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.CharPool;
021    import com.liferay.portal.kernel.util.LocaleUtil;
022    import com.liferay.portal.kernel.util.PropertiesUtil;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.tools.LangBuilder;
027    
028    import java.io.InputStream;
029    
030    import java.net.URL;
031    
032    import java.util.Collections;
033    import java.util.Enumeration;
034    import java.util.HashMap;
035    import java.util.Locale;
036    import java.util.Map;
037    import java.util.Properties;
038    import java.util.concurrent.ConcurrentHashMap;
039    
040    /**
041     * @author Shuyang Zhou
042     */
043    public class LanguageResources {
044    
045            public static String fixValue(String value) {
046                    if (value.endsWith(LangBuilder.AUTOMATIC_COPY)) {
047                            value = value.substring(
048                                    0, value.length() - LangBuilder.AUTOMATIC_COPY.length());
049                    }
050    
051                    if (value.endsWith(LangBuilder.AUTOMATIC_TRANSLATION)) {
052                            value = value.substring(
053                                    0, value.length() - LangBuilder.AUTOMATIC_TRANSLATION.length());
054                    }
055    
056                    return value;
057            }
058    
059            public static void fixValues(
060                    Map<String, String> languageMap, Properties properties) {
061    
062                    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
063                            String key = (String)entry.getKey();
064                            String value = (String)entry.getValue();
065    
066                            value = fixValue(value);
067    
068                            languageMap.put(key, value);
069                    }
070            }
071    
072            public static String getMessage(Locale locale, String key) {
073                    if (locale == null) {
074                            return null;
075                    }
076    
077                    Map<String, String> languageMap = _languageMaps.get(locale);
078    
079                    if (languageMap == null) {
080                            languageMap = _loadLocale(locale);
081                    }
082    
083                    String value = languageMap.get(key);
084    
085                    if (value == null) {
086                            return getMessage(getSuperLocale(locale), key);
087                    }
088                    else {
089                            return value;
090                    }
091            }
092    
093            public static Locale getSuperLocale(Locale locale) {
094                    String variant = locale.getVariant();
095    
096                    if (variant.length() > 0) {
097                            return new Locale(locale.getLanguage(), locale.getCountry());
098                    }
099    
100                    String country = locale.getCountry();
101    
102                    if (country.length() > 0) {
103                            Locale priorityLocale = LanguageUtil.getLocale(
104                                    locale.getLanguage());
105    
106                            if ((priorityLocale != null) && !locale.equals(priorityLocale)) {
107                                    return new Locale(
108                                            priorityLocale.getLanguage(), priorityLocale.getCountry());
109                            }
110    
111                            return LocaleUtil.fromLanguageId(locale.getLanguage(), false, true);
112                    }
113    
114                    String language = locale.getLanguage();
115    
116                    if (language.length() > 0) {
117                            return _blankLocale;
118                    }
119    
120                    return null;
121            }
122    
123            public static Map<String, String> putLanguageMap(
124                    Locale locale, Map<String, String> languageMap) {
125    
126                    Map<String, String> oldLanguageMap = _languageMaps.get(locale);
127    
128                    if (oldLanguageMap == null) {
129                            _loadLocale(locale);
130                            oldLanguageMap = _languageMaps.get(locale);
131                    }
132    
133                    Map<String, String> newLanguageMap = new HashMap<String, String>();
134    
135                    if (oldLanguageMap != null) {
136                            newLanguageMap.putAll(oldLanguageMap);
137                    }
138    
139                    newLanguageMap.putAll(languageMap);
140    
141                    _languageMaps.put(locale, newLanguageMap);
142    
143                    return oldLanguageMap;
144            }
145    
146            public void setConfig(String config) {
147                    _configNames = StringUtil.split(
148                            config.replace(CharPool.PERIOD, CharPool.SLASH));
149            }
150    
151            private static Map<String, String> _loadLocale(Locale locale) {
152                    Map<String, String> languageMap = null;
153    
154                    if (_configNames.length > 0) {
155                            String localeName = locale.toString();
156    
157                            languageMap = new HashMap<String, String>();
158    
159                            for (String name : _configNames) {
160                                    StringBundler sb = new StringBundler(4);
161    
162                                    sb.append(name);
163    
164                                    if (localeName.length() > 0) {
165                                            sb.append(StringPool.UNDERLINE);
166                                            sb.append(localeName);
167                                    }
168    
169                                    sb.append(".properties");
170    
171                                    Properties properties = _loadProperties(sb.toString());
172    
173                                    fixValues(languageMap, properties);
174                            }
175                    }
176                    else {
177                            languageMap = Collections.emptyMap();
178                    }
179    
180                    _languageMaps.put(locale, languageMap);
181    
182                    return languageMap;
183            }
184    
185            private static Properties _loadProperties(String name) {
186                    Properties properties = new Properties();
187    
188                    try {
189                            ClassLoader classLoader = LanguageResources.class.getClassLoader();
190    
191                            Enumeration<URL> enu = classLoader.getResources(name);
192    
193                            if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
194                                    _log.debug("No resources found for " + name);
195                            }
196    
197                            while (enu.hasMoreElements()) {
198                                    URL url = enu.nextElement();
199    
200                                    if (_log.isInfoEnabled()) {
201                                            _log.info("Loading " + name + " from " + url);
202                                    }
203    
204                                    InputStream inputStream = url.openStream();
205    
206                                    try {
207                                            Properties inputStreamProperties = PropertiesUtil.load(
208                                                    inputStream, StringPool.UTF8);
209    
210                                            properties.putAll(inputStreamProperties);
211    
212                                            if (_log.isInfoEnabled()) {
213                                                    _log.info(
214                                                            "Loading " + url + " with " +
215                                                                    inputStreamProperties.size() + " values");
216                                            }
217                                    }
218                                    finally {
219                                            inputStream.close();
220                                    }
221                            }
222                    }
223                    catch (Exception e) {
224                            if (_log.isWarnEnabled()) {
225                                    _log.warn(e, e);
226                            }
227                    }
228    
229                    return properties;
230            }
231    
232            private static Log _log = LogFactoryUtil.getLog(LanguageResources.class);
233    
234            private static Locale _blankLocale = new Locale(StringPool.BLANK);
235            private static String[] _configNames;
236            private static Map<Locale, Map<String, String>> _languageMaps =
237                    new ConcurrentHashMap<Locale, Map<String, String>>(64);
238    
239    }