/************************************************************************** OmegaT - Computer Assisted Translation (CAT) tool with fuzzy matching, translation memory, keyword search, glossaries, and translation leveraging into updated projects. Copyright (C) 2010 Alex Buloichik, Didier Briel 2011 Briac Pilpre, Alex Buloichik 2013 Didier Briel 2016 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.core.machinetranslators; import java.awt.Window; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JCheckBox; import org.omegat.gui.exttrans.MTConfigDialog; import org.omegat.util.JsonParser; import org.omegat.util.Language; import org.omegat.util.Log; import org.omegat.util.OStrings; import org.omegat.util.Preferences; import org.omegat.util.WikiGet; /** * Support of Google Translate API v.2 machine translation. * * @author Alex Buloichik (alex73mail@gmail.com) * @author Didier Briel * @author Briac Pilpre * @author Aaron Madlon-Kay * * @see <a href="https://cloud.google.com/translate/docs/getting-started">Translation API</a> */ public class Google2Translate extends BaseTranslate { protected static final String PROPERTY_PREMIUM_KEY = "google.api.premium"; protected static final String PROPERTY_API_KEY = "google.api.key"; protected static final String GT_URL = "https://translation.googleapis.com/language/translate/v2"; protected static final Pattern RE_HTML = Pattern.compile("&#([0-9]+);"); @Override protected String getPreferenceName() { return Preferences.ALLOW_GOOGLE2_TRANSLATE; } @Override public String getName() { return OStrings.getString("MT_ENGINE_GOOGLE2"); } @Override protected String translate(Language sLang, Language tLang, String text) throws Exception { String trText = text.length() > 5000 ? text.substring(0, 4997) + "..." : text; String prev = getFromCache(sLang, tLang, trText); if (prev != null) { return prev; } String targetLang = tLang.getLanguageCode(); // Differentiate in target between simplified and traditional Chinese if (tLang.getLanguage().compareToIgnoreCase("zh-cn") == 0 || tLang.getLanguage().compareToIgnoreCase("zh-tw") == 0) { targetLang = tLang.getLanguage(); } else if (tLang.getLanguage().compareToIgnoreCase("zh-hk") == 0) { targetLang = "ZH-TW"; // Google doesn't recognize ZH-HK } String googleKey = getCredential(PROPERTY_API_KEY); if (googleKey == null || googleKey.isEmpty()) { return OStrings.getString("GOOGLE_API_KEY_NOTFOUND"); } Map<String, String> params = new TreeMap<String, String>(); if (isPremium()) { params.put("model", "nmt"); } params.put("key", googleKey); params.put("source", sLang.getLanguageCode()); params.put("target", targetLang); params.put("q", trText); // The 'text' format mangles the tags, whereas the 'html' encodes some characters // as entities. Since it's more reliable to convert the entities back, we are // using 'html' and convert the text with the unescapeHTML() method. params.put("format", "html"); Map<String, String> headers = new TreeMap<String, String>(); headers.put("X-HTTP-Method-Override", "GET"); String v; try { v = WikiGet.post(GT_URL, params, headers); } catch (IOException e) { return e.getLocalizedMessage(); } String tr = getJsonResults(v); if (tr == null) { return ""; } tr = unescapeHTML(tr); tr = cleanSpacesAroundTags(tr, text); putToCache(sLang, tLang, trText, tr); return tr; } /** Convert entities to character. Ex: "'" to "'". */ private String unescapeHTML(String text) { text = text.replace(""", "\"") .replace(">", ">") .replace("<", "<") .replace("&", "&"); Matcher m = RE_HTML.matcher(text); while (m.find()) { String g = m.group(); int codePoint = Integer.parseInt(m.group(1)); String cpString = String.valueOf(Character.toChars(codePoint)); text = text.replace(g, cpString); } return text; } @SuppressWarnings("unchecked") protected String getJsonResults(String json) { Map<String, Object> rootNode; try { rootNode = (Map<String, Object>) JsonParser.parse(json); } catch (Exception e) { Log.logErrorRB(e, "MT_JSON_ERROR"); return OStrings.getString("MT_JSON_ERROR"); } try { Map<String, Object> dataNode = (Map<String, Object>) rootNode.get("data"); List<Object> translationsList = (List<Object>) dataNode.get("translations"); Map<String, String> translationNode = (Map<String, String>) translationsList.get(0); return translationNode.get("translatedText"); } catch (NullPointerException e) { return null; } } /** * Whether or not to use the new Neural Machine Translation System * * @see <a href="https://research.googleblog.com/2016/09/a-neural-network-for-machine.html">A Neural * Network for Machine Translation, at Production Scale</a> */ private boolean isPremium() { String value = System.getProperty(PROPERTY_PREMIUM_KEY, Preferences.getPreference(PROPERTY_PREMIUM_KEY)); return Boolean.parseBoolean(value); } @Override public boolean isConfigurable() { return true; } @Override public void showConfigurationUI(Window parent) { JCheckBox premiumCheckBox = new JCheckBox(OStrings.getString("MT_ENGINE_GOOGLE2_PREMIUM_LABEL")); premiumCheckBox.setSelected(isPremium()); MTConfigDialog dialog = new MTConfigDialog(parent, getName()) { @Override protected void onConfirm() { String key = panel.valueField1.getText().trim(); boolean temporary = panel.temporaryCheckBox.isSelected(); setCredential(PROPERTY_API_KEY, key, temporary); System.setProperty(PROPERTY_PREMIUM_KEY, Boolean.toString(premiumCheckBox.isSelected())); Preferences.setPreference(PROPERTY_PREMIUM_KEY, premiumCheckBox.isSelected()); } }; dialog.panel.valueLabel1.setText(OStrings.getString("MT_ENGINE_GOOGLE2_API_KEY_LABEL")); dialog.panel.valueField1.setText(getCredential(PROPERTY_API_KEY)); dialog.panel.valueLabel2.setVisible(false); dialog.panel.valueField2.setVisible(false); dialog.panel.temporaryCheckBox.setSelected(isCredentialStoredTemporarily(PROPERTY_API_KEY)); dialog.panel.itemsPanel.add(premiumCheckBox); dialog.show(); } }