package org.basex.core; import static org.basex.core.Text.COLS; import static org.basex.util.Util.errln; import static org.basex.util.Util.info; import static org.basex.util.Util.langkeys; import static org.basex.util.Util.language; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.JarURLConnection; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.StringTokenizer; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.basex.io.IO; import org.basex.io.IOFile; import org.basex.util.Token; import org.basex.util.Util; import org.basex.util.list.StringList; /** * This class loads language specific texts when the {@link #lang} * method is called for the first time. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen * @author Andreas Weiler */ public final class Lang { /** Throws an error if this class is loaded. This flag is used to check * if non-printing processes access the language files. */ private static final boolean DISALLOW = false; /** Checks which strings of the language file are not used. */ private static final boolean CHECK = true; /** Language suffix. */ private static final String SUFFIX = "lang"; /** Cached source files. */ private static final HashMap<String, String> TETXTS = new HashMap<String, String>(); /** Checks which strings have been applied. */ private static HashMap<String, Boolean> check; /** Private constructor. */ private Lang() { } /** Reads the language file. */ static { read(language, CHECK); } /** * Reads the specified language file. * @param lang language * @param chk check flag */ private static synchronized void read(final String lang, final boolean chk) { BufferedReader br = null; try { if(DISALLOW) throw new Error("Language file was accessed."); if(chk) check = new HashMap<String, Boolean>(); // changed Christoph Plutte // final String path = '/' + SUFFIX + '/' + lang + '.' + SUFFIX; // final String path = Prop.HOME + "WORK" + "\\" + SUFFIX + "\\" + // lang + "." + SUFFIX; // final InputStream is = Lang.class.getResourceAsStream(path); // if(is == null) { // errln(path + " not found."); // } else { // br = new BufferedReader(new InputStreamReader(is, Token.UTF8)); File f = new File(Prop.HOME + "WORK" + "/" + SUFFIX + "/" + lang + "." + SUFFIX); final URL url = f.toURI().toURL(); if (url == null) { Util.errln("%." + SUFFIX + " not found.", lang); } else { br = new BufferedReader(new InputStreamReader((InputStream) url.getContent(), Token.UTF8)); for(String line; (line = br.readLine()) != null;) { final int i = line.indexOf('='); if(i == -1 || line.startsWith("#")) continue; final String key = line.substring(0, i).trim(); String val = line.substring(i + 1).trim(); if(val.contains("\\n")) val = val.replaceAll("\\\\n", Prop.NL); if(langkeys) val = '[' + key + COLS + val + ']'; if(TETXTS.get(key) == null) { TETXTS.put(key, val); } else if(chk) { errln("%." + SUFFIX + ": '%' assigned twice", lang, key); } if(chk) check.put(key, true); } } } catch(final IOException ex) { errln(ex); } finally { if(br != null) try { br.close(); } catch(final IOException ex) { } } } /** * Returns the specified string. * @param key key * @return string */ static synchronized String lang(final String key) { if(key == null) { if(CHECK && !check.isEmpty()) { for(final String s : check.keySet()) errln("%." + SUFFIX + ": '%' not used", language, s); } return null; } final String val = TETXTS.get(key); if(val == null) { if(!TETXTS.isEmpty()) errln("%." + SUFFIX + ": '%' missing", language, key); return '[' + key + ']'; } if(CHECK) check.remove(key); return val; } /** * Returns the specified string with some text extensions included. * @param key key * @param e text text extensions * @return string */ static synchronized String lang(final String key, final Object... e) { return info(lang(key), e); } /** * Parses all available language files and returns the names and credits. * @return language arrays */ public static synchronized String[][] parse() { final StringList langs = new StringList(); final StringList creds = new StringList(); try { // supported protocols: jar and file final URL url = Lang.class.getResource('/' + SUFFIX); if(url.getProtocol().equals("jar")) { final JarURLConnection conn = (JarURLConnection) url.openConnection(); final String pre = conn.getEntryName(); final JarFile jar = conn.getJarFile(); final Enumeration<JarEntry> je = jar.entries(); while(je.hasMoreElements()) { final JarEntry entry = je.nextElement(); final String name = entry.getName(); if(!name.startsWith(pre) || !name.endsWith(SUFFIX)) continue; final byte[] cont = new byte[(int) entry.getSize()]; new DataInputStream(jar.getInputStream(entry)).readFully(cont); langs.add(name.replaceAll(".*/|." + SUFFIX, "")); creds.add(credits(cont)); } } else { // changed Christoph Plutte // for(final IO f : new IOFile(url.getFile()).children()) { for (final IO f : new IOFile(Prop.HOME + "WORK" + "/" + SUFFIX).children()) { langs.add(f.name().replaceAll('.' + SUFFIX, "")); creds.add(credits(f.read())); } } } catch(final IOException ex) { errln(ex); } return new String[][] { langs.toArray(), creds.toArray() }; } /** * Returns the credits from the specified file. * @param cont content * @return credits */ private static synchronized String credits(final byte[] cont) { final StringTokenizer st = new StringTokenizer(Token.string(cont), "\n"); st.nextToken(); return st.nextToken().replaceAll("# ", ""); } }