001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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                            variant = priorityLocale.getVariant();
107    
108                            if ((priorityLocale != null) && !locale.equals(priorityLocale) &&
109                                    (variant.length() <= 0)) {
110    
111                                    return new Locale(
112                                            priorityLocale.getLanguage(), priorityLocale.getCountry());
113                            }
114    
115                            return LocaleUtil.fromLanguageId(locale.getLanguage(), false, true);
116                    }
117    
118                    String language = locale.getLanguage();
119    
120                    if (language.length() > 0) {
121                            return _blankLocale;
122                    }
123    
124                    return null;
125            }
126    
127            public static Map<String, String> putLanguageMap(
128                    Locale locale, Map<String, String> languageMap) {
129    
130                    Map<String, String> oldLanguageMap = _languageMaps.get(locale);
131    
132                    if (oldLanguageMap == null) {
133                            _loadLocale(locale);
134                            oldLanguageMap = _languageMaps.get(locale);
135                    }
136    
137                    Map<String, String> newLanguageMap = new HashMap<String, String>();
138    
139                    if (oldLanguageMap != null) {
140                            newLanguageMap.putAll(oldLanguageMap);
141                    }
142    
143                    newLanguageMap.putAll(languageMap);
144    
145                    _languageMaps.put(locale, newLanguageMap);
146    
147                    return oldLanguageMap;
148            }
149    
150            public void setConfig(String config) {
151                    _configNames = StringUtil.split(
152                            config.replace(CharPool.PERIOD, CharPool.SLASH));
153            }
154    
155            private static Map<String, String> _loadLocale(Locale locale) {
156                    Map<String, String> languageMap = null;
157    
158                    if (_configNames.length > 0) {
159                            String localeName = locale.toString();
160    
161                            languageMap = new HashMap<String, String>();
162    
163                            for (String name : _configNames) {
164                                    StringBundler sb = new StringBundler(4);
165    
166                                    sb.append(name);
167    
168                                    if (localeName.length() > 0) {
169                                            sb.append(StringPool.UNDERLINE);
170                                            sb.append(localeName);
171                                    }
172    
173                                    sb.append(".properties");
174    
175                                    Properties properties = _loadProperties(sb.toString());
176    
177                                    fixValues(languageMap, properties);
178                            }
179                    }
180                    else {
181                            languageMap = Collections.emptyMap();
182                    }
183    
184                    _languageMaps.put(locale, languageMap);
185    
186                    return languageMap;
187            }
188    
189            private static Properties _loadProperties(String name) {
190                    Properties properties = new Properties();
191    
192                    try {
193                            ClassLoader classLoader = LanguageResources.class.getClassLoader();
194    
195                            Enumeration<URL> enu = classLoader.getResources(name);
196    
197                            if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
198                                    _log.debug("No resources found for " + name);
199                            }
200    
201                            while (enu.hasMoreElements()) {
202                                    URL url = enu.nextElement();
203    
204                                    if (_log.isInfoEnabled()) {
205                                            _log.info("Loading " + name + " from " + url);
206                                    }
207    
208                                    InputStream inputStream = url.openStream();
209    
210                                    try {
211                                            Properties inputStreamProperties = PropertiesUtil.load(
212                                                    inputStream, StringPool.UTF8);
213    
214                                            properties.putAll(inputStreamProperties);
215    
216                                            if (_log.isInfoEnabled()) {
217                                                    _log.info(
218                                                            "Loading " + url + " with " +
219                                                                    inputStreamProperties.size() + " values");
220                                            }
221                                    }
222                                    finally {
223                                            inputStream.close();
224                                    }
225                            }
226                    }
227                    catch (Exception e) {
228                            if (_log.isWarnEnabled()) {
229                                    _log.warn(e, e);
230                            }
231                    }
232    
233                    return properties;
234            }
235    
236            private static Log _log = LogFactoryUtil.getLog(LanguageResources.class);
237    
238            private static Locale _blankLocale = new Locale(StringPool.BLANK);
239            private static String[] _configNames;
240            private static Map<Locale, Map<String, String>> _languageMaps =
241                    new ConcurrentHashMap<Locale, Map<String, String>>(64);
242    
243    }