parent
28776ac178
commit
a2af88a36e
@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"en": "de",
|
||||||
|
"Paste does not exist, has expired or has been deleted.":
|
||||||
|
"Diesen Schnipsel gibt es nicht, er ist abgelaufen oder wurde gelöscht.",
|
||||||
|
"ZeroBin requires php 5.2.6 or above to work. Sorry.":
|
||||||
|
"ZeroBin benötigt PHP 5.2.6 oder höher um zu funktionieren, sorry.",
|
||||||
|
"ZeroBin requires configuration section [%s] to be present in configuration file.":
|
||||||
|
"ZeroBin benötigt die Konfigurationssektion [%s] in der Konfigurationsdatei um zu funktionieren.",
|
||||||
|
"Please wait %d seconds between each post.":
|
||||||
|
"Bitte warte %d Sekunden zwischen dem Absenden.",
|
||||||
|
"Paste is limited to %s of encrypted data.":
|
||||||
|
"Schnipsel sind auf %s verschlüsselte Datenmenge beschränkt.",
|
||||||
|
"Invalid data.":
|
||||||
|
"Ungültige Daten.",
|
||||||
|
"You are unlucky. Try again.":
|
||||||
|
"Du hast Pech. Versuchs nochmal.",
|
||||||
|
"Error saving comment. Sorry.":
|
||||||
|
"Fehler beim Speichern des Kommentars, sorry.",
|
||||||
|
"Error saving paste. Sorry.":
|
||||||
|
"Fehler beim Speichern des Schnipsels, sorry.",
|
||||||
|
"Invalid paste ID.":
|
||||||
|
"Ungültige Schnipsel ID.",
|
||||||
|
"Paste is not of burn-after-reading type.":
|
||||||
|
"Schnipsel ist kein \"Einweg\"-Typ.",
|
||||||
|
"Wrong deletion token. Paste was not deleted.":
|
||||||
|
"Falscher Lösch-Kode. Schnipsel wurde nicht gelöscht.",
|
||||||
|
"Paste was properly deleted.":
|
||||||
|
"Schnipsel wurde erfolgreich gelöscht.",
|
||||||
|
"ZeroBin": "ZeroBin",
|
||||||
|
"ZeroBin is a minimalist, opensource online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href=\"https://github.com/elrido/ZeroBin/wiki\">project page</a>.":
|
||||||
|
"ZeroBin ist ein minimalistischer, quelloffener \"pastebin\"-artiger Dienst bei dem der Server keinerlei Kenntnis der Daten-Schnipsel hat. Die Daten werden <i>im Browser</i> mit 256 Bit AES ver- und entschlüsselt. Weitere Informationen sind auf der <a href=\"https://github.com/elrido/ZeroBin/wiki\">Projektseite</a> zu finden.",
|
||||||
|
"Because ignorance is bliss":
|
||||||
|
"Was ich nicht weiss, macht mich nicht heiss",
|
||||||
|
"Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.":
|
||||||
|
"Javascript ist eine Voraussetzung um ZeroBin zu nutzen.<br />Bitte entschuldige die Unannehmlichkeiten.",
|
||||||
|
"ZeroBin requires a modern browser to work.":
|
||||||
|
"ZeroBin setzt einen modernen Browser voraus um funktionieren zu können.",
|
||||||
|
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
|
||||||
|
"Du benutzt immer noch den Internet Explorer? Tu Dir einen Gefallen und wechsle zu einem moderneren Browser:",
|
||||||
|
"New":
|
||||||
|
"Neu",
|
||||||
|
"Send":
|
||||||
|
"Senden",
|
||||||
|
"Clone":
|
||||||
|
"Klonen",
|
||||||
|
"Raw text":
|
||||||
|
"Reiner Text",
|
||||||
|
"Expires":
|
||||||
|
"Ablaufzeit",
|
||||||
|
"Burn after reading":
|
||||||
|
"Einweg-Schnipsel",
|
||||||
|
"Open discussion":
|
||||||
|
"Diskussion eröffnen",
|
||||||
|
"Password (recommended)":
|
||||||
|
"Passwort (empfohlen)",
|
||||||
|
"Discussion":
|
||||||
|
"Diskussion",
|
||||||
|
"Toggle navigation":
|
||||||
|
"Navigation umschalten",
|
||||||
|
"5 minutes":
|
||||||
|
"5 Minuten",
|
||||||
|
"10 minutes":
|
||||||
|
"10 Minuten",
|
||||||
|
"1 hour":
|
||||||
|
"1 Stunde",
|
||||||
|
"1 day":
|
||||||
|
"1 Tag",
|
||||||
|
"1 week":
|
||||||
|
"1 Woche",
|
||||||
|
"1 month":
|
||||||
|
"1 Monat",
|
||||||
|
"1 year":
|
||||||
|
"1 Jahr",
|
||||||
|
"Never":
|
||||||
|
"Nie",
|
||||||
|
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
|
||||||
|
"Hinweis: Dies ist ein Versuchsdienst. Daten können jederzeit gelöscht werden. Kätzchen werden sterben wenn Du diesen Dienst missbrauchst."
|
||||||
|
}
|
@ -0,0 +1,219 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ZeroBin
|
||||||
|
*
|
||||||
|
* a zero-knowledge paste bin
|
||||||
|
*
|
||||||
|
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
|
||||||
|
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
|
||||||
|
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
|
||||||
|
* @version 0.20
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i18n
|
||||||
|
*
|
||||||
|
* provides internationalization tools like translation, browser language detection, etc.
|
||||||
|
*/
|
||||||
|
class i18n
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* translation cache
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $_translations = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* translate a string, alias for translate()
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
* @param string $messageId
|
||||||
|
* @param mixed $args one or multiple parameters injected into placeholders
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function _($messageId)
|
||||||
|
{
|
||||||
|
return call_user_func_array(array('i18n', 'translate'), func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* translate a string
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
* @param string $messageId
|
||||||
|
* @param mixed $args one or multiple parameters injected into placeholders
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function translate($messageId)
|
||||||
|
{
|
||||||
|
if (empty($messageId))
|
||||||
|
{
|
||||||
|
return $messageId;
|
||||||
|
}
|
||||||
|
if (count(self::$_translations) === 0) {
|
||||||
|
self::loadTranslations();
|
||||||
|
}
|
||||||
|
if (!array_key_exists($messageId, self::$_translations))
|
||||||
|
{
|
||||||
|
self::$_translations[$messageId] = $messageId;
|
||||||
|
}
|
||||||
|
$args = func_get_args();
|
||||||
|
$args[0] = self::$_translations[$messageId];
|
||||||
|
return call_user_func_array('sprintf', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loads translations
|
||||||
|
*
|
||||||
|
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$match = self::_getMatchingLanguage(
|
||||||
|
self::getBrowserLanguages(), $availableLanguages
|
||||||
|
);
|
||||||
|
// load translations
|
||||||
|
if ($match != 'en')
|
||||||
|
{
|
||||||
|
self::$_translations = json_decode(
|
||||||
|
file_get_contents($path . DIRECTORY_SEPARATOR . $match . '.json'),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* detect the clients supported languages and return them ordered by preference
|
||||||
|
*
|
||||||
|
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getBrowserLanguages()
|
||||||
|
{
|
||||||
|
$languages = array();
|
||||||
|
if (array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER))
|
||||||
|
{
|
||||||
|
$languageRanges = explode(',', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']));
|
||||||
|
foreach ($languageRanges as $languageRange) {
|
||||||
|
if (preg_match(
|
||||||
|
'/(\*|[a-zA-Z0-9]{1,8}(?:-[a-zA-Z0-9]{1,8})*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?/',
|
||||||
|
trim($languageRange), $match
|
||||||
|
))
|
||||||
|
{
|
||||||
|
if (!isset($match[2]))
|
||||||
|
{
|
||||||
|
$match[2] = '1.0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$match[2] = (string) floatval($match[2]);
|
||||||
|
}
|
||||||
|
if (!isset($languages[$match[2]]))
|
||||||
|
{
|
||||||
|
$languages[$match[2]] = array();
|
||||||
|
}
|
||||||
|
$languages[$match[2]][] = strtolower($match[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
krsort($languages);
|
||||||
|
}
|
||||||
|
return $languages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compares two language preference arrays and returns the preferred match
|
||||||
|
*
|
||||||
|
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
|
||||||
|
*
|
||||||
|
* @param array $acceptedLanguages
|
||||||
|
* @param array $availableLanguages
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function _getMatchingLanguage($acceptedLanguages, $availableLanguages) {
|
||||||
|
$matches = array();
|
||||||
|
$any = false;
|
||||||
|
foreach ($acceptedLanguages as $acceptedQuality => $acceptedValues) {
|
||||||
|
$acceptedQuality = floatval($acceptedQuality);
|
||||||
|
if ($acceptedQuality === 0.0) continue;
|
||||||
|
foreach ($availableLanguages as $availableValue)
|
||||||
|
{
|
||||||
|
$availableQuality = 1.0;
|
||||||
|
foreach ($acceptedValues as $acceptedValue)
|
||||||
|
{
|
||||||
|
if ($acceptedValue === '*')
|
||||||
|
{
|
||||||
|
$any = true;
|
||||||
|
}
|
||||||
|
$matchingGrade = self::_matchLanguage($acceptedValue, $availableValue);
|
||||||
|
if ($matchingGrade > 0)
|
||||||
|
{
|
||||||
|
$q = (string) ($acceptedQuality * $availableQuality * $matchingGrade);
|
||||||
|
if (!isset($matches[$q]))
|
||||||
|
{
|
||||||
|
$matches[$q] = array();
|
||||||
|
}
|
||||||
|
if (!in_array($availableValue, $matches[$q]))
|
||||||
|
{
|
||||||
|
$matches[$q][] = $availableValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($matches) === 0 && $any)
|
||||||
|
{
|
||||||
|
if (count($availableLanguages) > 0)
|
||||||
|
{
|
||||||
|
$matches['1.0'] = $availableLanguages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($matches) === 0)
|
||||||
|
{
|
||||||
|
return 'en';
|
||||||
|
}
|
||||||
|
krsort($matches);
|
||||||
|
$topmatches = current($matches);
|
||||||
|
return current($topmatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compare two language IDs and return the degree they match
|
||||||
|
*
|
||||||
|
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
|
||||||
|
*
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
protected static function _matchLanguage($a, $b) {
|
||||||
|
$a = explode('-', $a);
|
||||||
|
$b = explode('-', $b);
|
||||||
|
for ($i=0, $n=min(count($a), count($b)); $i<$n; $i++)
|
||||||
|
{
|
||||||
|
if ($a[$i] !== $b[$i]) break;
|
||||||
|
}
|
||||||
|
return $i === 0 ? 0 : (float) $i / count($a);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
class i18nTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
private $_translations = array();
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
/* Setup Routine */
|
||||||
|
$this->_translations = json_decode(
|
||||||
|
file_get_contents(PATH . 'i18n' . DIRECTORY_SEPARATOR . 'de.json'),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
/* Tear Down Routine */
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTranslationFallback()
|
||||||
|
{
|
||||||
|
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'foobar';
|
||||||
|
$messageId = 'It does not matter if the message ID exists';
|
||||||
|
i18n::loadTranslations();
|
||||||
|
$this->assertEquals($messageId, i18n::_($messageId), 'fallback to en');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBrowserLanguageDetection()
|
||||||
|
{
|
||||||
|
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-CH,de;q=0.8,en-GB;q=0.6,en-US;q=0.4,en;q=0.2';
|
||||||
|
i18n::loadTranslations();
|
||||||
|
$this->assertEquals($this->_translations['en'], i18n::_('en'), 'browser language de');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testVariableInjection()
|
||||||
|
{
|
||||||
|
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'foobar';
|
||||||
|
i18n::loadTranslations();
|
||||||
|
$this->assertEquals('some string + 1', i18n::_('some %s + %d', 'string', 1), 'browser language de');
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue