Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Online translation #241

Merged
merged 8 commits into from
Apr 7, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
import edu.cornell.mannlib.vitro.webapp.utils.developer.Key;

/**
* A wrapper for a ResourceBundle that will not throw an exception, no matter
* what string you request.
Expand All @@ -20,7 +23,9 @@
*/
public class I18nBundle {
private static final Log log = LogFactory.getLog(I18nBundle.class);

private static final String startSep = "\u25a4";
private static final String endSep = "\u25a5";
private static final String intSep = "\u25a6";
private static final String MESSAGE_BUNDLE_NOT_FOUND = "Text bundle ''{0}'' not found.";
private static final String MESSAGE_KEY_NOT_FOUND = "Text bundle ''{0}'' has no text for ''{1}''";

Expand Down Expand Up @@ -75,13 +80,26 @@ public String text(String key, Object... parameters) {
key);
log.warn(message);
textString = "ERROR: " + message;
}
String result = formatString(textString, parameters);
}
String message = formatString(textString, parameters);

if (i18nLogger != null) {
i18nLogger.log(bundleName, key, parameters, textString, result);
i18nLogger.log(bundleName, key, parameters, textString, message);
}
return result;
if (isNeedExportInfo()) {
String separatedArgs = "";
for (int i = 0; i < parameters.length; i++) {
separatedArgs += parameters[i] + intSep;
}
return startSep + key + intSep + textString + intSep + separatedArgs + message + endSep;
} else {
return message;
}

}

private static boolean isNeedExportInfo() {
return DeveloperSettings.getInstance().getBoolean(Key.I18N_ONLINE_TRANSLATION);
}

private static String formatString(String textString, Object... parameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ public enum Key {
* Load language property files every time they are requested.
*/
I18N_DEFEAT_CACHE("developer.i18n.defeatCache", true),

/**
* Enable online translations.
*/
I18N_ONLINE_TRANSLATION("developer.i18n.onlineTranslation", true),
/**
* Enable the I18nLogger to log each string request.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

# developer.i18n.defeatCache = false
# developer.i18n.logStringRequests = false
# developer.i18n.onlineTranslation = false


#------------------------------------------------------------------------------
Expand Down
188 changes: 188 additions & 0 deletions webapp/src/main/webapp/js/developer/FileSaver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports !== "undefined") {
factory();
} else {
var mod = {
exports: {}
};
factory();
global.FileSaver = mod.exports;
}
})(this, function () {
"use strict";

/*
* FileSaver.js
* A saveAs() FileSaver implementation.
*
* By Eli Grey, http://eligrey.com
*
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
* source : http://purl.eligrey.com/github/FileSaver.js
*/
// The one and only way of getting global scope in all environments
// https://stackoverflow.com/q/3277182/1008999
var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0;

function bom(blob, opts) {
if (typeof opts === 'undefined') opts = {
autoBom: false
};else if (typeof opts !== 'object') {
console.warn('Deprecated: Expected third argument to be a object');
opts = {
autoBom: !opts
};
} // prepend BOM for UTF-8 XML and text/* types (including HTML)
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF

if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xFEFF), blob], {
type: blob.type
});
}

return blob;
}

function download(url, name, opts) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'blob';

xhr.onload = function () {
saveAs(xhr.response, name, opts);
};

xhr.onerror = function () {
console.error('could not download file');
};

xhr.send();
}

function corsEnabled(url) {
var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker

xhr.open('HEAD', url, false);

try {
xhr.send();
} catch (e) {}

return xhr.status >= 200 && xhr.status <= 299;
} // `a.click()` doesn't work for all browsers (#465)


function click(node) {
try {
node.dispatchEvent(new MouseEvent('click'));
} catch (e) {
var evt = document.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
node.dispatchEvent(evt);
}
} // Detect WebView inside a native macOS app by ruling out all browsers
// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos


var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent);
var saveAs = _global.saveAs || ( // probably in some web worker
typeof window !== 'object' || window !== _global ? function saveAs() {}
/* noop */
// Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
: 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) {
var URL = _global.URL || _global.webkitURL;
var a = document.createElement('a');
name = name || blob.name || 'download';
a.download = name;
a.rel = 'noopener'; // tabnabbing
// TODO: detect chrome extensions & packaged apps
// a.target = '_blank'

if (typeof blob === 'string') {
// Support regular links
a.href = blob;

if (a.origin !== location.origin) {
corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
} else {
click(a);
}
} else {
// Support blobs
a.href = URL.createObjectURL(blob);
setTimeout(function () {
URL.revokeObjectURL(a.href);
}, 4E4); // 40s

setTimeout(function () {
click(a);
}, 0);
}
} // Use msSaveOrOpenBlob as a second approach
: 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
name = name || blob.name || 'download';

if (typeof blob === 'string') {
if (corsEnabled(blob)) {
download(blob, name, opts);
} else {
var a = document.createElement('a');
a.href = blob;
a.target = '_blank';
setTimeout(function () {
click(a);
});
}
} else {
navigator.msSaveOrOpenBlob(bom(blob, opts), name);
}
} // Fallback to using FileReader and a popup
: function saveAs(blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker
// Mostly only available on user interaction and the fileReader is async so...
popup = popup || open('', '_blank');

if (popup) {
popup.document.title = popup.document.body.innerText = 'downloading...';
}

if (typeof blob === 'string') return download(blob, name, opts);
var force = blob.type === 'application/octet-stream';

var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;

var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);

if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') {
// Safari doesn't allow downloading of blob URLs
var reader = new FileReader();

reader.onloadend = function () {
var url = reader.result;
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
if (popup) popup.location.href = url;else location = url;
popup = null; // reverse-tabnabbing #460
};

reader.readAsDataURL(blob);
} else {
var URL = _global.URL || _global.webkitURL;
var url = URL.createObjectURL(blob);
if (popup) popup.location = url;else location.href = url;
popup = null; // reverse-tabnabbing #460

setTimeout(function () {
URL.revokeObjectURL(url);
}, 4E4); // 40s
}
});
_global.saveAs = saveAs.saveAs = saveAs;

if (typeof module !== 'undefined') {
module.exports = saveAs;
}
});
1 change: 1 addition & 0 deletions webapp/src/main/webapp/js/developer/developerPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function DeveloperPanel(developerAjaxUrl) {
document.getElementById("developer_pageContents_logCustomShortView").disabled = !developerEnabled;
document.getElementById("developer_i18n_defeatCache").disabled = !developerEnabled;
document.getElementById("developer_i18n_logStringRequests").disabled = !developerEnabled;
document.getElementById("developer_i18n_onlineTranslation").disabled = !developerEnabled;
document.getElementById("developer_loggingRDFService_enable").disabled = !developerEnabled;
document.getElementById("developer_searchIndex_enable").disabled = !developerEnabled;
document.getElementById("developer_searchIndex_logIndexingBreakdownTimings").disabled = !developerEnabled;
Expand Down
Loading