add optional (since it uses a session cookie) language selection

This commit is contained in:
El RIDO 2015-09-19 11:21:13 +02:00
parent 47efedf23c
commit a111357fae
12 changed files with 390 additions and 41 deletions

View File

@ -43,6 +43,11 @@ template = "bootstrap"
; use "1.7" if you are upgrading from a ZeroBin Alpha 0.19 installation
base64version = "2.1.9"
; by default ZeroBin will guess the visitors language based on the browsers
; settings. Optionally you can enable the language selection menu, which uses
; a session cookie to store the choice until the browser is closed.
languageselection = false
[expire]
; expire value that is selected per default
; make sure the value exists in [expire_options]

View File

@ -126,7 +126,7 @@ h3.title {
#copyhint { color: #666; font-size: 0.85em; }
button, .button, #expiration, #formatter {
button, .button {
color: #fff;
background-color: #323b47;
background-repeat: no-repeat;
@ -134,7 +134,7 @@ button, .button, #expiration, #formatter {
padding: 4px 8px;
font-size: 1em;
margin-right: 5px;
display: inline;
display: inline-block;
background-image: linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -o-linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -moz-linear-gradient(bottom, #323b47 0, #51606e 100%);
@ -185,7 +185,7 @@ button img {
top: 2px;
}
#expiration, #formatter, #rawtextbutton, #burnafterreadingoption, #opendisc {
.button {
background-color: #414d5a;
padding: 6px 8px;
margin: 0 5px 0 0;
@ -193,14 +193,14 @@ button img {
bottom: 1px; /* WTF ? Why is this shifted by 1 pixel ? */
}
#expiration select, #formatter select {
.button select {
color: #eee;
background: transparent;
border: none;
}
#expiration select option, #formatter select option {
.button select option {
color:#eee;
background: #414d5a;
}

View File

@ -130,7 +130,7 @@
"Markdown": "Markdown",
"Download attachment": "Anhang herunterladen",
"Cloned file attached.": "Kopierte Datei angehängt.",
"Attach a file:": "Datei anhängen:",
"Attach a file": "Datei anhängen",
"Remove attachment": "Anhang entfernen",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Dein Browser unterstützt das hochladen von verschlüsselten Dateien nicht. Bitte verwende einen neueren Browser.",

View File

@ -139,7 +139,7 @@
"Markdown": "Markdown",
"Download attachment": "Télécharger la pièce jointe",
"Cloned file attached.": "Cloner le fichier attaché.",
"Attach a file:": "Attacher un fichier :",
"Attach a file": "Attacher un fichier ",
"Remove attachment": "Enlever l'attachement",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Votre navigateur ne supporte pas l'envoi de fichiers chiffrés. Merci d'utiliser un navigateur plus récent.",

181
i18n/languages.json Normal file
View File

@ -0,0 +1,181 @@
{
"ab": ["аҧсуа бызшәа", "Abkhaz"],
"aa": ["Afaraf", "Afar"],
"af": ["Afrikaans", "Afrikaans"],
"ak": ["Akan", "Akan"],
"sq": ["Shqip", "Albanian"],
"am": ["አማርኛ", "Amharic"],
"ar": ["العربية", "Arabic"],
"an": ["aragonés", "Aragonese"],
"hy": ["Հայերեն", "Armenian"],
"as": ["অসমীয়া", "Assamese"],
"ac": ["Ástralic", "Australian"],
"av": ["авар мацӀ", "Avaric"],
"ae": ["avesta", "Avestan"],
"ay": ["aymar aru", "Aymara"],
"az": ["azərbaycan dili", "Azerbaijani"],
"bm": ["bamanankan", "Bambara"],
"ba": ["башҡорт теле", "Bashkir"],
"eu": ["euskara", "Basque"],
"be": ["беларуская мова", "Belarusian"],
"bn": ["বাংলা", "Bengali"],
"bh": ["भोजपुरी", "Bihari"],
"bi": ["Bislama", "Bislama"],
"bs": ["bosanski jezik", "Bosnian"],
"br": ["brezhoneg", "Breton"],
"bg": ["български език", "Bulgarian"],
"my": ["ဗမာစာ", "Burmese"],
"ca": ["català", "Catalan"],
"ch": ["Chamoru", "Chamorro"],
"ce": ["нохчийн мотт", "Chechen"],
"ny": ["chiCheŵa", "Chichewa"],
"zh": ["中文", "Chinese"],
"cv": ["чӑваш чӗлхи", "Chuvash"],
"kw": ["Kernewek", "Cornish"],
"co": ["corsu", "Corsican"],
"cr": ["ᓀᐦᐃᔭᐍᐏᐣ", "Cree"],
"hr": ["hrvatski jezik", "Croatian"],
"cs": ["čeština", "Czech"],
"da": ["dansk", "Danish"],
"dv": ["ދިވެހި", "Divehi"],
"nl": ["Nederlands", "Dutch"],
"dz": ["རྫོང་ཁ", "Dzongkha"],
"en": ["English", "English"],
"eo": ["Esperanto", "Esperanto"],
"et": ["eesti", "Estonian"],
"ee": ["Eʋegbe", "Ewe"],
"fo": ["føroyskt", "Faroese"],
"fj": ["vosa Vakaviti", "Fijian"],
"fi": ["suomi", "Finnish"],
"fr": ["français", "French"],
"ff": ["Fulfulde", "Fula"],
"gl": ["galego", "Galician"],
"ka": ["ქართული", "Georgian"],
"de": ["Deutsch", "German"],
"el": ["ελληνικά", "Greek"],
"gn": ["Avañe'ẽ", "Guaraní"],
"gu": ["ગુજરાતી", "Gujarati"],
"ht": ["Kreyòl ayisyen", "Haitian"],
"ha": ["هَوُسَ", "Hausa"],
"he": ["עברית", "Hebrew"],
"hz": ["Otjiherero", "Herero"],
"hi": ["हिन्दी", "Hindi"],
"ho": ["Hiri Motu", "Hiri Motu"],
"hu": ["magyar", "Hungarian"],
"ia": ["Interlingua", "Interlingua"],
"ie": ["Interlingue", "Interlingue"],
"ga": ["Gaeilge", "Irish"],
"ig": ["Asụsụ Igbo", "Igbo"],
"ik": ["Iñupiaq", "Inupiaq"],
"io": ["Ido", "Ido"],
"is": ["Íslenska", "Icelandic"],
"it": ["italiano", "Italian"],
"iu": ["ᐃᓄᒃᑎᑐᑦ", "Inuktitut"],
"ja": ["日本語", "Japanese"],
"jv": ["basa Jawa", "Javanese"],
"kl": ["kalaallisut", "Greenlandic"],
"kn": ["ಕನ್ನಡ", "Kannada"],
"kr": ["Kanuri", "Kanuri"],
"ks": ["कश्मीरी", "Kashmiri"],
"kk": ["қазақ тілі", "Kazakh"],
"km": ["ខ្មែរ", "Khmer"],
"ki": ["Gĩkũyũ", "Kikuyu"],
"rw": ["Ikinyarwanda", "Kinyarwanda"],
"ky": ["Кыргызча", "Kyrgyz"],
"kv": ["коми кыв", "Komi"],
"kg": ["Kikongo", "Kongo"],
"ko": ["한국어", "Korean"],
"ku": ["Kurdî", "Kurdish"],
"kj": ["Kuanyama", "Kwanyama"],
"la": ["lingua latina", "Latin"],
"lb": ["Lëtzebuergesch", "Luxembourgish"],
"lg": ["Luganda", "Ganda"],
"li": ["Limburgs", "Limburgish"],
"ln": ["Lingála", "Lingala"],
"lo": ["ພາສາລາວ", "Lao"],
"lt": ["lietuvių kalba", "Lithuanian"],
"lu": ["Tshiluba", "Luba-Katanga"],
"lv": ["latviešu valoda", "Latvian"],
"gv": ["Gaelg", "Manx"],
"mk": ["македонски јазик", "Macedonian"],
"mg": ["fiteny malagasy", "Malagasy"],
"ms": ["بهاس ملايو‎", "Malay"],
"ml": ["മലയാളം", "Malayalam"],
"mt": ["Malti", "Maltese"],
"mi": ["te reo Māori", "Māori"],
"mr": ["मराठी", "Marathi"],
"mh": ["Kajin M̧ajeļ", "Marshallese"],
"mn": ["Монгол хэл", "Mongolian"],
"na": ["Ekakairũ Naoero", "Nauru"],
"nv": ["Diné bizaad", "Navajo"],
"nd": ["isiNdebele", "Northern Ndebele"],
"ne": ["नेपाली", "Nepali"],
"ng": ["Owambo", "Ndonga"],
"no": ["Norsk", "Norwegian"],
"ii": ["ꆈꌠ꒿", "Nuosu"],
"nr": ["isiNdebele", "Southern Ndebele"],
"oc": ["occitan", "Occitan"],
"oj": ["ᐊᓂᔑᓈᐯᒧᐎᓐ", "Ojibwe"],
"om": ["Afaan Oromoo", "Oromo"],
"or": ["ଓଡ଼ିଆ", "Oriya"],
"os": ["ирон æвзаг", "Ossetian"],
"pa": ["ਪੰਜਾਬੀ", "Punjabi"],
"pi": ["पाऴि", "Pāli"],
"fa": ["فارسی", "Persian"],
"pl": ["polszczyzna", "Polish"],
"ps": ["پښتو", "Pashto"],
"pt": ["português", "Portuguese"],
"qu": ["Runa Simi", "Quechua"],
"rm": ["rumantsch grischun", "Romansh"],
"rn": ["Ikirundi", "Kirundi"],
"ro": ["limba română", "Romanian"],
"ru": ["Русский", "Russian"],
"sc": ["sardu", "Sardinian"],
"sd": ["सिन्धी", "Sindhi"],
"se": ["Davvisámegiella", "Northern Sami"],
"sm": ["gagana fa'a Samoa", "Samoan"],
"sg": ["yângâ tî sängö", "Sango"],
"sr": ["српски језик", "Serbian"],
"gd": ["Gàidhlig", "Gaelic"],
"sn": ["chiShona", "Shona"],
"si": ["සිංහල", "Sinhalese"],
"sk": ["slovenčina", "Slovak"],
"sl": ["slovenščina", "Slovene"],
"so": ["Soomaaliga", "Somali"],
"st": ["Sesotho", "Southern Sotho"],
"es": ["español", "Spanish"],
"su": ["Basa Sunda", "Sundanese"],
"sw": ["Kiswahili", "Swahili"],
"ss": ["SiSwati", "Swati"],
"sv": ["svenska", "Swedish"],
"ta": ["தமிழ்", "Tamil"],
"te": ["తెలుగు", "Telugu"],
"tg": ["тоҷикӣ", "Tajik"],
"th": ["ไทย", "Thai"],
"ti": ["ትግርኛ", "Tigrinya"],
"bo": ["བོད་ཡིག", "Tibetan"],
"tk": ["Түркмен", "Turkmen"],
"tl": ["ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔", "Tagalog"],
"tn": ["Setswana", "Tswana"],
"to": ["faka Tonga", "Tonga"],
"tr": ["Türkçe", "Turkish"],
"ts": ["Xitsonga", "Tsonga"],
"tt": ["татар теле", "Tatar"],
"ty": ["Reo Tahiti", "Tahitian"],
"ug": ["ئۇيغۇرچە‎", "Uyghur"],
"uk": ["українська мова", "Ukrainian"],
"ur": ["اردو", "Urdu"],
"uz": ["Oʻzbek", "Uzbek"],
"ve": ["Tshivenḓa", "Venda"],
"vi": ["Việt Nam", "Vietnamese"],
"vo": ["Volapük", "Volapük"],
"wa": ["walon", "Walloon"],
"cy": ["Cymraeg", "Welsh"],
"wo": ["Wollof", "Wolof"],
"fy": ["Frysk", "Western Frisian"],
"xh": ["isiXhosa", "Xhosa"],
"yi": ["ייִדיש", "Yiddish"],
"yo": ["Yorùbá", "Yoruba"],
"za": ["Saɯ cueŋƅ", "Zhuang"],
"zu": ["isiZulu", "Zulu"]
}

View File

@ -130,7 +130,7 @@
"Markdown": "Markdown",
"Download attachment": "Download attachment",
"Cloned file attached.": "Cloned file attached.",
"Attach a file:": "Attach a file:",
"Attach a file": "Attach a file",
"Remove attachment": "Remove attachment",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Your browser does not support uploading encrypted files. Please use a newer browser.",

View File

@ -266,6 +266,24 @@ $(function() {
}
return val;
});
},
/**
* get value of cookie, if it was set, empty string otherwise
* From: http://www.w3schools.com/js/js_cookies.asp
*
* @param string cname
* @return string
*/
getCookie: function(cname) {
var name = cname + '=';
var ca = document.cookie.split(';');
for(var i = 0; i < ca.length; ++i) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1);
if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
}
return '';
}
};
@ -361,7 +379,8 @@ $(function() {
*/
loadTranslations: function(callback)
{
var language = (navigator.language || navigator.userLanguage).substring(0, 2);
var selectedLang = helper.getCookie('lang');
var language = selectedLang.length > 0 ? selectedLang : (navigator.language || navigator.userLanguage).substring(0, 2);
// note that 'en' is built in, so no translation is necessary
if (this.supportedLanguages.indexOf(language) == -1)
{

View File

@ -26,6 +26,33 @@ class i18n
*/
protected static $_language = 'en';
/**
* language labels
*
* @access protected
* @static
* @var array
*/
protected static $_languageLabels = array();
/**
* available languages
*
* @access protected
* @static
* @var array
*/
protected static $_availableLanguages = array();
/**
* path to language files
*
* @access protected
* @static
* @var string
*/
protected static $_path = '';
/**
* translation cache
*
@ -94,36 +121,57 @@ class i18n
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @access protected
* @access public
* @static
* @return void
*/
public static function loadTranslations()
{
// find a matching translation file
$availableLanguages = array();
$path = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'i18n';
$i18n = dir($path);
while (false !== ($file = $i18n->read()))
{
if (preg_match('/^([a-z]{2}).json$/', $file, $match) === 1)
{
$availableLanguages[] = $match[1];
}
}
$availableLanguages = self::getAvailableLanguages();
$match = self::_getMatchingLanguage(
self::getBrowserLanguages(), $availableLanguages
);
// load translations
if ($match != 'en')
// check if the lang cookie was set and that language exists
if (array_key_exists('lang', $_COOKIE) && in_array($_COOKIE['lang'], $availableLanguages))
{
self::$_language = $match;
self::$_translations = json_decode(
file_get_contents($path . DIRECTORY_SEPARATOR . $match . '.json'),
true
$match = $_COOKIE['lang'];
}
// find a translation file matching the browsers language preferences
else
{
$match = self::_getMatchingLanguage(
self::getBrowserLanguages(), $availableLanguages
);
}
// load translations
self::$_language = $match;
self::$_translations = ($match == 'en') ? array() : json_decode(
file_get_contents(self::_getPath($match . '.json')),
true
);
}
/**
* get list of available translations based on files found
*
* @access public
* @static
* @return array
*/
public static function getAvailableLanguages()
{
if (count(self::$_availableLanguages) == 0)
{
$i18n = dir(self::_getPath());
while (false !== ($file = $i18n->read()))
{
if (preg_match('/^([a-z]{2}).json$/', $file, $match) === 1)
{
self::$_availableLanguages[] = $match[1];
}
}
self::$_availableLanguages[] = 'en';
}
return self::$_availableLanguages;
}
/**
@ -131,6 +179,8 @@ class i18n
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @access public
* @static
* @return array
*/
public static function getBrowserLanguages()
@ -165,12 +215,64 @@ class i18n
return $languages;
}
/**
* get currently loaded language
*
* @access public
* @static
* @return string
*/
public static function getLanguage()
{
return self::$_language;
}
/**
* get list of language labels
*
* Only for given language codes, otherwise all labels.
*
* @access public
* @static
* @param array $languages
* @return array
*/
public static function getLanguageLabels($languages = array())
{
$file = self::_getPath('languages.json');
if (count(self::$_languageLabels) == 0 && is_readable($file))
{
self::$_languageLabels = json_decode(file_get_contents($file), true);
}
if (count($languages) == 0) return self::$_languageLabels;
return array_intersect_key(self::$_languageLabels, array_flip($languages));
}
/**
* get language file path
*
* @access protected
* @static
* @param string $file
* @return string
*/
protected static function _getPath($file = '')
{
if (strlen(self::$_path) == 0)
{
self::$_path = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'i18n';
}
return self::$_path . (strlen($file) ? DIRECTORY_SEPARATOR . $file : '');
}
/**
* determines the plural form to use based on current language and given number
*
* From: http://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html
*
* @param int $n
* @access protected
* @static
* @param int $n
* @return int
*/
protected static function _getPluralForm($n)
@ -191,8 +293,10 @@ class i18n
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @param array $acceptedLanguages
* @param array $availableLanguages
* @access protected
* @static
* @param array $acceptedLanguages
* @param array $availableLanguages
* @return string
*/
protected static function _getMatchingLanguage($acceptedLanguages, $availableLanguages) {
@ -247,8 +351,10 @@ class i18n
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @param string $a
* @param string $b
* @access protected
* @static
* @param string $a
* @param string $b
* @return float
*/
protected static function _matchLanguage($a, $b) {

View File

@ -659,6 +659,14 @@ class zerobin
// translate all the formatter options
$formatters = array_map(array('i18n', 'translate'), $this->_conf['formatter_options']);
// set language cookie if that functionality was enabled
$languageselection = '';
if ($this->_getMainConfig('languageselection', false))
{
$languageselection = i18n::getLanguage();
setcookie('lang', $languageselection);
}
$page = new RainTPL;
$page::$path_replace = false;
// we escape it here because ENT_NOQUOTES can't be used in RainTPL templates
@ -678,6 +686,8 @@ class zerobin
$page->assign('PASSWORD', $this->_getMainConfig('password', true));
$page->assign('FILEUPLOAD', $this->_getMainConfig('fileupload', false));
$page->assign('BASE64JSVERSION', $this->_getMainConfig('base64version', '2.1.9'));
$page->assign('LANGUAGESELECTION', $languageselection);
$page->assign('LANGUAGES', i18n::getLanguageLabels(i18n::getAvailableLanguages()));
$page->assign('EXPIRE', $expire);
$page->assign('EXPIREDEFAULT', $this->_conf['expire']['default']);
$page->draw($this->_getMainConfig('template', 'page'));

View File

@ -118,7 +118,18 @@
</ul>
</li>{/if}
</ul>
<ul class="nav navbar-nav pull-right">
<ul class="nav navbar-nav pull-right">{if="strlen($LANGUAGESELECTION)"}
<li id="language" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-flag" aria-hidden="true"></span> {$LANGUAGES[$LANGUAGESELECTION][0]} <span class="caret"></span></a>
<ul class="dropdown-menu">
{loop="LANGUAGES"}
<li>
<a href="#" class="reloadlink" onclick="document.cookie='lang={$key}';">
{$value[0]} ({$value[1]})
</a>
</li>{/loop}
</ul>
</li>{/if}
<li>
<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> {function="t('New')"}

View File

@ -116,7 +116,18 @@
</ul>
</li>
</ul>
<ul class="nav navbar-nav pull-right">
<ul class="nav navbar-nav pull-right">{if="strlen($LANGUAGESELECTION)"}
<li id="language" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-flag" aria-hidden="true"></span> {$LANGUAGES[$LANGUAGESELECTION][0]} <span class="caret"></span></a>
<ul class="dropdown-menu">
{loop="LANGUAGES"}
<li>
<a href="#" class="reloadlink" onclick="document.cookie='lang={$key}';">
{$value[0]} ({$value[1]})
</a>
</li>{/loop}
</ul>
</li>{/if}
<li>
<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> {function="t('New')"}

View File

@ -46,7 +46,7 @@
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" />{function="t('Send')"}</button>
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" />{function="t('Clone')"}</button>
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" />{function="t('Raw text')"}</button>
<div id="expiration" class="hidden">{function="t('Expires')"}:
<div id="expiration" class="hidden button">{function="t('Expires')"}:
<select id="pasteExpiration" name="pasteExpiration">
{loop="EXPIRE"}
<option value="{$key}"{if="$key == $EXPIREDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
@ -69,7 +69,13 @@
{loop="FORMATTER"}
<option value="{$key}"{if="$key == $FORMATTERDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
</select>
</div>
</div>{if="strlen($LANGUAGESELECTION)"}
<div id="language" class="button">
<select name="lang">
{loop="LANGUAGES"}
<option class="reloadlink" onclick="document.cookie='lang={$key}';" value="{$key}"{if="$key == $LANGUAGESELECTION"} selected="selected"{/if}>{$value[0]} ({$value[1]})</option>{/loop}
</select>
</div>{/if}
</div>
<div id="pasteresult" class="hidden">
<div id="deletelink"></div>
@ -78,7 +84,7 @@
<div id="attachment" class="hidden"><a>{function="t('Download attachment')"}</a></div>
<div id="attach" class="hidden">
<span id="clonedfile" class="hidden">{function="t('Cloned file attached.')"}</span>
<span id="filewrap">{function="t('Attach a file:')"} <input type="file" id="file" name="file" /></span>
<span id="filewrap">{function="t('Attach a file')"}: <input type="file" id="file" name="file" /></span>
<button id="fileremovebutton">{function="t('Remove attachment')"}</button>
</div>{/if}
<div id="image" class="hidden"></div>