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 werkzeug.routing import Map, Rule, RequestRedirect
|
||||
from werkzeug.routing import Map, Rule, RequestRedirect, Submount
|
||||
from werkzeug.wsgi import pop_path_info
|
||||
from six.moves.urllib.parse import urljoin
|
||||
from six import iteritems
|
||||
@ -138,6 +138,17 @@ class FrontEndApp(object):
|
||||
:rtype: None
|
||||
"""
|
||||
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:
|
||||
self.url_map.add(route)
|
||||
|
||||
|
@ -68,6 +68,11 @@ class RewriterApp(object):
|
||||
jinja_env.jinja_env.install_null_translations()
|
||||
|
||||
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')
|
||||
|
||||
|
@ -3,11 +3,13 @@ from warcio.timeutils import timestamp_now
|
||||
|
||||
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 babel.support import Translations
|
||||
|
||||
from webassets.ext.jinja2 import AssetsExtension
|
||||
from webassets.loaders import YAMLLoader
|
||||
from webassets.env import Resolver
|
||||
@ -115,6 +117,90 @@ class JinjaEnv(object):
|
||||
|
||||
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):
|
||||
"""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;
|
||||
top: 0px !important;
|
||||
@ -9,24 +9,17 @@
|
||||
font-size: 18px !important;
|
||||
background-color: #444 !important;
|
||||
color: white !important;
|
||||
text-align: center !important;
|
||||
z-index: 2147483643 !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
#title_or_url {
|
||||
#title_or_url
|
||||
{
|
||||
display: block !important;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-right: 4px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#_wb_plain_banner
|
||||
{
|
||||
position: absolute !important;
|
||||
padding: 4px !important;
|
||||
border: 1px solid !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#_wb_frame_top_banner
|
||||
@ -34,6 +27,111 @@
|
||||
position: absolute !important;
|
||||
border: 0px;
|
||||
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
|
||||
@ -41,7 +139,7 @@
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 44px 4px 4px 0px;
|
||||
padding: 44px 0px 0px 0px;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
@ -53,7 +151,39 @@
|
||||
{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 2px solid #545454;
|
||||
border: 2px solid #FFF;
|
||||
border-width: 2px 0 0 0;
|
||||
padding: 0px 0px 0px 0px;
|
||||
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.state = null;
|
||||
this.title = '';
|
||||
this.loadingId = 'bannerLoading';
|
||||
this.bannerUrlSet = false;
|
||||
this.onMessage = this.onMessage.bind(this);
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
||||
* @returns {boolean}
|
||||
*/
|
||||
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
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @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.setAttribute('id', bid);
|
||||
this.banner.setAttribute('lang', 'en');
|
||||
this.captureInfo = document.createElement('span');
|
||||
this.captureInfo.innerHTML =
|
||||
'<span id="' + this.loadingId + '">Loading...</span>';
|
||||
this.captureInfo.id = '_wb_capture_info';
|
||||
|
||||
if (window.banner_info.logoImg) {
|
||||
var logo = document.createElement("a");
|
||||
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);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
@ -181,7 +249,7 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
||||
if (is_gmt) {
|
||||
return date.toGMTString();
|
||||
} 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 title_str;
|
||||
|
||||
if (!ts) {
|
||||
if (!url) {
|
||||
this.captureInfo.innerHTML = window.banner_info.loadingLabel;
|
||||
this.bannerUrlSet = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var date_str = this.ts_to_date(ts, true);
|
||||
if (!ts) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (title) {
|
||||
capture_str = title;
|
||||
@ -209,20 +281,27 @@ This file is part of pywb, https://github.com/webrecorder/pywb
|
||||
}
|
||||
|
||||
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) {
|
||||
title_str = ' pywb Live: ' + title_str;
|
||||
capture_str += '<i>Live on </i>';
|
||||
} else {
|
||||
title_str += 'pywb Archived: ' + title_str;
|
||||
capture_str += '<i>Archived on </i>';
|
||||
title_str = window.banner_info.liveMsg + " " + title_str;
|
||||
capture_str += "<b>" + window.banner_info.liveMsg + " </b>";
|
||||
}
|
||||
|
||||
title_str += ' (' + date_str + ')';
|
||||
capture_str += date_str;
|
||||
capture_str += this.ts_to_date(ts, window.banner_info.is_gmt);
|
||||
capture_str += "</span>";
|
||||
|
||||
this.calendarLink.setAttribute("href", window.banner_info.prefix + "*/" + url);
|
||||
this.calendarLink.style.display = is_live ? "none" : "";
|
||||
|
||||
this.captureInfo.innerHTML = capture_str;
|
||||
|
||||
window.document.title = title_str;
|
||||
|
||||
this.bannerUrlSet = true;
|
||||
};
|
||||
|
||||
// all banners will expose themselves by adding themselves as WBBanner on window
|
||||
|
@ -2,4 +2,26 @@
|
||||
<!-- default banner, create through js -->
|
||||
<script src='{{ static_prefix }}/default_banner.js'> </script>
|
||||
<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 %}
|
||||
|
@ -2,7 +2,7 @@
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<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>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -14,3 +14,4 @@ portalocker
|
||||
wsgiprox>=1.5.1
|
||||
fakeredis<1.0
|
||||
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