You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
12 KiB
296 lines
12 KiB
// TranslationManager.java
|
|
// -------------------------------------
|
|
// part of YACY
|
|
// (C) by Michael Peter Christen; mc@yacy.net
|
|
// first published on http://www.anomic.de
|
|
// Frankfurt, Germany, 2004
|
|
//
|
|
// This file ist contributed by Burkhard Buelte
|
|
// last major change: 2016-04-05
|
|
//
|
|
// $LastChangedDate$
|
|
// $LastChangedRevision$
|
|
// $LastChangedBy$
|
|
//
|
|
// This program 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 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program 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, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
package net.yacy.utils.translation;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.TreeMap;
|
|
import net.yacy.cora.util.ConcurrentLog;
|
|
import net.yacy.data.Translator;
|
|
import net.yacy.search.Switchboard;
|
|
import net.yacy.search.SwitchboardConstants;
|
|
|
|
/**
|
|
* Utility to create a translation master file from all existing translation
|
|
* with check file.exists and translation text exists.
|
|
* Also can join existing translation with master (currently ristrictive,
|
|
* means only translation text exist in master are included in resultin Map
|
|
*/
|
|
public class TranslationManager extends TranslatorXliff {
|
|
|
|
protected Map<String, Map<String, String>> mainTransLists; // current translation entries for one language
|
|
protected String loadedLng; // language loaded in mainTransLists (2-letter code)
|
|
|
|
public TranslationManager() {
|
|
super();
|
|
}
|
|
|
|
public TranslationManager(final File langfile) {
|
|
mainTransLists = loadTranslationsLists(langfile);
|
|
int pos = langfile.getName().indexOf('.');
|
|
if (pos >= 0) {
|
|
loadedLng = langfile.getName().substring(0, pos);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a translation text to the current map map
|
|
*
|
|
* @param relFileName relative filename the translation belongs to
|
|
* @param sourceLngTxt the english source text
|
|
* @param targetLngTxt the translated text
|
|
* @return true = if map was modified, otherwise false
|
|
*/
|
|
public boolean addTranslation(final String relFileName, final String sourceLngTxt, final String targetLngTxt) {
|
|
assert mainTransLists != null;
|
|
return addTranslation (mainTransLists, relFileName, sourceLngTxt, targetLngTxt);
|
|
}
|
|
|
|
/**
|
|
* Helper to add a translation text to the map
|
|
*
|
|
* @param translation to add the text to
|
|
* @param relFileName relative filename the translation belongs to
|
|
* @param sourceLngTxt the english source text
|
|
* @param targetLngTxt the translated text
|
|
* @return true = if map was modified, otherwise false
|
|
*/
|
|
public boolean addTranslation(Map<String, Map<String, String>> translation, final String relFileName, final String sourceLngTxt, final String targetLngTxt) {
|
|
boolean modified = false;
|
|
|
|
Map<String, String> transFile;
|
|
if (translation.containsKey(relFileName)) {
|
|
transFile = translation.get(relFileName);
|
|
} else {
|
|
transFile = new LinkedHashMap<String, String>();
|
|
translation.put(relFileName, transFile);
|
|
modified = true;
|
|
}
|
|
|
|
String oldLngTxt = transFile.put(sourceLngTxt, targetLngTxt);
|
|
if (oldLngTxt == null) {
|
|
modified = targetLngTxt != null;
|
|
} else if (!oldLngTxt.equals(targetLngTxt)) {
|
|
modified = true;
|
|
}
|
|
return modified;
|
|
}
|
|
|
|
/**
|
|
* Get the translation list for a ui/html file
|
|
* @param filename relative path to htroot
|
|
* @return translation map or null
|
|
*/
|
|
public Map<String, String> getTranslationForFile(String filename) {
|
|
return mainTransLists.get(filename);
|
|
}
|
|
|
|
/**
|
|
* Get a translation target text
|
|
* @param filename of the translation
|
|
* @param source english source text
|
|
* @return translated text or null
|
|
*/
|
|
public String getTranslation (String filename, String source) {
|
|
Map<String, String> tmp = mainTransLists.get(filename);
|
|
if (tmp != null)
|
|
return tmp.get(source);
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Translates one file. The relFilepath is the file name as given in the
|
|
* translation source lists. The source (english) file is expected under
|
|
* htroot path. The destination file is under DATA/LOCALE and calculated
|
|
* using the language of loaded data.
|
|
*
|
|
* @param relFilepath file name releative to htroot
|
|
* @return true on success
|
|
*/
|
|
public boolean translateFile(String relFilepath) {
|
|
assert loadedLng != null;
|
|
assert mainTransLists != null;
|
|
|
|
boolean result = false;
|
|
if (mainTransLists.containsKey(relFilepath)) {
|
|
Switchboard sb = Switchboard.getSwitchboard();
|
|
if (sb != null) {
|
|
final String htRootPath = sb.getConfig(SwitchboardConstants.HTROOT_PATH, SwitchboardConstants.HTROOT_PATH_DEFAULT);
|
|
final File sourceDir = new File(sb.getAppPath(), htRootPath);
|
|
final File destDir = new File(sb.getDataPath("locale.translated_html", "DATA/LOCALE/htroot"), loadedLng);
|
|
// get absolute file by adding relative filename
|
|
final File sourceFile = new File(sourceDir, relFilepath);
|
|
final File destFile = new File(destDir, relFilepath);
|
|
result = translateFile(sourceFile, destFile, mainTransLists.get(relFilepath)); // do the translation
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Create a master translation list by reading all translation files
|
|
* If a masterOutputFile exists, content is preserved (loaded first)
|
|
*
|
|
* @param masterOutpuFile output file (xliff format)
|
|
* @throws IOException
|
|
*/
|
|
public void createMasterTranslationLists(File masterOutputFile) throws IOException {
|
|
if (masterOutputFile.exists()) // if file exists, conserve existing master content (may be updated by external tool)
|
|
mainTransLists = loadTranslationsListsFromXliff(masterOutputFile);
|
|
else
|
|
mainTransLists = new TreeMap<String, Map<String, String>>();
|
|
|
|
List<String> lngFiles = Translator.langFiles(new File("locales"));
|
|
for (String filename : lngFiles) {
|
|
// load translation list
|
|
ConcurrentLog.info("TRANSLATOR", "include translation file " + filename);
|
|
Map<String, Map<String, String>> origTrans = loadTranslationsLists(new File("locales", filename));
|
|
|
|
for (String transfilename : origTrans.keySet()) { // get translation filename
|
|
File checkfile = new File("htroot", transfilename);
|
|
if (checkfile.exists()) { // include in master only if file exists
|
|
// load content to compare translation text is included
|
|
StringBuilder content = new StringBuilder();
|
|
BufferedReader br = null;
|
|
try {
|
|
br = new BufferedReader(new InputStreamReader(new FileInputStream(checkfile), StandardCharsets.UTF_8));
|
|
String line = null;
|
|
while ((line = br.readLine()) != null) {
|
|
content.append(line).append(net.yacy.server.serverCore.CRLF_STRING);
|
|
}
|
|
br.close();
|
|
} catch (final IOException e) {
|
|
} finally {
|
|
if (br != null) {
|
|
try {
|
|
br.close();
|
|
} catch (final Exception e) {
|
|
}
|
|
}
|
|
}
|
|
|
|
// compare translation list
|
|
Map<String, String> origList = origTrans.get(transfilename);
|
|
for (String sourcetxt : origList.keySet()) {
|
|
if (content.indexOf(sourcetxt) >= 0) {
|
|
String origVal = origList.get(sourcetxt);
|
|
// it is possible that intentionally empty translation is given
|
|
// in this case xliff target is missing (=null)
|
|
if (origVal != null && !origVal.isEmpty()) { // if translation exists
|
|
addTranslation(transfilename, sourcetxt, null); // add to master, set target text null
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
ConcurrentLog.fine("TRANSLATOR", "skip file for translation " + transfilename + " (from " + filename + ")");
|
|
}
|
|
}
|
|
}
|
|
// save as xliff file w/o language code
|
|
saveAsXliff(null, masterOutputFile, mainTransLists);
|
|
}
|
|
|
|
/**
|
|
* Joins translation master (xliff) and existing translation (lng).
|
|
* Only texts existing in master are included from the lngfile,
|
|
* the resulting map includes all keys from master with the matching translation
|
|
* from lngfile.
|
|
*
|
|
* @param xlifmaster master (with en text to be translated)
|
|
* @param lngfile existing translation
|
|
* @return resulting map with all entries from master and translation from lngfile
|
|
* @throws IOException
|
|
*/
|
|
public Map<String, Map<String, String>> joinMasterTranslationLists(File xlifmaster, File lngfile) throws IOException {
|
|
|
|
final String filename = lngfile.getName();
|
|
mainTransLists = loadTranslationsListsFromXliff(xlifmaster);
|
|
// load translation list
|
|
ConcurrentLog.info("TRANSLATOR", "join into master translation file " + filename);
|
|
Map<String, Map<String, String>> origTrans = loadTranslationsLists(lngfile);
|
|
|
|
for (String transfilename : origTrans.keySet()) { // get translation filename
|
|
// compare translation list
|
|
Map<String, String> origList = origTrans.get(transfilename);
|
|
Map<String, String> masterList = mainTransLists.get(transfilename);
|
|
for (String sourcetxt : origList.keySet()) {
|
|
if ((masterList != null) && (masterList.isEmpty() || masterList.containsKey(sourcetxt))) { // only if included in master (as all languages are in there but checked for occuance
|
|
String origVal = origList.get(sourcetxt);
|
|
// it is possible that intentionally empty translation is given
|
|
// in this case xliff target is missing (=null)
|
|
if (origVal != null && !origVal.isEmpty()) {
|
|
addTranslation(transfilename, sourcetxt, origVal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return mainTransLists;
|
|
}
|
|
|
|
/**
|
|
* Stores the loaded translations to a .lng file
|
|
* @param lng
|
|
* @param f
|
|
* @return
|
|
*/
|
|
public boolean saveXliff(final String lng, File f) {
|
|
return this.saveAsXliff(lng, f, mainTransLists);
|
|
}
|
|
|
|
/**
|
|
* Stores the loaded translations to a .xlf file
|
|
* @param lng
|
|
* @param f
|
|
* @return
|
|
*/
|
|
public boolean saveLng(final String lng, File f) {
|
|
return this.saveAsLngFile(lng, f, mainTransLists);
|
|
}
|
|
|
|
/**
|
|
* Total number of loaded translation entries
|
|
* @return
|
|
*/
|
|
public int size() {
|
|
int i = 0;
|
|
for (Map<String, String> trans : mainTransLists.values()) {
|
|
i += trans.size();
|
|
}
|
|
return i;
|
|
}
|
|
}
|