mirror of
https://github.com/webrecorder/pywb.git
synced 2025-03-15 00:03:28 +01:00
Localization and Banner Update (#517)
* banner: add banner and localization improvements from ukwa branch: - show 'view all captures' link if not live - optional logo - loc options, if available - banner options set via window.banner_info in banner.html localization support: - add init_loc() to templateview - loc available if config options set - tests: add tests for loading localized messages, override .gitignore to allow test messages.mo
This commit is contained in:
parent
66ac3ca114
commit
0d819aadeb
@ -1,6 +1,6 @@
|
|||||||
from gevent.monkey import patch_all; patch_all()
|
from gevent.monkey import patch_all; patch_all()
|
||||||
|
|
||||||
from werkzeug.routing import Map, Rule, RequestRedirect
|
from werkzeug.routing import Map, Rule, RequestRedirect, Submount
|
||||||
from werkzeug.wsgi import pop_path_info
|
from werkzeug.wsgi import pop_path_info
|
||||||
from six.moves.urllib.parse import urljoin
|
from six.moves.urllib.parse import urljoin
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
@ -138,6 +138,17 @@ class FrontEndApp(object):
|
|||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
routes = self._make_coll_routes(coll_prefix)
|
routes = self._make_coll_routes(coll_prefix)
|
||||||
|
|
||||||
|
# init loc routes, if any
|
||||||
|
loc_keys = list(self.rewriterapp.loc_map.keys())
|
||||||
|
if loc_keys:
|
||||||
|
routes.append(Rule('/', endpoint=self.serve_home))
|
||||||
|
|
||||||
|
submount_route = ', '.join(loc_keys)
|
||||||
|
submount_route = '/<any({0}):lang>'.format(submount_route)
|
||||||
|
|
||||||
|
self.url_map.add(Submount(submount_route, routes))
|
||||||
|
|
||||||
for route in routes:
|
for route in routes:
|
||||||
self.url_map.add(route)
|
self.url_map.add(route)
|
||||||
|
|
||||||
|
@ -68,6 +68,11 @@ class RewriterApp(object):
|
|||||||
jinja_env.jinja_env.install_null_translations()
|
jinja_env.jinja_env.install_null_translations()
|
||||||
|
|
||||||
self.jinja_env = jinja_env
|
self.jinja_env = jinja_env
|
||||||
|
self.loc_map = {}
|
||||||
|
|
||||||
|
self.jinja_env.init_loc(self.config.get('locales_root_dir'),
|
||||||
|
self.config.get('locales'),
|
||||||
|
self.loc_map)
|
||||||
|
|
||||||
self.redirect_to_exact = config.get('redirect_to_exact')
|
self.redirect_to_exact = config.get('redirect_to_exact')
|
||||||
|
|
||||||
|
@ -3,11 +3,13 @@ from warcio.timeutils import timestamp_now
|
|||||||
|
|
||||||
from pywb.utils.loaders import load
|
from pywb.utils.loaders import load
|
||||||
|
|
||||||
from six.moves.urllib.parse import urlsplit
|
from six.moves.urllib.parse import urlsplit, quote
|
||||||
|
|
||||||
from jinja2 import Environment, TemplateNotFound
|
from jinja2 import Environment, TemplateNotFound, contextfunction
|
||||||
from jinja2 import FileSystemLoader, PackageLoader, ChoiceLoader
|
from jinja2 import FileSystemLoader, PackageLoader, ChoiceLoader
|
||||||
|
|
||||||
|
from babel.support import Translations
|
||||||
|
|
||||||
from webassets.ext.jinja2 import AssetsExtension
|
from webassets.ext.jinja2 import AssetsExtension
|
||||||
from webassets.loaders import YAMLLoader
|
from webassets.loaders import YAMLLoader
|
||||||
from webassets.env import Resolver
|
from webassets.env import Resolver
|
||||||
@ -115,6 +117,90 @@ class JinjaEnv(object):
|
|||||||
|
|
||||||
return loaders
|
return loaders
|
||||||
|
|
||||||
|
def init_loc(self, locales_root_dir, locales, loc_map):
|
||||||
|
locales = locales or []
|
||||||
|
|
||||||
|
if locales_root_dir:
|
||||||
|
for loc in locales:
|
||||||
|
loc_map[loc] = Translations.load(locales_root_dir, [loc, 'en'])
|
||||||
|
#jinja_env.jinja_env.install_gettext_translations(translations)
|
||||||
|
|
||||||
|
def get_translate(context):
|
||||||
|
loc = context.get('env', {}).get('pywb_lang')
|
||||||
|
return loc_map.get(loc)
|
||||||
|
|
||||||
|
def override_func(jinja_env, name):
|
||||||
|
@contextfunction
|
||||||
|
def get_override(context, text):
|
||||||
|
translate = get_translate(context)
|
||||||
|
if not translate:
|
||||||
|
return text
|
||||||
|
|
||||||
|
func = getattr(translate, name)
|
||||||
|
return func(text)
|
||||||
|
|
||||||
|
jinja_env.globals[name] = get_override
|
||||||
|
|
||||||
|
# standard gettext() translation function
|
||||||
|
override_func(self.jinja_env, 'gettext')
|
||||||
|
|
||||||
|
# single/plural form translation function
|
||||||
|
override_func(self.jinja_env, 'ngettext')
|
||||||
|
|
||||||
|
# Special _Q() function to return %-encoded text, necessary for use
|
||||||
|
# with text in banner
|
||||||
|
@contextfunction
|
||||||
|
def quote_gettext(context, text):
|
||||||
|
translate = get_translate(context)
|
||||||
|
if not translate:
|
||||||
|
return text
|
||||||
|
|
||||||
|
text = translate.gettext(text)
|
||||||
|
return quote(text, safe='/: ')
|
||||||
|
|
||||||
|
self.jinja_env.globals['locales'] = list(loc_map.keys())
|
||||||
|
self.jinja_env.globals['_Q'] = quote_gettext
|
||||||
|
|
||||||
|
@contextfunction
|
||||||
|
def switch_locale(context, locale):
|
||||||
|
environ = context.get('env')
|
||||||
|
curr_loc = environ.get('pywb_lang', '')
|
||||||
|
|
||||||
|
request_uri = environ.get('REQUEST_URI', environ.get('PATH_INFO'))
|
||||||
|
|
||||||
|
if curr_loc:
|
||||||
|
return request_uri.replace(curr_loc, locale, 1)
|
||||||
|
|
||||||
|
app_prefix = environ.get('pywb.app_prefix', '')
|
||||||
|
|
||||||
|
if app_prefix and request_uri.startswith(app_prefix):
|
||||||
|
request_uri = request_uri.replace(app_prefix, '')
|
||||||
|
|
||||||
|
return app_prefix + '/' + locale + request_uri
|
||||||
|
|
||||||
|
@contextfunction
|
||||||
|
def get_locale_prefixes(context):
|
||||||
|
environ = context.get('env')
|
||||||
|
locale_prefixes = {}
|
||||||
|
|
||||||
|
orig_prefix = environ.get('pywb.app_prefix', '')
|
||||||
|
coll = environ.get('SCRIPT_NAME', '')
|
||||||
|
|
||||||
|
if orig_prefix:
|
||||||
|
coll = coll[len(orig_prefix):]
|
||||||
|
|
||||||
|
curr_loc = environ.get('pywb_lang', '')
|
||||||
|
if curr_loc:
|
||||||
|
coll = coll[len(curr_loc) + 1:]
|
||||||
|
|
||||||
|
for locale in loc_map.keys():
|
||||||
|
locale_prefixes[locale] = orig_prefix + '/' + locale + coll + '/'
|
||||||
|
|
||||||
|
return locale_prefixes
|
||||||
|
|
||||||
|
self.jinja_env.globals['switch_locale'] = switch_locale
|
||||||
|
self.jinja_env.globals['get_locale_prefixes'] = get_locale_prefixes
|
||||||
|
|
||||||
def template_filter(self, param=None):
|
def template_filter(self, param=None):
|
||||||
"""Returns a decorator that adds the wrapped function to dictionary of template filters.
|
"""Returns a decorator that adds the wrapped function to dictionary of template filters.
|
||||||
|
|
||||||
|
9
pywb/static/calendar.svg
Normal file
9
pywb/static/calendar.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 8 8" style="enable-background:new 0 0 8 8;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<path class="st0" d="M0,0v2h7V0H0z M0,3v4.9C0,8,0,8,0.1,8h6.8C7,8,7,8,7,7.9V3H0L0,3z M1,4h1v1H1V4z M3,4h1v1H3V4z M5,4h1v1H5V4z
|
||||||
|
M1,6h1v1H1V6z M3,6h1v1H3V6z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 467 B |
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
#_wb_plain_banner, #_wb_frame_top_banner
|
#_wb_frame_top_banner
|
||||||
{
|
{
|
||||||
display: block !important;
|
display: block !important;
|
||||||
top: 0px !important;
|
top: 0px !important;
|
||||||
@ -9,24 +9,17 @@
|
|||||||
font-size: 18px !important;
|
font-size: 18px !important;
|
||||||
background-color: #444 !important;
|
background-color: #444 !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
text-align: center !important;
|
|
||||||
z-index: 2147483643 !important;
|
z-index: 2147483643 !important;
|
||||||
line-height: normal !important;
|
line-height: normal !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#title_or_url {
|
#title_or_url
|
||||||
|
{
|
||||||
|
display: block !important;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
padding-right: 4px;
|
max-width: 100%;
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#_wb_plain_banner
|
|
||||||
{
|
|
||||||
position: absolute !important;
|
|
||||||
padding: 4px !important;
|
|
||||||
border: 1px solid !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#_wb_frame_top_banner
|
#_wb_frame_top_banner
|
||||||
@ -34,6 +27,111 @@
|
|||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
height: 44px !important;
|
height: 44px !important;
|
||||||
|
|
||||||
|
display: flex !important;
|
||||||
|
display: -webkit-box !important;
|
||||||
|
display: -moz-box !important;
|
||||||
|
display: -webkit-flex !important;
|
||||||
|
display: -ms-flexbox !important;
|
||||||
|
|
||||||
|
justify-content: space-between;
|
||||||
|
-webkit-box-pack: justify;
|
||||||
|
-moz-box-pack: justify;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-moz-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#_wb_frame_top_banner ._wb_linked_logo
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
height: 26px;
|
||||||
|
width: 71px;
|
||||||
|
margin-left: 15px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
-webkit-flex-shrink: 1 0;
|
||||||
|
-moz-flex-shrink: 1 0;
|
||||||
|
-ms-flex: 0 0 71px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#_wb_frame_top_banner ._wb_linked_logo img
|
||||||
|
{
|
||||||
|
width: auto;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#_wb_capture_info
|
||||||
|
{
|
||||||
|
flex-grow: 1;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-moz-box-flex: 1;
|
||||||
|
-webkit-flex-grow: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
|
||||||
|
min-width: 0;
|
||||||
|
margin: 0 15px;
|
||||||
|
|
||||||
|
display: flex !important;
|
||||||
|
display: -webkit-box !important;
|
||||||
|
display: -moz-box !important;
|
||||||
|
display: -webkit-flex !important;
|
||||||
|
display: -ms-flexbox !important;
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-moz-box-direction: normal;
|
||||||
|
-moz-box-orient: vertical;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-moz-box-pack: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-moz-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
._wb_capture_date
|
||||||
|
{
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#_wb_frame_top_banner #_wb_ancillary_links
|
||||||
|
{
|
||||||
|
font-size: 12px;
|
||||||
|
color: #FFF;
|
||||||
|
margin-right: 15px;
|
||||||
|
text-align: right;
|
||||||
|
flex-shrink: 1 0;
|
||||||
|
-webkit-flex-shrink: 1 0;
|
||||||
|
-moz-flex-shrink: 1 0;
|
||||||
|
-ms-flex: 0 0 115px;
|
||||||
|
}
|
||||||
|
#_wb_frame_top_banner #_wb_ancillary_links a:link,
|
||||||
|
#_wb_frame_top_banner #_wb_ancillary_links a:visited,
|
||||||
|
#_wb_frame_top_banner #_wb_ancillary_links a:active
|
||||||
|
{
|
||||||
|
color: #FFF;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#_wb_frame_top_banner #_wb_ancillary_links a:hover
|
||||||
|
{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
#_wb_frame_top_banner #_wb_ancillary_links a img
|
||||||
|
{
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wb_iframe_div
|
#wb_iframe_div
|
||||||
@ -41,7 +139,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 44px 4px 4px 0px;
|
padding: 44px 0px 0px 0px;
|
||||||
border: none;
|
border: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
@ -53,7 +151,39 @@
|
|||||||
{
|
{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: 2px solid #545454;
|
border: 2px solid #FFF;
|
||||||
|
border-width: 2px 0 0 0;
|
||||||
padding: 0px 0px 0px 0px;
|
padding: 0px 0px 0px 0px;
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
#_wb_frame_top_banner ._wb_linked_logo
|
||||||
|
{
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
#_wb_frame_top_banner ._wb_linked_logo img:not(.mobile)
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#_wb_frame_top_banner .mobile
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#_wb_capture_info
|
||||||
|
{
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#_wb_frame_top_banner .no-mobile
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -35,7 +35,7 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
|||||||
this.last_state = {};
|
this.last_state = {};
|
||||||
this.state = null;
|
this.state = null;
|
||||||
this.title = '';
|
this.title = '';
|
||||||
this.loadingId = 'bannerLoading';
|
this.bannerUrlSet = false;
|
||||||
this.onMessage = this.onMessage.bind(this);
|
this.onMessage = this.onMessage.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
DefaultBanner.prototype.stillIndicatesLoading = function() {
|
DefaultBanner.prototype.stillIndicatesLoading = function() {
|
||||||
return document.getElementById(this.loadingId) != null;
|
return !this.bannerUrlSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -129,6 +129,21 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
|||||||
|
|
||||||
// Functions internal to the default banner
|
// Functions internal to the default banner
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc Navigate to different language, if available
|
||||||
|
*/
|
||||||
|
|
||||||
|
DefaultBanner.prototype.changeLanguage = function(lang, evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
var path = window.location.href;
|
||||||
|
if (path.indexOf(window.banner_info.prefix) == 0) {
|
||||||
|
path = path.substring(window.banner_info.prefix.length);
|
||||||
|
if (window.banner_info.locale_prefixes && window.banner_info.locale_prefixes[lang]) {
|
||||||
|
window.location.pathname = window.banner_info.locale_prefixes[lang] + path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Creates the underlying HTML elements comprising the banner
|
* @desc Creates the underlying HTML elements comprising the banner
|
||||||
* @param {string} bid - The id for the banner
|
* @param {string} bid - The id for the banner
|
||||||
@ -137,11 +152,64 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
|||||||
this.banner = document.createElement('wb_div', true);
|
this.banner = document.createElement('wb_div', true);
|
||||||
this.banner.setAttribute('id', bid);
|
this.banner.setAttribute('id', bid);
|
||||||
this.banner.setAttribute('lang', 'en');
|
this.banner.setAttribute('lang', 'en');
|
||||||
this.captureInfo = document.createElement('span');
|
|
||||||
this.captureInfo.innerHTML =
|
if (window.banner_info.logoImg) {
|
||||||
'<span id="' + this.loadingId + '">Loading...</span>';
|
var logo = document.createElement("a");
|
||||||
this.captureInfo.id = '_wb_capture_info';
|
logo.setAttribute("href", "/" + (window.banner_info.locale ? window.banner_info.locale + "/" : ""));
|
||||||
|
logo.setAttribute("class", "_wb_linked_logo");
|
||||||
|
|
||||||
|
var logoContents = "";
|
||||||
|
logoContents += "<img src='" + window.banner_info.logoImg + "' alt='" + window.banner_info.logoAlt + "'>";
|
||||||
|
logoContents += "<img src='" + window.banner_info.logoImg + "' class='mobile' alt='" + window.banner_info.logoAlt + "'>";
|
||||||
|
|
||||||
|
logo.innerHTML = logoContents;
|
||||||
|
this.banner.appendChild(logo);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.captureInfo = document.createElement("span");
|
||||||
|
this.captureInfo.setAttribute("id", "_wb_capture_info");
|
||||||
|
this.captureInfo.innerHTML = window.banner_info.loadingLabel;
|
||||||
this.banner.appendChild(this.captureInfo);
|
this.banner.appendChild(this.captureInfo);
|
||||||
|
|
||||||
|
var ancillaryLinks = document.createElement("div");
|
||||||
|
ancillaryLinks.setAttribute("id", "_wb_ancillary_links");
|
||||||
|
|
||||||
|
var calendarImg = window.banner_info.calendarImg || window.banner_info.staticPrefix + "/calendar.svg";
|
||||||
|
|
||||||
|
var calendarLink = document.createElement("a");
|
||||||
|
calendarLink.setAttribute("id", "calendarLink");
|
||||||
|
calendarLink.setAttribute("href", "#");
|
||||||
|
calendarLink.innerHTML = "<img src='" + calendarImg + "' alt='" + window.banner_info.calendarAlt + "'><span class='no-mobile'> " +window.banner_info.calendarLabel + "</span>";
|
||||||
|
ancillaryLinks.appendChild(calendarLink);
|
||||||
|
this.calendarLink = calendarLink;
|
||||||
|
|
||||||
|
if (typeof window.banner_info.locales !== "undefined" && window.banner_info.locales.length) {
|
||||||
|
var locales = window.banner_info.locales;
|
||||||
|
var languages = document.createElement("div");
|
||||||
|
|
||||||
|
var label = document.createElement("span");
|
||||||
|
label.setAttribute("class", "no-mobile");
|
||||||
|
label.appendChild(document.createTextNode(window.banner_info.choiceLabel + " "));
|
||||||
|
languages.appendChild(label);
|
||||||
|
|
||||||
|
for(var i = 0; i < locales.length; i++) {
|
||||||
|
var locale = locales[i];
|
||||||
|
var langLink = document.createElement("a");
|
||||||
|
langLink.setAttribute("href", "#");
|
||||||
|
langLink.addEventListener("click", this.changeLanguage.bind(this, locale));
|
||||||
|
langLink.appendChild(document.createTextNode(locale));
|
||||||
|
|
||||||
|
languages.appendChild(langLink);
|
||||||
|
if (i !== locales.length - 1) {
|
||||||
|
languages.appendChild(document.createTextNode(" / "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ancillaryLinks.appendChild(languages);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.banner.appendChild(ancillaryLinks);
|
||||||
|
|
||||||
document.body.insertBefore(this.banner, document.body.firstChild);
|
document.body.insertBefore(this.banner, document.body.firstChild);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,7 +249,7 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
|||||||
if (is_gmt) {
|
if (is_gmt) {
|
||||||
return date.toGMTString();
|
return date.toGMTString();
|
||||||
} else {
|
} else {
|
||||||
return date.toLocaleString();
|
return date.toLocaleString(window.banner_info.locale);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,11 +264,15 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
|||||||
var capture_str;
|
var capture_str;
|
||||||
var title_str;
|
var title_str;
|
||||||
|
|
||||||
if (!ts) {
|
if (!url) {
|
||||||
|
this.captureInfo.innerHTML = window.banner_info.loadingLabel;
|
||||||
|
this.bannerUrlSet = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var date_str = this.ts_to_date(ts, true);
|
if (!ts) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
capture_str = title;
|
capture_str = title;
|
||||||
@ -209,20 +281,27 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
|||||||
}
|
}
|
||||||
|
|
||||||
title_str = capture_str;
|
title_str = capture_str;
|
||||||
capture_str = "<b id='title_or_url'>" + capture_str + '</b>';
|
|
||||||
|
capture_str = "<b id='title_or_url' title='" + capture_str + "'>" + capture_str + "</b>";
|
||||||
|
|
||||||
|
capture_str += "<span class='_wb_capture_date'>";
|
||||||
|
|
||||||
if (is_live) {
|
if (is_live) {
|
||||||
title_str = ' pywb Live: ' + title_str;
|
title_str = window.banner_info.liveMsg + " " + title_str;
|
||||||
capture_str += '<i>Live on </i>';
|
capture_str += "<b>" + window.banner_info.liveMsg + " </b>";
|
||||||
} else {
|
|
||||||
title_str += 'pywb Archived: ' + title_str;
|
|
||||||
capture_str += '<i>Archived on </i>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
title_str += ' (' + date_str + ')';
|
capture_str += this.ts_to_date(ts, window.banner_info.is_gmt);
|
||||||
capture_str += date_str;
|
capture_str += "</span>";
|
||||||
|
|
||||||
|
this.calendarLink.setAttribute("href", window.banner_info.prefix + "*/" + url);
|
||||||
|
this.calendarLink.style.display = is_live ? "none" : "";
|
||||||
|
|
||||||
this.captureInfo.innerHTML = capture_str;
|
this.captureInfo.innerHTML = capture_str;
|
||||||
|
|
||||||
window.document.title = title_str;
|
window.document.title = title_str;
|
||||||
|
|
||||||
|
this.bannerUrlSet = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// all banners will expose themselves by adding themselves as WBBanner on window
|
// all banners will expose themselves by adding themselves as WBBanner on window
|
||||||
|
@ -2,4 +2,26 @@
|
|||||||
<!-- default banner, create through js -->
|
<!-- default banner, create through js -->
|
||||||
<script src='{{ static_prefix }}/default_banner.js'> </script>
|
<script src='{{ static_prefix }}/default_banner.js'> </script>
|
||||||
<link rel='stylesheet' href='{{ static_prefix }}/default_banner.css'/>
|
<link rel='stylesheet' href='{{ static_prefix }}/default_banner.css'/>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.banner_info = {
|
||||||
|
is_gmt: true,
|
||||||
|
|
||||||
|
liveMsg: decodeURIComponent("{{ _Q('Live on') }}"),
|
||||||
|
|
||||||
|
calendarAlt: decodeURIComponent("{{ _Q('Calendar icon') }}"),
|
||||||
|
calendarLabel: decodeURIComponent("{{ _Q('View All Captures') }}"),
|
||||||
|
choiceLabel: decodeURIComponent("{{ _Q('Language:') }}"),
|
||||||
|
loadingLabel: decodeURIComponent("{{ _Q('Loading...') }}"),
|
||||||
|
logoAlt: decodeURIComponent("{{ _Q('Logo') }}"),
|
||||||
|
|
||||||
|
locale: "{{ env.pywb_lang | default('en') }}",
|
||||||
|
curr_locale: "{{ env.pywb_lang }}",
|
||||||
|
locales: {{ locales }},
|
||||||
|
locale_prefixes: {{ get_locale_prefixes() | tojson }},
|
||||||
|
prefix: "{{ wb_prefix }}",
|
||||||
|
staticPrefix: "{{ static_prefix }}"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h2 class="display-2">Pywb Wayback Machine</h2>
|
<h2 class="display-2">{{ _('Pywb Wayback Machine') }}</h2>
|
||||||
<p class="lead">This archive contains the following collections:</p>
|
<p class="lead">This archive contains the following collections:</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -14,3 +14,4 @@ portalocker
|
|||||||
wsgiprox>=1.5.1
|
wsgiprox>=1.5.1
|
||||||
fakeredis<1.0
|
fakeredis<1.0
|
||||||
tldextract
|
tldextract
|
||||||
|
babel
|
||||||
|
14
tests/config_test_loc.yaml
Normal file
14
tests/config_test_loc.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
debug: true
|
||||||
|
|
||||||
|
collections:
|
||||||
|
pywb:
|
||||||
|
index_paths: ./sample_archive/cdx/
|
||||||
|
archive_paths: ./sample_archive/warcs/
|
||||||
|
|
||||||
|
# i18n
|
||||||
|
locales_root_dir: ./tests/i18n-data/
|
||||||
|
locales:
|
||||||
|
- en
|
||||||
|
- 'l337'
|
||||||
|
|
||||||
|
|
1
tests/i18n-data/.gitignore
vendored
Normal file
1
tests/i18n-data/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
#allow .mo
|
BIN
tests/i18n-data/l337/LC_MESSAGES/messages.mo
Normal file
BIN
tests/i18n-data/l337/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
31
tests/i18n-data/l337/LC_MESSAGES/messages.po
Normal file
31
tests/i18n-data/l337/LC_MESSAGES/messages.po
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Lithuanian translations for pywb.
|
||||||
|
# Copyright (C) 2019 pywb
|
||||||
|
# This file is distributed under the same license as the pywb project.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: pywb 2.4.0rc0\n"
|
||||||
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
|
"POT-Creation-Date: 2019-11-06 20:20-0800\n"
|
||||||
|
"PO-Revision-Date: 2019-11-06 20:25-0800\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language: lt\n"
|
||||||
|
"Language-Team: lt <LL@li.org>\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||||
|
"(n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Generated-By: Babel 2.5.3\n"
|
||||||
|
|
||||||
|
#: pywb/templates/banner.html:14
|
||||||
|
msgid "Language:"
|
||||||
|
msgstr "L4n9u4g3:"
|
||||||
|
|
||||||
|
|
||||||
|
#: pywb/templates/index.html:5
|
||||||
|
msgid "Pywb Wayback Machine"
|
||||||
|
msgstr "Py\\/\\/b W4yb4ck /\\/\\4ch1n3"
|
||||||
|
|
||||||
|
|
31
tests/test_locales.py
Normal file
31
tests/test_locales.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from .base_config_test import BaseConfigTest
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
class TestLocales(BaseConfigTest):
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
super(TestLocales, cls).setup_class('config_test_loc.yaml')
|
||||||
|
|
||||||
|
def test_locale_en_home(self):
|
||||||
|
res = self.testapp.get('/en/')
|
||||||
|
|
||||||
|
assert 'Pywb Wayback Machine' in res.text, res.text
|
||||||
|
|
||||||
|
def test_locale_l337_home(self):
|
||||||
|
res = self.testapp.get('/l337/')
|
||||||
|
|
||||||
|
print(res.text)
|
||||||
|
assert r'Py\/\/b W4yb4ck /\/\4ch1n3' in res.text
|
||||||
|
|
||||||
|
def test_locale_en_replay_banner(self):
|
||||||
|
res = self.testapp.get('/en/pywb/mp_/https://example.com/')
|
||||||
|
assert '"en"' in res.text
|
||||||
|
assert '"Language:"' in res.text
|
||||||
|
|
||||||
|
def test_locale_l337_replay_banner(self):
|
||||||
|
res = self.testapp.get('/l337/pywb/mp_/https://example.com/')
|
||||||
|
assert '"l337"' in res.text
|
||||||
|
assert '"L4n9u4g3:"' in res.text
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user