package fi.utu.ville.exercises.stub; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Logger; /** * A class wrapping the actual parsing of contents of an Ville-translation (.trl) file. * * @author Riku Haavisto * */ public final class TranslationFileParser { private static final String keyConstant = "@key:"; private static final String splitter = ":"; private static final String prefixSplitter = "."; /** * Static method for parsing list of strings from a .trl-file and prefixing all the translations with given prefix. * * @param prefix * prefix or namespace to use for this set of translations * @param trlFileLines * lines of a .trl-file that will be parsed * @return a map from language specifier strings to maps of (prefixed) key-translation -pairs */ public static Map<String, Map<String, String>> parseTranslationFile( String prefix, List<String> trlFileLines) { TranslationFileParser actParser = new TranslationFileParser(); return actParser.parseFile(prefix, trlFileLines); } private static final Logger logger = Logger .getLogger(TranslationFileParser.class.getName()); private final Map<String, Map<String, String>> dictsByLang = new HashMap<String, Map<String, String>>();; private final List<String> allIsoLangs = Arrays.asList(Locale .getISOLanguages()); private String currKey = ""; private String currOpenTranslationLang = ""; private String currOpenTranslation = ""; private String currPrefix = ""; // just use the static method private TranslationFileParser() { } /** * Method for looping through the lines of a Ville-translation file and parsing all the keys and translations it contains and returning them as a map. * * @param prefix * namespace or prefix to be added to all translation-keys * @param lines * lines of the Ville-translation file to load * @return a map from language specifier strings to maps of (prefixed) key-translation -pairs */ public Map<String, Map<String, String>> parseFile(String prefix, List<String> lines) { currPrefix = prefix; // Process the file: remove comments and empty lines for (int i = 0; i < lines.size(); i++) { String currLine = lines.get(i); logger.fine("line: " + currLine); logger.fine(currKey + "; " + currOpenTranslationLang + "; " + currOpenTranslation); if (!checkLineFormat(currLine)) { throw new IllegalArgumentException( "Language file has illegal format"); } if (currLine.startsWith("//")) { continue; // comment line } // breaks the current key else if (currLine.startsWith(keyConstant)) { addCurrOpenTranslation(); String keyPart = currLine.substring(keyConstant.length()); currKey = keyPart.trim(); // currKey = parts[1].trim(); currOpenTranslationLang = ""; currOpenTranslation = ""; } // breaks the current translation but not the current key // only way to start a new translation, is to start by lang-tag else if (currLine.matches("^@\\w+:.*$")) { addCurrOpenTranslation(); String langPart = currLine.substring(1, currLine.indexOf(splitter)); String transPart = currLine.substring(currLine .indexOf(splitter) + 1); currOpenTranslationLang = langPart.trim(); currOpenTranslation = transPart; } // appends to the current translation else { currOpenTranslation += currLine; } } // add the final hanging translation addCurrOpenTranslation(); return dictsByLang; } /** * Adds the currently open key-translation pair to the map of known translations. State is not cleared as it depends on the reason for adding the * open-translation to map (ie. whether translation language or translation key changed). */ private void addCurrOpenTranslation() { if (!"".equals(currOpenTranslationLang) && !"".equals(currKey) && !"".equals(currOpenTranslation)) { if (!allIsoLangs.contains(currOpenTranslationLang)) { throw new IllegalStateException( "Not a valid ISO-language-code: " + currOpenTranslationLang); } if (!dictsByLang.containsKey(currOpenTranslationLang)) { if (!dictsByLang.containsKey(currOpenTranslationLang)) { dictsByLang.put(currOpenTranslationLang, new HashMap<String, String>()); } } String oldValue = null; if (null != (oldValue = dictsByLang.get(currOpenTranslationLang) .put(currPrefix + prefixSplitter + currKey, currOpenTranslation))) { logger.warning("Overrid entry for key: " + currPrefix + prefixSplitter + currKey + " and language: " + currOpenTranslationLang + "\nOld value: " + oldValue + "\nNew value: " + currOpenTranslation); } else { logger.fine("Added for key: " + currPrefix + prefixSplitter + currKey + " and language: " + currOpenTranslationLang + "\nValue: " + currOpenTranslation); } } } // TODO: it would probably be a good idea to implement some simple // format-checking... private static boolean checkLineFormat(String line) { return true; } }