diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1159b3f..6225f9c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
# PrivateBin version history
* **1.3 (not yet released)**
+ * ADDED: Translation for Czech (#424)
* ADDED: Threat modeled the application (#177)
* CHANGED: Minimum required PHP version is 5.5, due to a change in the identicon library
* CHANGED: Minimum required browser versions are Firefox 54, Chrome 57, Opera 44, Safari 11, Edge 16, due to use of WebCrypto API, async/await, ES6 & WebAssembly features - all Internet Explorer versions are incompatible
diff --git a/CREDITS.md b/CREDITS.md
index 688dcc38..0f1b45f3 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -41,3 +41,4 @@ Sébastien Sauvage - original idea and main developer
* Tulio Leao - Portuguese
* Michael van Schaik - Dutch
* Péter Tabajdi - Hungarian
+* info-path - Czech
\ No newline at end of file
diff --git a/i18n/cs.json b/i18n/cs.json
new file mode 100644
index 00000000..a36ef8ba
--- /dev/null
+++ b/i18n/cs.json
@@ -0,0 +1,165 @@
+{
+ "PrivateBin": "PrivateBin",
+ "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bits AES. More information on the project page.":
+ "%s je minimalistický open source 'pastebin' server, který neanalyzuje vložená data. Data jsou šifrována v prohlížeči pomocí 256 bitů AES. Více informací na stránce projetu.",
+ "Because ignorance is bliss":
+ "Protože nevědomost je sladká",
+ "en": "cs",
+ "Paste does not exist, has expired or has been deleted.":
+ "Vložený text neexistuje, expiroval nebo byl odstraněn.",
+ "%s requires php %s or above to work. Sorry.":
+ "%s vyžaduje php %s nebo vyšší. Lituji.",
+ "%s requires configuration section [%s] to be present in configuration file.":
+ "%s requires configuration section [%s] to be present in configuration file.",
+ "Please wait %d seconds between each post.":
+ "Počet sekund do dalšího příspěvku: %d.",
+ "Paste is limited to %s of encrypted data.":
+ "Příspěvek je limitován na %s šífrovaných dat",
+ "Invalid data.":
+ "Chybná data.",
+ "You are unlucky. Try again.":
+ "Lituji, zkuste to znovu.",
+ "Error saving comment. Sorry.":
+ "Chyba při ukládání komentáře.",
+ "Error saving paste. Sorry.":
+ "Chyba při ukládání příspěvku.",
+ "Invalid paste ID.":
+ "Chybně vložené ID.",
+ "Paste is not of burn-after-reading type.":
+ "Paste is not of burn-after-reading type.",
+ "Wrong deletion token. Paste was not deleted.":
+ "Wrong deletion token. Paste was not deleted.",
+ "Paste was properly deleted.":
+ "Paste was properly deleted.",
+ "JavaScript is required for %s to work.
Sorry for the inconvenience.":
+ "JavaScript is required for %s to work.
Sorry for the inconvenience.",
+ "%s requires a modern browser to work.":
+ "%%s requires a modern browser to work.",
+ "Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
+ "Still using Internet Explorer? Do yourself a favor, switch to a modern browser:",
+ "New":
+ "Nový",
+ "Send":
+ "Odeslat",
+ "Clone":
+ "Klonovat",
+ "Raw text":
+ "Pouze Text",
+ "Expires":
+ "Expirace",
+ "Burn after reading":
+ "Po přečtení smazat",
+ "Open discussion":
+ "Povolit komentáře",
+ "Password (recommended)":
+ "Heslo (doporučeno)",
+ "Discussion":
+ "Komentáře",
+ "Toggle navigation":
+ "Toggle navigation",
+ "%d seconds": ["%d sekuda", "%d sekundy", "%d sekund"],
+ "%d minutes": ["%d minuta", "%d minuty", "%d minut"],
+ "%d hours": ["%d hodin", "%d hodiny", "%d hodin"],
+ "%d days": ["%d den", "%d dny", "%d dní"],
+ "%d weeks": ["%d týden", "%d týdeny", "%d týdnů"],
+ "%d months": ["%d měsíc", "%d měsíce", "%d měsíců"],
+ "%d years": ["%d rok", "%d roky", "%d roků"],
+ "Never":
+ "Nikdy",
+ "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
+ "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.",
+ "This document will expire in %d seconds.":
+ ["Tento dokument expiruje za %d sekundu.", "Tento dokument expiruje za %d sekundy.", "Tento dokument expiruje za %d sekund."],
+ "This document will expire in %d minutes.":
+ ["Tento dokument expiruje za %d minutu.", "Tento dokument expiruje za %d minuty.", "Tento dokument expiruje za %d minut."],
+ "This document will expire in %d hours.":
+ ["Tento dokument expiruje za %d hodinu.", "Tento dokument expiruje za %d hodiny.", "Tento dokument expiruje za %d hodin."],
+ "This document will expire in %d days.":
+ ["Tento dokument expiruje za %d den.", "Tento dokument expiruje za %d dny.", "Tento dokument expiruje za %d dny."],
+ "This document will expire in %d months.":
+ ["Tento dokument expiruje za %d měsíc.", "Tento dokument expiruje za %d měsíce.", "Tento dokument expiruje za %d měsíců."],
+ "Please enter the password for this paste:":
+ "Zadejte prosím heslo:",
+ "Could not decrypt data (Wrong key?)":
+ "Could not decrypt data (Wrong key?)",
+ "Could not delete the paste, it was not stored in burn after reading mode.":
+ "Could not delete the paste, it was not stored in burn after reading mode.",
+ "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
+ "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.",
+ "Could not decrypt comment; Wrong key?":
+ "Could not decrypt comment; Wrong key?",
+ "Reply":
+ "Reply",
+ "Anonymous":
+ "Anonym",
+ "Avatar generated from IP address":
+ "Avatar generated from IP address",
+ "Add comment":
+ "Přidat komentář",
+ "Optional nickname…":
+ "Volitelný nickname…",
+ "Post comment":
+ "Odeslat komentář",
+ "Sending comment…":
+ "Odesílání komentáře…",
+ "Comment posted.":
+ "Komentář odeslán.",
+ "Could not refresh display: %s":
+ "Could not refresh display: %s",
+ "unknown status":
+ "neznámý stav",
+ "server error or not responding":
+ "Chyba na serveru nebo server neodpovídá",
+ "Could not post comment: %s":
+ "Nelze odeslat komentář: %s",
+ "Sending paste…":
+ "Odesílání příspěvku…",
+ "Your paste is %s (Hit [Ctrl]+[c] to copy)":
+ "Váš link je %s (Stiskněte [Ctrl]+[c] pro zkopírování)",
+ "Delete data":
+ "Odstranit data",
+ "Could not create paste: %s":
+ "Nelze vytvořit příspěvek: %s",
+ "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
+ "Nepodařilo se dešifrovat příspěvek: V adrese chybí dešifrovací klíč (Možnou příčinou může být URL shortener?)",
+ "Format": "Formát",
+ "Plain Text": "Prostý Text",
+ "Source Code": "Zdrojový kód",
+ "Markdown": "Markdown",
+ "Download attachment": "Stáhnout přílohu",
+ "Cloned: '%s'": "Klonováno: '%s'",
+ "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.",
+ "Attach a file": "Připojit soubor",
+ "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard",
+ "File too large, to display a preview. Please download the attachment.": "Soubor je příliš velký pro zobrazení náhledu. Stáhněte si přílohu.",
+ "Remove attachment": "Odstranit přílohu",
+ "Your browser does not support uploading encrypted files. Please use a newer browser.":
+ "Váš prohlížeč nepodporuje nahrávání šifrovaných souborů. Použijte modernější verzi prohlížeče.",
+ "Invalid attachment.": "Chybná příloha.",
+ "Options": "Volby",
+ "Shorten URL": "Shorten URL",
+ "Editor": "Editor",
+ "Preview": "Náhled",
+ "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.":
+ "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.",
+ "Decrypt":
+ "Decrypt",
+ "Enter password":
+ "Zadejte heslo",
+ "Loading…": "Loading…",
+ "Decrypting paste…": "Decrypting paste…",
+ "Preparing new paste…": "Preparing new paste…",
+ "In case this message never disappears please have a look at this FAQ for information to troubleshoot.":
+ "In case this message never disappears please have a look at this FAQ for information to troubleshoot.",
+ "+++ no paste text +++": "+++ žádný vložený text +++",
+ "Could not get paste data: %s":
+ "Could not get paste data: %s",
+ "QR code": "QR code",
+ "I love you too, bot…": "I love you too, bot…",
+ "This website is using an insecure HTTP connection! Please use it only for testing.":
+ "This website is using an insecure HTTP connection! Please use it only for testing.",
+ "For more information see this FAQ entry.":
+ "For more information see this FAQ entry.",
+ "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.":
+ "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS."
+}
diff --git a/js/privatebin.js b/js/privatebin.js
index 51ffbee8..831d813d 100644
--- a/js/privatebin.js
+++ b/js/privatebin.js
@@ -420,7 +420,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @prop {string[]}
* @readonly
*/
- const supportedLanguages = ['de', 'es', 'fr', 'it', 'hu', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'];
+ const supportedLanguages = ['cs', 'de', 'es', 'fr', 'it', 'hu', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'];
/**
* built in language
@@ -571,6 +571,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.getPluralForm = function(n) {
switch (language)
{
+ case 'cs':
+ return n === 1 ? 0 : (n >= 2 && n <=4 ? 1 : 2);
case 'fr':
case 'oc':
case 'zh':
diff --git a/lib/I18n.php b/lib/I18n.php
index b85b29d5..12fadd2d 100644
--- a/lib/I18n.php
+++ b/lib/I18n.php
@@ -294,6 +294,8 @@ class I18n
protected static function _getPluralForm($n)
{
switch (self::$_language) {
+ case 'cs':
+ return $n == 1 ? 0 : ($n >= 2 && $n <=4 ? 1 : 2);
case 'fr':
case 'oc':
case 'zh':
diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php
index 5f231d59..6e2e2122 100644
--- a/tpl/bootstrap.php
+++ b/tpl/bootstrap.php
@@ -72,7 +72,7 @@ if ($MARKDOWN):
endif;
?>
-
+
diff --git a/tpl/page.php b/tpl/page.php
index e535f6f2..82fa0167 100644
--- a/tpl/page.php
+++ b/tpl/page.php
@@ -50,7 +50,7 @@ if ($MARKDOWN):
endif;
?>
-
+
diff --git a/tst/I18nTest.php b/tst/I18nTest.php
index 8be09fa1..f366720a 100644
--- a/tst/I18nTest.php
+++ b/tst/I18nTest.php
@@ -130,6 +130,17 @@ class I18nTest extends PHPUnit_Framework_TestCase
$this->assertEquals('104 ur', I18n::_('%d hours', 104), '104 hours in Slowene');
}
+ public function testBrowserLanguageCsDetection()
+ {
+ $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'cs;q=0.8,en-GB;q=0.6,en-US;q=0.4,en;q=0.2';
+ I18n::loadTranslations();
+ $this->assertEquals('cs', I18n::_('en'), 'browser language cs');
+ $this->assertEquals('1 hodin', I18n::_('%d hours', 1), '1 hour in Czech');
+ $this->assertEquals('2 hodiny', I18n::_('%d hours', 2), '2 hours in Czech');
+ $this->assertEquals('5 minut', I18n::_('%d minutes', 5), '5 minutes in Czech');
+ $this->assertEquals('14 minut', I18n::_('%d minutes', 14), '14 minutes in Czech');
+ }
+
public function testBrowserLanguageAnyDetection()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = '*';