/* * Created on Nov 6, 2007 */ package net.atlanticbb.tantlinger.i18n; import java.io.File; import java.io.FileFilter; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import java.util.StringTokenizer; /** * @author Bob Tantlinger * */ public class I18n { private static final File LANG_PACK_DIR = new File(System.getProperty("user.dir"), "languages"); private static final String DEFAULT_BUNDLE_NAME = "messages"; private static final String MNEM_POSTFIX = ".mnemonic"; public static final Properties BUNDLE_PROPS = new Properties(); public static final Map I18NS = new HashMap(); public static Locale locale = Locale.getDefault(); private ResourceBundle bundle; private String _package; private I18n(String _package) { this._package = _package; } public String str(String key) { try { if(bundle == null) { bundle = createBundle(getLocale()); } return bundle.getString(key); } catch(Exception ex) { return '!' + key + '!'; } } public String str(String key, Locale locale) { try { return createBundle(locale).getString(key); } catch(Exception ex) { return '!' + key + '!'; } } public char mnem(String key) { String s = str(key + MNEM_POSTFIX); if(s != null && s.length() > 0) return s.charAt(0); return '!'; } public char mnem(String key, Locale loc) { String s = str(key + MNEM_POSTFIX, loc); if(s != null && s.length() > 0) return s.charAt(0); return '!'; } private ResourceBundle createBundle(Locale loc) { String bun = getBundleForPackage(_package); File[] packs = getAvailableLanguagePacks(); if(packs != null && packs.length > 0) { URL[] urls = new URL[packs.length]; try { for(int i = 0; i < urls.length; i++) urls[i] = packs[i].toURL(); return ResourceBundle.getBundle(bun, loc, URLClassLoader.newInstance(urls)); } catch(MalformedURLException muex) { } catch(MissingResourceException rex) { } } return ResourceBundle.getBundle(bun, loc); //just return default } public static I18n getInstance(String _package) { I18n i18n = (I18n)I18NS.get(_package); if(i18n == null) { i18n = new I18n(_package); I18NS.put(_package, i18n); } return i18n; } public static void setLocale(Locale loc) { locale = loc; for(Iterator it = I18NS.values().iterator(); it.hasNext();) { I18n i18n = (I18n)it.next(); i18n.bundle = null; //reset so bundle with new locale gets created... } } public static void setLocale(String locStr) throws IllegalArgumentException { Locale loc = localeFromString(locStr); if(loc == null) throw new IllegalArgumentException("The locale " + locStr + " was not properly formatted"); setLocale(loc); } public static Locale getLocale() { if(locale == null) Locale.getDefault(); return locale; } /** * Converts slashes to dots in a pathname * @param path * @return */ private static String slashesToDots(String path) { StringBuffer sb = new StringBuffer(); StringTokenizer st = new StringTokenizer(path, "/"); while(st.hasMoreTokens()) { sb.append("."); sb.append(st.nextToken()); } if(sb.toString().startsWith(".")) sb.deleteCharAt(0); return sb.toString(); } private static String createBundleName(String bundlePackage, String bundleName) { StringBuffer sb = new StringBuffer(slashesToDots(bundlePackage)); if(!sb.toString().endsWith(".")) sb.append('.'); sb.append(bundleName); return sb.toString(); } public static void setBundleForPackage(String _package, String bundle) { if(bundle == null) BUNDLE_PROPS.remove(_package); else BUNDLE_PROPS.setProperty(_package, bundle); I18n i18n = (I18n)I18NS.get(_package); if(i18n != null) i18n.bundle = null; //reset to null so the bundle is recreated for the new name } public static String getBundleForPackage(String _package) { String bun = BUNDLE_PROPS.getProperty(_package); if(bun == null)//use default bun = createBundleName(_package, DEFAULT_BUNDLE_NAME); return bun; } public static File getLanguagePackDirectory() { return LANG_PACK_DIR; } public static File[] getAvailableLanguagePacks() { Locale[] locs = getAvailableLanguagePackLocales(); List packs = new ArrayList(); for(int i = 0; i < locs.length; i++) { String name = locs[i].toString() + ".zip"; File f = new File(LANG_PACK_DIR, name); if(f.isFile() && f.canRead()) packs.add(f); } return (File[])packs.toArray(new File[packs.size()]); } public static Locale[] getAvailableLanguagePackLocales() { List locs = new ArrayList(); File dir = getLanguagePackDirectory(); if(dir.isDirectory() && dir.canRead()) { File[] packs = dir.listFiles(new ZipFileFilter()); if(packs != null) { for(int i = 0; i < packs.length; i++) { String name = packs[i].getName(); int p = name.lastIndexOf("."); if(p != -1) { String locStr = name.substring(0, p); Locale loc = localeFromString(locStr); if(loc != null) locs.add(loc); } } } } return (Locale[])locs.toArray(new Locale[locs.size()]); } public static Locale localeFromString(String locStr) { String[] parts = locStr.split("_"); if(parts.length > 0 || parts.length <= 3) { String lang = parts[0]; String country = (parts.length > 1) ? parts[1] : ""; String varient = (parts.length > 2) ? parts[2] : ""; return new Locale(lang, country, varient); } return null; } private static class ZipFileFilter implements FileFilter { public boolean accept(File f) { if(f.isFile() && f.canRead()) { String name = f.getName().toLowerCase(); if(name.endsWith(".zip")) return true; } return false; } } }