001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019 020package lucee.runtime.i18n; 021 022import java.util.Arrays; 023import java.util.Iterator; 024import java.util.LinkedHashMap; 025import java.util.Locale; 026import java.util.Map; 027import java.util.Map.Entry; 028import java.util.regex.Matcher; 029import java.util.regex.Pattern; 030 031import lucee.runtime.exp.ExpressionException; 032import lucee.runtime.type.util.ListUtil; 033 034 035/** 036 * Factory to create Locales by CFML rules 037 */ 038public final class LocaleFactory { 039 //private static Pattern localePattern = Pattern.compile("^\\s*([^\\s\\(]+)\\s*(\\(\\s*([^\\s\\)]+)\\s*\\))?\\s*$"); 040 private static Pattern localePattern = Pattern.compile("^\\s*([^\\(]+)\\s*(\\(\\s*([^\\)]+)\\s*\\))?\\s*$"); 041 private static Pattern localePattern2 = Pattern.compile("^([a-z]{2})_([a-z]{2,3})$"); 042 private static Pattern localePattern3 = Pattern.compile("^([a-z]{2})_([a-z]{2,3})_([a-z]{2,})$"); 043 044 private static Map<String,Locale> locales=new LinkedHashMap<String,Locale>(); 045 private static Map<String,Locale> localeAlias=new LinkedHashMap<String,Locale>(); 046 047 private static String list; 048 static { 049 Locale[] ls = Locale.getAvailableLocales(); 050 051 052 String key; 053 StringBuilder sb=new StringBuilder(); 054 for(int i=0;i<ls.length;i++) { 055 key=ls[i].getDisplayName(Locale.US).toLowerCase(); 056 locales.put(key, ls[i]); 057 if(key.indexOf(',')!=-1){ 058 key=ls[i].toString(); 059 //print.ln(key); 060 061 } 062 if(i>0)sb.append(","); 063 sb.append(key); 064 } 065 list=sb.toString(); 066 067 068 setLocalAlias("albanian (albania)", LocaleConstant.ALBANIAN_ALBANIA); 069 070 setLocalAlias("arabic (algeria)", LocaleConstant.ARABIC_ALGERIA); 071 setLocalAlias("arabic (bahrain)", LocaleConstant.ARABIC_BAHRAIN); 072 setLocalAlias("arabic (egypt)", LocaleConstant.ARABIC_EGYPT); 073 setLocalAlias("arabic (iraq)", LocaleConstant.ARABIC_IRAQ); 074 setLocalAlias("arabic (jordan)", LocaleConstant.ARABIC_JORDAN); 075 setLocalAlias("arabic (kuwait)", LocaleConstant.ARABIC_KUWAIT); 076 setLocalAlias("arabic (lebanon)", LocaleConstant.ARABIC_LEBANON); 077 setLocalAlias("arabic (libya)", LocaleConstant.ARABIC_LIBYA); 078 setLocalAlias("arabic (morocco)", LocaleConstant.ARABIC_MAROCCO); 079 setLocalAlias("arabic (oman)", LocaleConstant.ARABIC_OMAN); 080 setLocalAlias("arabic (qatar)", LocaleConstant.ARABIC_QATAR); 081 setLocalAlias("arabic (saudi arabia)", LocaleConstant.ARABIC_SAUDI_ARABIA); 082 setLocalAlias("arabic (sudan)", LocaleConstant.ARABIC_SUDAN); 083 setLocalAlias("arabic (syria)", LocaleConstant.ARABIC_SYRIA); 084 setLocalAlias("arabic (tunisia)", LocaleConstant.ARABIC_TUNISIA); 085 setLocalAlias("arabic (united arab emirates)", LocaleConstant.ARABIC_UNITED_ARAB_EMIRATES); 086 setLocalAlias("arabic (yemen)", LocaleConstant.ARABIC_YEMEN); 087 088 setLocalAlias("chinese (china)", Locale.CHINA); 089 setLocalAlias("chinese (hong kong)",LocaleConstant.CHINESE_HONG_KONG); 090 setLocalAlias("chinese (singapore)",LocaleConstant.CHINESE_SINGAPORE); 091 setLocalAlias("chinese (taiwan)",LocaleConstant.CHINESE_TAIWAN); 092 setLocalAlias("dutch (belgian)",LocaleConstant.DUTCH_BELGIUM); 093 setLocalAlias("dutch (belgium)",LocaleConstant.DUTCH_BELGIUM); 094 setLocalAlias("dutch (standard)",LocaleConstant.DUTCH_NETHERLANDS); 095 setLocalAlias("english (australian)",LocaleConstant.ENGLISH_AUSTRALIA); 096 setLocalAlias("english (australia)",LocaleConstant.ENGLISH_AUSTRALIA); 097 setLocalAlias("english (canadian)",LocaleConstant.ENGLISH_CANADA); 098 setLocalAlias("english (canada)",LocaleConstant.ENGLISH_CANADA); 099 setLocalAlias("english (new zealand)",LocaleConstant.ENGLISH_NEW_ZEALAND); 100 setLocalAlias("english (uk)",LocaleConstant.ENGLISH_UNITED_KINDOM); 101 setLocalAlias("english (united kingdom)",LocaleConstant.ENGLISH_UNITED_KINDOM); 102 setLocalAlias("english (gb)",LocaleConstant.ENGLISH_UNITED_KINDOM); 103 setLocalAlias("english (great britan)",LocaleConstant.ENGLISH_UNITED_KINDOM); 104 setLocalAlias("english (us)",LocaleConstant.ENGLISH_UNITED_STATES); 105 setLocalAlias("english (united states)",LocaleConstant.ENGLISH_UNITED_STATES); 106 setLocalAlias("english (united states of america)",LocaleConstant.ENGLISH_UNITED_STATES); 107 setLocalAlias("english (usa)",LocaleConstant.ENGLISH_UNITED_STATES); 108 setLocalAlias("french (belgium)",new Locale("fr","BE")); 109 setLocalAlias("french (belgian)",new Locale("fr","BE")); 110 setLocalAlias("french (canadian)",new Locale("fr","CA")); 111 setLocalAlias("french (canadia)",new Locale("fr","CA")); 112 setLocalAlias("french (standard)",new Locale("fr","FRA")); 113 setLocalAlias("french (swiss)",new Locale("fr","CH")); 114 setLocalAlias("german (austrian)",new Locale("de","AT")); 115 setLocalAlias("german (austria)",new Locale("de","AT")); 116 setLocalAlias("german (standard)",new Locale("de","DE")); 117 setLocalAlias("german (swiss)",new Locale("de","CH")); 118 setLocalAlias("italian (standard)",new Locale("it","IT")); 119 setLocalAlias("italian (swiss)",new Locale("it","CH")); 120 setLocalAlias("japanese",new Locale("ja","JP")); 121 setLocalAlias("korean",Locale.KOREAN); 122 setLocalAlias("norwegian (bokmal)",new Locale("no","NO")); 123 setLocalAlias("norwegian (nynorsk)",new Locale("no","NO")); 124 setLocalAlias("portuguese (brazilian)",LocaleConstant.PORTUGUESE_BRASIL); 125 setLocalAlias("portuguese (brazil)",LocaleConstant.PORTUGUESE_BRASIL); 126 setLocalAlias("portuguese (standard)",LocaleConstant.PORTUGUESE_PORTUGAL); 127 setLocalAlias("rhaeto-romance (swiss)",new Locale("rm","CH")); 128 locales.put("rhaeto-romance (swiss)",new Locale("rm","CH")); 129 setLocalAlias("spanish (modern)",new Locale("es","ES")); 130 setLocalAlias("spanish (standard)",new Locale("es","ES")); 131 setLocalAlias("swedish",new Locale("sv","SE")); 132 } 133 134 private LocaleFactory(){} 135 136 private static void setLocalAlias(String name, Locale locale) { 137 if(!localeAlias.containsKey(name))localeAlias.put(name, locale); 138 } 139 140 /** 141 * @param strLocale 142 * @param defaultValue 143 * @return return locale match to String 144 */ 145 public static Locale getLocale(String strLocale, Locale defaultValue) { 146 try { 147 return getLocale(strLocale); 148 } catch (ExpressionException e) { 149 return defaultValue; 150 } 151 } 152 153 154 /** 155 * @param strLocale 156 * @return return locale match to String 157 * @throws ExpressionException 158 */ 159 public static Locale getLocale(String strLocale) throws ExpressionException { 160 String strLocaleLC = strLocale.toLowerCase().trim(); 161 Locale l=locales.get(strLocaleLC); 162 if(l!=null) return l; 163 164 l=localeAlias.get(strLocaleLC); 165 if(l!=null) return l; 166 167 Matcher matcher = localePattern2.matcher(strLocaleLC); 168 if(matcher.find()) { 169 int len=matcher.groupCount(); 170 if(len==2) { 171 String lang=matcher.group(1).trim(); 172 String country=matcher.group(2).trim(); 173 Locale locale=new Locale(lang,country); 174 175 try { 176 locale.getISO3Language(); 177 setLocalAlias(strLocaleLC, locale); 178 return locale; 179 } 180 catch(Exception e) {} 181 } 182 } 183 184 matcher = localePattern3.matcher(strLocaleLC); 185 if(matcher.find()) { 186 int len=matcher.groupCount(); 187 if(len==3) { 188 String lang=matcher.group(1).trim(); 189 String country=matcher.group(2).trim(); 190 String variant=matcher.group(3).trim(); 191 Locale locale=new Locale(lang,country,variant); 192 193 try { 194 locale.getISO3Language(); 195 setLocalAlias(strLocaleLC, locale); 196 return locale; 197 } 198 catch(Exception e) {} 199 } 200 } 201 202 203 matcher=localePattern.matcher(strLocaleLC); 204 if(matcher.find()) { 205 int len=matcher.groupCount(); 206 207 if(len==3) { 208 209 String lang=matcher.group(1).trim(); 210 String country=matcher.group(3); 211 if(country!=null)country=country.trim(); 212 Object objLocale=null; 213 214 if(country!=null) objLocale=locales.get(lang.toLowerCase()+" ("+(country.toLowerCase())+")"); 215 else objLocale=locales.get(lang.toLowerCase()); 216 if(objLocale!=null)return (Locale)objLocale; 217 218 Locale locale; 219 if(country!=null)locale=new Locale(lang.toUpperCase(),country.toLowerCase()); 220 else locale=new Locale(lang); 221 222 try { 223 locale.getISO3Language(); 224 } 225 catch(Exception e) { 226 if(strLocale.indexOf('-')!=-1) return getLocale(strLocale.replace('-', '_')); 227 throw new ExpressionException("unsupported Locale ["+strLocale+"]","supported Locales are:"+getSupportedLocalesAsString()); 228 } 229 setLocalAlias(strLocaleLC, locale); 230 return locale; 231 232 } 233 } 234 235 236 throw new ExpressionException("can't cast value ("+strLocale+") to a Locale","supported Locales are:"+getSupportedLocalesAsString()); 237 } 238 239 240 private static String getSupportedLocalesAsString() { 241 // TODO chnge from ArryObject to string 242 String[] arr = locales.keySet().toArray(new String[locales.size()]); 243 Arrays.sort(arr); 244 return ListUtil.arrayToList(arr,","); 245 246 } 247 248 /** 249 * @param locale 250 * @return cast a Locale to a String 251 */ 252 public static String toString(Locale locale) { 253 String lang=locale.getLanguage(); 254 String country=locale.getCountry(); 255 256 synchronized(localeAlias){ 257 Iterator<Entry<String, Locale>> it = localeAlias.entrySet().iterator(); 258 Map.Entry<String, Locale> entry; 259 while(it.hasNext()) { 260 entry= it.next(); 261 //Object qkey=it.next(); 262 Locale curr=entry.getValue(); 263 if(lang.equals(curr.getLanguage()) && country.equals(curr.getCountry())) { 264 return entry.getKey().toString(); 265 } 266 } 267 } 268 return locale.getDisplayName(Locale.ENGLISH); 269 } 270 271 /** 272 * @return Returns the locales. 273 */ 274 public static Map getLocales() { 275 return locales; 276 } 277 public static String getLocaleList() { 278 return list; 279 } 280}