/************************************************************************** OmegaT - Computer Assisted Translation (CAT) tool with fuzzy matching, translation memory, keyword search, glossaries, and translation leveraging into updated projects. Copyright (C) 2012 Alex Buloichik, 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.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; 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.StringUtil; import org.omegat.util.WikiGet; /** * Support of Microsoft Translator machine translation. * * @author Alex Buloichik (alex73mail@gmail.com) * @author Didier Briel * @author Aaron Madlon-Kay * * @see <a href="https://www.microsoft.com/en-us/translator/translatorapi.aspx">Translator API</a> * @see <a href="https://msdn.microsoft.com/en-us/library/ff512421.aspx">Translate Method reference</a> */ public class MicrosoftTranslate extends BaseTranslate { protected static final String PROPERTY_CLIENT_ID = "microsoft.api.client_id"; protected static final String PROPERTY_CLIENT_SECRET = "microsoft.api.client_secret"; protected static final String URL_TOKEN = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13/"; protected static final String URL_TRANSLATE = "http://api.microsofttranslator.com/v2/Http.svc/Translate"; protected static final Pattern RE_RESPONSE = Pattern.compile("<string.+?>(.+)</string>"); protected String accessToken; @Override protected String getPreferenceName() { return Preferences.ALLOW_MICROSOFT_TRANSLATE; } public String getName() { return OStrings.getString("MT_ENGINE_MICROSOFT"); } @Override protected synchronized String translate(Language sLang, Language tLang, String text) throws Exception { text = text.length() > 10000 ? text.substring(0, 9997) + "..." : text; String prev = getFromCache(sLang, tLang, text); if (prev != null) { return prev; } String langFrom = checkMSLang(sLang); String langTo = checkMSLang(tLang); try { String translation; if (accessToken == null) { requestToken(); translation = requestTranslate(langFrom, langTo, text); } else { try { translation = requestTranslate(langFrom, langTo, text); } catch (WikiGet.ResponseError ex) { if (ex.code == 400) { requestToken(); translation = requestTranslate(langFrom, langTo, text); } else { throw ex; } } } if (translation != null) { putToCache(sLang, tLang, text, translation); } return translation; } catch (WikiGet.ResponseError ex) { return ex.getLocalizedMessage(); } catch (Exception ex) { Log.log(ex); return ex.getLocalizedMessage(); } } /** * Converts language codes to Microsoft ones. * @param language * a project language * @return either a language code, or a Chinese language code plus a Microsoft variant */ private String checkMSLang(Language language) { if (language.getLanguage().compareToIgnoreCase("zh-cn") == 0) { return "zh-CHS"; } else if ((language.getLanguage().compareToIgnoreCase("zh-tw") == 0) || (language.getLanguage().compareToIgnoreCase("zh-hk") == 0)) { return "zh-CHT"; } else { return language.getLanguageCode(); } } @SuppressWarnings("unchecked") private void requestToken() throws Exception { String id = getCredential(PROPERTY_CLIENT_ID); String secret = getCredential(PROPERTY_CLIENT_SECRET); if (StringUtil.isEmpty(id) || StringUtil.isEmpty(secret)) { throw new Exception(OStrings.getString("MT_ENGINE_MICROSOFT_KEY_NOTFOUND")); } Map<String, String> p = new TreeMap<String, String>(); p.put("client_id", id); p.put("client_secret", secret); p.put("scope", "http://api.microsofttranslator.com"); p.put("grant_type", "client_credentials"); String r = WikiGet.post(URL_TOKEN, p, null); Map<String, Object> rmap = (Map<String, Object>) JsonParser.parse(r); accessToken = (String) rmap.get("access_token"); } private String requestTranslate(String langFrom, String langTo, String text) throws Exception { Map<String, String> p = new TreeMap<String, String>(); p.put("appId", "Bearer " + accessToken); p.put("text", text); p.put("from", langFrom); p.put("to", langTo); p.put("contentType", "text/plain"); String r = WikiGet.get(URL_TRANSLATE, p, null); Matcher m = RE_RESPONSE.matcher(r); if (m.matches()) { String translatedText = m.group(1); translatedText = translatedText.replace("<", "<"); translatedText = translatedText.replace(">", ">"); return translatedText; } else { Log.logWarningRB("MT_ENGINE_MICROSOFT_WRONG_RESPONSE"); return null; } } @Override public boolean isConfigurable() { return true; } @Override public void showConfigurationUI(Window parent) { MTConfigDialog dialog = new MTConfigDialog(parent, getName()) { @Override protected void onConfirm() { String id = panel.valueField1.getText().trim(); String secret = panel.valueField2.getText().trim(); boolean temporary = panel.temporaryCheckBox.isSelected(); setCredential(PROPERTY_CLIENT_ID, id, temporary); setCredential(PROPERTY_CLIENT_SECRET, secret, temporary); } }; dialog.panel.valueLabel1.setText(OStrings.getString("MT_ENGINE_MICROSOFT_CLIENT_ID_LABEL")); dialog.panel.valueField1.setText(getCredential(PROPERTY_CLIENT_ID)); dialog.panel.valueLabel2.setText(OStrings.getString("MT_ENGINE_MICROSOFT_CLIENT_SECRET_LABEL")); dialog.panel.valueField2.setText(getCredential(PROPERTY_CLIENT_SECRET)); dialog.panel.temporaryCheckBox.setSelected(isCredentialStoredTemporarily(PROPERTY_CLIENT_SECRET)); dialog.show(); } }