/************************************************************************** OmegaT - Computer Assisted Translation (CAT) tool with fuzzy matching, translation memory, keyword search, glossaries, and translation leveraging into updated projects. Copyright (C) 2012 Thomas Cordonnier 2013 Aaron Madlon-Kay Home page: http://www.omegat.org/ Support center: http://groups.yahoo.com/group/OmegaT/ This file is part of OmegaT. OmegaT is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OmegaT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. **************************************************************************/ package org.omegat.util; import java.io.File; import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.omegat.core.Core; import org.omegat.core.data.ProjectProperties; /** * This class is used to transform a string by expansion of variables it * contains. It can expand: * <ul> * <li>Entries in Bundle.properties: see {@link #expandBundleEntries(String)} * for syntax * <li>Variables: see {@link #expandVariables(Object)} for syntax * </ul> * Here we define variables which depends only on the project. This class should * be overriden to define more specific substitutions. * * @author Thomas CORDONNIER * @author Aaron Madlon-Kay */ public abstract class VarExpansion<Param> { // ------------------------------ definitions ------------------- public static final String VAR_SOURCE_TEXT = "${sourceText}"; public static final String VAR_TARGET_TEXT = "${targetText}"; public static final String VAR_PROJECT_SOURCE_LANG = "${projectSourceLang}"; public static final String VAR_PROJECT_SOURCE_LANG_CODE = "${projectSourceLangCode}"; public static final String VAR_PROJECT_TARGET_LANG = "${projectTargetLang}"; public static final String VAR_PROJECT_TARGET_LANG_CODE = "${projectTargetLangCode}"; public static final String VAR_FILE_NAME = "${fileName}"; public static final String VAR_FILE_NAME_ONLY = "${fileNameOnly}"; public static final String VAR_FILE_EXTENSION = "${fileExtension}"; public static final String VAR_FILE_PATH = "${filePath}"; public static final String VAR_FILE_SHORT_PATH = "${fileShortPath}"; public static final Pattern PATTERN_BUNDLE_ENTRY = Pattern.compile("#\\{([\\w\\.]+?)\\}(\\[.+?\\])*"); protected String template; public VarExpansion(String template) { // Optimisation : pre-expand all what is not one-match-dependant // Bundle entries template = expandBundleEntries(template); // Variables if (Core.getProject().isProjectLoaded()) { ProjectProperties prop = Core.getProject().getProjectProperties(); template = template.replace(VAR_PROJECT_TARGET_LANG, prop.getTargetLanguage().getLanguage()); template = template.replace(VAR_PROJECT_TARGET_LANG_CODE, prop.getTargetLanguage().getLanguageCode()); template = template.replace(VAR_PROJECT_SOURCE_LANG, prop.getSourceLanguage().getLanguage()); template = template.replace(VAR_PROJECT_SOURCE_LANG_CODE, prop.getSourceLanguage().getLanguageCode()); } this.template = template; } // ------------------------------ functions ------------------- /** * Replace bundle entries with their translation <br> * Format : #{BUNDLE_ENTRY_NAME}[param0][param1][param2]... * (parameters can contain expanded variables but not with [ or ]) * @param localTemplate Initial template. * @return Expanded template */ protected static String expandBundleEntries(String localTemplate) { Matcher matcher; while ((matcher = PATTERN_BUNDLE_ENTRY.matcher(localTemplate)).find()) { String original = matcher.group(); String translation = OStrings.getString(matcher.group(1)); if (!StringUtil.isEmpty(matcher.group(2))) { String vars = matcher.group(2); List<String> values = new ArrayList<String>(); matcher = Pattern.compile("\\[(.+?)\\]").matcher(vars); while (matcher.find()) { values.add(matcher.group(1)); } translation = MessageFormat.format(translation, values.toArray()); } localTemplate = localTemplate.replace(original, translation); } return localTemplate; } /** * Expands all variables relating to file name : * <ul> * <li>${filePath} = full file path * <li>${fileShortPath} = file path relative to given root * <li>${fileName} = full file name (w/o path but with extension) * <li>${fileNameOnly} = file name without extension * <li>${fileNameOnly-1}, ${fileNameOnly-2}, ... = filename with 1, 2, ... extensions * <li>${fileExtension} = all extensions after '.' * <li>${fileExtension-1}, ${fileExtension-2}, ... = ${fileExtension} after removing 1, 2, ... extensions * </ul> * * @param localTemplate * initial template. If null, use instance's template but does not modify it * @param filePath * path used by variable ${fileShortPath} * @return Copy of the template with mentioned variables expanded. Other variables remain unchanged */ public String expandFileNames(String localTemplate, String[] filePaths, String baseDir) { if (localTemplate == null) { localTemplate = this.template; // copy } String filePath = filePaths[0]; String numHint = ""; if (filePaths.length > 1) { numHint = filePath.equals("") ? OStrings.getString("MATCHES_THIS_PROJECT") : ""; numHint += " " + StringUtil.format(OStrings.getString("MATCHES_MULTI_FILE_HINT"), filePaths.length - 1); } localTemplate = localTemplate.replace(VAR_FILE_PATH, filePath + numHint); try { filePath = Paths.get(baseDir).relativize(Paths.get(filePath)).toString(); } catch (IllegalArgumentException ex) { } localTemplate = localTemplate.replace(VAR_FILE_SHORT_PATH, filePath + numHint); // path without TMRoot if (filePath.contains(File.separator)) { filePath = filePath.substring(filePath.lastIndexOf(File.separator) + 1); } localTemplate = localTemplate.replace(VAR_FILE_NAME, filePath + numHint); if (filePath.contains(".")) { String[] splitName = filePath.split("\\."); StringBuilder nameOnlyBuf = new StringBuilder(splitName[0]); StringBuilder extensionBuf = new StringBuilder(splitName[splitName.length - 1]); localTemplate = localTemplate.replace(VAR_FILE_NAME_ONLY, nameOnlyBuf.toString()); localTemplate = localTemplate.replace(VAR_FILE_EXTENSION, extensionBuf.toString()); for (int i = 0; i < splitName.length; i++) { localTemplate = localTemplate.replaceAll("\\$\\{fileNameOnly-" + i + "\\}", nameOnlyBuf.toString()); localTemplate = localTemplate.replaceAll("\\$\\{fileExtension-" + i + "\\}", extensionBuf.toString()); if (i + 1 < splitName.length) { nameOnlyBuf.append(".").append(splitName[i + 1]); extensionBuf.insert(0, splitName[splitName.length - i - 2] + '.'); } } } // prevent unexpanded fileName variables in case the file has less extensions than expected localTemplate = localTemplate.replaceAll("\\$\\{fileNameOnly(-\\d+)?\\}", filePath); localTemplate = localTemplate.replaceAll("\\$\\{fileExtension(-\\d+)?\\}", ""); return localTemplate; } public String expandFileName(String localTemplate, String filePath, String baseDir) { return expandFileNames(localTemplate, new String[] { filePath }, baseDir); } public abstract String expandVariables(Param param); }