diff options
71 files changed, 2811 insertions, 286 deletions
diff --git a/.gitattributes b/.gitattributes index 93900602..b191e227 100644 --- a/.gitattributes +++ b/.gitattributes | |||
@@ -22,6 +22,7 @@ Dockerfile text | |||
22 | *.ttf binary | 22 | *.ttf binary |
23 | *.min.css binary | 23 | *.min.css binary |
24 | *.min.js binary | 24 | *.min.js binary |
25 | *.mo binary | ||
25 | 26 | ||
26 | # Exclude from Git archives | 27 | # Exclude from Git archives |
27 | .editorconfig export-ignore | 28 | .editorconfig export-ignore |
@@ -18,6 +18,7 @@ vendor/ | |||
18 | # Release archives | 18 | # Release archives |
19 | *.tar.gz | 19 | *.tar.gz |
20 | *.zip | 20 | *.zip |
21 | inc/languages/*/LC_MESSAGES/shaarli.mo | ||
21 | 22 | ||
22 | # Development and test resources | 23 | # Development and test resources |
23 | coverage | 24 | coverage |
diff --git a/.travis.yml b/.travis.yml index b6b9bddf..322e4337 100644 --- a/.travis.yml +++ b/.travis.yml | |||
@@ -13,6 +13,8 @@ install: | |||
13 | - composer self-update | 13 | - composer self-update |
14 | - composer install --prefer-dist | 14 | - composer install --prefer-dist |
15 | - locale -a | 15 | - locale -a |
16 | before_script: | ||
17 | - PATH=${PATH//:\.\/node_modules\/\.bin/} | ||
16 | script: | 18 | script: |
17 | - make clean | 19 | - make clean |
18 | - make check_permissions | 20 | - make check_permissions |
@@ -130,12 +130,12 @@ check_permissions: | |||
130 | # See phpunit.xml for configuration | 130 | # See phpunit.xml for configuration |
131 | # https://phpunit.de/manual/current/en/appendixes.configuration.html | 131 | # https://phpunit.de/manual/current/en/appendixes.configuration.html |
132 | ## | 132 | ## |
133 | test: | 133 | test: translate |
134 | @echo "-------" | 134 | @echo "-------" |
135 | @echo "PHPUNIT" | 135 | @echo "PHPUNIT" |
136 | @echo "-------" | 136 | @echo "-------" |
137 | @mkdir -p sandbox coverage | 137 | @mkdir -p sandbox coverage |
138 | @$(BIN)/phpunit --coverage-php coverage/main.cov --testsuite unit-tests | 138 | @$(BIN)/phpunit --coverage-php coverage/main.cov --bootstrap tests/bootstrap.php --testsuite unit-tests |
139 | 139 | ||
140 | locale_test_%: | 140 | locale_test_%: |
141 | @UT_LOCALE=$*.utf8 \ | 141 | @UT_LOCALE=$*.utf8 \ |
@@ -168,15 +168,15 @@ composer_dependencies: clean | |||
168 | composer install --no-dev --prefer-dist | 168 | composer install --no-dev --prefer-dist |
169 | find vendor/ -name ".git" -type d -exec rm -rf {} + | 169 | find vendor/ -name ".git" -type d -exec rm -rf {} + |
170 | 170 | ||
171 | ### generate a release tarball and include 3rd-party dependencies | 171 | ### generate a release tarball and include 3rd-party dependencies and translations |
172 | release_tar: composer_dependencies htmldoc | 172 | release_tar: composer_dependencies htmldoc translate |
173 | git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).tar HEAD | 173 | git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).tar HEAD |
174 | tar rvf $(ARCHIVE_VERSION).tar --transform "s|^vendor|$(ARCHIVE_PREFIX)vendor|" vendor/ | 174 | tar rvf $(ARCHIVE_VERSION).tar --transform "s|^vendor|$(ARCHIVE_PREFIX)vendor|" vendor/ |
175 | tar rvf $(ARCHIVE_VERSION).tar --transform "s|^doc/html|$(ARCHIVE_PREFIX)doc/html|" doc/html/ | 175 | tar rvf $(ARCHIVE_VERSION).tar --transform "s|^doc/html|$(ARCHIVE_PREFIX)doc/html|" doc/html/ |
176 | gzip $(ARCHIVE_VERSION).tar | 176 | gzip $(ARCHIVE_VERSION).tar |
177 | 177 | ||
178 | ### generate a release zip and include 3rd-party dependencies | 178 | ### generate a release zip and include 3rd-party dependencies and translations |
179 | release_zip: composer_dependencies htmldoc | 179 | release_zip: composer_dependencies htmldoc translate |
180 | git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).zip -9 HEAD | 180 | git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).zip -9 HEAD |
181 | mkdir -p $(ARCHIVE_PREFIX)/{doc,vendor} | 181 | mkdir -p $(ARCHIVE_PREFIX)/{doc,vendor} |
182 | rsync -a doc/html/ $(ARCHIVE_PREFIX)doc/html/ | 182 | rsync -a doc/html/ $(ARCHIVE_PREFIX)doc/html/ |
@@ -213,3 +213,8 @@ htmldoc: | |||
213 | mkdocs build' | 213 | mkdocs build' |
214 | find doc/html/ -type f -exec chmod a-x '{}' \; | 214 | find doc/html/ -type f -exec chmod a-x '{}' \; |
215 | rm -r venv | 215 | rm -r venv |
216 | |||
217 | |||
218 | ### Generate Shaarli's translation compiled file (.mo) | ||
219 | translate: | ||
220 | @find inc/languages/ -name shaarli.po -execdir msgfmt shaarli.po -o shaarli.mo \; \ No newline at end of file | ||
diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php index 5643f4a0..911873a0 100644 --- a/application/ApplicationUtils.php +++ b/application/ApplicationUtils.php | |||
@@ -149,12 +149,13 @@ class ApplicationUtils | |||
149 | public static function checkPHPVersion($minVersion, $curVersion) | 149 | public static function checkPHPVersion($minVersion, $curVersion) |
150 | { | 150 | { |
151 | if (version_compare($curVersion, $minVersion) < 0) { | 151 | if (version_compare($curVersion, $minVersion) < 0) { |
152 | throw new Exception( | 152 | $msg = t( |
153 | 'Your PHP version is obsolete!' | 153 | 'Your PHP version is obsolete!' |
154 | .' Shaarli requires at least PHP '.$minVersion.', and thus cannot run.' | 154 | . ' Shaarli requires at least PHP %s, and thus cannot run.' |
155 | .' Your PHP version has known security vulnerabilities and should be' | 155 | . ' Your PHP version has known security vulnerabilities and should be' |
156 | .' updated as soon as possible.' | 156 | . ' updated as soon as possible.' |
157 | ); | 157 | ); |
158 | throw new Exception(sprintf($msg, $minVersion)); | ||
158 | } | 159 | } |
159 | } | 160 | } |
160 | 161 | ||
@@ -179,7 +180,7 @@ class ApplicationUtils | |||
179 | $rainTplDir.'/'.$conf->get('resource.theme'), | 180 | $rainTplDir.'/'.$conf->get('resource.theme'), |
180 | ) as $path) { | 181 | ) as $path) { |
181 | if (! is_readable(realpath($path))) { | 182 | if (! is_readable(realpath($path))) { |
182 | $errors[] = '"'.$path.'" directory is not readable'; | 183 | $errors[] = '"'.$path.'" '. t('directory is not readable'); |
183 | } | 184 | } |
184 | } | 185 | } |
185 | 186 | ||
@@ -191,10 +192,10 @@ class ApplicationUtils | |||
191 | $conf->get('resource.raintpl_tmp'), | 192 | $conf->get('resource.raintpl_tmp'), |
192 | ) as $path) { | 193 | ) as $path) { |
193 | if (! is_readable(realpath($path))) { | 194 | if (! is_readable(realpath($path))) { |
194 | $errors[] = '"'.$path.'" directory is not readable'; | 195 | $errors[] = '"'.$path.'" '. t('directory is not readable'); |
195 | } | 196 | } |
196 | if (! is_writable(realpath($path))) { | 197 | if (! is_writable(realpath($path))) { |
197 | $errors[] = '"'.$path.'" directory is not writable'; | 198 | $errors[] = '"'.$path.'" '. t('directory is not writable'); |
198 | } | 199 | } |
199 | } | 200 | } |
200 | 201 | ||
@@ -212,10 +213,10 @@ class ApplicationUtils | |||
212 | } | 213 | } |
213 | 214 | ||
214 | if (! is_readable(realpath($path))) { | 215 | if (! is_readable(realpath($path))) { |
215 | $errors[] = '"'.$path.'" file is not readable'; | 216 | $errors[] = '"'.$path.'" '. t('file is not readable'); |
216 | } | 217 | } |
217 | if (! is_writable(realpath($path))) { | 218 | if (! is_writable(realpath($path))) { |
218 | $errors[] = '"'.$path.'" file is not writable'; | 219 | $errors[] = '"'.$path.'" '. t('file is not writable'); |
219 | } | 220 | } |
220 | } | 221 | } |
221 | 222 | ||
diff --git a/application/Cache.php b/application/Cache.php index 5d050165..e5d43e61 100644 --- a/application/Cache.php +++ b/application/Cache.php | |||
@@ -13,7 +13,7 @@ | |||
13 | function purgeCachedPages($pageCacheDir) | 13 | function purgeCachedPages($pageCacheDir) |
14 | { | 14 | { |
15 | if (! is_dir($pageCacheDir)) { | 15 | if (! is_dir($pageCacheDir)) { |
16 | $error = 'Cannot purge '.$pageCacheDir.': no directory'; | 16 | $error = sprintf(t('Cannot purge %s: no directory'), $pageCacheDir); |
17 | error_log($error); | 17 | error_log($error); |
18 | return $error; | 18 | return $error; |
19 | } | 19 | } |
diff --git a/application/FeedBuilder.php b/application/FeedBuilder.php index 7377bcec..3cfaafb4 100644 --- a/application/FeedBuilder.php +++ b/application/FeedBuilder.php | |||
@@ -148,9 +148,9 @@ class FeedBuilder | |||
148 | $link['url'] = $pageaddr . $link['url']; | 148 | $link['url'] = $pageaddr . $link['url']; |
149 | } | 149 | } |
150 | if ($this->usePermalinks === true) { | 150 | if ($this->usePermalinks === true) { |
151 | $permalink = '<a href="'. $link['url'] .'" title="Direct link">Direct link</a>'; | 151 | $permalink = '<a href="'. $link['url'] .'" title="'. t('Direct link') .'">'. t('Direct link') .'</a>'; |
152 | } else { | 152 | } else { |
153 | $permalink = '<a href="'. $link['guid'] .'" title="Permalink">Permalink</a>'; | 153 | $permalink = '<a href="'. $link['guid'] .'" title="'. t('Permalink') .'">'. t('Permalink') .'</a>'; |
154 | } | 154 | } |
155 | $link['description'] = format_description($link['description'], '', $pageaddr); | 155 | $link['description'] = format_description($link['description'], '', $pageaddr); |
156 | $link['description'] .= PHP_EOL .'<br>— '. $permalink; | 156 | $link['description'] .= PHP_EOL .'<br>— '. $permalink; |
diff --git a/application/History.php b/application/History.php index 5e3b1b72..35ec016a 100644 --- a/application/History.php +++ b/application/History.php | |||
@@ -171,7 +171,7 @@ class History | |||
171 | } | 171 | } |
172 | 172 | ||
173 | if (! is_writable($this->historyFilePath)) { | 173 | if (! is_writable($this->historyFilePath)) { |
174 | throw new Exception('History file isn\'t readable or writable'); | 174 | throw new Exception(t('History file isn\'t readable or writable')); |
175 | } | 175 | } |
176 | } | 176 | } |
177 | 177 | ||
@@ -182,7 +182,7 @@ class History | |||
182 | { | 182 | { |
183 | $this->history = FileUtils::readFlatDB($this->historyFilePath, []); | 183 | $this->history = FileUtils::readFlatDB($this->historyFilePath, []); |
184 | if ($this->history === false) { | 184 | if ($this->history === false) { |
185 | throw new Exception('Could not parse history file'); | 185 | throw new Exception(t('Could not parse history file')); |
186 | } | 186 | } |
187 | } | 187 | } |
188 | 188 | ||
diff --git a/application/Languages.php b/application/Languages.php index c8b0a25a..357c7524 100644 --- a/application/Languages.php +++ b/application/Languages.php | |||
@@ -1,21 +1,164 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | namespace Shaarli; | ||
4 | |||
5 | use Gettext\GettextTranslator; | ||
6 | use Gettext\Merge; | ||
7 | use Gettext\Translations; | ||
8 | use Gettext\Translator; | ||
9 | use Gettext\TranslatorInterface; | ||
10 | use Shaarli\Config\ConfigManager; | ||
11 | |||
3 | /** | 12 | /** |
4 | * Wrapper function for translation which match the API | 13 | * Class Languages |
5 | * of gettext()/_() and ngettext(). | 14 | * |
15 | * Load Shaarli translations using 'gettext/gettext'. | ||
16 | * This class allows to either use PHP gettext extension, or a PHP implementation of gettext, | ||
17 | * with a fixed language, or dynamically using autoLocale(). | ||
6 | * | 18 | * |
7 | * Not doing translation for now. | 19 | * Translation files PO/MO files follow gettext standard and must be placed under: |
20 | * <translation path>/<language>/LC_MESSAGES/<domain>.[po|mo] | ||
8 | * | 21 | * |
9 | * @param string $text Text to translate. | 22 | * Pros/cons: |
10 | * @param string $nText The plural message ID. | 23 | * - gettext extension is faster |
11 | * @param int $nb The number of items for plural forms. | 24 | * - gettext is very system dependent (PHP extension, the locale must be installed, and web server reloaded) |
12 | * | 25 | * |
13 | * @return String Text translated. | 26 | * Settings: |
27 | * - translation.mode: | ||
28 | * - auto: use default setting (PHP implementation) | ||
29 | * - php: use PHP implementation | ||
30 | * - gettext: use gettext wrapper | ||
31 | * - translation.language: | ||
32 | * - auto: use autoLocale() and the language change according to user HTTP headers | ||
33 | * - fixed language: e.g. 'fr' | ||
34 | * - translation.extensions: | ||
35 | * - domain => translation_path: allow plugins and themes to extend the defaut extension | ||
36 | * The domain must be unique, and translation path must be relative, and contains the tree mentioned above. | ||
37 | * | ||
38 | * @package Shaarli | ||
14 | */ | 39 | */ |
15 | function t($text, $nText = '', $nb = 0) { | 40 | class Languages |
16 | if (empty($nText)) { | 41 | { |
17 | return $text; | 42 | /** |
43 | * Core translations domain | ||
44 | */ | ||
45 | const DEFAULT_DOMAIN = 'shaarli'; | ||
46 | |||
47 | /** | ||
48 | * @var TranslatorInterface | ||
49 | */ | ||
50 | protected $translator; | ||
51 | |||
52 | /** | ||
53 | * @var string | ||
54 | */ | ||
55 | protected $language; | ||
56 | |||
57 | /** | ||
58 | * @var ConfigManager | ||
59 | */ | ||
60 | protected $conf; | ||
61 | |||
62 | /** | ||
63 | * Languages constructor. | ||
64 | * | ||
65 | * @param string $language lang determined by autoLocale(), can be overridden. | ||
66 | * @param ConfigManager $conf instance. | ||
67 | */ | ||
68 | public function __construct($language, $conf) | ||
69 | { | ||
70 | $this->conf = $conf; | ||
71 | $confLanguage = $this->conf->get('translation.language', 'auto'); | ||
72 | if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) { | ||
73 | $this->language = substr($language, 0, 5); | ||
74 | } else { | ||
75 | $this->language = $confLanguage; | ||
76 | } | ||
77 | |||
78 | if (! extension_loaded('gettext') | ||
79 | || in_array($this->conf->get('translation.mode', 'auto'), ['auto', 'php']) | ||
80 | ) { | ||
81 | $this->initPhpTranslator(); | ||
82 | } else { | ||
83 | $this->initGettextTranslator(); | ||
84 | } | ||
85 | |||
86 | // Register default functions (e.g. '__()') to use our Translator | ||
87 | $this->translator->register(); | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * Initialize the translator using php gettext extension (gettext dependency act as a wrapper). | ||
92 | */ | ||
93 | protected function initGettextTranslator () | ||
94 | { | ||
95 | $this->translator = new GettextTranslator(); | ||
96 | $this->translator->setLanguage($this->language); | ||
97 | $this->translator->loadDomain(self::DEFAULT_DOMAIN, 'inc/languages'); | ||
98 | |||
99 | foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) { | ||
100 | if ($domain !== self::DEFAULT_DOMAIN) { | ||
101 | $this->translator->loadDomain($domain, $translationPath, false); | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * Initialize the translator using a PHP implementation of gettext. | ||
108 | * | ||
109 | * Note that if language po file doesn't exist, errors are ignored (e.g. not installed language). | ||
110 | */ | ||
111 | protected function initPhpTranslator() | ||
112 | { | ||
113 | $this->translator = new Translator(); | ||
114 | $translations = new Translations(); | ||
115 | // Core translations | ||
116 | try { | ||
117 | /** @var Translations $translations */ | ||
118 | $translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po'); | ||
119 | $translations->setDomain('shaarli'); | ||
120 | $this->translator->loadTranslations($translations); | ||
121 | } catch (\InvalidArgumentException $e) {} | ||
122 | |||
123 | |||
124 | // Extension translations (plugins, themes, etc.). | ||
125 | foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) { | ||
126 | if ($domain === self::DEFAULT_DOMAIN) { | ||
127 | continue; | ||
128 | } | ||
129 | |||
130 | try { | ||
131 | /** @var Translations $extension */ | ||
132 | $extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'); | ||
133 | $extension->setDomain($domain); | ||
134 | $this->translator->loadTranslations($extension); | ||
135 | } catch (\InvalidArgumentException $e) {} | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * Checks if a language string is valid. | ||
141 | * | ||
142 | * @param string $language e.g. 'fr' or 'en_US' | ||
143 | * | ||
144 | * @return bool true if valid, false otherwise | ||
145 | */ | ||
146 | protected function isValidLanguage($language) | ||
147 | { | ||
148 | return preg_match('/^[a-z]{2}(_[A-Z]{2})?/', $language) === 1; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * Get the list of available languages for Shaarli. | ||
153 | * | ||
154 | * @return array List of available languages, with their label. | ||
155 | */ | ||
156 | public static function getAvailableLanguages() | ||
157 | { | ||
158 | return [ | ||
159 | 'auto' => t('Automatic'), | ||
160 | 'en' => t('English'), | ||
161 | 'fr' => t('French'), | ||
162 | ]; | ||
18 | } | 163 | } |
19 | $actualForm = $nb > 1 ? $nText : $text; | ||
20 | return sprintf($actualForm, $nb); | ||
21 | } | 164 | } |
diff --git a/application/LinkDB.php b/application/LinkDB.php index 22c1f0ab..f026a041 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php | |||
@@ -133,16 +133,16 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
133 | { | 133 | { |
134 | // TODO: use exceptions instead of "die" | 134 | // TODO: use exceptions instead of "die" |
135 | if (!$this->loggedIn) { | 135 | if (!$this->loggedIn) { |
136 | die('You are not authorized to add a link.'); | 136 | die(t('You are not authorized to add a link.')); |
137 | } | 137 | } |
138 | if (!isset($value['id']) || empty($value['url'])) { | 138 | if (!isset($value['id']) || empty($value['url'])) { |
139 | die('Internal Error: A link should always have an id and URL.'); | 139 | die(t('Internal Error: A link should always have an id and URL.')); |
140 | } | 140 | } |
141 | if (($offset !== null && ! is_int($offset)) || ! is_int($value['id'])) { | 141 | if (($offset !== null && ! is_int($offset)) || ! is_int($value['id'])) { |
142 | die('You must specify an integer as a key.'); | 142 | die(t('You must specify an integer as a key.')); |
143 | } | 143 | } |
144 | if ($offset !== null && $offset !== $value['id']) { | 144 | if ($offset !== null && $offset !== $value['id']) { |
145 | die('Array offset and link ID must be equal.'); | 145 | die(t('Array offset and link ID must be equal.')); |
146 | } | 146 | } |
147 | 147 | ||
148 | // If the link exists, we reuse the real offset, otherwise new entry | 148 | // If the link exists, we reuse the real offset, otherwise new entry |
@@ -248,13 +248,13 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
248 | $this->links = array(); | 248 | $this->links = array(); |
249 | $link = array( | 249 | $link = array( |
250 | 'id' => 1, | 250 | 'id' => 1, |
251 | 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone', | 251 | 'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'), |
252 | 'url'=>'https://shaarli.readthedocs.io', | 252 | 'url'=>'https://shaarli.readthedocs.io', |
253 | 'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. | 253 | 'description'=>t('Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. |
254 | 254 | ||
255 | To learn how to use Shaarli, consult the link "Help/documentation" at the bottom of this page. | 255 | To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page. |
256 | 256 | ||
257 | You use the community supported version of the original Shaarli project, by Sebastien Sauvage.', | 257 | You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'), |
258 | 'private'=>0, | 258 | 'private'=>0, |
259 | 'created'=> new DateTime(), | 259 | 'created'=> new DateTime(), |
260 | 'tags'=>'opensource software' | 260 | 'tags'=>'opensource software' |
@@ -264,9 +264,9 @@ You use the community supported version of the original Shaarli project, by Seba | |||
264 | 264 | ||
265 | $link = array( | 265 | $link = array( |
266 | 'id' => 0, | 266 | 'id' => 0, |
267 | 'title'=>'My secret stuff... - Pastebin.com', | 267 | 'title'=> t('My secret stuff... - Pastebin.com'), |
268 | 'url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=', | 268 | 'url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=', |
269 | 'description'=>'Shhhh! I\'m a private link only YOU can see. You can delete me too.', | 269 | 'description'=> t('Shhhh! I\'m a private link only YOU can see. You can delete me too.'), |
270 | 'private'=>1, | 270 | 'private'=>1, |
271 | 'created'=> new DateTime('1 minute ago'), | 271 | 'created'=> new DateTime('1 minute ago'), |
272 | 'tags'=>'secretstuff', | 272 | 'tags'=>'secretstuff', |
diff --git a/application/LinkFilter.php b/application/LinkFilter.php index 99ecd1e2..12376e27 100644 --- a/application/LinkFilter.php +++ b/application/LinkFilter.php | |||
@@ -444,5 +444,11 @@ class LinkFilter | |||
444 | 444 | ||
445 | class LinkNotFoundException extends Exception | 445 | class LinkNotFoundException extends Exception |
446 | { | 446 | { |
447 | protected $message = 'The link you are trying to reach does not exist or has been deleted.'; | 447 | /** |
448 | * LinkNotFoundException constructor. | ||
449 | */ | ||
450 | public function __construct() | ||
451 | { | ||
452 | $this->message = t('The link you are trying to reach does not exist or has been deleted.'); | ||
453 | } | ||
448 | } | 454 | } |
diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index 31796367..dd7057f8 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php | |||
@@ -32,11 +32,10 @@ class NetscapeBookmarkUtils | |||
32 | { | 32 | { |
33 | // see tpl/export.html for possible values | 33 | // see tpl/export.html for possible values |
34 | if (! in_array($selection, array('all', 'public', 'private'))) { | 34 | if (! in_array($selection, array('all', 'public', 'private'))) { |
35 | throw new Exception('Invalid export selection: "'.$selection.'"'); | 35 | throw new Exception(t('Invalid export selection:') .' "'.$selection.'"'); |
36 | } | 36 | } |
37 | 37 | ||
38 | $bookmarkLinks = array(); | 38 | $bookmarkLinks = array(); |
39 | |||
40 | foreach ($linkDb as $link) { | 39 | foreach ($linkDb as $link) { |
41 | if ($link['private'] != 0 && $selection == 'public') { | 40 | if ($link['private'] != 0 && $selection == 'public') { |
42 | continue; | 41 | continue; |
@@ -79,14 +78,14 @@ class NetscapeBookmarkUtils | |||
79 | $duration=0 | 78 | $duration=0 |
80 | ) | 79 | ) |
81 | { | 80 | { |
82 | $status = 'File '.$filename.' ('.$filesize.' bytes) '; | 81 | $status = sprintf(t('File %s (%d bytes) '), $filename, $filesize); |
83 | if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) { | 82 | if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) { |
84 | $status .= 'has an unknown file format. Nothing was imported.'; | 83 | $status .= t('has an unknown file format. Nothing was imported.'); |
85 | } else { | 84 | } else { |
86 | $status .= 'was successfully processed in '. $duration .' seconds: '; | 85 | $status .= vsprintf( |
87 | $status .= $importCount.' links imported, '; | 86 | t('was successfully processed in %d seconds: %d links imported, %d links overwritten, %d links skipped.'), |
88 | $status .= $overwriteCount.' links overwritten, '; | 87 | [$duration, $importCount, $overwriteCount, $skipCount] |
89 | $status .= $skipCount.' links skipped.'; | 88 | ); |
90 | } | 89 | } |
91 | return $status; | 90 | return $status; |
92 | } | 91 | } |
diff --git a/application/PageBuilder.php b/application/PageBuilder.php index 291860ad..af290671 100644 --- a/application/PageBuilder.php +++ b/application/PageBuilder.php | |||
@@ -159,9 +159,12 @@ class PageBuilder | |||
159 | * | 159 | * |
160 | * @param string $message A messate to display what is not found | 160 | * @param string $message A messate to display what is not found |
161 | */ | 161 | */ |
162 | public function render404($message = 'The page you are trying to reach does not exist or has been deleted.') | 162 | public function render404($message = '') |
163 | { | 163 | { |
164 | header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); | 164 | if (empty($message)) { |
165 | $message = t('The page you are trying to reach does not exist or has been deleted.'); | ||
166 | } | ||
167 | header($_SERVER['SERVER_PROTOCOL'] .' '. t('404 Not Found')); | ||
165 | $this->tpl->assign('error_message', $message); | 168 | $this->tpl->assign('error_message', $message); |
166 | $this->renderPage('404'); | 169 | $this->renderPage('404'); |
167 | } | 170 | } |
diff --git a/application/PluginManager.php b/application/PluginManager.php index 59ece4fa..cf603845 100644 --- a/application/PluginManager.php +++ b/application/PluginManager.php | |||
@@ -188,6 +188,9 @@ class PluginManager | |||
188 | $metaData[$plugin] = parse_ini_file($metaFile); | 188 | $metaData[$plugin] = parse_ini_file($metaFile); |
189 | $metaData[$plugin]['order'] = array_search($plugin, $this->authorizedPlugins); | 189 | $metaData[$plugin]['order'] = array_search($plugin, $this->authorizedPlugins); |
190 | 190 | ||
191 | if (isset($metaData[$plugin]['description'])) { | ||
192 | $metaData[$plugin]['description'] = t($metaData[$plugin]['description']); | ||
193 | } | ||
191 | // Read parameters and format them into an array. | 194 | // Read parameters and format them into an array. |
192 | if (isset($metaData[$plugin]['parameters'])) { | 195 | if (isset($metaData[$plugin]['parameters'])) { |
193 | $params = explode(';', $metaData[$plugin]['parameters']); | 196 | $params = explode(';', $metaData[$plugin]['parameters']); |
@@ -203,7 +206,7 @@ class PluginManager | |||
203 | $metaData[$plugin]['parameters'][$param]['value'] = ''; | 206 | $metaData[$plugin]['parameters'][$param]['value'] = ''; |
204 | // Optional parameter description in parameter.PARAM_NAME= | 207 | // Optional parameter description in parameter.PARAM_NAME= |
205 | if (isset($metaData[$plugin]['parameter.'. $param])) { | 208 | if (isset($metaData[$plugin]['parameter.'. $param])) { |
206 | $metaData[$plugin]['parameters'][$param]['desc'] = $metaData[$plugin]['parameter.'. $param]; | 209 | $metaData[$plugin]['parameters'][$param]['desc'] = t($metaData[$plugin]['parameter.'. $param]); |
207 | } | 210 | } |
208 | } | 211 | } |
209 | } | 212 | } |
@@ -237,6 +240,6 @@ class PluginFileNotFoundException extends Exception | |||
237 | */ | 240 | */ |
238 | public function __construct($pluginName) | 241 | public function __construct($pluginName) |
239 | { | 242 | { |
240 | $this->message = 'Plugin "'. $pluginName .'" files not found.'; | 243 | $this->message = sprintf(t('Plugin "%s" files not found.'), $pluginName); |
241 | } | 244 | } |
242 | } | 245 | } |
diff --git a/application/Updater.php b/application/Updater.php index 72b2def0..723a7a81 100644 --- a/application/Updater.php +++ b/application/Updater.php | |||
@@ -73,7 +73,7 @@ class Updater | |||
73 | } | 73 | } |
74 | 74 | ||
75 | if ($this->methods === null) { | 75 | if ($this->methods === null) { |
76 | throw new UpdaterException('Couldn\'t retrieve Updater class methods.'); | 76 | throw new UpdaterException(t('Couldn\'t retrieve Updater class methods.')); |
77 | } | 77 | } |
78 | 78 | ||
79 | foreach ($this->methods as $method) { | 79 | foreach ($this->methods as $method) { |
@@ -482,7 +482,7 @@ class UpdaterException extends Exception | |||
482 | } | 482 | } |
483 | 483 | ||
484 | if (! empty($this->method)) { | 484 | if (! empty($this->method)) { |
485 | $out .= 'An error occurred while running the update '. $this->method . PHP_EOL; | 485 | $out .= t('An error occurred while running the update ') . $this->method . PHP_EOL; |
486 | } | 486 | } |
487 | 487 | ||
488 | if (! empty($this->previous)) { | 488 | if (! empty($this->previous)) { |
@@ -522,11 +522,11 @@ function read_updates_file($updatesFilepath) | |||
522 | function write_updates_file($updatesFilepath, $updates) | 522 | function write_updates_file($updatesFilepath, $updates) |
523 | { | 523 | { |
524 | if (empty($updatesFilepath)) { | 524 | if (empty($updatesFilepath)) { |
525 | throw new Exception('Updates file path is not set, can\'t write updates.'); | 525 | throw new Exception(t('Updates file path is not set, can\'t write updates.')); |
526 | } | 526 | } |
527 | 527 | ||
528 | $res = file_put_contents($updatesFilepath, implode(';', $updates)); | 528 | $res = file_put_contents($updatesFilepath, implode(';', $updates)); |
529 | if ($res === false) { | 529 | if ($res === false) { |
530 | throw new Exception('Unable to write updates in '. $updatesFilepath . '.'); | 530 | throw new Exception(t('Unable to write updates in '. $updatesFilepath . '.')); |
531 | } | 531 | } |
532 | } | 532 | } |
diff --git a/application/Utils.php b/application/Utils.php index 4a2f5561..2f38a8de 100644 --- a/application/Utils.php +++ b/application/Utils.php | |||
@@ -452,7 +452,7 @@ function get_max_upload_size($limitPost, $limitUpload, $format = true) | |||
452 | */ | 452 | */ |
453 | function alphabetical_sort(&$data, $reverse = false, $byKeys = false) | 453 | function alphabetical_sort(&$data, $reverse = false, $byKeys = false) |
454 | { | 454 | { |
455 | $callback = function($a, $b) use ($reverse) { | 455 | $callback = function ($a, $b) use ($reverse) { |
456 | // Collator is part of PHP intl. | 456 | // Collator is part of PHP intl. |
457 | if (class_exists('Collator')) { | 457 | if (class_exists('Collator')) { |
458 | $collator = new Collator(setlocale(LC_COLLATE, 0)); | 458 | $collator = new Collator(setlocale(LC_COLLATE, 0)); |
@@ -470,3 +470,18 @@ function alphabetical_sort(&$data, $reverse = false, $byKeys = false) | |||
470 | usort($data, $callback); | 470 | usort($data, $callback); |
471 | } | 471 | } |
472 | } | 472 | } |
473 | |||
474 | /** | ||
475 | * Wrapper function for translation which match the API | ||
476 | * of gettext()/_() and ngettext(). | ||
477 | * | ||
478 | * @param string $text Text to translate. | ||
479 | * @param string $nText The plural message ID. | ||
480 | * @param int $nb The number of items for plural forms. | ||
481 | * @param string $domain The domain where the translation is stored (default: shaarli). | ||
482 | * | ||
483 | * @return string Text translated. | ||
484 | */ | ||
485 | function t($text, $nText = '', $nb = 1, $domain = 'shaarli') { | ||
486 | return dn__($domain, $text, $nText, $nb); | ||
487 | } | ||
diff --git a/application/config/ConfigJson.php b/application/config/ConfigJson.php index 9ef2ef56..8c8d5610 100644 --- a/application/config/ConfigJson.php +++ b/application/config/ConfigJson.php | |||
@@ -22,10 +22,15 @@ class ConfigJson implements ConfigIO | |||
22 | $data = json_decode($data, true); | 22 | $data = json_decode($data, true); |
23 | if ($data === null) { | 23 | if ($data === null) { |
24 | $errorCode = json_last_error(); | 24 | $errorCode = json_last_error(); |
25 | $error = 'An error occurred while parsing JSON configuration file ('. $filepath .'): error code #'; | 25 | $error = sprintf( |
26 | $error .= $errorCode. '<br>➜ <code>' . json_last_error_msg() .'</code>'; | 26 | 'An error occurred while parsing JSON configuration file (%s): error code #%d', |
27 | $filepath, | ||
28 | $errorCode | ||
29 | ); | ||
30 | $error .= '<br>➜ <code>' . json_last_error_msg() .'</code>'; | ||
27 | if ($errorCode === JSON_ERROR_SYNTAX) { | 31 | if ($errorCode === JSON_ERROR_SYNTAX) { |
28 | $error .= '<br>Please check your JSON syntax (without PHP comment tags) using a JSON lint tool such as '; | 32 | $error .= '<br>'; |
33 | $error .= 'Please check your JSON syntax (without PHP comment tags) using a JSON lint tool such as '; | ||
29 | $error .= '<a href="http://jsonlint.com/">jsonlint.com</a>.'; | 34 | $error .= '<a href="http://jsonlint.com/">jsonlint.com</a>.'; |
30 | } | 35 | } |
31 | throw new \Exception($error); | 36 | throw new \Exception($error); |
@@ -44,8 +49,8 @@ class ConfigJson implements ConfigIO | |||
44 | if (!file_put_contents($filepath, $data)) { | 49 | if (!file_put_contents($filepath, $data)) { |
45 | throw new \IOException( | 50 | throw new \IOException( |
46 | $filepath, | 51 | $filepath, |
47 | 'Shaarli could not create the config file. | 52 | t('Shaarli could not create the config file. '. |
48 | Please make sure Shaarli has the right to write in the folder is it installed in.' | 53 | 'Please make sure Shaarli has the right to write in the folder is it installed in.') |
49 | ); | 54 | ); |
50 | } | 55 | } |
51 | } | 56 | } |
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php index 7ff2fe67..9e4c9f63 100644 --- a/application/config/ConfigManager.php +++ b/application/config/ConfigManager.php | |||
@@ -132,7 +132,7 @@ class ConfigManager | |||
132 | public function set($setting, $value, $write = false, $isLoggedIn = false) | 132 | public function set($setting, $value, $write = false, $isLoggedIn = false) |
133 | { | 133 | { |
134 | if (empty($setting) || ! is_string($setting)) { | 134 | if (empty($setting) || ! is_string($setting)) { |
135 | throw new \Exception('Invalid setting key parameter. String expected, got: '. gettype($setting)); | 135 | throw new \Exception(t('Invalid setting key parameter. String expected, got: '). gettype($setting)); |
136 | } | 136 | } |
137 | 137 | ||
138 | // During the ConfigIO transition, map legacy settings to the new ones. | 138 | // During the ConfigIO transition, map legacy settings to the new ones. |
@@ -339,6 +339,10 @@ class ConfigManager | |||
339 | $this->setEmpty('redirector.url', ''); | 339 | $this->setEmpty('redirector.url', ''); |
340 | $this->setEmpty('redirector.encode_url', true); | 340 | $this->setEmpty('redirector.encode_url', true); |
341 | 341 | ||
342 | $this->setEmpty('translation.language', 'auto'); | ||
343 | $this->setEmpty('translation.mode', 'php'); | ||
344 | $this->setEmpty('translation.extensions', []); | ||
345 | |||
342 | $this->setEmpty('plugins', array()); | 346 | $this->setEmpty('plugins', array()); |
343 | } | 347 | } |
344 | 348 | ||
diff --git a/application/config/ConfigPhp.php b/application/config/ConfigPhp.php index 2633824d..2f66e8e0 100644 --- a/application/config/ConfigPhp.php +++ b/application/config/ConfigPhp.php | |||
@@ -118,8 +118,8 @@ class ConfigPhp implements ConfigIO | |||
118 | ) { | 118 | ) { |
119 | throw new \IOException( | 119 | throw new \IOException( |
120 | $filepath, | 120 | $filepath, |
121 | 'Shaarli could not create the config file. | 121 | t('Shaarli could not create the config file. '. |
122 | Please make sure Shaarli has the right to write in the folder is it installed in.' | 122 | 'Please make sure Shaarli has the right to write in the folder is it installed in.') |
123 | ); | 123 | ); |
124 | } | 124 | } |
125 | } | 125 | } |
diff --git a/application/config/exception/MissingFieldConfigException.php b/application/config/exception/MissingFieldConfigException.php index 6346c6a9..9e0a9359 100644 --- a/application/config/exception/MissingFieldConfigException.php +++ b/application/config/exception/MissingFieldConfigException.php | |||
@@ -18,6 +18,6 @@ class MissingFieldConfigException extends \Exception | |||
18 | public function __construct($field) | 18 | public function __construct($field) |
19 | { | 19 | { |
20 | $this->field = $field; | 20 | $this->field = $field; |
21 | $this->message = 'Configuration value is required for '. $this->field; | 21 | $this->message = sprintf(t('Configuration value is required for %s'), $this->field); |
22 | } | 22 | } |
23 | } | 23 | } |
diff --git a/application/config/exception/PluginConfigOrderException.php b/application/config/exception/PluginConfigOrderException.php index f9d68750..f82ec26e 100644 --- a/application/config/exception/PluginConfigOrderException.php +++ b/application/config/exception/PluginConfigOrderException.php | |||
@@ -12,6 +12,6 @@ class PluginConfigOrderException extends \Exception | |||
12 | */ | 12 | */ |
13 | public function __construct() | 13 | public function __construct() |
14 | { | 14 | { |
15 | $this->message = 'An error occurred while trying to save plugins loading order.'; | 15 | $this->message = t('An error occurred while trying to save plugins loading order.'); |
16 | } | 16 | } |
17 | } | 17 | } |
diff --git a/application/config/exception/UnauthorizedConfigException.php b/application/config/exception/UnauthorizedConfigException.php index 79672c1b..72311fae 100644 --- a/application/config/exception/UnauthorizedConfigException.php +++ b/application/config/exception/UnauthorizedConfigException.php | |||
@@ -13,6 +13,6 @@ class UnauthorizedConfigException extends \Exception | |||
13 | */ | 13 | */ |
14 | public function __construct() | 14 | public function __construct() |
15 | { | 15 | { |
16 | $this->message = 'You are not authorized to alter config.'; | 16 | $this->message = t('You are not authorized to alter config.'); |
17 | } | 17 | } |
18 | } | 18 | } |
diff --git a/application/exceptions/IOException.php b/application/exceptions/IOException.php index b563b23d..18e46b77 100644 --- a/application/exceptions/IOException.php +++ b/application/exceptions/IOException.php | |||
@@ -16,7 +16,7 @@ class IOException extends Exception | |||
16 | public function __construct($path, $message = '') | 16 | public function __construct($path, $message = '') |
17 | { | 17 | { |
18 | $this->path = $path; | 18 | $this->path = $path; |
19 | $this->message = empty($message) ? 'Error accessing' : $message; | 19 | $this->message = empty($message) ? t('Error accessing') : $message; |
20 | $this->message .= ' "' . $this->path .'"'; | 20 | $this->message .= ' "' . $this->path .'"'; |
21 | } | 21 | } |
22 | } | 22 | } |
diff --git a/composer.json b/composer.json index afb8aca4..f331d6ca 100644 --- a/composer.json +++ b/composer.json | |||
@@ -19,7 +19,8 @@ | |||
19 | "shaarli/netscape-bookmark-parser": "^2.0", | 19 | "shaarli/netscape-bookmark-parser": "^2.0", |
20 | "erusev/parsedown": "1.6", | 20 | "erusev/parsedown": "1.6", |
21 | "slim/slim": "^3.0", | 21 | "slim/slim": "^3.0", |
22 | "pubsubhubbub/publisher": "dev-master" | 22 | "pubsubhubbub/publisher": "dev-master", |
23 | "gettext/gettext": "^4.4" | ||
23 | }, | 24 | }, |
24 | "require-dev": { | 25 | "require-dev": { |
25 | "phpmd/phpmd" : "@stable", | 26 | "phpmd/phpmd" : "@stable", |
diff --git a/composer.lock b/composer.lock index 435d6a88..39909b8f 100644 --- a/composer.lock +++ b/composer.lock | |||
@@ -4,7 +4,7 @@ | |||
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", | 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", |
5 | "This file is @generated automatically" | 5 | "This file is @generated automatically" |
6 | ], | 6 | ], |
7 | "content-hash": "68beedbfa104c788029b079800cfd6e8", | 7 | "content-hash": "13b7e1e474fe9264b098ba86face0feb", |
8 | "packages": [ | 8 | "packages": [ |
9 | { | 9 | { |
10 | "name": "container-interop/container-interop", | 10 | "name": "container-interop/container-interop", |
@@ -77,6 +77,129 @@ | |||
77 | "time": "2015-10-04T16:44:32+00:00" | 77 | "time": "2015-10-04T16:44:32+00:00" |
78 | }, | 78 | }, |
79 | { | 79 | { |
80 | "name": "gettext/gettext", | ||
81 | "version": "v4.4.3", | ||
82 | "source": { | ||
83 | "type": "git", | ||
84 | "url": "https://github.com/oscarotero/Gettext.git", | ||
85 | "reference": "4f57f004635cc6311a20815ebfdc0757cb337113" | ||
86 | }, | ||
87 | "dist": { | ||
88 | "type": "zip", | ||
89 | "url": "https://api.github.com/repos/oscarotero/Gettext/zipball/4f57f004635cc6311a20815ebfdc0757cb337113", | ||
90 | "reference": "4f57f004635cc6311a20815ebfdc0757cb337113", | ||
91 | "shasum": "" | ||
92 | }, | ||
93 | "require": { | ||
94 | "gettext/languages": "^2.3", | ||
95 | "php": ">=5.4.0" | ||
96 | }, | ||
97 | "require-dev": { | ||
98 | "illuminate/view": "*", | ||
99 | "phpunit/phpunit": "^4.8|^5.7", | ||
100 | "squizlabs/php_codesniffer": "^3.0", | ||
101 | "symfony/yaml": "~2", | ||
102 | "twig/extensions": "*", | ||
103 | "twig/twig": "^1.31|^2.0" | ||
104 | }, | ||
105 | "suggest": { | ||
106 | "illuminate/view": "Is necessary if you want to use the Blade extractor", | ||
107 | "symfony/yaml": "Is necessary if you want to use the Yaml extractor/generator", | ||
108 | "twig/extensions": "Is necessary if you want to use the Twig extractor", | ||
109 | "twig/twig": "Is necessary if you want to use the Twig extractor" | ||
110 | }, | ||
111 | "type": "library", | ||
112 | "autoload": { | ||
113 | "psr-4": { | ||
114 | "Gettext\\": "src" | ||
115 | } | ||
116 | }, | ||
117 | "notification-url": "https://packagist.org/downloads/", | ||
118 | "license": [ | ||
119 | "MIT" | ||
120 | ], | ||
121 | "authors": [ | ||
122 | { | ||
123 | "name": "Oscar Otero", | ||
124 | "email": "oom@oscarotero.com", | ||
125 | "homepage": "http://oscarotero.com", | ||
126 | "role": "Developer" | ||
127 | } | ||
128 | ], | ||
129 | "description": "PHP gettext manager", | ||
130 | "homepage": "https://github.com/oscarotero/Gettext", | ||
131 | "keywords": [ | ||
132 | "JS", | ||
133 | "gettext", | ||
134 | "i18n", | ||
135 | "mo", | ||
136 | "po", | ||
137 | "translation" | ||
138 | ], | ||
139 | "time": "2017-08-09T16:59:46+00:00" | ||
140 | }, | ||
141 | { | ||
142 | "name": "gettext/languages", | ||
143 | "version": "2.3.0", | ||
144 | "source": { | ||
145 | "type": "git", | ||
146 | "url": "https://github.com/mlocati/cldr-to-gettext-plural-rules.git", | ||
147 | "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7" | ||
148 | }, | ||
149 | "dist": { | ||
150 | "type": "zip", | ||
151 | "url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/49c39e51569963cc917a924b489e7025bfb9d8c7", | ||
152 | "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7", | ||
153 | "shasum": "" | ||
154 | }, | ||
155 | "require": { | ||
156 | "php": ">=5.3" | ||
157 | }, | ||
158 | "require-dev": { | ||
159 | "phpunit/phpunit": "^4" | ||
160 | }, | ||
161 | "bin": [ | ||
162 | "bin/export-plural-rules", | ||
163 | "bin/export-plural-rules.php" | ||
164 | ], | ||
165 | "type": "library", | ||
166 | "autoload": { | ||
167 | "psr-4": { | ||
168 | "Gettext\\Languages\\": "src/" | ||
169 | } | ||
170 | }, | ||
171 | "notification-url": "https://packagist.org/downloads/", | ||
172 | "license": [ | ||
173 | "MIT" | ||
174 | ], | ||
175 | "authors": [ | ||
176 | { | ||
177 | "name": "Michele Locati", | ||
178 | "email": "mlocati@gmail.com", | ||
179 | "role": "Developer" | ||
180 | } | ||
181 | ], | ||
182 | "description": "gettext languages with plural rules", | ||
183 | "homepage": "https://github.com/mlocati/cldr-to-gettext-plural-rules", | ||
184 | "keywords": [ | ||
185 | "cldr", | ||
186 | "i18n", | ||
187 | "internationalization", | ||
188 | "l10n", | ||
189 | "language", | ||
190 | "languages", | ||
191 | "localization", | ||
192 | "php", | ||
193 | "plural", | ||
194 | "plural rules", | ||
195 | "plurals", | ||
196 | "translate", | ||
197 | "translations", | ||
198 | "unicode" | ||
199 | ], | ||
200 | "time": "2017-03-23T17:02:28+00:00" | ||
201 | }, | ||
202 | { | ||
80 | "name": "katzgrau/klogger", | 203 | "name": "katzgrau/klogger", |
81 | "version": "1.2.1", | 204 | "version": "1.2.1", |
82 | "source": { | 205 | "source": { |
@@ -371,12 +494,12 @@ | |||
371 | "source": { | 494 | "source": { |
372 | "type": "git", | 495 | "type": "git", |
373 | "url": "https://github.com/pubsubhubbub/php-publisher.git", | 496 | "url": "https://github.com/pubsubhubbub/php-publisher.git", |
374 | "reference": "a5d6a0e1cc9d49101c3904480e5b06cbb8addba7" | 497 | "reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f" |
375 | }, | 498 | }, |
376 | "dist": { | 499 | "dist": { |
377 | "type": "zip", | 500 | "type": "zip", |
378 | "url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/a5d6a0e1cc9d49101c3904480e5b06cbb8addba7", | 501 | "url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/0d224daebd504ab61c22fee4db58f8d1fc18945f", |
379 | "reference": "a5d6a0e1cc9d49101c3904480e5b06cbb8addba7", | 502 | "reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f", |
380 | "shasum": "" | 503 | "shasum": "" |
381 | }, | 504 | }, |
382 | "require": { | 505 | "require": { |
@@ -406,7 +529,7 @@ | |||
406 | "publishers", | 529 | "publishers", |
407 | "pubsubhubbub" | 530 | "pubsubhubbub" |
408 | ], | 531 | ], |
409 | "time": "2016-11-15T06:24:01+00:00" | 532 | "time": "2017-10-08T10:59:41+00:00" |
410 | }, | 533 | }, |
411 | { | 534 | { |
412 | "name": "shaarli/netscape-bookmark-parser", | 535 | "name": "shaarli/netscape-bookmark-parser", |
@@ -632,16 +755,16 @@ | |||
632 | }, | 755 | }, |
633 | { | 756 | { |
634 | "name": "phpdocumentor/reflection-common", | 757 | "name": "phpdocumentor/reflection-common", |
635 | "version": "1.0", | 758 | "version": "1.0.1", |
636 | "source": { | 759 | "source": { |
637 | "type": "git", | 760 | "type": "git", |
638 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", | 761 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", |
639 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" | 762 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" |
640 | }, | 763 | }, |
641 | "dist": { | 764 | "dist": { |
642 | "type": "zip", | 765 | "type": "zip", |
643 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", | 766 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", |
644 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", | 767 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", |
645 | "shasum": "" | 768 | "shasum": "" |
646 | }, | 769 | }, |
647 | "require": { | 770 | "require": { |
@@ -682,20 +805,20 @@ | |||
682 | "reflection", | 805 | "reflection", |
683 | "static analysis" | 806 | "static analysis" |
684 | ], | 807 | ], |
685 | "time": "2015-12-27T11:43:31+00:00" | 808 | "time": "2017-09-11T18:02:19+00:00" |
686 | }, | 809 | }, |
687 | { | 810 | { |
688 | "name": "phpdocumentor/reflection-docblock", | 811 | "name": "phpdocumentor/reflection-docblock", |
689 | "version": "3.2.1", | 812 | "version": "3.2.2", |
690 | "source": { | 813 | "source": { |
691 | "type": "git", | 814 | "type": "git", |
692 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", | 815 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", |
693 | "reference": "183824db76118b9dddffc7e522b91fa175f75119" | 816 | "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157" |
694 | }, | 817 | }, |
695 | "dist": { | 818 | "dist": { |
696 | "type": "zip", | 819 | "type": "zip", |
697 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/183824db76118b9dddffc7e522b91fa175f75119", | 820 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157", |
698 | "reference": "183824db76118b9dddffc7e522b91fa175f75119", | 821 | "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157", |
699 | "shasum": "" | 822 | "shasum": "" |
700 | }, | 823 | }, |
701 | "require": { | 824 | "require": { |
@@ -727,7 +850,7 @@ | |||
727 | } | 850 | } |
728 | ], | 851 | ], |
729 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", | 852 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", |
730 | "time": "2017-08-04T20:55:59+00:00" | 853 | "time": "2017-08-08T06:39:58+00:00" |
731 | }, | 854 | }, |
732 | { | 855 | { |
733 | "name": "phpdocumentor/type-resolver", | 856 | "name": "phpdocumentor/type-resolver", |
@@ -844,22 +967,22 @@ | |||
844 | }, | 967 | }, |
845 | { | 968 | { |
846 | "name": "phpspec/prophecy", | 969 | "name": "phpspec/prophecy", |
847 | "version": "v1.7.0", | 970 | "version": "v1.7.2", |
848 | "source": { | 971 | "source": { |
849 | "type": "git", | 972 | "type": "git", |
850 | "url": "https://github.com/phpspec/prophecy.git", | 973 | "url": "https://github.com/phpspec/prophecy.git", |
851 | "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" | 974 | "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" |
852 | }, | 975 | }, |
853 | "dist": { | 976 | "dist": { |
854 | "type": "zip", | 977 | "type": "zip", |
855 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", | 978 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", |
856 | "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", | 979 | "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", |
857 | "shasum": "" | 980 | "shasum": "" |
858 | }, | 981 | }, |
859 | "require": { | 982 | "require": { |
860 | "doctrine/instantiator": "^1.0.2", | 983 | "doctrine/instantiator": "^1.0.2", |
861 | "php": "^5.3|^7.0", | 984 | "php": "^5.3|^7.0", |
862 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", | 985 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", |
863 | "sebastian/comparator": "^1.1|^2.0", | 986 | "sebastian/comparator": "^1.1|^2.0", |
864 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" | 987 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" |
865 | }, | 988 | }, |
@@ -870,7 +993,7 @@ | |||
870 | "type": "library", | 993 | "type": "library", |
871 | "extra": { | 994 | "extra": { |
872 | "branch-alias": { | 995 | "branch-alias": { |
873 | "dev-master": "1.6.x-dev" | 996 | "dev-master": "1.7.x-dev" |
874 | } | 997 | } |
875 | }, | 998 | }, |
876 | "autoload": { | 999 | "autoload": { |
@@ -903,7 +1026,7 @@ | |||
903 | "spy", | 1026 | "spy", |
904 | "stub" | 1027 | "stub" |
905 | ], | 1028 | ], |
906 | "time": "2017-03-02T20:05:34+00:00" | 1029 | "time": "2017-09-04T11:05:03+00:00" |
907 | }, | 1030 | }, |
908 | { | 1031 | { |
909 | "name": "phpunit/php-code-coverage", | 1032 | "name": "phpunit/php-code-coverage", |
@@ -1875,20 +1998,20 @@ | |||
1875 | }, | 1998 | }, |
1876 | { | 1999 | { |
1877 | "name": "symfony/config", | 2000 | "name": "symfony/config", |
1878 | "version": "v3.3.6", | 2001 | "version": "v3.3.10", |
1879 | "source": { | 2002 | "source": { |
1880 | "type": "git", | 2003 | "type": "git", |
1881 | "url": "https://github.com/symfony/config.git", | 2004 | "url": "https://github.com/symfony/config.git", |
1882 | "reference": "54ee12b0dd60f294132cabae6f5da9573d2e5297" | 2005 | "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd" |
1883 | }, | 2006 | }, |
1884 | "dist": { | 2007 | "dist": { |
1885 | "type": "zip", | 2008 | "type": "zip", |
1886 | "url": "https://api.github.com/repos/symfony/config/zipball/54ee12b0dd60f294132cabae6f5da9573d2e5297", | 2009 | "url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd", |
1887 | "reference": "54ee12b0dd60f294132cabae6f5da9573d2e5297", | 2010 | "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd", |
1888 | "shasum": "" | 2011 | "shasum": "" |
1889 | }, | 2012 | }, |
1890 | "require": { | 2013 | "require": { |
1891 | "php": ">=5.5.9", | 2014 | "php": "^5.5.9|>=7.0.8", |
1892 | "symfony/filesystem": "~2.8|~3.0" | 2015 | "symfony/filesystem": "~2.8|~3.0" |
1893 | }, | 2016 | }, |
1894 | "conflict": { | 2017 | "conflict": { |
@@ -1933,20 +2056,20 @@ | |||
1933 | ], | 2056 | ], |
1934 | "description": "Symfony Config Component", | 2057 | "description": "Symfony Config Component", |
1935 | "homepage": "https://symfony.com", | 2058 | "homepage": "https://symfony.com", |
1936 | "time": "2017-07-19T07:37:29+00:00" | 2059 | "time": "2017-10-04T18:56:58+00:00" |
1937 | }, | 2060 | }, |
1938 | { | 2061 | { |
1939 | "name": "symfony/console", | 2062 | "name": "symfony/console", |
1940 | "version": "v2.8.26", | 2063 | "version": "v2.8.28", |
1941 | "source": { | 2064 | "source": { |
1942 | "type": "git", | 2065 | "type": "git", |
1943 | "url": "https://github.com/symfony/console.git", | 2066 | "url": "https://github.com/symfony/console.git", |
1944 | "reference": "32a3c6b3398de5db8ed381f4ef92970c59c2fcdd" | 2067 | "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853" |
1945 | }, | 2068 | }, |
1946 | "dist": { | 2069 | "dist": { |
1947 | "type": "zip", | 2070 | "type": "zip", |
1948 | "url": "https://api.github.com/repos/symfony/console/zipball/32a3c6b3398de5db8ed381f4ef92970c59c2fcdd", | 2071 | "url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853", |
1949 | "reference": "32a3c6b3398de5db8ed381f4ef92970c59c2fcdd", | 2072 | "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853", |
1950 | "shasum": "" | 2073 | "shasum": "" |
1951 | }, | 2074 | }, |
1952 | "require": { | 2075 | "require": { |
@@ -1994,7 +2117,7 @@ | |||
1994 | ], | 2117 | ], |
1995 | "description": "Symfony Console Component", | 2118 | "description": "Symfony Console Component", |
1996 | "homepage": "https://symfony.com", | 2119 | "homepage": "https://symfony.com", |
1997 | "time": "2017-07-29T21:26:04+00:00" | 2120 | "time": "2017-10-01T21:00:16+00:00" |
1998 | }, | 2121 | }, |
1999 | { | 2122 | { |
2000 | "name": "symfony/debug", | 2123 | "name": "symfony/debug", |
@@ -2055,20 +2178,20 @@ | |||
2055 | }, | 2178 | }, |
2056 | { | 2179 | { |
2057 | "name": "symfony/dependency-injection", | 2180 | "name": "symfony/dependency-injection", |
2058 | "version": "v3.3.6", | 2181 | "version": "v3.3.10", |
2059 | "source": { | 2182 | "source": { |
2060 | "type": "git", | 2183 | "type": "git", |
2061 | "url": "https://github.com/symfony/dependency-injection.git", | 2184 | "url": "https://github.com/symfony/dependency-injection.git", |
2062 | "reference": "8d70987f991481e809c63681ffe8ce3f3fde68a0" | 2185 | "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1" |
2063 | }, | 2186 | }, |
2064 | "dist": { | 2187 | "dist": { |
2065 | "type": "zip", | 2188 | "type": "zip", |
2066 | "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8d70987f991481e809c63681ffe8ce3f3fde68a0", | 2189 | "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1", |
2067 | "reference": "8d70987f991481e809c63681ffe8ce3f3fde68a0", | 2190 | "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1", |
2068 | "shasum": "" | 2191 | "shasum": "" |
2069 | }, | 2192 | }, |
2070 | "require": { | 2193 | "require": { |
2071 | "php": ">=5.5.9", | 2194 | "php": "^5.5.9|>=7.0.8", |
2072 | "psr/container": "^1.0" | 2195 | "psr/container": "^1.0" |
2073 | }, | 2196 | }, |
2074 | "conflict": { | 2197 | "conflict": { |
@@ -2121,24 +2244,24 @@ | |||
2121 | ], | 2244 | ], |
2122 | "description": "Symfony DependencyInjection Component", | 2245 | "description": "Symfony DependencyInjection Component", |
2123 | "homepage": "https://symfony.com", | 2246 | "homepage": "https://symfony.com", |
2124 | "time": "2017-07-28T15:27:31+00:00" | 2247 | "time": "2017-10-04T17:15:30+00:00" |
2125 | }, | 2248 | }, |
2126 | { | 2249 | { |
2127 | "name": "symfony/filesystem", | 2250 | "name": "symfony/filesystem", |
2128 | "version": "v3.3.6", | 2251 | "version": "v3.3.10", |
2129 | "source": { | 2252 | "source": { |
2130 | "type": "git", | 2253 | "type": "git", |
2131 | "url": "https://github.com/symfony/filesystem.git", | 2254 | "url": "https://github.com/symfony/filesystem.git", |
2132 | "reference": "427987eb4eed764c3b6e38d52a0f87989e010676" | 2255 | "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1" |
2133 | }, | 2256 | }, |
2134 | "dist": { | 2257 | "dist": { |
2135 | "type": "zip", | 2258 | "type": "zip", |
2136 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/427987eb4eed764c3b6e38d52a0f87989e010676", | 2259 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1", |
2137 | "reference": "427987eb4eed764c3b6e38d52a0f87989e010676", | 2260 | "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1", |
2138 | "shasum": "" | 2261 | "shasum": "" |
2139 | }, | 2262 | }, |
2140 | "require": { | 2263 | "require": { |
2141 | "php": ">=5.5.9" | 2264 | "php": "^5.5.9|>=7.0.8" |
2142 | }, | 2265 | }, |
2143 | "type": "library", | 2266 | "type": "library", |
2144 | "extra": { | 2267 | "extra": { |
@@ -2170,24 +2293,24 @@ | |||
2170 | ], | 2293 | ], |
2171 | "description": "Symfony Filesystem Component", | 2294 | "description": "Symfony Filesystem Component", |
2172 | "homepage": "https://symfony.com", | 2295 | "homepage": "https://symfony.com", |
2173 | "time": "2017-07-11T07:17:58+00:00" | 2296 | "time": "2017-10-03T13:33:10+00:00" |
2174 | }, | 2297 | }, |
2175 | { | 2298 | { |
2176 | "name": "symfony/finder", | 2299 | "name": "symfony/finder", |
2177 | "version": "v3.3.6", | 2300 | "version": "v3.3.10", |
2178 | "source": { | 2301 | "source": { |
2179 | "type": "git", | 2302 | "type": "git", |
2180 | "url": "https://github.com/symfony/finder.git", | 2303 | "url": "https://github.com/symfony/finder.git", |
2181 | "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4" | 2304 | "reference": "773e19a491d97926f236942484cb541560ce862d" |
2182 | }, | 2305 | }, |
2183 | "dist": { | 2306 | "dist": { |
2184 | "type": "zip", | 2307 | "type": "zip", |
2185 | "url": "https://api.github.com/repos/symfony/finder/zipball/baea7f66d30854ad32988c11a09d7ffd485810c4", | 2308 | "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d", |
2186 | "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4", | 2309 | "reference": "773e19a491d97926f236942484cb541560ce862d", |
2187 | "shasum": "" | 2310 | "shasum": "" |
2188 | }, | 2311 | }, |
2189 | "require": { | 2312 | "require": { |
2190 | "php": ">=5.5.9" | 2313 | "php": "^5.5.9|>=7.0.8" |
2191 | }, | 2314 | }, |
2192 | "type": "library", | 2315 | "type": "library", |
2193 | "extra": { | 2316 | "extra": { |
@@ -2219,20 +2342,20 @@ | |||
2219 | ], | 2342 | ], |
2220 | "description": "Symfony Finder Component", | 2343 | "description": "Symfony Finder Component", |
2221 | "homepage": "https://symfony.com", | 2344 | "homepage": "https://symfony.com", |
2222 | "time": "2017-06-01T21:01:25+00:00" | 2345 | "time": "2017-10-02T06:42:24+00:00" |
2223 | }, | 2346 | }, |
2224 | { | 2347 | { |
2225 | "name": "symfony/polyfill-mbstring", | 2348 | "name": "symfony/polyfill-mbstring", |
2226 | "version": "v1.4.0", | 2349 | "version": "v1.6.0", |
2227 | "source": { | 2350 | "source": { |
2228 | "type": "git", | 2351 | "type": "git", |
2229 | "url": "https://github.com/symfony/polyfill-mbstring.git", | 2352 | "url": "https://github.com/symfony/polyfill-mbstring.git", |
2230 | "reference": "f29dca382a6485c3cbe6379f0c61230167681937" | 2353 | "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" |
2231 | }, | 2354 | }, |
2232 | "dist": { | 2355 | "dist": { |
2233 | "type": "zip", | 2356 | "type": "zip", |
2234 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f29dca382a6485c3cbe6379f0c61230167681937", | 2357 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", |
2235 | "reference": "f29dca382a6485c3cbe6379f0c61230167681937", | 2358 | "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", |
2236 | "shasum": "" | 2359 | "shasum": "" |
2237 | }, | 2360 | }, |
2238 | "require": { | 2361 | "require": { |
@@ -2244,7 +2367,7 @@ | |||
2244 | "type": "library", | 2367 | "type": "library", |
2245 | "extra": { | 2368 | "extra": { |
2246 | "branch-alias": { | 2369 | "branch-alias": { |
2247 | "dev-master": "1.4-dev" | 2370 | "dev-master": "1.6-dev" |
2248 | } | 2371 | } |
2249 | }, | 2372 | }, |
2250 | "autoload": { | 2373 | "autoload": { |
@@ -2278,24 +2401,24 @@ | |||
2278 | "portable", | 2401 | "portable", |
2279 | "shim" | 2402 | "shim" |
2280 | ], | 2403 | ], |
2281 | "time": "2017-06-09T14:24:12+00:00" | 2404 | "time": "2017-10-11T12:05:26+00:00" |
2282 | }, | 2405 | }, |
2283 | { | 2406 | { |
2284 | "name": "symfony/yaml", | 2407 | "name": "symfony/yaml", |
2285 | "version": "v3.3.6", | 2408 | "version": "v3.3.10", |
2286 | "source": { | 2409 | "source": { |
2287 | "type": "git", | 2410 | "type": "git", |
2288 | "url": "https://github.com/symfony/yaml.git", | 2411 | "url": "https://github.com/symfony/yaml.git", |
2289 | "reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed" | 2412 | "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46" |
2290 | }, | 2413 | }, |
2291 | "dist": { | 2414 | "dist": { |
2292 | "type": "zip", | 2415 | "type": "zip", |
2293 | "url": "https://api.github.com/repos/symfony/yaml/zipball/ddc23324e6cfe066f3dd34a37ff494fa80b617ed", | 2416 | "url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", |
2294 | "reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed", | 2417 | "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", |
2295 | "shasum": "" | 2418 | "shasum": "" |
2296 | }, | 2419 | }, |
2297 | "require": { | 2420 | "require": { |
2298 | "php": ">=5.5.9" | 2421 | "php": "^5.5.9|>=7.0.8" |
2299 | }, | 2422 | }, |
2300 | "require-dev": { | 2423 | "require-dev": { |
2301 | "symfony/console": "~2.8|~3.0" | 2424 | "symfony/console": "~2.8|~3.0" |
@@ -2333,7 +2456,7 @@ | |||
2333 | ], | 2456 | ], |
2334 | "description": "Symfony Yaml Component", | 2457 | "description": "Symfony Yaml Component", |
2335 | "homepage": "https://symfony.com", | 2458 | "homepage": "https://symfony.com", |
2336 | "time": "2017-07-23T12:43:26+00:00" | 2459 | "time": "2017-10-05T14:43:42+00:00" |
2337 | }, | 2460 | }, |
2338 | { | 2461 | { |
2339 | "name": "theseer/fdomdocument", | 2462 | "name": "theseer/fdomdocument", |
diff --git a/doc/md/Download-and-Installation.md b/doc/md/Download-and-Installation.md index 3453e8b4..be848c97 100644 --- a/doc/md/Download-and-Installation.md +++ b/doc/md/Download-and-Installation.md | |||
@@ -44,6 +44,7 @@ Cloning using `git` or downloading Github branches as zip files requires additio | |||
44 | $ mkdir -p /path/to/shaarli && cd /path/to/shaarli/ | 44 | $ mkdir -p /path/to/shaarli && cd /path/to/shaarli/ |
45 | $ git clone -b latest https://github.com/shaarli/Shaarli.git . | 45 | $ git clone -b latest https://github.com/shaarli/Shaarli.git . |
46 | $ composer install --no-dev --prefer-dist | 46 | $ composer install --no-dev --prefer-dist |
47 | $ make translate | ||
47 | ``` | 48 | ``` |
48 | 49 | ||
49 | ## Stable version | 50 | ## Stable version |
@@ -91,13 +92,14 @@ $ git clone https://github.com/shaarli/Shaarli.git -b master /path/to/shaarli/ | |||
91 | # install/update third-party dependencies | 92 | # install/update third-party dependencies |
92 | $ cd /path/to/shaarli | 93 | $ cd /path/to/shaarli |
93 | $ composer install --no-dev --prefer-dist | 94 | $ composer install --no-dev --prefer-dist |
95 | $ make translate | ||
94 | ``` | 96 | ``` |
95 | 97 | ||
96 | ## Finish Installation | 98 | ## Finish Installation |
97 | 99 | ||
98 | Once Shaarli is downloaded and files have been placed at the correct location, open it this location your favorite browser. | 100 | Once Shaarli is downloaded and files have been placed at the correct location, open it this location your favorite browser. |
99 | 101 | ||
100 | ![install screenshot](http://i.imgur.com/wuMpDSN.png) | 102 | ![install screenshot](images/install-shaarli.png) |
101 | 103 | ||
102 | Setup your Shaarli installation, and it's ready to use! | 104 | Setup your Shaarli installation, and it's ready to use! |
103 | 105 | ||
diff --git a/doc/md/Server-requirements.md b/doc/md/Server-requirements.md index 707af762..400b85a9 100644 --- a/doc/md/Server-requirements.md +++ b/doc/md/Server-requirements.md | |||
@@ -39,3 +39,4 @@ Extension | Required? | Usage | |||
39 | [`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing | 39 | [`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing |
40 | [`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`) | 40 | [`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`) |
41 | [`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way | 41 | [`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way |
42 | [`php-gettext`](http://php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster) | ||
diff --git a/doc/md/Shaarli-configuration.md b/doc/md/Shaarli-configuration.md index 99b25ba7..920c7e27 100644 --- a/doc/md/Shaarli-configuration.md +++ b/doc/md/Shaarli-configuration.md | |||
@@ -81,6 +81,20 @@ _These settings should not be edited_ | |||
81 | - **page_cache**: Shaarli's internal cache directory. | 81 | - **page_cache**: Shaarli's internal cache directory. |
82 | - **ban_file**: Banned IP file path. | 82 | - **ban_file**: Banned IP file path. |
83 | 83 | ||
84 | ### Translation | ||
85 | |||
86 | - **language**: translation language (also see [Translations](Translations)) | ||
87 | - **auto** (default): The translation language is chosen from the browser locale. | ||
88 | It means that the language can be different for 2 different visitors depending on their locale. | ||
89 | - **en**: Use the English translation. | ||
90 | - **fr**: Use the French translation. | ||
91 | - **mode**: | ||
92 | - **auto** or **php** (default): Use the PHP implementation of gettext (slower) | ||
93 | - **gettext**: Use PHP builtin gettext extension | ||
94 | (faster, but requires `php-gettext` to be installed and to reload the web server on update) | ||
95 | - **extension**: Translation extensions for custom themes or plugins. | ||
96 | Must be an associative array: `translation domain => translation path`. | ||
97 | |||
84 | ### Updates | 98 | ### Updates |
85 | 99 | ||
86 | - **check_updates**: Enable or disable update check to the git repository. | 100 | - **check_updates**: Enable or disable update check to the git repository. |
@@ -211,6 +225,13 @@ _These settings should not be edited_ | |||
211 | "plugins": { | 225 | "plugins": { |
212 | "WALLABAG_URL": "http://demo.wallabag.org", | 226 | "WALLABAG_URL": "http://demo.wallabag.org", |
213 | "WALLABAG_VERSION": "1" | 227 | "WALLABAG_VERSION": "1" |
228 | }, | ||
229 | "translation": { | ||
230 | "language": "fr", | ||
231 | "mode": "php", | ||
232 | "extensions": { | ||
233 | "demo": "plugins/demo_plugin/languages/" | ||
234 | } | ||
214 | } | 235 | } |
215 | } ?> | 236 | } ?> |
216 | ``` | 237 | ``` |
diff --git a/doc/md/Translations.md b/doc/md/Translations.md new file mode 100644 index 00000000..54a36655 --- /dev/null +++ b/doc/md/Translations.md | |||
@@ -0,0 +1,152 @@ | |||
1 | ## Translations | ||
2 | |||
3 | Shaarli supports [gettext](https://www.gnu.org/software/gettext/manual/gettext.html) translations | ||
4 | since `>= v0.9.2`. | ||
5 | |||
6 | Note that only the `default` theme supports translations. | ||
7 | |||
8 | ### Contributing | ||
9 | |||
10 | We encourage the community to contribute to Shaarli's translation either by improving existing | ||
11 | translations or submitting a new language. | ||
12 | |||
13 | Contributing to the translation does not require development skill. | ||
14 | |||
15 | Please submit a pull request with the `.po` file updated/created. Note that the compiled file (`.mo`) | ||
16 | is not stored on the repository, and is generated during the release process. | ||
17 | |||
18 | ### How to | ||
19 | |||
20 | First, install [Poedit](https://poedit.net/) tool. | ||
21 | |||
22 | Poedit will extract strings to translate from the PHP source code. | ||
23 | |||
24 | **Important**: due to the usage of a template engine, it's important to generate PHP cache files to extract | ||
25 | every translatable string. | ||
26 | |||
27 | You can either use [this script](https://gist.github.com/ArthurHoaro/5d0323f758ab2401ef444a53f54e9a07) (recommended) | ||
28 | or visit every template page in your browser to generate cache files, while logged in. | ||
29 | |||
30 | Here is a list : | ||
31 | |||
32 | ``` | ||
33 | http://<replace_domain>/ | ||
34 | http://<replace_domain>/?nonope | ||
35 | http://<replace_domain>/?do=addlink | ||
36 | http://<replace_domain>/?do=changepasswd | ||
37 | http://<replace_domain>/?do=changetag | ||
38 | http://<replace_domain>/?do=configure | ||
39 | http://<replace_domain>/?do=tools | ||
40 | http://<replace_domain>/?do=daily | ||
41 | http://<replace_domain>/?post | ||
42 | http://<replace_domain>/?do=export | ||
43 | http://<replace_domain>/?do=import | ||
44 | http://<replace_domain>/?do=login | ||
45 | http://<replace_domain>/?do=picwall | ||
46 | http://<replace_domain>/?do=pluginadmin | ||
47 | http://<replace_domain>/?do=tagcloud | ||
48 | http://<replace_domain>/?do=taglist | ||
49 | ``` | ||
50 | |||
51 | #### Improve existing translation | ||
52 | |||
53 | In Poedit, click on "Edit a Translation", and from Shaarli's directory open | ||
54 | `inc/languages/<lang>/LC_MESSAGES/shaarli.po`. | ||
55 | |||
56 | The existing list of translatable strings should have been loaded, then click on the "Update" button. | ||
57 | |||
58 | You can start editing the translation. | ||
59 | |||
60 | ![poedit-screenshot](images/poedit-1.jpg) | ||
61 | |||
62 | Save when you're done, then you can submit a pull request containing the updated `shaarli.po`. | ||
63 | |||
64 | #### Add a new language | ||
65 | |||
66 | Open Poedit and select "Create New Translation", then from Shaarli's directory open | ||
67 | `inc/languages/<lang>/LC_MESSAGES/shaarli.po`. | ||
68 | |||
69 | Then select the language you want to create. | ||
70 | |||
71 | Click on `File > Save as...`, and save your file in `<shaarli directory>/inc/language/<new language>/LC_MESSAGES/shaarli.po`. | ||
72 | `<new language>` here should be the language code respecting the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-2) | ||
73 | format in lowercase (e.g. `de` for German). | ||
74 | |||
75 | Then click on the "Update" button, and you can start to translate every available string. | ||
76 | |||
77 | Save when you're done, then you can submit a pull request containing the new `shaarli.po`. | ||
78 | |||
79 | ### Extend Shaarli's translation | ||
80 | |||
81 | If you're writing a custom theme, or a non official plugin, you might want to use the translation system, | ||
82 | but you won't be able to able to override Shaarli's translation. | ||
83 | |||
84 | However, you can add your own translation domain which extends the main translation list. | ||
85 | |||
86 | > Note that you can find a live example of translation extension in the `demo_plugin`. | ||
87 | |||
88 | First, create your translation files tree directory: | ||
89 | |||
90 | ``` | ||
91 | <your_module>/languages/<ISO 3166-1 alpha-2 language code>/LC_MESSAGES/ | ||
92 | ``` | ||
93 | |||
94 | Your `.po` files must be named like your domain. E.g. if your translation domain is `my_theme`, then your file will be | ||
95 | `my_theme.po`. | ||
96 | |||
97 | Users have to register your extension in their configuration with the parameter | ||
98 | `translation.extensions.<domain>: <translation files path>`. | ||
99 | |||
100 | Example: | ||
101 | |||
102 | ```php | ||
103 | if (! $conf->exists('translation.extensions.my_theme')) { | ||
104 | $conf->set('translation.extensions.my_theme', '<your_module>/languages/'); | ||
105 | $conf->write(true); | ||
106 | } | ||
107 | ``` | ||
108 | |||
109 | > Note that the page needs to be reloaded after the registration. | ||
110 | |||
111 | It is then recommended to create a custom translation function which will call the `t()` function with your domain. | ||
112 | For example : | ||
113 | |||
114 | ```php | ||
115 | function my_theme_t($text, $nText = '', $nb = 1) | ||
116 | { | ||
117 | return t($text, $nText, $nb, 'my_theme'); // the last parameter is your translation domain. | ||
118 | } | ||
119 | ``` | ||
120 | |||
121 | All strings which can be translated should be processed through your function: | ||
122 | |||
123 | ```php | ||
124 | my_theme_t('Comment'); | ||
125 | my_theme_t('Comment', 'Comments', 2); | ||
126 | ``` | ||
127 | |||
128 | Or in templates: | ||
129 | |||
130 | ```php | ||
131 | {'Comment'|my_theme_t} | ||
132 | {function="my_theme_t('Comment', 'Comments', 2)"} | ||
133 | ``` | ||
134 | |||
135 | > Note than in template, you need to visit your page at least once to generate a cache file. | ||
136 | |||
137 | When you're done, open Poedit and load translation strings from sources: | ||
138 | |||
139 | 1. `File > New` | ||
140 | 2. Choose your language | ||
141 | 3. Save your `PO` file in `<your_module>/languages/<language code>/LC_MESSAGES/my_theme.po`. | ||
142 | 4. Go to `Catalog > Properties...` | ||
143 | 5. Fill the `Translation Properties` tab | ||
144 | 6. Add your source path in the `Sources Paths` tab | ||
145 | 7. In the `Sources Keywords` tab uncheck "Also use default keywords" and add the following lines: | ||
146 | |||
147 | ``` | ||
148 | my_theme_t | ||
149 | my_theme_t:1,2 | ||
150 | ``` | ||
151 | |||
152 | Click on the "Update" button and you're free to start your translations! | ||
diff --git a/doc/md/Upgrade-and-migration.md b/doc/md/Upgrade-and-migration.md index 7033cd41..1dc07339 100644 --- a/doc/md/Upgrade-and-migration.md +++ b/doc/md/Upgrade-and-migration.md | |||
@@ -39,7 +39,10 @@ We recommend that you use the latest release tarball with the `-full` suffix. It | |||
39 | 39 | ||
40 | Once downloaded, extract the archive locally and update your remote installation (e.g. via FTP) -be sure you keep the content of the `data` directory! | 40 | Once downloaded, extract the archive locally and update your remote installation (e.g. via FTP) -be sure you keep the content of the `data` directory! |
41 | 41 | ||
42 | After upgrading, access your fresh Shaarli installation from a web browser; the configuration and data store will then be automatically updated, and new settings added to `data/config.json.php` (see [Shaarli configuration](Shaarli-configuration) for more details). | 42 | If you use translations in gettext mode - meaning you manually changed the default mode -, |
43 | reload your web server. | ||
44 | |||
45 | After upgrading, access your fresh Shaarli installation from a web browser; the configuration and data store will then be automatically updated, and new settings added to `data/config.json.php` (see [Shaarli configuration](Shaarli configuration) for more details). | ||
43 | 46 | ||
44 | ## Upgrading with Git | 47 | ## Upgrading with Git |
45 | 48 | ||
@@ -72,6 +75,14 @@ Updating dependencies | |||
72 | Downloading: 100% | 75 | Downloading: 100% |
73 | ``` | 76 | ``` |
74 | 77 | ||
78 | Shaarli >= `v0.9.2` supports translations: | ||
79 | |||
80 | ```bash | ||
81 | $ make translate | ||
82 | ``` | ||
83 | |||
84 | If you use translations in gettext mode, reload your web server. | ||
85 | |||
75 | ### Migrating and upgrading from Sebsauvage's repository | 86 | ### Migrating and upgrading from Sebsauvage's repository |
76 | 87 | ||
77 | If you have installed Shaarli from [Sebsauvage's original Git repository](https://github.com/sebsauvage/Shaarli), you can use [Git remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) to update your working copy. | 88 | If you have installed Shaarli from [Sebsauvage's original Git repository](https://github.com/sebsauvage/Shaarli), you can use [Git remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) to update your working copy. |
@@ -151,6 +162,14 @@ Updating dependencies | |||
151 | Downloading: 100% | 162 | Downloading: 100% |
152 | ``` | 163 | ``` |
153 | 164 | ||
165 | Shaarli >= `v0.9.2` supports translations: | ||
166 | |||
167 | ```bash | ||
168 | $ make translate | ||
169 | ``` | ||
170 | |||
171 | If you use translations in gettext mode, reload your web server. | ||
172 | |||
154 | Optionally, you can delete information related to the legacy version: | 173 | Optionally, you can delete information related to the legacy version: |
155 | 174 | ||
156 | ```bash | 175 | ```bash |
diff --git a/doc/md/docker/shaarli-images.md b/doc/md/docker/shaarli-images.md index 6d108d21..1d19510a 100644 --- a/doc/md/docker/shaarli-images.md +++ b/doc/md/docker/shaarli-images.md | |||
@@ -5,14 +5,23 @@ The images can be found in the [`shaarli/shaarli`](https://hub.docker.com/r/shaa | |||
5 | repository. | 5 | repository. |
6 | 6 | ||
7 | ### Available image tags | 7 | ### Available image tags |
8 | - `latest`: master branch (tarball release) | 8 | - `latest`: latest branch (tarball release) |
9 | - `master`: master branch (tarball release) | ||
9 | - `stable`: stable branch (tarball release) | 10 | - `stable`: stable branch (tarball release) |
10 | 11 | ||
11 | All images rely on: | 12 | The `latest` and `master` images rely on: |
13 | |||
14 | - [Alpine Linux](https://www.alpinelinux.org/) | ||
15 | - [PHP7-FPM](http://php-fpm.org/) | ||
16 | - [Nginx](http://nginx.org/) | ||
17 | |||
18 | The `stable` image relies on: | ||
19 | |||
12 | - [Debian 8 Jessie](https://hub.docker.com/_/debian/) | 20 | - [Debian 8 Jessie](https://hub.docker.com/_/debian/) |
13 | - [PHP5-FPM](http://php-fpm.org/) | 21 | - [PHP5-FPM](http://php-fpm.org/) |
14 | - [Nginx](http://nginx.org/) | 22 | - [Nginx](http://nginx.org/) |
15 | 23 | ||
24 | |||
16 | ### Download from DockerHub | 25 | ### Download from DockerHub |
17 | ```bash | 26 | ```bash |
18 | $ docker pull shaarli/shaarli | 27 | $ docker pull shaarli/shaarli |
diff --git a/doc/md/images/install-shaarli.png b/doc/md/images/install-shaarli.png new file mode 100644 index 00000000..7ae33816 --- /dev/null +++ b/doc/md/images/install-shaarli.png | |||
Binary files differ | |||
diff --git a/doc/md/images/poedit-1.jpg b/doc/md/images/poedit-1.jpg new file mode 100644 index 00000000..673ae6d6 --- /dev/null +++ b/doc/md/images/poedit-1.jpg | |||
Binary files differ | |||
diff --git a/docker/alpine/Dockerfile.latest b/docker/alpine/Dockerfile.latest new file mode 100644 index 00000000..dd4a173c --- /dev/null +++ b/docker/alpine/Dockerfile.latest | |||
@@ -0,0 +1,47 @@ | |||
1 | FROM alpine:3.6 | ||
2 | MAINTAINER Shaarli Community | ||
3 | |||
4 | RUN apk --update --no-cache add \ | ||
5 | ca-certificates \ | ||
6 | curl \ | ||
7 | nginx \ | ||
8 | php7 \ | ||
9 | php7-ctype \ | ||
10 | php7-curl \ | ||
11 | php7-fpm \ | ||
12 | php7-gd \ | ||
13 | php7-iconv \ | ||
14 | php7-intl \ | ||
15 | php7-json \ | ||
16 | php7-mbstring \ | ||
17 | php7-openssl \ | ||
18 | php7-phar \ | ||
19 | php7-session \ | ||
20 | php7-xml \ | ||
21 | php7-zlib \ | ||
22 | s6 | ||
23 | |||
24 | COPY nginx.conf /etc/nginx/nginx.conf | ||
25 | COPY php-fpm.conf /etc/php7/php-fpm.conf | ||
26 | COPY services.d /etc/services.d | ||
27 | |||
28 | RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer \ | ||
29 | && rm -rf /etc/php7/php-fpm.d/www.conf \ | ||
30 | && sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php7/php.ini \ | ||
31 | && sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php7/php.ini | ||
32 | |||
33 | |||
34 | WORKDIR /var/www | ||
35 | RUN curl -L https://github.com/shaarli/Shaarli/archive/latest.tar.gz | tar xzf - \ | ||
36 | && mv Shaarli-latest shaarli \ | ||
37 | && cd shaarli \ | ||
38 | && composer --prefer-dist --no-dev install \ | ||
39 | && rm -rf ~/.composer \ | ||
40 | && chown -R nginx:nginx . | ||
41 | |||
42 | VOLUME /var/www/shaarli/data | ||
43 | |||
44 | EXPOSE 80 | ||
45 | |||
46 | ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"] | ||
47 | CMD [] | ||
diff --git a/docker/alpine/IMAGE.md b/docker/alpine/IMAGE.md index 6f827b35..a8952257 100644 --- a/docker/alpine/IMAGE.md +++ b/docker/alpine/IMAGE.md | |||
@@ -1,5 +1,10 @@ | |||
1 | ## shaarli:latest | 1 | ## Alpine images |
2 | - [Debian 8 Jessie](https://hub.docker.com/_/debian/) | 2 | - [Alpine Linux](https://www.alpinelinux.org/) |
3 | - [PHP5-FPM](http://php-fpm.org/) | 3 | - [PHP-FPM](http://php-fpm.org/) |
4 | - [Nginx](http://nginx.org/) | 4 | - [Nginx](http://nginx.org/) |
5 | - [Shaarli](https://github.com/shaarli/Shaarli) | 5 | |
6 | ### `shaarli/shaarli:latest` | ||
7 | - [Shaarli](https://github.com/shaarli/Shaarli), `latest` branch | ||
8 | |||
9 | ### `shaarli/shaarli:master` | ||
10 | - [Shaarli](https://github.com/shaarli/Shaarli), `master` branch | ||
diff --git a/inc/languages/fr/LC_MESSAGES/shaarli.po b/inc/languages/fr/LC_MESSAGES/shaarli.po new file mode 100644 index 00000000..6b2de950 --- /dev/null +++ b/inc/languages/fr/LC_MESSAGES/shaarli.po | |||
@@ -0,0 +1,1366 @@ | |||
1 | msgid "" | ||
2 | msgstr "" | ||
3 | "Project-Id-Version: Shaarli\n" | ||
4 | "POT-Creation-Date: 2017-10-22 13:13+0200\n" | ||
5 | "PO-Revision-Date: 2017-10-22 13:14+0200\n" | ||
6 | "Last-Translator: \n" | ||
7 | "Language-Team: Shaarli\n" | ||
8 | "Language: fr_FR\n" | ||
9 | "MIME-Version: 1.0\n" | ||
10 | "Content-Type: text/plain; charset=UTF-8\n" | ||
11 | "Content-Transfer-Encoding: 8bit\n" | ||
12 | "X-Generator: Poedit 2.0.4\n" | ||
13 | "X-Poedit-Basepath: ../../../..\n" | ||
14 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" | ||
15 | "X-Poedit-SourceCharset: UTF-8\n" | ||
16 | "X-Poedit-KeywordsList: t:1,2;t\n" | ||
17 | "X-Poedit-SearchPath-0: .\n" | ||
18 | |||
19 | #: application/ApplicationUtils.php:153 | ||
20 | #, php-format | ||
21 | msgid "" | ||
22 | "Your PHP version is obsolete! Shaarli requires at least PHP %s, and thus " | ||
23 | "cannot run. Your PHP version has known security vulnerabilities and should " | ||
24 | "be updated as soon as possible." | ||
25 | msgstr "" | ||
26 | "Votre version de PHP est obsolète ! Shaarli nécessite au moins PHP %s, et ne " | ||
27 | "peut donc pas fonctionner. Votre version de PHP a des failles de sécurités " | ||
28 | "connues et devrait être mise à jour au plus tôt." | ||
29 | |||
30 | #: application/ApplicationUtils.php:183 application/ApplicationUtils.php:195 | ||
31 | msgid "directory is not readable" | ||
32 | msgstr "le répertoire n'est pas accessible en lecture" | ||
33 | |||
34 | #: application/ApplicationUtils.php:198 | ||
35 | msgid "directory is not writable" | ||
36 | msgstr "le répertoire n'est pas accessible en écriture" | ||
37 | |||
38 | #: application/ApplicationUtils.php:216 | ||
39 | msgid "file is not readable" | ||
40 | msgstr "le fichier n'est pas accessible en lecture" | ||
41 | |||
42 | #: application/ApplicationUtils.php:219 | ||
43 | msgid "file is not writable" | ||
44 | msgstr "le fichier n'est pas accessible en écriture" | ||
45 | |||
46 | #: application/Cache.php:16 | ||
47 | #, php-format | ||
48 | msgid "Cannot purge %s: no directory" | ||
49 | msgstr "Impossible de purger %s: le répertoire n'existe pas" | ||
50 | |||
51 | #: application/FeedBuilder.php:151 | ||
52 | msgid "Direct link" | ||
53 | msgstr "Liens directs" | ||
54 | |||
55 | #: application/FeedBuilder.php:153 | ||
56 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:88 | ||
57 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:178 | ||
58 | msgid "Permalink" | ||
59 | msgstr "Permalien" | ||
60 | |||
61 | #: application/History.php:174 | ||
62 | msgid "History file isn't readable or writable" | ||
63 | msgstr "Le fichier d'historique n'est pas accessible en lecture ou en écriture" | ||
64 | |||
65 | #: application/History.php:185 | ||
66 | msgid "Could not parse history file" | ||
67 | msgstr "Format incorrect pour le fichier d'historique" | ||
68 | |||
69 | #: application/Languages.php:159 | ||
70 | msgid "Automatic" | ||
71 | msgstr "Automatique" | ||
72 | |||
73 | #: application/Languages.php:160 | ||
74 | msgid "English" | ||
75 | msgstr "Anglais" | ||
76 | |||
77 | #: application/Languages.php:161 | ||
78 | msgid "French" | ||
79 | msgstr "Français" | ||
80 | |||
81 | #: application/LinkDB.php:136 | ||
82 | msgid "You are not authorized to add a link." | ||
83 | msgstr "Vous n'êtes pas autorisé à ajouter un lien." | ||
84 | |||
85 | #: application/LinkDB.php:139 | ||
86 | msgid "Internal Error: A link should always have an id and URL." | ||
87 | msgstr "Erreur interne : un lien devrait toujours avoir un ID et une URL." | ||
88 | |||
89 | #: application/LinkDB.php:142 | ||
90 | msgid "You must specify an integer as a key." | ||
91 | msgstr "Vous devez utiliser un entier comme clé." | ||
92 | |||
93 | #: application/LinkDB.php:145 | ||
94 | msgid "Array offset and link ID must be equal." | ||
95 | msgstr "La clé du tableau et l'ID du lien doivent être égaux." | ||
96 | |||
97 | #: application/LinkDB.php:251 | ||
98 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | ||
99 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 | ||
100 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:14 | ||
101 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:48 | ||
102 | msgid "" | ||
103 | "The personal, minimalist, super-fast, database free, bookmarking service" | ||
104 | msgstr "" | ||
105 | "Le gestionnaire de marque-page personnel, minimaliste, et sans base de " | ||
106 | "données" | ||
107 | |||
108 | #: application/LinkDB.php:253 | ||
109 | msgid "" | ||
110 | "Welcome to Shaarli! This is your first public bookmark. To edit or delete " | ||
111 | "me, you must first login.\n" | ||
112 | "\n" | ||
113 | "To learn how to use Shaarli, consult the link \"Documentation\" at the " | ||
114 | "bottom of this page.\n" | ||
115 | "\n" | ||
116 | "You use the community supported version of the original Shaarli project, by " | ||
117 | "Sebastien Sauvage." | ||
118 | msgstr "" | ||
119 | "Bienvenue sur Shaarli ! Ceci est votre premier marque-page public. Pour me " | ||
120 | "modifier ou me supprimer, vous devez d'abord vous connecter.\n" | ||
121 | "\n" | ||
122 | "Pour apprendre comment utiliser Shaarli, consultez le lien « Documentation » " | ||
123 | "en bas de page.\n" | ||
124 | "\n" | ||
125 | "Vous utilisez la version supportée par la communauté du projet original " | ||
126 | "Shaarli, de Sébastien Sauvage." | ||
127 | |||
128 | #: application/LinkDB.php:267 | ||
129 | msgid "My secret stuff... - Pastebin.com" | ||
130 | msgstr "Mes trucs secrets... - Pastebin.com" | ||
131 | |||
132 | #: application/LinkDB.php:269 | ||
133 | msgid "Shhhh! I'm a private link only YOU can see. You can delete me too." | ||
134 | msgstr "" | ||
135 | "Pssst ! Je suis un lien privé que VOUS êtes le seul à voir. Vous pouvez me " | ||
136 | "supprimer aussi." | ||
137 | |||
138 | #: application/LinkFilter.php:452 | ||
139 | msgid "The link you are trying to reach does not exist or has been deleted." | ||
140 | msgstr "Le lien que vous essayez de consulter n'existe pas ou a été supprimé." | ||
141 | |||
142 | #: application/NetscapeBookmarkUtils.php:35 | ||
143 | msgid "Invalid export selection:" | ||
144 | msgstr "Sélection d'export invalide :" | ||
145 | |||
146 | #: application/NetscapeBookmarkUtils.php:81 | ||
147 | #, php-format | ||
148 | msgid "File %s (%d bytes) " | ||
149 | msgstr "Le fichier %s (%d octets) " | ||
150 | |||
151 | #: application/NetscapeBookmarkUtils.php:83 | ||
152 | msgid "has an unknown file format. Nothing was imported." | ||
153 | msgstr "a un format inconnu. Rien n'a été importé." | ||
154 | |||
155 | #: application/NetscapeBookmarkUtils.php:86 | ||
156 | #, php-format | ||
157 | msgid "" | ||
158 | "was successfully processed in %d seconds: %d links imported, %d links " | ||
159 | "overwritten, %d links skipped." | ||
160 | msgstr "" | ||
161 | "a été importé avec succès en %d secondes : %d liens importés, %d liens " | ||
162 | "écrasés, %d liens ignorés." | ||
163 | |||
164 | #: application/PageBuilder.php:165 | ||
165 | msgid "The page you are trying to reach does not exist or has been deleted." | ||
166 | msgstr "La page que vous essayez de consulter n'existe pas ou a été supprimée." | ||
167 | |||
168 | #: application/PageBuilder.php:167 | ||
169 | msgid "404 Not Found" | ||
170 | msgstr "404 Introuvable" | ||
171 | |||
172 | #: application/PluginManager.php:243 | ||
173 | #, php-format | ||
174 | msgid "Plugin \"%s\" files not found." | ||
175 | msgstr "Les fichiers de l'extension \"%s\" sont introuvables." | ||
176 | |||
177 | #: application/Updater.php:76 | ||
178 | msgid "Couldn't retrieve Updater class methods." | ||
179 | msgstr "Impossible de récupérer les méthodes de la classe Updater." | ||
180 | |||
181 | #: application/Updater.php:485 | ||
182 | msgid "An error occurred while running the update " | ||
183 | msgstr "Une erreur s'est produite lors de l'exécution de la mise à jour " | ||
184 | |||
185 | #: application/Updater.php:525 | ||
186 | msgid "Updates file path is not set, can't write updates." | ||
187 | msgstr "" | ||
188 | "Le chemin vers le fichier de mise à jour n'est pas défini, impossible " | ||
189 | "d'écrire les mises à jour." | ||
190 | |||
191 | #: application/Updater.php:530 | ||
192 | msgid "Unable to write updates in " | ||
193 | msgstr "Impossible d'écrire les mises à jour dans " | ||
194 | |||
195 | #: application/Utils.php:406 tests/UtilsTest.php:398 | ||
196 | msgid "Setting not set" | ||
197 | msgstr "Paramètre non défini" | ||
198 | |||
199 | #: application/Utils.php:413 tests/UtilsTest.php:396 tests/UtilsTest.php:397 | ||
200 | msgid "Unlimited" | ||
201 | msgstr "Illimité" | ||
202 | |||
203 | #: application/Utils.php:416 tests/UtilsTest.php:393 tests/UtilsTest.php:394 | ||
204 | #: tests/UtilsTest.php:408 | ||
205 | msgid "B" | ||
206 | msgstr "o" | ||
207 | |||
208 | #: application/Utils.php:416 tests/UtilsTest.php:387 tests/UtilsTest.php:388 | ||
209 | #: tests/UtilsTest.php:395 | ||
210 | msgid "kiB" | ||
211 | msgstr "ko" | ||
212 | |||
213 | #: application/Utils.php:416 tests/UtilsTest.php:389 tests/UtilsTest.php:390 | ||
214 | #: tests/UtilsTest.php:406 tests/UtilsTest.php:407 | ||
215 | msgid "MiB" | ||
216 | msgstr "Mo" | ||
217 | |||
218 | #: application/Utils.php:416 tests/UtilsTest.php:391 tests/UtilsTest.php:392 | ||
219 | msgid "GiB" | ||
220 | msgstr "Go" | ||
221 | |||
222 | #: application/config/ConfigJson.php:52 application/config/ConfigPhp.php:121 | ||
223 | msgid "" | ||
224 | "Shaarli could not create the config file. Please make sure Shaarli has the " | ||
225 | "right to write in the folder is it installed in." | ||
226 | msgstr "" | ||
227 | "Shaarli n'a pas pu créer le fichier de configuration. Merci de vérifier que " | ||
228 | "Shaarli a les droits d'écriture dans le dossier dans lequel il est installé." | ||
229 | |||
230 | #: application/config/ConfigManager.php:135 | ||
231 | msgid "Invalid setting key parameter. String expected, got: " | ||
232 | msgstr "Clé de paramétrage invalide. Chaîne de caractères obtenue, attendu : " | ||
233 | |||
234 | #: application/config/exception/MissingFieldConfigException.php:21 | ||
235 | #, php-format | ||
236 | msgid "Configuration value is required for %s" | ||
237 | msgstr "Le paramètre %s est obligatoire" | ||
238 | |||
239 | #: application/config/exception/PluginConfigOrderException.php:15 | ||
240 | msgid "An error occurred while trying to save plugins loading order." | ||
241 | msgstr "" | ||
242 | "Une erreur s'est produite lors de la sauvegarde de l'ordre des extensions." | ||
243 | |||
244 | #: application/config/exception/UnauthorizedConfigException.php:16 | ||
245 | msgid "You are not authorized to alter config." | ||
246 | msgstr "Vous n'êtes pas autorisé à modifier la configuration." | ||
247 | |||
248 | #: application/exceptions/IOException.php:19 | ||
249 | msgid "Error accessing" | ||
250 | msgstr "Une erreur s'est produite en accédant à " | ||
251 | |||
252 | #: index.php:133 | ||
253 | msgid "Shared links on " | ||
254 | msgstr "Liens partagés sur " | ||
255 | |||
256 | #: index.php:155 | ||
257 | msgid "Insufficient permissions:" | ||
258 | msgstr "Permissions insuffisantes :" | ||
259 | |||
260 | #: index.php:382 | ||
261 | msgid "I said: NO. You are banned for the moment. Go away." | ||
262 | msgstr "NON. Vous êtes banni pour le moment. Revenez plus tard." | ||
263 | |||
264 | #: index.php:447 | ||
265 | msgid "Wrong login/password." | ||
266 | msgstr "Nom d'utilisateur ou mot de passe incorrects." | ||
267 | |||
268 | #: index.php:1107 | ||
269 | msgid "You are not supposed to change a password on an Open Shaarli." | ||
270 | msgstr "" | ||
271 | "Vous n'êtes pas censé modifier le mot de passe d'un Shaarli en mode ouvert." | ||
272 | |||
273 | #: index.php:1112 index.php:1153 index.php:1229 index.php:1259 index.php:1359 | ||
274 | msgid "Wrong token." | ||
275 | msgstr "Jeton invalide." | ||
276 | |||
277 | #: index.php:1117 | ||
278 | msgid "The old password is not correct." | ||
279 | msgstr "L'ancien mot de passe est incorrect." | ||
280 | |||
281 | #: index.php:1137 | ||
282 | msgid "Your password has been changed" | ||
283 | msgstr "Votre mot de passe a été modifié" | ||
284 | |||
285 | #: index.php:1190 | ||
286 | msgid "Configuration was saved." | ||
287 | msgstr "La configuration a été sauvegardé." | ||
288 | |||
289 | #: index.php:1241 | ||
290 | #, php-format | ||
291 | msgid "The tag was removed from %d link." | ||
292 | msgid_plural "The tag was removed from %d links." | ||
293 | msgstr[0] "Le tag a été supprimé de %d lien." | ||
294 | msgstr[1] "Le tag a été supprimé de %d liens." | ||
295 | |||
296 | #: index.php:1242 | ||
297 | #, php-format | ||
298 | msgid "The tag was renamed in %d link." | ||
299 | msgid_plural "The tag was renamed in %d links." | ||
300 | msgstr[0] "Le tag a été renommé dans %d lien." | ||
301 | msgstr[1] "Le tag a été renommé dans %d liens." | ||
302 | |||
303 | #: index.php:1458 | ||
304 | msgid "Note: " | ||
305 | msgstr "Note : " | ||
306 | |||
307 | #: index.php:1567 | ||
308 | #, php-format | ||
309 | msgid "" | ||
310 | "The file you are trying to upload is probably bigger than what this " | ||
311 | "webserver can accept (%s). Please upload in smaller chunks." | ||
312 | msgstr "" | ||
313 | "Le fichier que vous essayer d'envoyer est probablement plus lourd que ce que " | ||
314 | "le serveur web peut accepter (%s). Merci de l'envoyer en parties plus " | ||
315 | "légères." | ||
316 | |||
317 | #: index.php:1983 | ||
318 | #, php-format | ||
319 | msgid "" | ||
320 | "<pre>Sessions do not seem to work correctly on your server.<br>Make sure the " | ||
321 | "variable \"session.save_path\" is set correctly in your PHP config, and that " | ||
322 | "you have write access to it.<br>It currently points to %s.<br>On some " | ||
323 | "browsers, accessing your server via a hostname like 'localhost' or any " | ||
324 | "custom hostname without a dot causes cookie storage to fail. We recommend " | ||
325 | "accessing your server via it's IP address or Fully Qualified Domain Name.<br>" | ||
326 | msgstr "" | ||
327 | "<pre>Les sesssions ne semble pas fonctionner sur ce serveur.<br>Assurez vous " | ||
328 | "que la variable « session.save_path » est correctement définie dans votre " | ||
329 | "fichier de configuration PHP, et que vous y avez les droits d'écriture." | ||
330 | "<br>Ce paramètre pointe actuellement sur %s.<br>Sur certains navigateurs, " | ||
331 | "accéder à votre serveur depuis un nom d'hôte comme « localhost » ou autre " | ||
332 | "nom personnalisé sans point '.' entraine l'échec de la sauvegarde des " | ||
333 | "cookies. Nous vous recommandons d'accéder à votre serveur depuis son adresse " | ||
334 | "IP ou un <em>Fully Qualified Domain Name</em>.<br>" | ||
335 | |||
336 | #: index.php:1993 | ||
337 | msgid "Click to try again." | ||
338 | msgstr "Cliquer ici pour réessayer." | ||
339 | |||
340 | #: plugins/addlink_toolbar/addlink_toolbar.php:29 | ||
341 | msgid "URI" | ||
342 | msgstr "URI" | ||
343 | |||
344 | #: plugins/addlink_toolbar/addlink_toolbar.php:33 | ||
345 | #: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | ||
346 | msgid "Add link" | ||
347 | msgstr "Shaare" | ||
348 | |||
349 | #: plugins/addlink_toolbar/addlink_toolbar.php:50 | ||
350 | msgid "Adds the addlink input on the linklist page." | ||
351 | msgstr "Ajout le formulaire d'ajout de liens sur la page principale." | ||
352 | |||
353 | #: plugins/archiveorg/archiveorg.php:23 | ||
354 | msgid "View on archive.org" | ||
355 | msgstr "Voir sur archive.org" | ||
356 | |||
357 | #: plugins/archiveorg/archiveorg.php:36 | ||
358 | msgid "For each link, add an Archive.org icon." | ||
359 | msgstr "Pour chaque lien, ajoute une icône pour Archive.org." | ||
360 | |||
361 | #: plugins/demo_plugin/demo_plugin.php:469 | ||
362 | msgid "" | ||
363 | "A demo plugin covering all use cases for template designers and plugin " | ||
364 | "developers." | ||
365 | msgstr "" | ||
366 | "Une extension de démonstration couvrant tous les cas d'utilisation pour les " | ||
367 | "designers et les développeurs." | ||
368 | |||
369 | #: plugins/isso/isso.php:20 | ||
370 | msgid "" | ||
371 | "Isso plugin error: Please define the \"ISSO_SERVER\" setting in the plugin " | ||
372 | "administration page." | ||
373 | msgstr "" | ||
374 | "Erreur de l'extension Isso : Merci de définir le paramètre « ISSO_SERVER » " | ||
375 | "dans la page d'administration des extensions." | ||
376 | |||
377 | #: plugins/isso/isso.php:63 | ||
378 | msgid "Let visitor comment your shaares on permalinks with Isso." | ||
379 | msgstr "" | ||
380 | "Permet aux visiteurs de commenter vos shaares sur les permaliens avec Isso." | ||
381 | |||
382 | #: plugins/isso/isso.php:64 | ||
383 | msgid "Isso server URL (without 'http://')" | ||
384 | msgstr "URL du serveur Isso (sans 'http://')" | ||
385 | |||
386 | #: plugins/markdown/markdown.php:159 | ||
387 | msgid "Description will be rendered with" | ||
388 | msgstr "La description sera générée avec" | ||
389 | |||
390 | #: plugins/markdown/markdown.php:160 | ||
391 | msgid "Markdown syntax documentation" | ||
392 | msgstr "Documentation sur la syntaxe Markdown" | ||
393 | |||
394 | #: plugins/markdown/markdown.php:161 | ||
395 | msgid "Markdown syntax" | ||
396 | msgstr "la syntaxe Markdown" | ||
397 | |||
398 | #: plugins/markdown/markdown.php:340 | ||
399 | msgid "" | ||
400 | "Render shaare description with Markdown syntax.<br><strong>Warning</" | ||
401 | "strong>:\n" | ||
402 | "If your shaared descriptions contained HTML tags before enabling the " | ||
403 | "markdown plugin,\n" | ||
404 | "enabling it might break your page.\n" | ||
405 | "See the <a href=\"https://github.com/shaarli/Shaarli/tree/master/plugins/" | ||
406 | "markdown#html-rendering\">README</a>." | ||
407 | msgstr "" | ||
408 | "Utilise la syntaxe Markdown pour la description des liens." | ||
409 | "<br><strong>Attention</strong> :\n" | ||
410 | "Si vous aviez des descriptions contenant du HTML avant d'activer cette " | ||
411 | "extension,\n" | ||
412 | "l'activer pourrait déformer vos pages.\n" | ||
413 | "Voir le <a href=\"https://github.com/shaarli/Shaarli/tree/master/plugins/" | ||
414 | "markdown#html-rendering\">README</a>." | ||
415 | |||
416 | #: plugins/piwik/piwik.php:21 | ||
417 | msgid "" | ||
418 | "Piwik plugin error: Please define PIWIK_URL and PIWIK_SITEID in the plugin " | ||
419 | "administration page." | ||
420 | msgstr "" | ||
421 | "Erreur de l'extension Piwik : Merci de définir les paramètres PIWIK_URL et " | ||
422 | "PIWIK_SITEID dans la page d'administration des extensions." | ||
423 | |||
424 | #: plugins/piwik/piwik.php:70 | ||
425 | msgid "A plugin that adds Piwik tracking code to Shaarli pages." | ||
426 | msgstr "Ajoute le code de traçage de Piwik sur les pages de Shaarli." | ||
427 | |||
428 | #: plugins/piwik/piwik.php:71 | ||
429 | msgid "Piwik URL" | ||
430 | msgstr "URL de Piwik" | ||
431 | |||
432 | #: plugins/piwik/piwik.php:72 | ||
433 | msgid "Piwik site ID" | ||
434 | msgstr "Site ID de Piwik" | ||
435 | |||
436 | #: plugins/playvideos/playvideos.php:22 | ||
437 | msgid "Video player" | ||
438 | msgstr "Lecteur vidéo" | ||
439 | |||
440 | #: plugins/playvideos/playvideos.php:25 | ||
441 | msgid "Play Videos" | ||
442 | msgstr "Jouer les vidéos" | ||
443 | |||
444 | #: plugins/playvideos/playvideos.php:56 | ||
445 | msgid "Add a button in the toolbar allowing to watch all videos." | ||
446 | msgstr "" | ||
447 | "Ajoute un bouton dans la barre de menu pour regarder toutes les vidéos." | ||
448 | |||
449 | #: plugins/playvideos/youtube_playlist.js:214 | ||
450 | msgid "plugins/playvideos/jquery-1.11.2.min.js" | ||
451 | msgstr "" | ||
452 | |||
453 | #: plugins/pubsubhubbub/pubsubhubbub.php:69 | ||
454 | #, php-format | ||
455 | msgid "Could not publish to PubSubHubbub: %s" | ||
456 | msgstr "Impossible de publier vers PubSubHubbub : %s" | ||
457 | |||
458 | #: plugins/pubsubhubbub/pubsubhubbub.php:95 | ||
459 | #, php-format | ||
460 | msgid "Could not post to %s" | ||
461 | msgstr "Impossible de publier vers %s" | ||
462 | |||
463 | #: plugins/pubsubhubbub/pubsubhubbub.php:99 | ||
464 | #, php-format | ||
465 | msgid "Bad response from the hub %s" | ||
466 | msgstr "Mauvaise réponse du hub %s" | ||
467 | |||
468 | #: plugins/pubsubhubbub/pubsubhubbub.php:110 | ||
469 | msgid "Enable PubSubHubbub feed publishing." | ||
470 | msgstr "Active la publication de flux vers PubSubHubbub." | ||
471 | |||
472 | #: plugins/qrcode/qrcode.php:69 plugins/wallabag/wallabag.php:68 | ||
473 | msgid "For each link, add a QRCode icon." | ||
474 | msgstr "Pour chaque liens, ajouter une icône de QRCode." | ||
475 | |||
476 | #: plugins/wallabag/wallabag.php:21 | ||
477 | msgid "" | ||
478 | "Wallabag plugin error: Please define the \"WALLABAG_URL\" setting in the " | ||
479 | "plugin administration page." | ||
480 | msgstr "" | ||
481 | "Erreur de l'extension Wallabag : Merci de définir le paramètre « " | ||
482 | "WALLABAG_URL » dans la page d'administration des extensions." | ||
483 | |||
484 | #: plugins/wallabag/wallabag.php:47 | ||
485 | msgid "Save to wallabag" | ||
486 | msgstr "Sauvegarder dans Wallabag" | ||
487 | |||
488 | #: plugins/wallabag/wallabag.php:69 | ||
489 | msgid "Wallabag API URL" | ||
490 | msgstr "URL de l'API Wallabag" | ||
491 | |||
492 | #: plugins/wallabag/wallabag.php:70 | ||
493 | msgid "Wallabag API version (1 or 2)" | ||
494 | msgstr "Version de l'API Wallabag (1 ou 2)" | ||
495 | |||
496 | #: tests/LanguagesTest.php:188 tests/LanguagesTest.php:201 | ||
497 | #: tests/languages/fr/LanguagesFrTest.php:160 | ||
498 | #: tests/languages/fr/LanguagesFrTest.php:173 | ||
499 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:81 | ||
500 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:81 | ||
501 | msgid "Search" | ||
502 | msgid_plural "Search" | ||
503 | msgstr[0] "Rechercher" | ||
504 | msgstr[1] "Rechercher" | ||
505 | |||
506 | #: tmp/404.b91ef64efc3688266305ea9b42e5017e.rtpl.php:12 | ||
507 | msgid "Sorry, nothing to see here." | ||
508 | msgstr "Désolé, il y a rien à voir ici." | ||
509 | |||
510 | #: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | ||
511 | msgid "Shaare a new link" | ||
512 | msgstr "Partager un nouveau lien" | ||
513 | |||
514 | #: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
515 | msgid "URL or leave empty to post a note" | ||
516 | msgstr "URL ou laisser vide pour créer une note" | ||
517 | |||
518 | #: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | ||
519 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 | ||
520 | msgid "Change password" | ||
521 | msgstr "Modification du mot de passe" | ||
522 | |||
523 | #: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
524 | msgid "Current password" | ||
525 | msgstr "Mot de passe actuel" | ||
526 | |||
527 | #: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | ||
528 | msgid "New password" | ||
529 | msgstr "Nouveau mot de passe" | ||
530 | |||
531 | #: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23 | ||
532 | msgid "Change" | ||
533 | msgstr "Changer" | ||
534 | |||
535 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | ||
536 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | ||
537 | msgid "Manage tags" | ||
538 | msgstr "Gérer les tags" | ||
539 | |||
540 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
541 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 | ||
542 | msgid "Tag" | ||
543 | msgstr "Tag" | ||
544 | |||
545 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 | ||
546 | msgid "New name" | ||
547 | msgstr "Nouveau nom" | ||
548 | |||
549 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
550 | msgid "Case sensitive" | ||
551 | msgstr "Sensible à la casse" | ||
552 | |||
553 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 | ||
554 | msgid "Rename" | ||
555 | msgstr "Renommer" | ||
556 | |||
557 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 | ||
558 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79 | ||
559 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:172 | ||
560 | msgid "Delete" | ||
561 | msgstr "Supprimer" | ||
562 | |||
563 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39 | ||
564 | msgid "You can also edit tags in the" | ||
565 | msgstr "Vous pouvez aussi modifier les tags dans la" | ||
566 | |||
567 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39 | ||
568 | msgid "tag list" | ||
569 | msgstr "liste des tags" | ||
570 | |||
571 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 | ||
572 | msgid "Configure" | ||
573 | msgstr "Configurer" | ||
574 | |||
575 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 | ||
576 | msgid "title" | ||
577 | msgstr "titre" | ||
578 | |||
579 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:43 | ||
580 | msgid "Home link" | ||
581 | msgstr "Lien vers l'accueil" | ||
582 | |||
583 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 | ||
584 | msgid "Default value" | ||
585 | msgstr "Valeur par défaut" | ||
586 | |||
587 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:58 | ||
588 | msgid "Theme" | ||
589 | msgstr "Thème" | ||
590 | |||
591 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:87 | ||
592 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:78 | ||
593 | msgid "Language" | ||
594 | msgstr "Langue" | ||
595 | |||
596 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:116 | ||
597 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 | ||
598 | msgid "Timezone" | ||
599 | msgstr "Fuseau horaire" | ||
600 | |||
601 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 | ||
602 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:103 | ||
603 | msgid "Continent" | ||
604 | msgstr "Continent" | ||
605 | |||
606 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 | ||
607 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:103 | ||
608 | msgid "City" | ||
609 | msgstr "Ville" | ||
610 | |||
611 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:163 | ||
612 | msgid "Redirector" | ||
613 | msgstr "Redirecteur" | ||
614 | |||
615 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:164 | ||
616 | msgid "e. g." | ||
617 | msgstr "ex :" | ||
618 | |||
619 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:164 | ||
620 | msgid "will mask the HTTP_REFERER" | ||
621 | msgstr "masque le HTTP_REFERER" | ||
622 | |||
623 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:179 | ||
624 | msgid "Disable session cookie hijacking protection" | ||
625 | msgstr "Désactiver la protection contre le détournement de cookies" | ||
626 | |||
627 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:181 | ||
628 | msgid "Check this if you get disconnected or if your IP address changes often" | ||
629 | msgstr "" | ||
630 | "Cocher cette case si vous êtes souvent déconnecté ou si votre adresse IP " | ||
631 | "change souvent" | ||
632 | |||
633 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:198 | ||
634 | msgid "Private links by default" | ||
635 | msgstr "Liens privés par défaut" | ||
636 | |||
637 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 | ||
638 | msgid "All new links are private by default" | ||
639 | msgstr "Tous les nouveaux liens sont privés par défaut" | ||
640 | |||
641 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:214 | ||
642 | msgid "RSS direct links" | ||
643 | msgstr "Liens directs dans le flux RSS" | ||
644 | |||
645 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:215 | ||
646 | msgid "Check this to use direct URL instead of permalink in feeds" | ||
647 | msgstr "" | ||
648 | "Cocher cette case pour utiliser des liens directs au lieu des permaliens " | ||
649 | "dans le flux RSS" | ||
650 | |||
651 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:230 | ||
652 | msgid "Hide public links" | ||
653 | msgstr "Cacher les liens publics" | ||
654 | |||
655 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:231 | ||
656 | msgid "Do not show any links if the user is not logged in" | ||
657 | msgstr "N'afficher aucun lien sans être connecté" | ||
658 | |||
659 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:246 | ||
660 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:150 | ||
661 | msgid "Check updates" | ||
662 | msgstr "Vérifier les mises à jour" | ||
663 | |||
664 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:247 | ||
665 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:152 | ||
666 | msgid "Notify me when a new release is ready" | ||
667 | msgstr "Me notifier lorsqu'une nouvelle version est disponible" | ||
668 | |||
669 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:262 | ||
670 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 | ||
671 | msgid "Enable REST API" | ||
672 | msgstr "Activer l'API REST" | ||
673 | |||
674 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:263 | ||
675 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170 | ||
676 | msgid "Allow third party software to use Shaarli such as mobile application" | ||
677 | msgstr "" | ||
678 | "Permets aux applications tierces d'utiliser Shaarli, par exemple les " | ||
679 | "applications mobiles" | ||
680 | |||
681 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:278 | ||
682 | msgid "API secret" | ||
683 | msgstr "Clé d'API secrète" | ||
684 | |||
685 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:289 | ||
686 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 | ||
687 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 | ||
688 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:192 | ||
689 | msgid "Save" | ||
690 | msgstr "Enregistrer" | ||
691 | |||
692 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 | ||
693 | msgid "The Daily Shaarli" | ||
694 | msgstr "Le Quotidien Shaarli" | ||
695 | |||
696 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:17 | ||
697 | msgid "1 RSS entry per day" | ||
698 | msgstr "1 entrée RSS par jour" | ||
699 | |||
700 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:37 | ||
701 | msgid "Previous day" | ||
702 | msgstr "Jour précédent" | ||
703 | |||
704 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 | ||
705 | msgid "All links of one day in a single page." | ||
706 | msgstr "Tous les liens d'un jour sur une page." | ||
707 | |||
708 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:51 | ||
709 | msgid "Next day" | ||
710 | msgstr "Jour suivant" | ||
711 | |||
712 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | ||
713 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170 | ||
714 | msgid "Edit" | ||
715 | msgstr "Modifier" | ||
716 | |||
717 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
718 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 | ||
719 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:26 | ||
720 | msgid "Shaare" | ||
721 | msgstr "Shaare" | ||
722 | |||
723 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:25 | ||
724 | msgid "Created:" | ||
725 | msgstr "Création :" | ||
726 | |||
727 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 | ||
728 | msgid "URL" | ||
729 | msgstr "URL" | ||
730 | |||
731 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 | ||
732 | msgid "Title" | ||
733 | msgstr "Titre" | ||
734 | |||
735 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 | ||
736 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 | ||
737 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:75 | ||
738 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:99 | ||
739 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:124 | ||
740 | msgid "Description" | ||
741 | msgstr "Description" | ||
742 | |||
743 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 | ||
744 | msgid "Tags" | ||
745 | msgstr "Tags" | ||
746 | |||
747 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:59 | ||
748 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | ||
749 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:168 | ||
750 | msgid "Private" | ||
751 | msgstr "Privé" | ||
752 | |||
753 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 | ||
754 | msgid "Apply Changes" | ||
755 | msgstr "Appliquer les changements" | ||
756 | |||
757 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
758 | msgid "Export Database" | ||
759 | msgstr "Exporter les données" | ||
760 | |||
761 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 | ||
762 | msgid "Selection" | ||
763 | msgstr "Choisir" | ||
764 | |||
765 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
766 | msgid "All" | ||
767 | msgstr "Tous" | ||
768 | |||
769 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 | ||
770 | msgid "Public" | ||
771 | msgstr "Publics" | ||
772 | |||
773 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:52 | ||
774 | msgid "Prepend note permalinks with this Shaarli instance's URL" | ||
775 | msgstr "Préfixer les liens de notes avec l'URL de l'instance de Shaarli" | ||
776 | |||
777 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:53 | ||
778 | msgid "Useful to import bookmarks in a web browser" | ||
779 | msgstr "Utile pour importer les marques-pages dans un navigateur" | ||
780 | |||
781 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 | ||
782 | msgid "Export" | ||
783 | msgstr "Exporter" | ||
784 | |||
785 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
786 | msgid "Import Database" | ||
787 | msgstr "Importer des données" | ||
788 | |||
789 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23 | ||
790 | msgid "Maximum size allowed:" | ||
791 | msgstr "Taille maximum autorisée :" | ||
792 | |||
793 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 | ||
794 | msgid "Visibility" | ||
795 | msgstr "Visibilité" | ||
796 | |||
797 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | ||
798 | msgid "Use values from the imported file, default to public" | ||
799 | msgstr "" | ||
800 | "Utiliser les valeurs présentes dans le fichier d'import, public par défaut" | ||
801 | |||
802 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 | ||
803 | msgid "Import all bookmarks as private" | ||
804 | msgstr "Importer tous les liens comme privés" | ||
805 | |||
806 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 | ||
807 | msgid "Import all bookmarks as public" | ||
808 | msgstr "Importer tous les liens comme publics" | ||
809 | |||
810 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:57 | ||
811 | msgid "Overwrite existing bookmarks" | ||
812 | msgstr "Remplacer les liens existants" | ||
813 | |||
814 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:58 | ||
815 | msgid "Duplicates based on URL" | ||
816 | msgstr "Les doublons s'appuient sur les URL" | ||
817 | |||
818 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 | ||
819 | msgid "Add default tags" | ||
820 | msgstr "Ajouter des tags par défaut" | ||
821 | |||
822 | #: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 | ||
823 | msgid "Import" | ||
824 | msgstr "Importer" | ||
825 | |||
826 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 | ||
827 | msgid "Install Shaarli" | ||
828 | msgstr "Installation de Shaarli" | ||
829 | |||
830 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:25 | ||
831 | msgid "It looks like it's the first time you run Shaarli. Please configure it." | ||
832 | msgstr "" | ||
833 | "Il semblerait que ça soit la première fois que vous lancez Shaarli. Merci de " | ||
834 | "le configurer." | ||
835 | |||
836 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33 | ||
837 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 | ||
838 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147 | ||
839 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:147 | ||
840 | msgid "Username" | ||
841 | msgstr "Nom d'utilisateur" | ||
842 | |||
843 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 | ||
844 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 | ||
845 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148 | ||
846 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:148 | ||
847 | msgid "Password" | ||
848 | msgstr "Mot de passe" | ||
849 | |||
850 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:63 | ||
851 | msgid "Shaarli title" | ||
852 | msgstr "Titre du Shaarli" | ||
853 | |||
854 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:69 | ||
855 | msgid "My links" | ||
856 | msgstr "Mes liens" | ||
857 | |||
858 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:182 | ||
859 | msgid "Install" | ||
860 | msgstr "Installer" | ||
861 | |||
862 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | ||
863 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:80 | ||
864 | msgid "shaare" | ||
865 | msgid_plural "shaares" | ||
866 | msgstr[0] "shaare" | ||
867 | msgstr[1] "shaares" | ||
868 | |||
869 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18 | ||
870 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:84 | ||
871 | msgid "private link" | ||
872 | msgid_plural "private links" | ||
873 | msgstr[0] "lien privé" | ||
874 | msgstr[1] "liens privés" | ||
875 | |||
876 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
877 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 | ||
878 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:117 | ||
879 | msgid "Search text" | ||
880 | msgstr "Recherche texte" | ||
881 | |||
882 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38 | ||
883 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:124 | ||
884 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:124 | ||
885 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33 | ||
886 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:61 | ||
887 | #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33 | ||
888 | #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 | ||
889 | msgid "Filter by tag" | ||
890 | msgstr "Filtrer par tag" | ||
891 | |||
892 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:111 | ||
893 | msgid "Nothing found." | ||
894 | msgstr "Aucun résultat." | ||
895 | |||
896 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:119 | ||
897 | #, php-format | ||
898 | msgid "%s result" | ||
899 | msgid_plural "%s results" | ||
900 | msgstr[0] "%s résultat" | ||
901 | msgstr[1] "%s résultats" | ||
902 | |||
903 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:123 | ||
904 | msgid "for" | ||
905 | msgstr "pour" | ||
906 | |||
907 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:130 | ||
908 | msgid "tagged" | ||
909 | msgstr "taggé" | ||
910 | |||
911 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134 | ||
912 | msgid "Remove tag" | ||
913 | msgstr "Retirer le tag" | ||
914 | |||
915 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:143 | ||
916 | msgid "with status" | ||
917 | msgstr "avec le statut" | ||
918 | |||
919 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154 | ||
920 | msgid "without any tag" | ||
921 | msgstr "sans tag" | ||
922 | |||
923 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:174 | ||
924 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 | ||
925 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:42 | ||
926 | msgid "Fold" | ||
927 | msgstr "Replier" | ||
928 | |||
929 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176 | ||
930 | msgid "Edited: " | ||
931 | msgstr "Modifié : " | ||
932 | |||
933 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:180 | ||
934 | msgid "permalink" | ||
935 | msgstr "permalien" | ||
936 | |||
937 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:182 | ||
938 | msgid "Add tag" | ||
939 | msgstr "Ajouter un tag" | ||
940 | |||
941 | #: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:7 | ||
942 | #: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:7 | ||
943 | msgid "Filters" | ||
944 | msgstr "Filtres" | ||
945 | |||
946 | #: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:12 | ||
947 | #: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:12 | ||
948 | msgid "Filter private links" | ||
949 | msgstr "Filtrer par liens privés" | ||
950 | |||
951 | #: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18 | ||
952 | #: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:18 | ||
953 | msgid "Filter untagged links" | ||
954 | msgstr "Filtrer par liens privés" | ||
955 | |||
956 | #: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 | ||
957 | #: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 | ||
958 | #: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:22 | ||
959 | #: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:74 | ||
960 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:43 | ||
961 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:43 | ||
962 | msgid "Fold all" | ||
963 | msgstr "Replier tout" | ||
964 | |||
965 | #: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:67 | ||
966 | #: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:67 | ||
967 | msgid "Links per page" | ||
968 | msgstr "Liens par page" | ||
969 | |||
970 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 | ||
971 | msgid "" | ||
972 | "You have been banned after too many failed login attempts. Try again later." | ||
973 | msgstr "" | ||
974 | "Vous avez été banni après trop d'échec d'authentification. Merci de " | ||
975 | "réessayer plus tard." | ||
976 | |||
977 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 | ||
978 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 | ||
979 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 | ||
980 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:95 | ||
981 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:71 | ||
982 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:95 | ||
983 | msgid "Login" | ||
984 | msgstr "Connexion" | ||
985 | |||
986 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 | ||
987 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:151 | ||
988 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:151 | ||
989 | msgid "Remember me" | ||
990 | msgstr "Rester connecté" | ||
991 | |||
992 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | ||
993 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 | ||
994 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:14 | ||
995 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:48 | ||
996 | msgid "by the Shaarli community" | ||
997 | msgstr "par la communauté Shaarli" | ||
998 | |||
999 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 | ||
1000 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:15 | ||
1001 | msgid "Documentation" | ||
1002 | msgstr "Documentation" | ||
1003 | |||
1004 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 | ||
1005 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:44 | ||
1006 | msgid "Expand" | ||
1007 | msgstr "Déplier" | ||
1008 | |||
1009 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:45 | ||
1010 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:45 | ||
1011 | msgid "Expand all" | ||
1012 | msgstr "Déplier tout" | ||
1013 | |||
1014 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 | ||
1015 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:46 | ||
1016 | msgid "Are you sure you want to delete this link?" | ||
1017 | msgstr "Êtes-vous sûr de vouloir supprimer ce lien ?" | ||
1018 | |||
1019 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
1020 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:31 | ||
1021 | msgid "Tools" | ||
1022 | msgstr "Outils" | ||
1023 | |||
1024 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | ||
1025 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:36 | ||
1026 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | ||
1027 | msgid "Tag cloud" | ||
1028 | msgstr "Nuage de tags" | ||
1029 | |||
1030 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39 | ||
1031 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:39 | ||
1032 | msgid "Picture wall" | ||
1033 | msgstr "Mur d'images" | ||
1034 | |||
1035 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 | ||
1036 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:42 | ||
1037 | msgid "Daily" | ||
1038 | msgstr "Quotidien" | ||
1039 | |||
1040 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:61 | ||
1041 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 | ||
1042 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:61 | ||
1043 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:86 | ||
1044 | msgid "RSS Feed" | ||
1045 | msgstr "Flux RSS" | ||
1046 | |||
1047 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:66 | ||
1048 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 | ||
1049 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:66 | ||
1050 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:102 | ||
1051 | msgid "Logout" | ||
1052 | msgstr "Déconnexion" | ||
1053 | |||
1054 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 | ||
1055 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:169 | ||
1056 | msgid "is available" | ||
1057 | msgstr "est disponible" | ||
1058 | |||
1059 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176 | ||
1060 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:176 | ||
1061 | msgid "Error" | ||
1062 | msgstr "Erreur" | ||
1063 | |||
1064 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
1065 | msgid "Picture Wall" | ||
1066 | msgstr "Mur d'images" | ||
1067 | |||
1068 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
1069 | msgid "pics" | ||
1070 | msgstr "images" | ||
1071 | |||
1072 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 | ||
1073 | msgid "You need to enable Javascript to change plugin loading order." | ||
1074 | msgstr "" | ||
1075 | "Vous devez activer Javascript pour pouvoir modifier l'ordre des extensions." | ||
1076 | |||
1077 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 | ||
1078 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 | ||
1079 | msgid "Plugin administration" | ||
1080 | msgstr "Administration des extensions" | ||
1081 | |||
1082 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 | ||
1083 | msgid "Enabled Plugins" | ||
1084 | msgstr "Extensions activées" | ||
1085 | |||
1086 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 | ||
1087 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155 | ||
1088 | msgid "No plugin enabled." | ||
1089 | msgstr "Aucune extension activée." | ||
1090 | |||
1091 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 | ||
1092 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:73 | ||
1093 | msgid "Disable" | ||
1094 | msgstr "Désactiver" | ||
1095 | |||
1096 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 | ||
1097 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 | ||
1098 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:98 | ||
1099 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:123 | ||
1100 | msgid "Name" | ||
1101 | msgstr "Nom" | ||
1102 | |||
1103 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:43 | ||
1104 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76 | ||
1105 | msgid "Order" | ||
1106 | msgstr "Ordre" | ||
1107 | |||
1108 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 | ||
1109 | msgid "Disabled Plugins" | ||
1110 | msgstr "Extensions désactivées" | ||
1111 | |||
1112 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:91 | ||
1113 | msgid "No plugin disabled." | ||
1114 | msgstr "Aucune extension désactivée." | ||
1115 | |||
1116 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:97 | ||
1117 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:122 | ||
1118 | msgid "Enable" | ||
1119 | msgstr "Activer" | ||
1120 | |||
1121 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134 | ||
1122 | msgid "More plugins available" | ||
1123 | msgstr "Plus d'extensions disponibles" | ||
1124 | |||
1125 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:136 | ||
1126 | msgid "in the documentation" | ||
1127 | msgstr "dans la documentation" | ||
1128 | |||
1129 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:150 | ||
1130 | msgid "Plugin configuration" | ||
1131 | msgstr "Configuration des extensions" | ||
1132 | |||
1133 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | ||
1134 | #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | ||
1135 | msgid "tags" | ||
1136 | msgstr "tags" | ||
1137 | |||
1138 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23 | ||
1139 | #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23 | ||
1140 | msgid "List all links with those tags" | ||
1141 | msgstr "Lister tous les liens avec ces tags" | ||
1142 | |||
1143 | #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | ||
1144 | msgid "Tag list" | ||
1145 | msgstr "List des tags" | ||
1146 | |||
1147 | #: tmp/tag.sort.b91ef64efc3688266305ea9b42e5017e.rtpl.php:3 | ||
1148 | #: tmp/tag.sort.cedf684561d925457130839629000a81.rtpl.php:3 | ||
1149 | msgid "Sort by:" | ||
1150 | msgstr "Trier par :" | ||
1151 | |||
1152 | #: tmp/tag.sort.b91ef64efc3688266305ea9b42e5017e.rtpl.php:5 | ||
1153 | #: tmp/tag.sort.cedf684561d925457130839629000a81.rtpl.php:5 | ||
1154 | msgid "Cloud" | ||
1155 | msgstr "Nuage" | ||
1156 | |||
1157 | #: tmp/tag.sort.b91ef64efc3688266305ea9b42e5017e.rtpl.php:6 | ||
1158 | #: tmp/tag.sort.cedf684561d925457130839629000a81.rtpl.php:6 | ||
1159 | msgid "Most used" | ||
1160 | msgstr "Plus utilisés" | ||
1161 | |||
1162 | #: tmp/tag.sort.b91ef64efc3688266305ea9b42e5017e.rtpl.php:7 | ||
1163 | #: tmp/tag.sort.cedf684561d925457130839629000a81.rtpl.php:7 | ||
1164 | msgid "Alphabetical" | ||
1165 | msgstr "Alphabétique" | ||
1166 | |||
1167 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | ||
1168 | msgid "Settings" | ||
1169 | msgstr "Paramètres" | ||
1170 | |||
1171 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
1172 | msgid "Change Shaarli settings: title, timezone, etc." | ||
1173 | msgstr "Changer les paramètres de Shaarli : titre, fuseau horaire, etc." | ||
1174 | |||
1175 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:17 | ||
1176 | msgid "Configure your Shaarli" | ||
1177 | msgstr "Conguration de Shaarli" | ||
1178 | |||
1179 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:21 | ||
1180 | msgid "Enable, disable and configure plugins" | ||
1181 | msgstr "Activer, désactiver et configurer les extensions" | ||
1182 | |||
1183 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 | ||
1184 | msgid "Change your password" | ||
1185 | msgstr "Modification du mot de passe" | ||
1186 | |||
1187 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 | ||
1188 | msgid "Rename or delete a tag in all links" | ||
1189 | msgstr "Rename or delete a tag in all links" | ||
1190 | |||
1191 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 | ||
1192 | msgid "" | ||
1193 | "Import Netscape HTML bookmarks (as exported from Firefox, Chrome, Opera, " | ||
1194 | "delicious...)" | ||
1195 | msgstr "" | ||
1196 | "Importer des marques pages au format Netscape HTML (comme exportés depuis " | ||
1197 | "Firefox, Chrome, Opera, delicious...)" | ||
1198 | |||
1199 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 | ||
1200 | msgid "Import links" | ||
1201 | msgstr "Importer des liens" | ||
1202 | |||
1203 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:47 | ||
1204 | msgid "" | ||
1205 | "Export Netscape HTML bookmarks (which can be imported in Firefox, Chrome, " | ||
1206 | "Opera, delicious...)" | ||
1207 | msgstr "" | ||
1208 | "Exporter les marques pages au format Netscape HTML (comme exportés depuis " | ||
1209 | "Firefox, Chrome, Opera, delicious...)" | ||
1210 | |||
1211 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 | ||
1212 | msgid "Export database" | ||
1213 | msgstr "Exporter les données" | ||
1214 | |||
1215 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 | ||
1216 | msgid "" | ||
1217 | "Drag one of these button to your bookmarks toolbar or right-click it and " | ||
1218 | "\"Bookmark This Link\"" | ||
1219 | msgstr "" | ||
1220 | "Glisser un de ces bouttons dans votre barre de favoris ou cliquer droit " | ||
1221 | "dessus et « Ajouter aux favoris »" | ||
1222 | |||
1223 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 | ||
1224 | msgid "then click on the bookmarklet in any page you want to share." | ||
1225 | msgstr "" | ||
1226 | "puis cliquer sur le marque page depuis un site que vous souhaitez partager." | ||
1227 | |||
1228 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76 | ||
1229 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:100 | ||
1230 | msgid "" | ||
1231 | "Drag this link to your bookmarks toolbar or right-click it and Bookmark This " | ||
1232 | "Link" | ||
1233 | msgstr "" | ||
1234 | "Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « " | ||
1235 | "Ajouter aux favoris »" | ||
1236 | |||
1237 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 | ||
1238 | msgid "then click ✚Shaare link button in any page you want to share" | ||
1239 | msgstr "puis cliquer sur ✚Shaare depuis un site que vous souhaitez partager" | ||
1240 | |||
1241 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 | ||
1242 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:108 | ||
1243 | msgid "The selected text is too long, it will be truncated." | ||
1244 | msgstr "Le texte sélectionné est trop long, il sera tronqué." | ||
1245 | |||
1246 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:96 | ||
1247 | msgid "Shaare link" | ||
1248 | msgstr "Shaare" | ||
1249 | |||
1250 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:101 | ||
1251 | msgid "" | ||
1252 | "Then click ✚Add Note button anytime to start composing a private Note (text " | ||
1253 | "post) to your Shaarli" | ||
1254 | msgstr "" | ||
1255 | "Puis cliquer sur ✚Add Note pour commencer à rédiger une Note sur Shaarli" | ||
1256 | |||
1257 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 | ||
1258 | msgid "Add Note" | ||
1259 | msgstr "Ajouter une Note" | ||
1260 | |||
1261 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:129 | ||
1262 | msgid "" | ||
1263 | "You need to browse your Shaarli over <strong>HTTPS</strong> to use this " | ||
1264 | "functionality." | ||
1265 | msgstr "" | ||
1266 | "Vous devez utiliser Shaarli en <strong>HTTPS</strong> pour utiliser cette " | ||
1267 | "fonctionalité." | ||
1268 | |||
1269 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134 | ||
1270 | msgid "Add to" | ||
1271 | msgstr "Ajouter à " | ||
1272 | |||
1273 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:145 | ||
1274 | msgid "3rd party" | ||
1275 | msgstr "Applications tierces" | ||
1276 | |||
1277 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147 | ||
1278 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:153 | ||
1279 | msgid "Plugin" | ||
1280 | msgstr "Extension" | ||
1281 | |||
1282 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148 | ||
1283 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154 | ||
1284 | msgid "plugin" | ||
1285 | msgstr "extension" | ||
1286 | |||
1287 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:175 | ||
1288 | msgid "" | ||
1289 | "Drag this link to your bookmarks toolbar, or right-click it and choose " | ||
1290 | "Bookmark This Link" | ||
1291 | msgstr "" | ||
1292 | "Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « " | ||
1293 | "Ajouter aux favoris »" | ||
1294 | |||
1295 | #~ msgid "" | ||
1296 | #~ "An error occurred while parsing JSON configuration file (%s): error code #" | ||
1297 | #~ "%d" | ||
1298 | #~ msgstr "" | ||
1299 | #~ "Une erreur s'est produite lors de la lecture du fichier de configuration " | ||
1300 | #~ "JSON (%s) : code d'erreur #%d" | ||
1301 | |||
1302 | #~ msgid "" | ||
1303 | #~ "Please check your JSON syntax (without PHP comment tags) using a JSON " | ||
1304 | #~ "lint tool such as " | ||
1305 | #~ msgstr "" | ||
1306 | #~ "Merci de vérifier la syntaxe JSON (sans les balises de commentaires PHP) " | ||
1307 | #~ "en utilisant un validateur de JSON tel que " | ||
1308 | |||
1309 | #~ msgid "" | ||
1310 | #~ "Error: missing Composer dependencies\n" | ||
1311 | #~ "\n" | ||
1312 | #~ "If you installed Shaarli through Git or using the development branch,\n" | ||
1313 | #~ "please refer to the installation documentation to install PHP " | ||
1314 | #~ "dependencies using Composer:\n" | ||
1315 | #~ msgstr "" | ||
1316 | #~ "Erreur : les dépendances Composer sont manquantes\n" | ||
1317 | #~ "\n" | ||
1318 | #~ "Si vous avez installé Shaarli avec Git ou depuis la branche de " | ||
1319 | #~ "développement\n" | ||
1320 | #~ "merci de consulter la documentation d'installation pour installer les " | ||
1321 | #~ "dépendances Composer :\n" | ||
1322 | #~ "\n" | ||
1323 | |||
1324 | #~ msgid "Sessions do not seem to work correctly on your server." | ||
1325 | #~ msgstr "Les sessions ne semblent " | ||
1326 | |||
1327 | #~ msgid "Tag was renamed in " | ||
1328 | #~ msgstr "Le tag a été renommé dans " | ||
1329 | |||
1330 | #, fuzzy | ||
1331 | #~| msgid "My links" | ||
1332 | #~ msgid " links" | ||
1333 | #~ msgstr "Mes liens" | ||
1334 | |||
1335 | #, fuzzy | ||
1336 | #~| msgid "" | ||
1337 | #~| "Error: missing Composer configuration\n" | ||
1338 | #~| "\n" | ||
1339 | #~ msgid "Error: missing Composer configuration" | ||
1340 | #~ msgstr "" | ||
1341 | #~ "Erreur : la configuration Composer est manquante\n" | ||
1342 | #~ "\n" | ||
1343 | |||
1344 | #, fuzzy | ||
1345 | #~| msgid "" | ||
1346 | #~| "Shaarli could not create the config file. Please make sure Shaarli has " | ||
1347 | #~| "the right to write in the folder is it installed in." | ||
1348 | #~ msgid "" | ||
1349 | #~ "Shaarli could not create the config file. \n" | ||
1350 | #~ " Please make sure Shaarli has the right to write in the " | ||
1351 | #~ "folder is it installed in." | ||
1352 | #~ msgstr "" | ||
1353 | #~ "Shaarli n'a pas pu créer le fichier de configuration. Merci de vérifier " | ||
1354 | #~ "que Shaarli a les droits d'écriture dans le dossier dans lequel il est " | ||
1355 | #~ "installé." | ||
1356 | |||
1357 | #, fuzzy | ||
1358 | #~| msgid "Plugin" | ||
1359 | #~ msgid "Plugin \"" | ||
1360 | #~ msgstr "Extension" | ||
1361 | |||
1362 | #~ msgid "Your PHP version is obsolete!" | ||
1363 | #~ msgstr "Votre version de PHP est obsolète !" | ||
1364 | |||
1365 | #~ msgid " Shaarli requires at least PHP " | ||
1366 | #~ msgstr "Shaarli nécessite au moins PHP" | ||
@@ -64,7 +64,6 @@ require_once 'application/FeedBuilder.php'; | |||
64 | require_once 'application/FileUtils.php'; | 64 | require_once 'application/FileUtils.php'; |
65 | require_once 'application/History.php'; | 65 | require_once 'application/History.php'; |
66 | require_once 'application/HttpUtils.php'; | 66 | require_once 'application/HttpUtils.php'; |
67 | require_once 'application/Languages.php'; | ||
68 | require_once 'application/LinkDB.php'; | 67 | require_once 'application/LinkDB.php'; |
69 | require_once 'application/LinkFilter.php'; | 68 | require_once 'application/LinkFilter.php'; |
70 | require_once 'application/LinkUtils.php'; | 69 | require_once 'application/LinkUtils.php'; |
@@ -76,6 +75,7 @@ require_once 'application/Utils.php'; | |||
76 | require_once 'application/PluginManager.php'; | 75 | require_once 'application/PluginManager.php'; |
77 | require_once 'application/Router.php'; | 76 | require_once 'application/Router.php'; |
78 | require_once 'application/Updater.php'; | 77 | require_once 'application/Updater.php'; |
78 | use \Shaarli\Languages; | ||
79 | use \Shaarli\ThemeUtils; | 79 | use \Shaarli\ThemeUtils; |
80 | use \Shaarli\Config\ConfigManager; | 80 | use \Shaarli\Config\ConfigManager; |
81 | 81 | ||
@@ -121,8 +121,16 @@ if (isset($_COOKIE['shaarli']) && !is_session_id_valid($_COOKIE['shaarli'])) { | |||
121 | } | 121 | } |
122 | 122 | ||
123 | $conf = new ConfigManager(); | 123 | $conf = new ConfigManager(); |
124 | |||
125 | // Sniff browser language and set date format accordingly. | ||
126 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | ||
127 | autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']); | ||
128 | } | ||
129 | |||
130 | new Languages(setlocale(LC_MESSAGES, 0), $conf); | ||
131 | |||
124 | $conf->setEmpty('general.timezone', date_default_timezone_get()); | 132 | $conf->setEmpty('general.timezone', date_default_timezone_get()); |
125 | $conf->setEmpty('general.title', 'Shared links on '. escape(index_url($_SERVER))); | 133 | $conf->setEmpty('general.title', t('Shared links on '). escape(index_url($_SERVER))); |
126 | RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl').'/'.$conf->get('resource.theme').'/'; // template directory | 134 | RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl').'/'.$conf->get('resource.theme').'/'; // template directory |
127 | RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory | 135 | RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory |
128 | 136 | ||
@@ -144,7 +152,7 @@ if (! is_file($conf->getConfigFileExt())) { | |||
144 | $errors = ApplicationUtils::checkResourcePermissions($conf); | 152 | $errors = ApplicationUtils::checkResourcePermissions($conf); |
145 | 153 | ||
146 | if ($errors != array()) { | 154 | if ($errors != array()) { |
147 | $message = '<p>Insufficient permissions:</p><ul>'; | 155 | $message = '<p>'. t('Insufficient permissions:') .'</p><ul>'; |
148 | 156 | ||
149 | foreach ($errors as $error) { | 157 | foreach ($errors as $error) { |
150 | $message .= '<li>'.$error.'</li>'; | 158 | $message .= '<li>'.$error.'</li>'; |
@@ -163,11 +171,6 @@ if (! is_file($conf->getConfigFileExt())) { | |||
163 | // a token depending of deployment salt, user password, and the current ip | 171 | // a token depending of deployment salt, user password, and the current ip |
164 | define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); | 172 | define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); |
165 | 173 | ||
166 | // Sniff browser language and set date format accordingly. | ||
167 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | ||
168 | autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']); | ||
169 | } | ||
170 | |||
171 | /** | 174 | /** |
172 | * Checking session state (i.e. is the user still logged in) | 175 | * Checking session state (i.e. is the user still logged in) |
173 | * | 176 | * |
@@ -376,7 +379,7 @@ function ban_canLogin($conf) | |||
376 | // Process login form: Check if login/password is correct. | 379 | // Process login form: Check if login/password is correct. |
377 | if (isset($_POST['login'])) | 380 | if (isset($_POST['login'])) |
378 | { | 381 | { |
379 | if (!ban_canLogin($conf)) die('I said: NO. You are banned for the moment. Go away.'); | 382 | if (!ban_canLogin($conf)) die(t('I said: NO. You are banned for the moment. Go away.')); |
380 | if (isset($_POST['password']) | 383 | if (isset($_POST['password']) |
381 | && tokenOk($_POST['token']) | 384 | && tokenOk($_POST['token']) |
382 | && (check_auth($_POST['login'], $_POST['password'], $conf)) | 385 | && (check_auth($_POST['login'], $_POST['password'], $conf)) |
@@ -440,7 +443,8 @@ if (isset($_POST['login'])) | |||
440 | } | 443 | } |
441 | } | 444 | } |
442 | } | 445 | } |
443 | echo '<script>alert("Wrong login/password.");document.location=\'?do=login'.$redir.'\';</script>'; // Redirect to login screen. | 446 | // Redirect to login screen. |
447 | echo '<script>alert("'. t("Wrong login/password.") .'");document.location=\'?do=login'.$redir.'\';</script>'; | ||
444 | exit; | 448 | exit; |
445 | } | 449 | } |
446 | } | 450 | } |
@@ -1100,16 +1104,19 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1100 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) | 1104 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) |
1101 | { | 1105 | { |
1102 | if ($conf->get('security.open_shaarli')) { | 1106 | if ($conf->get('security.open_shaarli')) { |
1103 | die('You are not supposed to change a password on an Open Shaarli.'); | 1107 | die(t('You are not supposed to change a password on an Open Shaarli.')); |
1104 | } | 1108 | } |
1105 | 1109 | ||
1106 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) | 1110 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) |
1107 | { | 1111 | { |
1108 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! | 1112 | if (!tokenOk($_POST['token'])) die(t('Wrong token.')); // Go away! |
1109 | 1113 | ||
1110 | // Make sure old password is correct. | 1114 | // Make sure old password is correct. |
1111 | $oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')); | 1115 | $oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')); |
1112 | if ($oldhash!= $conf->get('credentials.hash')) { echo '<script>alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; } | 1116 | if ($oldhash!= $conf->get('credentials.hash')) { |
1117 | echo '<script>alert("'. t('The old password is not correct.') .'");document.location=\'?do=changepasswd\';</script>'; | ||
1118 | exit; | ||
1119 | } | ||
1113 | // Save new password | 1120 | // Save new password |
1114 | // Salt renders rainbow-tables attacks useless. | 1121 | // Salt renders rainbow-tables attacks useless. |
1115 | $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); | 1122 | $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); |
@@ -1127,7 +1134,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1127 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>'; | 1134 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>'; |
1128 | exit; | 1135 | exit; |
1129 | } | 1136 | } |
1130 | echo '<script>alert("Your password has been changed.");document.location=\'?do=tools\';</script>'; | 1137 | echo '<script>alert("'. t('Your password has been changed') .'");document.location=\'?do=tools\';</script>'; |
1131 | exit; | 1138 | exit; |
1132 | } | 1139 | } |
1133 | else // show the change password form. | 1140 | else // show the change password form. |
@@ -1143,7 +1150,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1143 | if (!empty($_POST['title']) ) | 1150 | if (!empty($_POST['title']) ) |
1144 | { | 1151 | { |
1145 | if (!tokenOk($_POST['token'])) { | 1152 | if (!tokenOk($_POST['token'])) { |
1146 | die('Wrong token.'); // Go away! | 1153 | die(t('Wrong token.')); // Go away! |
1147 | } | 1154 | } |
1148 | $tz = 'UTC'; | 1155 | $tz = 'UTC'; |
1149 | if (!empty($_POST['continent']) && !empty($_POST['city']) | 1156 | if (!empty($_POST['continent']) && !empty($_POST['city']) |
@@ -1163,6 +1170,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1163 | $conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks'])); | 1170 | $conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks'])); |
1164 | $conf->set('api.enabled', !empty($_POST['enableApi'])); | 1171 | $conf->set('api.enabled', !empty($_POST['enableApi'])); |
1165 | $conf->set('api.secret', escape($_POST['apiSecret'])); | 1172 | $conf->set('api.secret', escape($_POST['apiSecret'])); |
1173 | $conf->set('translation.language', escape($_POST['language'])); | ||
1174 | |||
1166 | try { | 1175 | try { |
1167 | $conf->write(isLoggedIn()); | 1176 | $conf->write(isLoggedIn()); |
1168 | $history->updateSettings(); | 1177 | $history->updateSettings(); |
@@ -1178,7 +1187,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1178 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=configure\';</script>'; | 1187 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=configure\';</script>'; |
1179 | exit; | 1188 | exit; |
1180 | } | 1189 | } |
1181 | echo '<script>alert("Configuration was saved.");document.location=\'?do=configure\';</script>'; | 1190 | echo '<script>alert("'. t('Configuration was saved.') .'");document.location=\'?do=configure\';</script>'; |
1182 | exit; | 1191 | exit; |
1183 | } | 1192 | } |
1184 | else // Show the configuration form. | 1193 | else // Show the configuration form. |
@@ -1200,6 +1209,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1200 | $PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false)); | 1209 | $PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false)); |
1201 | $PAGE->assign('api_enabled', $conf->get('api.enabled', true)); | 1210 | $PAGE->assign('api_enabled', $conf->get('api.enabled', true)); |
1202 | $PAGE->assign('api_secret', $conf->get('api.secret')); | 1211 | $PAGE->assign('api_secret', $conf->get('api.secret')); |
1212 | $PAGE->assign('languages', Languages::getAvailableLanguages()); | ||
1213 | $PAGE->assign('language', $conf->get('translation.language')); | ||
1203 | $PAGE->renderPage('configure'); | 1214 | $PAGE->renderPage('configure'); |
1204 | exit; | 1215 | exit; |
1205 | } | 1216 | } |
@@ -1215,7 +1226,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1215 | } | 1226 | } |
1216 | 1227 | ||
1217 | if (!tokenOk($_POST['token'])) { | 1228 | if (!tokenOk($_POST['token'])) { |
1218 | die('Wrong token.'); | 1229 | die(t('Wrong token.')); |
1219 | } | 1230 | } |
1220 | 1231 | ||
1221 | $alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), escape($_POST['totag'])); | 1232 | $alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), escape($_POST['totag'])); |
@@ -1225,9 +1236,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1225 | } | 1236 | } |
1226 | $delete = empty($_POST['totag']); | 1237 | $delete = empty($_POST['totag']); |
1227 | $redirect = $delete ? 'do=changetag' : 'searchtags='. urlencode(escape($_POST['totag'])); | 1238 | $redirect = $delete ? 'do=changetag' : 'searchtags='. urlencode(escape($_POST['totag'])); |
1239 | $count = count($alteredLinks); | ||
1228 | $alert = $delete | 1240 | $alert = $delete |
1229 | ? sprintf(t('The tag was removed from %d links.'), count($alteredLinks)) | 1241 | ? sprintf(t('The tag was removed from %d link.', 'The tag was removed from %d links.', $count), $count) |
1230 | : sprintf(t('The tag was renamed in %d links.'), count($alteredLinks)); | 1242 | : sprintf(t('The tag was renamed in %d link.', 'The tag was renamed in %d links.', $count), $count); |
1231 | echo '<script>alert("'. $alert .'");document.location=\'?'. $redirect .'\';</script>'; | 1243 | echo '<script>alert("'. $alert .'");document.location=\'?'. $redirect .'\';</script>'; |
1232 | exit; | 1244 | exit; |
1233 | } | 1245 | } |
@@ -1244,7 +1256,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1244 | { | 1256 | { |
1245 | // Go away! | 1257 | // Go away! |
1246 | if (! tokenOk($_POST['token'])) { | 1258 | if (! tokenOk($_POST['token'])) { |
1247 | die('Wrong token.'); | 1259 | die(t('Wrong token.')); |
1248 | } | 1260 | } |
1249 | 1261 | ||
1250 | // lf_id should only be present if the link exists. | 1262 | // lf_id should only be present if the link exists. |
@@ -1344,7 +1356,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1344 | if ($targetPage == Router::$PAGE_DELETELINK) | 1356 | if ($targetPage == Router::$PAGE_DELETELINK) |
1345 | { | 1357 | { |
1346 | if (! tokenOk($_GET['token'])) { | 1358 | if (! tokenOk($_GET['token'])) { |
1347 | die('Wrong token.'); | 1359 | die(t('Wrong token.')); |
1348 | } | 1360 | } |
1349 | 1361 | ||
1350 | $ids = trim($_GET['lf_linkdate']); | 1362 | $ids = trim($_GET['lf_linkdate']); |
@@ -1443,7 +1455,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1443 | 1455 | ||
1444 | if ($url == '') { | 1456 | if ($url == '') { |
1445 | $url = '?' . smallHash($linkdate . $LINKSDB->getNextId()); | 1457 | $url = '?' . smallHash($linkdate . $LINKSDB->getNextId()); |
1446 | $title = $conf->get('general.default_note_title', 'Note: '); | 1458 | $title = $conf->get('general.default_note_title', t('Note: ')); |
1447 | } | 1459 | } |
1448 | $url = escape($url); | 1460 | $url = escape($url); |
1449 | $title = escape($title); | 1461 | $title = escape($title); |
@@ -1550,11 +1562,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1550 | // Import bookmarks from an uploaded file | 1562 | // Import bookmarks from an uploaded file |
1551 | if (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size'] == 0) { | 1563 | if (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size'] == 0) { |
1552 | // The file is too big or some form field may be missing. | 1564 | // The file is too big or some form field may be missing. |
1553 | echo '<script>alert("The file you are trying to upload is probably' | 1565 | $msg = sprintf( |
1554 | .' bigger than what this webserver can accept (' | 1566 | t( |
1555 | .get_max_upload_size(ini_get('post_max_size'), ini_get('upload_max_filesize')).').' | 1567 | 'The file you are trying to upload is probably bigger than what this webserver can accept' |
1556 | .' Please upload in smaller chunks.");document.location=\'?do=' | 1568 | .' (%s). Please upload in smaller chunks.' |
1557 | .Router::$PAGE_IMPORT .'\';</script>'; | 1569 | ), |
1570 | get_max_upload_size(ini_get('post_max_size'), ini_get('upload_max_filesize')) | ||
1571 | ); | ||
1572 | echo '<script>alert("'. $msg .'");document.location=\'?do='.Router::$PAGE_IMPORT .'\';</script>'; | ||
1558 | exit; | 1573 | exit; |
1559 | } | 1574 | } |
1560 | if (! tokenOk($_POST['token'])) { | 1575 | if (! tokenOk($_POST['token'])) { |
@@ -1962,12 +1977,20 @@ function install($conf) | |||
1962 | // (Because on some hosts, session.save_path may not be set correctly, | 1977 | // (Because on some hosts, session.save_path may not be set correctly, |
1963 | // or we may not have write access to it.) | 1978 | // or we may not have write access to it.) |
1964 | if (isset($_GET['test_session']) && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working')) | 1979 | if (isset($_GET['test_session']) && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working')) |
1965 | { // Step 2: Check if data in session is correct. | 1980 | { |
1966 | echo '<pre>Sessions do not seem to work correctly on your server.<br>'; | 1981 | // Step 2: Check if data in session is correct. |
1967 | echo 'Make sure the variable session.save_path is set correctly in your php config, and that you have write access to it.<br>'; | 1982 | $msg = t( |
1968 | echo 'It currently points to '.session_save_path().'<br>'; | 1983 | '<pre>Sessions do not seem to work correctly on your server.<br>'. |
1969 | echo 'Check that the hostname used to access Shaarli contains a dot. On some browsers, accessing your server via a hostname like \'localhost\' or any custom hostname without a dot causes cookie storage to fail. We recommend accessing your server via it\'s IP address or Fully Qualified Domain Name.<br>'; | 1984 | 'Make sure the variable "session.save_path" is set correctly in your PHP config, '. |
1970 | echo '<br><a href="?">Click to try again.</a></pre>'; | 1985 | 'and that you have write access to it.<br>'. |
1986 | 'It currently points to %s.<br>'. | ||
1987 | 'On some browsers, accessing your server via a hostname like \'localhost\' '. | ||
1988 | 'or any custom hostname without a dot causes cookie storage to fail. '. | ||
1989 | 'We recommend accessing your server via it\'s IP address or Fully Qualified Domain Name.<br>' | ||
1990 | ); | ||
1991 | $msg = sprintf($msg, session_save_path()); | ||
1992 | echo $msg; | ||
1993 | echo '<br><a href="?">'. t('Click to try again.') .'</a></pre>'; | ||
1971 | die; | 1994 | die; |
1972 | } | 1995 | } |
1973 | if (!isset($_SESSION['session_tested'])) | 1996 | if (!isset($_SESSION['session_tested'])) |
@@ -2000,6 +2023,7 @@ function install($conf) | |||
2000 | } else { | 2023 | } else { |
2001 | $conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER))); | 2024 | $conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER))); |
2002 | } | 2025 | } |
2026 | $conf->set('translation.language', escape($_POST['language'])); | ||
2003 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); | 2027 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); |
2004 | $conf->set('api.enabled', !empty($_POST['enableApi'])); | 2028 | $conf->set('api.enabled', !empty($_POST['enableApi'])); |
2005 | $conf->set( | 2029 | $conf->set( |
@@ -2031,6 +2055,7 @@ function install($conf) | |||
2031 | list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); | 2055 | list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); |
2032 | $PAGE->assign('continents', $continents); | 2056 | $PAGE->assign('continents', $continents); |
2033 | $PAGE->assign('cities', $cities); | 2057 | $PAGE->assign('cities', $cities); |
2058 | $PAGE->assign('languages', Languages::getAvailableLanguages()); | ||
2034 | $PAGE->renderPage('install'); | 2059 | $PAGE->renderPage('install'); |
2035 | exit; | 2060 | exit; |
2036 | } | 2061 | } |
@@ -43,6 +43,7 @@ pages: | |||
43 | - Versioning and Branches: Versioning-and-Branches.md | 43 | - Versioning and Branches: Versioning-and-Branches.md |
44 | - Security: Security.md | 44 | - Security: Security.md |
45 | - Static analysis: Static-analysis.md | 45 | - Static analysis: Static-analysis.md |
46 | - Translations: Translations.md | ||
46 | - Theming: Theming.md | 47 | - Theming: Theming.md |
47 | - Unit tests: Unit-tests.md | 48 | - Unit tests: Unit-tests.md |
48 | - Unit tests inside Docker: Unit-tests-Docker.md | 49 | - Unit tests inside Docker: Unit-tests-Docker.md |
diff --git a/plugins/TODO.md b/plugins/TODO.md deleted file mode 100644 index e3313d67..00000000 --- a/plugins/TODO.md +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | https://github.com/shaarli/Shaarli/issues/181 - Add Disqus or Isso comments box on a permalink page | ||
2 | |||
3 | * http://posativ.org/isso/ | ||
4 | * install debian package https://packages.debian.org/sid/isso | ||
5 | * configure server http://posativ.org/isso/docs/configuration/server/ | ||
6 | * configure client http://posativ.org/isso/docs/configuration/client/ | ||
7 | * http://posativ.org/isso/docs/quickstart/ and add `<script data-isso="//comments.example.tld/" src="//comments.example.tld/js/embed.min.js"></script>` to includes.html template; then add `<section id="isso-thread"></section>` in the linklist template where you want the comments (in the linklist_plugins loop for example) | ||
8 | |||
9 | |||
10 | Problem: by default, Isso thread ID is guessed from the current url (only one thread per page). | ||
11 | if we want multiple threads on a single page (shaarli linklist), we must use : the `data-isso-id` client config, | ||
12 | with data-isso-id being the permalink of an item. | ||
13 | |||
14 | `<section data-isso-id="aH7klxW" id="isso-thread"></section>` | ||
15 | `data-isso-id: Set a custom thread id, defaults to current URI.` | ||
16 | |||
17 | Problem: feature is currently broken https://github.com/posativ/isso/issues/27 | ||
18 | |||
19 | Another option, only display isso threads when current URL is a permalink (`\?(A-Z|a-z|0-9|-){7}`) (only show thread | ||
20 | when displaying only this link), and just display a "comments" button on each linklist item. Optionally show the comment | ||
21 | count on each item using the API (http://posativ.org/isso/docs/extras/api/#get-comment-count). API requests can be done | ||
22 | by raintpl `{function` or client-side with js. The former should be faster if isso and shaarli are on ther same server. | ||
23 | |||
24 | Showing all full isso threads in the linklist would destroy layout | ||
25 | |||
26 | ----------------------------------------------------------- | ||
27 | |||
28 | http://www.git-attitude.fr/2014/11/04/git-rerere/ for the merge | ||
diff --git a/plugins/addlink_toolbar/addlink_toolbar.php b/plugins/addlink_toolbar/addlink_toolbar.php index ddf50aaf..8c05a231 100644 --- a/plugins/addlink_toolbar/addlink_toolbar.php +++ b/plugins/addlink_toolbar/addlink_toolbar.php | |||
@@ -26,11 +26,11 @@ function hook_addlink_toolbar_render_header($data) | |||
26 | array( | 26 | array( |
27 | 'type' => 'text', | 27 | 'type' => 'text', |
28 | 'name' => 'post', | 28 | 'name' => 'post', |
29 | 'placeholder' => 'URI', | 29 | 'placeholder' => t('URI'), |
30 | ), | 30 | ), |
31 | array( | 31 | array( |
32 | 'type' => 'submit', | 32 | 'type' => 'submit', |
33 | 'value' => 'Add link', | 33 | 'value' => t('Add link'), |
34 | 'class' => 'bigbutton', | 34 | 'class' => 'bigbutton', |
35 | ), | 35 | ), |
36 | ), | 36 | ), |
@@ -40,3 +40,12 @@ function hook_addlink_toolbar_render_header($data) | |||
40 | 40 | ||
41 | return $data; | 41 | return $data; |
42 | } | 42 | } |
43 | |||
44 | /** | ||
45 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
46 | */ | ||
47 | function addlink_toolbar_dummy_translation() | ||
48 | { | ||
49 | // meta | ||
50 | t('Adds the addlink input on the linklist page.'); | ||
51 | } | ||
diff --git a/plugins/archiveorg/archiveorg.html b/plugins/archiveorg/archiveorg.html index 0781fe35..ad501f47 100644 --- a/plugins/archiveorg/archiveorg.html +++ b/plugins/archiveorg/archiveorg.html | |||
@@ -1 +1,5 @@ | |||
1 | <span><a href="https://web.archive.org/web/%s"><img class="linklist-plugin-icon" src="plugins/archiveorg/internetarchive.png" title="View on archive.org" alt="archive.org" /></a></span> | 1 | <span> |
2 | <a href="https://web.archive.org/web/%s"> | ||
3 | <img class="linklist-plugin-icon" src="plugins/archiveorg/internetarchive.png" title="%s" alt="archive.org" /> | ||
4 | </a> | ||
5 | </span> | ||
diff --git a/plugins/archiveorg/archiveorg.php b/plugins/archiveorg/archiveorg.php index 03d13d0e..cda35751 100644 --- a/plugins/archiveorg/archiveorg.php +++ b/plugins/archiveorg/archiveorg.php | |||
@@ -20,9 +20,18 @@ function hook_archiveorg_render_linklist($data) | |||
20 | if($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) { | 20 | if($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) { |
21 | continue; | 21 | continue; |
22 | } | 22 | } |
23 | $archive = sprintf($archive_html, $value['url']); | 23 | $archive = sprintf($archive_html, $value['url'], t('View on archive.org')); |
24 | $value['link_plugin'][] = $archive; | 24 | $value['link_plugin'][] = $archive; |
25 | } | 25 | } |
26 | 26 | ||
27 | return $data; | 27 | return $data; |
28 | } | 28 | } |
29 | |||
30 | /** | ||
31 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
32 | */ | ||
33 | function archiveorg_dummy_translation() | ||
34 | { | ||
35 | // meta | ||
36 | t('For each link, add an Archive.org icon.'); | ||
37 | } | ||
diff --git a/plugins/demo_plugin/demo_plugin.php b/plugins/demo_plugin/demo_plugin.php index 8fdbf663..b80a2b6d 100644 --- a/plugins/demo_plugin/demo_plugin.php +++ b/plugins/demo_plugin/demo_plugin.php | |||
@@ -14,6 +14,26 @@ | |||
14 | * and check user status with _LOGGEDIN_. | 14 | * and check user status with _LOGGEDIN_. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | use Shaarli\Config\ConfigManager; | ||
18 | |||
19 | /** | ||
20 | * In the footer hook, there is a working example of a translation extension for Shaarli. | ||
21 | * | ||
22 | * The extension must be attached to a new translation domain (i.e. NOT 'shaarli'). | ||
23 | * Use case: any custom theme or non official plugin can use the translation system. | ||
24 | * | ||
25 | * See the documentation for more information. | ||
26 | */ | ||
27 | const EXT_TRANSLATION_DOMAIN = 'demo'; | ||
28 | |||
29 | /* | ||
30 | * This is not necessary, but it's easier if you don't want Poedit to mix up your translations. | ||
31 | */ | ||
32 | function demo_plugin_t($text, $nText = '', $nb = 1) | ||
33 | { | ||
34 | return t($text, $nText, $nb, EXT_TRANSLATION_DOMAIN); | ||
35 | } | ||
36 | |||
17 | /** | 37 | /** |
18 | * Initialization function. | 38 | * Initialization function. |
19 | * It will be called when the plugin is loaded. | 39 | * It will be called when the plugin is loaded. |
@@ -27,6 +47,12 @@ function demo_plugin_init($conf) | |||
27 | { | 47 | { |
28 | $conf->get('toto', 'nope'); | 48 | $conf->get('toto', 'nope'); |
29 | 49 | ||
50 | if (! $conf->exists('translation.extensions.demo')) { | ||
51 | // Custom translation with the domain 'demo' | ||
52 | $conf->set('translation.extensions.demo', 'plugins/demo_plugin/languages/'); | ||
53 | $conf->write(true); | ||
54 | } | ||
55 | |||
30 | $errors[] = 'This a demo init error.'; | 56 | $errors[] = 'This a demo init error.'; |
31 | return $errors; | 57 | return $errors; |
32 | } | 58 | } |
@@ -160,7 +186,7 @@ function hook_demo_plugin_render_includes($data) | |||
160 | function hook_demo_plugin_render_footer($data) | 186 | function hook_demo_plugin_render_footer($data) |
161 | { | 187 | { |
162 | // footer text | 188 | // footer text |
163 | $data['text'][] = 'Shaarli is now enhanced by the awesome demo_plugin.'; | 189 | $data['text'][] = '<br>'. demo_plugin_t('Shaarli is now enhanced by the awesome demo_plugin.'); |
164 | 190 | ||
165 | // Free elements at the end of the page. | 191 | // Free elements at the end of the page. |
166 | $data['endofpage'][] = '<marquee id="demo_marquee">' . | 192 | $data['endofpage'][] = '<marquee id="demo_marquee">' . |
@@ -433,3 +459,12 @@ function hook_demo_plugin_render_feed($data) | |||
433 | } | 459 | } |
434 | return $data; | 460 | return $data; |
435 | } | 461 | } |
462 | |||
463 | /** | ||
464 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
465 | */ | ||
466 | function demo_dummy_translation() | ||
467 | { | ||
468 | // meta | ||
469 | t('A demo plugin covering all use cases for template designers and plugin developers.'); | ||
470 | } | ||
diff --git a/plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.mo b/plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.mo new file mode 100644 index 00000000..0f80f6ed --- /dev/null +++ b/plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.mo | |||
Binary files differ | |||
diff --git a/plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.po b/plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.po new file mode 100644 index 00000000..921379c0 --- /dev/null +++ b/plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.po | |||
@@ -0,0 +1,21 @@ | |||
1 | msgid "" | ||
2 | msgstr "" | ||
3 | "Project-Id-Version: Demo plugin\n" | ||
4 | "POT-Creation-Date: 2017-08-19 10:45+0200\n" | ||
5 | "PO-Revision-Date: 2017-08-19 11:28+0200\n" | ||
6 | "Last-Translator: \n" | ||
7 | "Language-Team: demo\n" | ||
8 | "Language: fr\n" | ||
9 | "MIME-Version: 1.0\n" | ||
10 | "Content-Type: text/plain; charset=UTF-8\n" | ||
11 | "Content-Transfer-Encoding: 8bit\n" | ||
12 | "X-Generator: Poedit 2.0.2\n" | ||
13 | "X-Poedit-Basepath: ../../..\n" | ||
14 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" | ||
15 | "X-Poedit-KeywordsList: ;demo_plugin_t:1,2;demo_plugin_t\n" | ||
16 | "X-Poedit-SourceCharset: UTF-8\n" | ||
17 | "X-Poedit-SearchPath-0: .\n" | ||
18 | |||
19 | #: demo_plugin.php:173 | ||
20 | msgid "Shaarli is now enhanced by the awesome demo_plugin." | ||
21 | msgstr "Shaarli est maintenant amélioré avec le fantastique demo_plugin." | ||
diff --git a/plugins/isso/isso.php b/plugins/isso/isso.php index ce16645f..5bc1cce2 100644 --- a/plugins/isso/isso.php +++ b/plugins/isso/isso.php | |||
@@ -4,10 +4,11 @@ | |||
4 | * Plugin Isso. | 4 | * Plugin Isso. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | use Shaarli\Config\ConfigManager; | ||
8 | |||
7 | /** | 9 | /** |
8 | * Display an error everywhere if the plugin is enabled without configuration. | 10 | * Display an error everywhere if the plugin is enabled without configuration. |
9 | * | 11 | * |
10 | * @param $data array List of links | ||
11 | * @param $conf ConfigManager instance | 12 | * @param $conf ConfigManager instance |
12 | * | 13 | * |
13 | * @return mixed - linklist data with Isso plugin. | 14 | * @return mixed - linklist data with Isso plugin. |
@@ -16,8 +17,8 @@ function isso_init($conf) | |||
16 | { | 17 | { |
17 | $issoUrl = $conf->get('plugins.ISSO_SERVER'); | 18 | $issoUrl = $conf->get('plugins.ISSO_SERVER'); |
18 | if (empty($issoUrl)) { | 19 | if (empty($issoUrl)) { |
19 | $error = 'Isso plugin error: '. | 20 | $error = t('Isso plugin error: '. |
20 | 'Please define the "ISSO_SERVER" setting in the plugin administration page.'; | 21 | 'Please define the "ISSO_SERVER" setting in the plugin administration page.'); |
21 | return array($error); | 22 | return array($error); |
22 | } | 23 | } |
23 | } | 24 | } |
@@ -52,3 +53,13 @@ function hook_isso_render_linklist($data, $conf) | |||
52 | 53 | ||
53 | return $data; | 54 | return $data; |
54 | } | 55 | } |
56 | |||
57 | /** | ||
58 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
59 | */ | ||
60 | function isso_dummy_translation() | ||
61 | { | ||
62 | // meta | ||
63 | t('Let visitor comment your shaares on permalinks with Isso.'); | ||
64 | t('Isso server URL (without \'http://\')'); | ||
65 | } | ||
diff --git a/plugins/markdown/help.html b/plugins/markdown/help.html index 9c4e5ae0..ded3d347 100644 --- a/plugins/markdown/help.html +++ b/plugins/markdown/help.html | |||
@@ -1,5 +1,5 @@ | |||
1 | <div class="md_help"> | 1 | <div class="md_help"> |
2 | Description will be rendered with | 2 | %s |
3 | <a href="http://daringfireball.net/projects/markdown/syntax" title="Markdown syntax documentation"> | 3 | <a href="http://daringfireball.net/projects/markdown/syntax" title="%s"> |
4 | Markdown syntax</a>. | 4 | %s</a>. |
5 | </div> | 5 | </div> |
diff --git a/plugins/markdown/markdown.php b/plugins/markdown/markdown.php index 772c56e8..1531549d 100644 --- a/plugins/markdown/markdown.php +++ b/plugins/markdown/markdown.php | |||
@@ -154,8 +154,13 @@ function hook_markdown_render_includes($data) | |||
154 | function hook_markdown_render_editlink($data) | 154 | function hook_markdown_render_editlink($data) |
155 | { | 155 | { |
156 | // Load help HTML into a string | 156 | // Load help HTML into a string |
157 | $data['edit_link_plugin'][] = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html'); | 157 | $txt = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html'); |
158 | 158 | $translations = [ | |
159 | t('Description will be rendered with'), | ||
160 | t('Markdown syntax documentation'), | ||
161 | t('Markdown syntax'), | ||
162 | ]; | ||
163 | $data['edit_link_plugin'][] = vsprintf($txt, $translations); | ||
159 | // Add no markdown 'meta-tag' in tag list if it was never used, for autocompletion. | 164 | // Add no markdown 'meta-tag' in tag list if it was never used, for autocompletion. |
160 | if (! in_array(NO_MD_TAG, $data['tags'])) { | 165 | if (! in_array(NO_MD_TAG, $data['tags'])) { |
161 | $data['tags'][NO_MD_TAG] = 0; | 166 | $data['tags'][NO_MD_TAG] = 0; |
@@ -325,3 +330,15 @@ function process_markdown($description, $escape = true, $allowedProtocols = []) | |||
325 | 330 | ||
326 | return $processedDescription; | 331 | return $processedDescription; |
327 | } | 332 | } |
333 | |||
334 | /** | ||
335 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
336 | */ | ||
337 | function markdown_dummy_translation() | ||
338 | { | ||
339 | // meta | ||
340 | t('Render shaare description with Markdown syntax.<br><strong>Warning</strong>: | ||
341 | If your shaared descriptions contained HTML tags before enabling the markdown plugin, | ||
342 | enabling it might break your page. | ||
343 | See the <a href="https://github.com/shaarli/Shaarli/tree/master/plugins/markdown#html-rendering">README</a>.'); | ||
344 | } | ||
diff --git a/plugins/piwik/piwik.php b/plugins/piwik/piwik.php index 4a2b48a1..ca00c2be 100644 --- a/plugins/piwik/piwik.php +++ b/plugins/piwik/piwik.php | |||
@@ -18,8 +18,8 @@ function piwik_init($conf) | |||
18 | $piwikUrl = $conf->get('plugins.PIWIK_URL'); | 18 | $piwikUrl = $conf->get('plugins.PIWIK_URL'); |
19 | $piwikSiteid = $conf->get('plugins.PIWIK_SITEID'); | 19 | $piwikSiteid = $conf->get('plugins.PIWIK_SITEID'); |
20 | if (empty($piwikUrl) || empty($piwikSiteid)) { | 20 | if (empty($piwikUrl) || empty($piwikSiteid)) { |
21 | $error = 'Piwik plugin error: ' . | 21 | $error = t('Piwik plugin error: ' . |
22 | 'Please define PIWIK_URL and PIWIK_SITEID in the plugin administration page.'; | 22 | 'Please define PIWIK_URL and PIWIK_SITEID in the plugin administration page.'); |
23 | return array($error); | 23 | return array($error); |
24 | } | 24 | } |
25 | } | 25 | } |
@@ -60,3 +60,14 @@ function hook_piwik_render_footer($data, $conf) | |||
60 | 60 | ||
61 | return $data; | 61 | return $data; |
62 | } | 62 | } |
63 | |||
64 | /** | ||
65 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
66 | */ | ||
67 | function piwik_dummy_translation() | ||
68 | { | ||
69 | // meta | ||
70 | t('A plugin that adds Piwik tracking code to Shaarli pages.'); | ||
71 | t('Piwik URL'); | ||
72 | t('Piwik site ID'); | ||
73 | } | ||
diff --git a/plugins/playvideos/playvideos.php b/plugins/playvideos/playvideos.php index 64484504..c6d6b0cc 100644 --- a/plugins/playvideos/playvideos.php +++ b/plugins/playvideos/playvideos.php | |||
@@ -19,10 +19,10 @@ function hook_playvideos_render_header($data) | |||
19 | $playvideo = array( | 19 | $playvideo = array( |
20 | 'attr' => array( | 20 | 'attr' => array( |
21 | 'href' => '#', | 21 | 'href' => '#', |
22 | 'title' => 'Video player', | 22 | 'title' => t('Video player'), |
23 | 'id' => 'playvideos', | 23 | 'id' => 'playvideos', |
24 | ), | 24 | ), |
25 | 'html' => 'â–º Play Videos' | 25 | 'html' => 'â–º '. t('Play Videos') |
26 | ); | 26 | ); |
27 | $data['buttons_toolbar'][] = $playvideo; | 27 | $data['buttons_toolbar'][] = $playvideo; |
28 | } | 28 | } |
@@ -46,3 +46,12 @@ function hook_playvideos_render_footer($data) | |||
46 | 46 | ||
47 | return $data; | 47 | return $data; |
48 | } | 48 | } |
49 | |||
50 | /** | ||
51 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
52 | */ | ||
53 | function playvideos_dummy_translation() | ||
54 | { | ||
55 | // meta | ||
56 | t('Add a button in the toolbar allowing to watch all videos.'); | ||
57 | } | ||
diff --git a/plugins/pubsubhubbub/pubsubhubbub.php b/plugins/pubsubhubbub/pubsubhubbub.php index 03b6757b..184b588b 100644 --- a/plugins/pubsubhubbub/pubsubhubbub.php +++ b/plugins/pubsubhubbub/pubsubhubbub.php | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | use pubsubhubbub\publisher\Publisher; | 12 | use pubsubhubbub\publisher\Publisher; |
13 | use Shaarli\Config\ConfigManager; | ||
13 | 14 | ||
14 | /** | 15 | /** |
15 | * Plugin init function - set the hub to the default appspot one. | 16 | * Plugin init function - set the hub to the default appspot one. |
@@ -65,7 +66,7 @@ function hook_pubsubhubbub_save_link($data, $conf) | |||
65 | $p = new Publisher($conf->get('plugins.PUBSUBHUB_URL')); | 66 | $p = new Publisher($conf->get('plugins.PUBSUBHUB_URL')); |
66 | $p->publish_update($feeds, $httpPost); | 67 | $p->publish_update($feeds, $httpPost); |
67 | } catch (Exception $e) { | 68 | } catch (Exception $e) { |
68 | error_log('Could not publish to PubSubHubbub: ' . $e->getMessage()); | 69 | error_log(sprintf(t('Could not publish to PubSubHubbub: %s'), $e->getMessage())); |
69 | } | 70 | } |
70 | 71 | ||
71 | return $data; | 72 | return $data; |
@@ -91,11 +92,20 @@ function nocurl_http_post($url, $postString) { | |||
91 | $context = stream_context_create($params); | 92 | $context = stream_context_create($params); |
92 | $fp = @fopen($url, 'rb', false, $context); | 93 | $fp = @fopen($url, 'rb', false, $context); |
93 | if (!$fp) { | 94 | if (!$fp) { |
94 | throw new Exception('Could not post to '. $url); | 95 | throw new Exception(sprintf(t('Could not post to %s'), $url)); |
95 | } | 96 | } |
96 | $response = @stream_get_contents($fp); | 97 | $response = @stream_get_contents($fp); |
97 | if ($response === false) { | 98 | if ($response === false) { |
98 | throw new Exception('Bad response from the hub '. $url); | 99 | throw new Exception(sprintf(t('Bad response from the hub %s'), $url)); |
99 | } | 100 | } |
100 | return $response; | 101 | return $response; |
101 | } | 102 | } |
103 | |||
104 | /** | ||
105 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
106 | */ | ||
107 | function pubsubhubbub_dummy_translation() | ||
108 | { | ||
109 | // meta | ||
110 | t('Enable PubSubHubbub feed publishing.'); | ||
111 | } | ||
diff --git a/plugins/qrcode/qrcode.meta b/plugins/qrcode/qrcode.meta index cbf371ea..1812cd21 100644 --- a/plugins/qrcode/qrcode.meta +++ b/plugins/qrcode/qrcode.meta | |||
@@ -1 +1 @@ | |||
description="For each link, add a QRCode icon ." | description="For each link, add a QRCode icon." | ||
diff --git a/plugins/qrcode/qrcode.php b/plugins/qrcode/qrcode.php index 8bc610d1..0f96a106 100644 --- a/plugins/qrcode/qrcode.php +++ b/plugins/qrcode/qrcode.php | |||
@@ -59,3 +59,12 @@ function hook_qrcode_render_includes($data) | |||
59 | 59 | ||
60 | return $data; | 60 | return $data; |
61 | } | 61 | } |
62 | |||
63 | /** | ||
64 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
65 | */ | ||
66 | function qrcode_dummy_translation() | ||
67 | { | ||
68 | // meta | ||
69 | t('For each link, add a QRCode icon.'); | ||
70 | } | ||
diff --git a/plugins/wallabag/wallabag.html b/plugins/wallabag/wallabag.html index e861536d..4c57691d 100644 --- a/plugins/wallabag/wallabag.html +++ b/plugins/wallabag/wallabag.html | |||
@@ -1 +1,5 @@ | |||
1 | <span><a href="%s%s" target="_blank"><img class="linklist-plugin-icon" src="%s/wallabag/wallabag.png" title="Save to wallabag" alt="wallabag" /></a></span> | 1 | <span> |
2 | <a href="%s%s" target="_blank"> | ||
3 | <img class="linklist-plugin-icon" src="%s/wallabag/wallabag.png" title="%s" alt="wallabag" /> | ||
4 | </a> | ||
5 | </span> | ||
diff --git a/plugins/wallabag/wallabag.php b/plugins/wallabag/wallabag.php index 641e4cc2..9dfd079e 100644 --- a/plugins/wallabag/wallabag.php +++ b/plugins/wallabag/wallabag.php | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | require_once 'WallabagInstance.php'; | 7 | require_once 'WallabagInstance.php'; |
8 | use Shaarli\Config\ConfigManager; | ||
8 | 9 | ||
9 | /** | 10 | /** |
10 | * Init function, return an error if the server is not set. | 11 | * Init function, return an error if the server is not set. |
@@ -17,8 +18,8 @@ function wallabag_init($conf) | |||
17 | { | 18 | { |
18 | $wallabagUrl = $conf->get('plugins.WALLABAG_URL'); | 19 | $wallabagUrl = $conf->get('plugins.WALLABAG_URL'); |
19 | if (empty($wallabagUrl)) { | 20 | if (empty($wallabagUrl)) { |
20 | $error = 'Wallabag plugin error: '. | 21 | $error = t('Wallabag plugin error: '. |
21 | 'Please define the "WALLABAG_URL" setting in the plugin administration page.'; | 22 | 'Please define the "WALLABAG_URL" setting in the plugin administration page.'); |
22 | return array($error); | 23 | return array($error); |
23 | } | 24 | } |
24 | } | 25 | } |
@@ -43,12 +44,14 @@ function hook_wallabag_render_linklist($data, $conf) | |||
43 | 44 | ||
44 | $wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html'); | 45 | $wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html'); |
45 | 46 | ||
47 | $linkTitle = t('Save to wallabag'); | ||
46 | foreach ($data['links'] as &$value) { | 48 | foreach ($data['links'] as &$value) { |
47 | $wallabag = sprintf( | 49 | $wallabag = sprintf( |
48 | $wallabagHtml, | 50 | $wallabagHtml, |
49 | $wallabagInstance->getWallabagUrl(), | 51 | $wallabagInstance->getWallabagUrl(), |
50 | urlencode($value['url']), | 52 | urlencode($value['url']), |
51 | PluginManager::$PLUGINS_PATH | 53 | PluginManager::$PLUGINS_PATH, |
54 | $linkTitle | ||
52 | ); | 55 | ); |
53 | $value['link_plugin'][] = $wallabag; | 56 | $value['link_plugin'][] = $wallabag; |
54 | } | 57 | } |
@@ -56,3 +59,14 @@ function hook_wallabag_render_linklist($data, $conf) | |||
56 | return $data; | 59 | return $data; |
57 | } | 60 | } |
58 | 61 | ||
62 | /** | ||
63 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
64 | */ | ||
65 | function wallabag_dummy_translation() | ||
66 | { | ||
67 | // meta | ||
68 | t('For each link, add a QRCode icon.'); | ||
69 | t('Wallabag API URL'); | ||
70 | t('Wallabag API version (1 or 2)'); | ||
71 | } | ||
72 | |||
diff --git a/tests/LanguagesTest.php b/tests/LanguagesTest.php index 79c136c8..864ce630 100644 --- a/tests/LanguagesTest.php +++ b/tests/LanguagesTest.php | |||
@@ -1,41 +1,203 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | require_once 'application/Languages.php'; | 3 | namespace Shaarli; |
4 | |||
5 | use Shaarli\Config\ConfigManager; | ||
4 | 6 | ||
5 | /** | 7 | /** |
6 | * Class LanguagesTest. | 8 | * Class LanguagesTest. |
7 | */ | 9 | */ |
8 | class LanguagesTest extends PHPUnit_Framework_TestCase | 10 | class LanguagesTest extends \PHPUnit_Framework_TestCase |
9 | { | 11 | { |
10 | /** | 12 | /** |
13 | * @var string Config file path (without extension). | ||
14 | */ | ||
15 | protected static $configFile = 'tests/utils/config/configJson'; | ||
16 | |||
17 | /** | ||
18 | * @var ConfigManager | ||
19 | */ | ||
20 | protected $conf; | ||
21 | |||
22 | /** | ||
23 | * | ||
24 | */ | ||
25 | public function setUp() | ||
26 | { | ||
27 | $this->conf = new ConfigManager(self::$configFile); | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * Test t() with a simple non identified value. | ||
32 | */ | ||
33 | public function testTranslateSingleNotIDGettext() | ||
34 | { | ||
35 | $this->conf->set('translation.mode', 'gettext'); | ||
36 | new Languages('en', $this->conf); | ||
37 | $text = 'abcdé 564 fgK'; | ||
38 | $this->assertEquals($text, t($text)); | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * Test t() with a simple identified value in gettext mode. | ||
43 | */ | ||
44 | public function testTranslateSingleIDGettext() | ||
45 | { | ||
46 | $this->conf->set('translation.mode', 'gettext'); | ||
47 | new Languages('en', $this->conf); | ||
48 | $text = 'permalink'; | ||
49 | $this->assertEquals($text, t($text)); | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * Test t() with a non identified plural form in gettext mode. | ||
54 | */ | ||
55 | public function testTranslatePluralNotIDGettext() | ||
56 | { | ||
57 | $this->conf->set('translation.mode', 'gettext'); | ||
58 | new Languages('en', $this->conf); | ||
59 | $text = 'sandwich'; | ||
60 | $nText = 'sandwiches'; | ||
61 | $this->assertEquals('sandwiches', t($text, $nText, 0)); | ||
62 | $this->assertEquals('sandwich', t($text, $nText, 1)); | ||
63 | $this->assertEquals('sandwiches', t($text, $nText, 2)); | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Test t() with an identified plural form in gettext mode. | ||
68 | */ | ||
69 | public function testTranslatePluralIDGettext() | ||
70 | { | ||
71 | $this->conf->set('translation.mode', 'gettext'); | ||
72 | new Languages('en', $this->conf); | ||
73 | $text = 'shaare'; | ||
74 | $nText = 'shaares'; | ||
75 | // In english, zero is followed by plural form | ||
76 | $this->assertEquals('shaares', t($text, $nText, 0)); | ||
77 | $this->assertEquals('shaare', t($text, $nText, 1)); | ||
78 | $this->assertEquals('shaares', t($text, $nText, 2)); | ||
79 | } | ||
80 | |||
81 | /** | ||
11 | * Test t() with a simple non identified value. | 82 | * Test t() with a simple non identified value. |
12 | */ | 83 | */ |
13 | public function testTranslateSingleNotID() | 84 | public function testTranslateSingleNotIDPhp() |
14 | { | 85 | { |
86 | $this->conf->set('translation.mode', 'php'); | ||
87 | new Languages('en', $this->conf); | ||
15 | $text = 'abcdé 564 fgK'; | 88 | $text = 'abcdé 564 fgK'; |
16 | $this->assertEquals($text, t($text)); | 89 | $this->assertEquals($text, t($text)); |
17 | } | 90 | } |
18 | 91 | ||
19 | /** | 92 | /** |
20 | * Test t() with a non identified plural form. | 93 | * Test t() with a simple identified value in PHP mode. |
21 | */ | 94 | */ |
22 | public function testTranslatePluralNotID() | 95 | public function testTranslateSingleIDPhp() |
23 | { | 96 | { |
24 | $text = '%s sandwich'; | 97 | $this->conf->set('translation.mode', 'php'); |
25 | $nText = '%s sandwiches'; | 98 | new Languages('en', $this->conf); |
26 | $this->assertEquals('0 sandwich', t($text, $nText)); | 99 | $text = 'permalink'; |
27 | $this->assertEquals('1 sandwich', t($text, $nText, 1)); | 100 | $this->assertEquals($text, t($text)); |
28 | $this->assertEquals('2 sandwiches', t($text, $nText, 2)); | ||
29 | } | 101 | } |
30 | 102 | ||
31 | /** | 103 | /** |
32 | * Test t() with a non identified invalid plural form. | 104 | * Test t() with a non identified plural form in PHP mode. |
33 | */ | 105 | */ |
34 | public function testTranslatePluralNotIDInvalid() | 106 | public function testTranslatePluralNotIDPhp() |
35 | { | 107 | { |
108 | $this->conf->set('translation.mode', 'php'); | ||
109 | new Languages('en', $this->conf); | ||
36 | $text = 'sandwich'; | 110 | $text = 'sandwich'; |
37 | $nText = 'sandwiches'; | 111 | $nText = 'sandwiches'; |
112 | $this->assertEquals('sandwiches', t($text, $nText, 0)); | ||
38 | $this->assertEquals('sandwich', t($text, $nText, 1)); | 113 | $this->assertEquals('sandwich', t($text, $nText, 1)); |
39 | $this->assertEquals('sandwiches', t($text, $nText, 2)); | 114 | $this->assertEquals('sandwiches', t($text, $nText, 2)); |
40 | } | 115 | } |
116 | |||
117 | /** | ||
118 | * Test t() with an identified plural form in PHP mode. | ||
119 | */ | ||
120 | public function testTranslatePluralIDPhp() | ||
121 | { | ||
122 | $this->conf->set('translation.mode', 'php'); | ||
123 | new Languages('en', $this->conf); | ||
124 | $text = 'shaare'; | ||
125 | $nText = 'shaares'; | ||
126 | // In english, zero is followed by plural form | ||
127 | $this->assertEquals('shaares', t($text, $nText, 0)); | ||
128 | $this->assertEquals('shaare', t($text, $nText, 1)); | ||
129 | $this->assertEquals('shaares', t($text, $nText, 2)); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * Test t() with an invalid language set in the configuration in gettext mode. | ||
134 | */ | ||
135 | public function testTranslateWithInvalidConfLanguageGettext() | ||
136 | { | ||
137 | $this->conf->set('translation.mode', 'gettext'); | ||
138 | $this->conf->set('translation.language', 'nope'); | ||
139 | new Languages('fr', $this->conf); | ||
140 | $text = 'grumble'; | ||
141 | $this->assertEquals($text, t($text)); | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * Test t() with an invalid language set in the configuration in PHP mode. | ||
146 | */ | ||
147 | public function testTranslateWithInvalidConfLanguagePhp() | ||
148 | { | ||
149 | $this->conf->set('translation.mode', 'php'); | ||
150 | $this->conf->set('translation.language', 'nope'); | ||
151 | new Languages('fr', $this->conf); | ||
152 | $text = 'grumble'; | ||
153 | $this->assertEquals($text, t($text)); | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * Test t() with an invalid language set with auto language in gettext mode. | ||
158 | */ | ||
159 | public function testTranslateWithInvalidAutoLanguageGettext() | ||
160 | { | ||
161 | $this->conf->set('translation.mode', 'gettext'); | ||
162 | new Languages('nope', $this->conf); | ||
163 | $text = 'grumble'; | ||
164 | $this->assertEquals($text, t($text)); | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * Test t() with an invalid language set with auto language in PHP mode. | ||
169 | */ | ||
170 | public function testTranslateWithInvalidAutoLanguagePhp() | ||
171 | { | ||
172 | $this->conf->set('translation.mode', 'php'); | ||
173 | new Languages('nope', $this->conf); | ||
174 | $text = 'grumble'; | ||
175 | $this->assertEquals($text, t($text)); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * Test t() with an extension language file in gettext mode | ||
180 | */ | ||
181 | public function testTranslationExtensionGettext() | ||
182 | { | ||
183 | $this->conf->set('translation.mode', 'gettext'); | ||
184 | $this->conf->set('translation.extensions.test', 'tests/utils/languages/'); | ||
185 | new Languages('en', $this->conf); | ||
186 | $txt = 'car'; // ignore me poedit | ||
187 | $this->assertEquals('car', t($txt, $txt, 1, 'test')); | ||
188 | $this->assertEquals('Search', t('Search', 'Search', 1, 'test')); | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * Test t() with an extension language file in PHP mode | ||
193 | */ | ||
194 | public function testTranslationExtensionPhp() | ||
195 | { | ||
196 | $this->conf->set('translation.mode', 'php'); | ||
197 | $this->conf->set('translation.extensions.test', 'tests/utils/languages/'); | ||
198 | new Languages('en', $this->conf); | ||
199 | $txt = 'car'; // ignore me poedit | ||
200 | $this->assertEquals('car', t($txt, $txt, 1, 'test')); | ||
201 | $this->assertEquals('Search', t('Search', 'Search', 1, 'test')); | ||
202 | } | ||
41 | } | 203 | } |
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php index 3d1aa653..840eaf21 100644 --- a/tests/UtilsTest.php +++ b/tests/UtilsTest.php | |||
@@ -384,18 +384,18 @@ class UtilsTest extends PHPUnit_Framework_TestCase | |||
384 | */ | 384 | */ |
385 | public function testHumanBytes() | 385 | public function testHumanBytes() |
386 | { | 386 | { |
387 | $this->assertEquals('2kiB', human_bytes(2 * 1024)); | 387 | $this->assertEquals('2'. t('kiB'), human_bytes(2 * 1024)); |
388 | $this->assertEquals('2kiB', human_bytes(strval(2 * 1024))); | 388 | $this->assertEquals('2'. t('kiB'), human_bytes(strval(2 * 1024))); |
389 | $this->assertEquals('2MiB', human_bytes(2 * (pow(1024, 2)))); | 389 | $this->assertEquals('2'. t('MiB'), human_bytes(2 * (pow(1024, 2)))); |
390 | $this->assertEquals('2MiB', human_bytes(strval(2 * (pow(1024, 2))))); | 390 | $this->assertEquals('2'. t('MiB'), human_bytes(strval(2 * (pow(1024, 2))))); |
391 | $this->assertEquals('2GiB', human_bytes(2 * (pow(1024, 3)))); | 391 | $this->assertEquals('2'. t('GiB'), human_bytes(2 * (pow(1024, 3)))); |
392 | $this->assertEquals('2GiB', human_bytes(strval(2 * (pow(1024, 3))))); | 392 | $this->assertEquals('2'. t('GiB'), human_bytes(strval(2 * (pow(1024, 3))))); |
393 | $this->assertEquals('374B', human_bytes(374)); | 393 | $this->assertEquals('374'. t('B'), human_bytes(374)); |
394 | $this->assertEquals('374B', human_bytes('374')); | 394 | $this->assertEquals('374'. t('B'), human_bytes('374')); |
395 | $this->assertEquals('232kiB', human_bytes(237481)); | 395 | $this->assertEquals('232'. t('kiB'), human_bytes(237481)); |
396 | $this->assertEquals('Unlimited', human_bytes('0')); | 396 | $this->assertEquals(t('Unlimited'), human_bytes('0')); |
397 | $this->assertEquals('Unlimited', human_bytes(0)); | 397 | $this->assertEquals(t('Unlimited'), human_bytes(0)); |
398 | $this->assertEquals('Setting not set', human_bytes('')); | 398 | $this->assertEquals(t('Setting not set'), human_bytes('')); |
399 | } | 399 | } |
400 | 400 | ||
401 | /** | 401 | /** |
@@ -403,9 +403,9 @@ class UtilsTest extends PHPUnit_Framework_TestCase | |||
403 | */ | 403 | */ |
404 | public function testGetMaxUploadSize() | 404 | public function testGetMaxUploadSize() |
405 | { | 405 | { |
406 | $this->assertEquals('1MiB', get_max_upload_size(2097152, '1024k')); | 406 | $this->assertEquals('1'. t('MiB'), get_max_upload_size(2097152, '1024k')); |
407 | $this->assertEquals('1MiB', get_max_upload_size('1m', '2m')); | 407 | $this->assertEquals('1'. t('MiB'), get_max_upload_size('1m', '2m')); |
408 | $this->assertEquals('100B', get_max_upload_size(100, 100)); | 408 | $this->assertEquals('100'. t('B'), get_max_upload_size(100, 100)); |
409 | } | 409 | } |
410 | 410 | ||
411 | /** | 411 | /** |
diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 00000000..d36d73cd --- /dev/null +++ b/tests/bootstrap.php | |||
@@ -0,0 +1,6 @@ | |||
1 | <?php | ||
2 | |||
3 | require_once 'vendor/autoload.php'; | ||
4 | |||
5 | $conf = new \Shaarli\Config\ConfigManager('tests/utils/config/configJson'); | ||
6 | new \Shaarli\Languages('en', $conf); | ||
diff --git a/tests/languages/bootstrap.php b/tests/languages/bootstrap.php index 95609210..da6ac2e4 100644 --- a/tests/languages/bootstrap.php +++ b/tests/languages/bootstrap.php | |||
@@ -1,7 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | if (! empty('UT_LOCALE')) { | 2 | require_once 'tests/bootstrap.php'; |
3 | |||
4 | if (! empty(getenv('UT_LOCALE'))) { | ||
3 | setlocale(LC_ALL, getenv('UT_LOCALE')); | 5 | setlocale(LC_ALL, getenv('UT_LOCALE')); |
4 | } | 6 | } |
5 | |||
6 | require_once 'vendor/autoload.php'; | ||
7 | |||
diff --git a/tests/languages/fr/LanguagesFrTest.php b/tests/languages/fr/LanguagesFrTest.php new file mode 100644 index 00000000..79d05172 --- /dev/null +++ b/tests/languages/fr/LanguagesFrTest.php | |||
@@ -0,0 +1,175 @@ | |||
1 | <?php | ||
2 | |||
3 | |||
4 | namespace Shaarli; | ||
5 | |||
6 | |||
7 | use Shaarli\Config\ConfigManager; | ||
8 | |||
9 | /** | ||
10 | * Class LanguagesFrTest | ||
11 | * | ||
12 | * Test the translation system in PHP and gettext mode with French language. | ||
13 | * | ||
14 | * @package Shaarli | ||
15 | */ | ||
16 | class LanguagesFrTest extends \PHPUnit_Framework_TestCase | ||
17 | { | ||
18 | /** | ||
19 | * @var string Config file path (without extension). | ||
20 | */ | ||
21 | protected static $configFile = 'tests/utils/config/configJson'; | ||
22 | |||
23 | /** | ||
24 | * @var ConfigManager | ||
25 | */ | ||
26 | protected $conf; | ||
27 | |||
28 | /** | ||
29 | * Init: force French | ||
30 | */ | ||
31 | public function setUp() | ||
32 | { | ||
33 | $this->conf = new ConfigManager(self::$configFile); | ||
34 | $this->conf->set('translation.language', 'fr'); | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * Reset the locale since gettext seems to mess with it, making it too long | ||
39 | */ | ||
40 | public static function tearDownAfterClass() | ||
41 | { | ||
42 | if (! empty(getenv('UT_LOCALE'))) { | ||
43 | setlocale(LC_ALL, getenv('UT_LOCALE')); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * Test t() with a simple non identified value. | ||
49 | */ | ||
50 | public function testTranslateSingleNotIDGettext() | ||
51 | { | ||
52 | $this->conf->set('translation.mode', 'gettext'); | ||
53 | new Languages('en', $this->conf); | ||
54 | $text = 'abcdé 564 fgK'; | ||
55 | $this->assertEquals($text, t($text)); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Test t() with a simple identified value in gettext mode. | ||
60 | */ | ||
61 | public function testTranslateSingleIDGettext() | ||
62 | { | ||
63 | $this->conf->set('translation.mode', 'gettext'); | ||
64 | new Languages('en', $this->conf); | ||
65 | $text = 'permalink'; | ||
66 | $this->assertEquals('permalien', t($text)); | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * Test t() with a non identified plural form in gettext mode. | ||
71 | */ | ||
72 | public function testTranslatePluralNotIDGettext() | ||
73 | { | ||
74 | $this->conf->set('translation.mode', 'gettext'); | ||
75 | new Languages('en', $this->conf); | ||
76 | $text = 'sandwich'; | ||
77 | $nText = 'sandwiches'; | ||
78 | // Not ID, so English fallback, and in english, plural 0 | ||
79 | $this->assertEquals('sandwiches', t($text, $nText, 0)); | ||
80 | $this->assertEquals('sandwich', t($text, $nText, 1)); | ||
81 | $this->assertEquals('sandwiches', t($text, $nText, 2)); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * Test t() with an identified plural form in gettext mode. | ||
86 | */ | ||
87 | public function testTranslatePluralIDGettext() | ||
88 | { | ||
89 | $this->conf->set('translation.mode', 'gettext'); | ||
90 | new Languages('en', $this->conf); | ||
91 | $text = 'shaare'; | ||
92 | $nText = 'shaares'; | ||
93 | $this->assertEquals('shaare', t($text, $nText, 0)); | ||
94 | $this->assertEquals('shaare', t($text, $nText, 1)); | ||
95 | $this->assertEquals('shaares', t($text, $nText, 2)); | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * Test t() with a simple non identified value. | ||
100 | */ | ||
101 | public function testTranslateSingleNotIDPhp() | ||
102 | { | ||
103 | $this->conf->set('translation.mode', 'php'); | ||
104 | new Languages('en', $this->conf); | ||
105 | $text = 'abcdé 564 fgK'; | ||
106 | $this->assertEquals($text, t($text)); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * Test t() with a simple identified value in PHP mode. | ||
111 | */ | ||
112 | public function testTranslateSingleIDPhp() | ||
113 | { | ||
114 | $this->conf->set('translation.mode', 'php'); | ||
115 | new Languages('en', $this->conf); | ||
116 | $text = 'permalink'; | ||
117 | $this->assertEquals('permalien', t($text)); | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * Test t() with a non identified plural form in PHP mode. | ||
122 | */ | ||
123 | public function testTranslatePluralNotIDPhp() | ||
124 | { | ||
125 | $this->conf->set('translation.mode', 'php'); | ||
126 | new Languages('en', $this->conf); | ||
127 | $text = 'sandwich'; | ||
128 | $nText = 'sandwiches'; | ||
129 | // Not ID, so English fallback, and in english, plural 0 | ||
130 | $this->assertEquals('sandwiches', t($text, $nText, 0)); | ||
131 | $this->assertEquals('sandwich', t($text, $nText, 1)); | ||
132 | $this->assertEquals('sandwiches', t($text, $nText, 2)); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * Test t() with an identified plural form in PHP mode. | ||
137 | */ | ||
138 | public function testTranslatePluralIDPhp() | ||
139 | { | ||
140 | $this->conf->set('translation.mode', 'php'); | ||
141 | new Languages('en', $this->conf); | ||
142 | $text = 'shaare'; | ||
143 | $nText = 'shaares'; | ||
144 | // In english, zero is followed by plural form | ||
145 | $this->assertEquals('shaare', t($text, $nText, 0)); | ||
146 | $this->assertEquals('shaare', t($text, $nText, 1)); | ||
147 | $this->assertEquals('shaares', t($text, $nText, 2)); | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Test t() with an extension language file in gettext mode | ||
152 | */ | ||
153 | public function testTranslationExtensionGettext() | ||
154 | { | ||
155 | $this->conf->set('translation.mode', 'gettext'); | ||
156 | $this->conf->set('translation.extensions.test', 'tests/utils/languages/'); | ||
157 | new Languages('en', $this->conf); | ||
158 | $txt = 'car'; // ignore me poedit | ||
159 | $this->assertEquals('voiture', t($txt, $txt, 1, 'test')); | ||
160 | $this->assertEquals('Fouille', t('Search', 'Search', 1, 'test')); | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * Test t() with an extension language file in PHP mode | ||
165 | */ | ||
166 | public function testTranslationExtensionPhp() | ||
167 | { | ||
168 | $this->conf->set('translation.mode', 'php'); | ||
169 | $this->conf->set('translation.extensions.test', 'tests/utils/languages/'); | ||
170 | new Languages('en', $this->conf); | ||
171 | $txt = 'car'; // ignore me poedit | ||
172 | $this->assertEquals('voiture', t($txt, $txt, 1, 'test')); | ||
173 | $this->assertEquals('Fouille', t('Search', 'Search', 1, 'test')); | ||
174 | } | ||
175 | } | ||
diff --git a/tests/utils/languages/fr/LC_MESSAGES/test.mo b/tests/utils/languages/fr/LC_MESSAGES/test.mo new file mode 100644 index 00000000..416c7831 --- /dev/null +++ b/tests/utils/languages/fr/LC_MESSAGES/test.mo | |||
Binary files differ | |||
diff --git a/tests/utils/languages/fr/LC_MESSAGES/test.po b/tests/utils/languages/fr/LC_MESSAGES/test.po new file mode 100644 index 00000000..89a4fd9b --- /dev/null +++ b/tests/utils/languages/fr/LC_MESSAGES/test.po | |||
@@ -0,0 +1,19 @@ | |||
1 | msgid "" | ||
2 | msgstr "" | ||
3 | "Project-Id-Version: Extension test\n" | ||
4 | "POT-Creation-Date: 2017-05-20 13:54+0200\n" | ||
5 | "PO-Revision-Date: 2017-05-20 14:16+0200\n" | ||
6 | "Last-Translator: \n" | ||
7 | "Language-Team: Shaarli\n" | ||
8 | "Language: fr_FR\n" | ||
9 | "MIME-Version: 1.0\n" | ||
10 | "Content-Type: text/plain; charset=UTF-8\n" | ||
11 | "Content-Transfer-Encoding: 8bit\n" | ||
12 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" | ||
13 | "X-Generator: Poedit 2.0.1\n" | ||
14 | |||
15 | msgid "car" | ||
16 | msgstr "voiture" | ||
17 | |||
18 | msgid "Search" | ||
19 | msgstr "Fouille" | ||
diff --git a/tpl/default/changetag.html b/tpl/default/changetag.html index 49dd20d9..6606c4fa 100644 --- a/tpl/default/changetag.html +++ b/tpl/default/changetag.html | |||
@@ -32,7 +32,7 @@ | |||
32 | </div> | 32 | </div> |
33 | </form> | 33 | </form> |
34 | 34 | ||
35 | <p>You can also edit tags in the <a href="?do=taglist&sort=usage">tag list</a>.</p> | 35 | <p>{'You can also edit tags in the'|t} <a href="?do=taglist&sort=usage">{'tag list'|t}</a>.</p> |
36 | </div> | 36 | </div> |
37 | </div> | 37 | </div> |
38 | {include="page.footer"} | 38 | {include="page.footer"} |
diff --git a/tpl/default/configure.html b/tpl/default/configure.html index 76a1b9fd..cc3b299b 100644 --- a/tpl/default/configure.html +++ b/tpl/default/configure.html | |||
@@ -70,6 +70,30 @@ | |||
70 | </div> | 70 | </div> |
71 | </div> | 71 | </div> |
72 | <div class="pure-g"> | 72 | <div class="pure-g"> |
73 | <div class="pure-u-lg-{$ratioLabel} pure-u-1"> | ||
74 | <div class="form-label"> | ||
75 | <label for="language"> | ||
76 | <span class="label-name">{'Language'|t}</span> | ||
77 | </label> | ||
78 | </div> | ||
79 | </div> | ||
80 | <div class="pure-u-lg-{$ratioInput} pure-u-1"> | ||
81 | <div class="form-input"> | ||
82 | <select name="language" id="language" class="align"> | ||
83 | {loop="$languages"} | ||
84 | <option value="{$key}" | ||
85 | {if="$key===$language"} | ||
86 | selected="selected" | ||
87 | {/if} | ||
88 | > | ||
89 | {$value} | ||
90 | </option> | ||
91 | {/loop} | ||
92 | </select> | ||
93 | </div> | ||
94 | </div> | ||
95 | </div> | ||
96 | <div class="pure-g"> | ||
73 | <div class="pure-u-lg-{$ratioLabel} pure-u-1 "> | 97 | <div class="pure-u-lg-{$ratioLabel} pure-u-1 "> |
74 | <div class="form-label"> | 98 | <div class="form-label"> |
75 | <label> | 99 | <label> |
diff --git a/tpl/default/import.html b/tpl/default/import.html index 1f040685..000a50ac 100644 --- a/tpl/default/import.html +++ b/tpl/default/import.html | |||
@@ -18,7 +18,7 @@ | |||
18 | <div class="center" id="import-field"> | 18 | <div class="center" id="import-field"> |
19 | <input type="hidden" name="MAX_FILE_SIZE" value="{$maxfilesize}"> | 19 | <input type="hidden" name="MAX_FILE_SIZE" value="{$maxfilesize}"> |
20 | <input type="file" name="filetoupload"> | 20 | <input type="file" name="filetoupload"> |
21 | <p><br>Maximum size allowed: <strong>{$maxfilesizeHuman}</strong></p> | 21 | <p><br>{'Maximum size allowed:'|t} <strong>{$maxfilesizeHuman}</strong></p> |
22 | </div> | 22 | </div> |
23 | 23 | ||
24 | <div class="pure-g"> | 24 | <div class="pure-g"> |
@@ -31,15 +31,15 @@ | |||
31 | <div class="radio-buttons"> | 31 | <div class="radio-buttons"> |
32 | <div> | 32 | <div> |
33 | <input type="radio" name="privacy" value="default" checked="checked"> | 33 | <input type="radio" name="privacy" value="default" checked="checked"> |
34 | Use values from the imported file, default to public | 34 | {'Use values from the imported file, default to public'|t} |
35 | </div> | 35 | </div> |
36 | <div> | 36 | <div> |
37 | <input type="radio" name="privacy" value="private"> | 37 | <input type="radio" name="privacy" value="private"> |
38 | Import all bookmarks as private | 38 | {'Import all bookmarks as private'|t} |
39 | </div> | 39 | </div> |
40 | <div> | 40 | <div> |
41 | <input type="radio" name="privacy" value="public"> | 41 | <input type="radio" name="privacy" value="public"> |
42 | Import all bookmarks as public | 42 | {'Import all bookmarks as public'|t} |
43 | </div> | 43 | </div> |
44 | </div> | 44 | </div> |
45 | </div> | 45 | </div> |
diff --git a/tpl/default/install.html b/tpl/default/install.html index 164d453b..6199b33d 100644 --- a/tpl/default/install.html +++ b/tpl/default/install.html | |||
@@ -68,6 +68,27 @@ | |||
68 | <div class="pure-g"> | 68 | <div class="pure-g"> |
69 | <div class="pure-u-lg-{$ratioLabel} pure-u-1"> | 69 | <div class="pure-u-lg-{$ratioLabel} pure-u-1"> |
70 | <div class="form-label"> | 70 | <div class="form-label"> |
71 | <label for="language"> | ||
72 | <span class="label-name">{'Language'|t}</span> | ||
73 | </label> | ||
74 | </div> | ||
75 | </div> | ||
76 | <div class="pure-u-lg-{$ratioInput} pure-u-1"> | ||
77 | <div class="form-input"> | ||
78 | <select name="language" id="language" class="align"> | ||
79 | {loop="$languages"} | ||
80 | <option value="{$key}"> | ||
81 | {$value} | ||
82 | </option> | ||
83 | {/loop} | ||
84 | </select> | ||
85 | </div> | ||
86 | </div> | ||
87 | </div> | ||
88 | |||
89 | <div class="pure-g"> | ||
90 | <div class="pure-u-lg-{$ratioLabel} pure-u-1"> | ||
91 | <div class="form-label"> | ||
71 | <label> | 92 | <label> |
72 | <span class="label-name">{'Timezone'|t}</span><br> | 93 | <span class="label-name">{'Timezone'|t}</span><br> |
73 | <span class="label-desc">{'Continent'|t} · {'City'|t}</span> | 94 | <span class="label-desc">{'Continent'|t} · {'City'|t}</span> |
diff --git a/tpl/default/js/shaarli.js b/tpl/default/js/shaarli.js index 55656f80..09b07eed 100644 --- a/tpl/default/js/shaarli.js +++ b/tpl/default/js/shaarli.js | |||
@@ -138,6 +138,9 @@ window.onload = function () { | |||
138 | }); | 138 | }); |
139 | foldAllButton.firstElementChild.classList.toggle('fa-chevron-down'); | 139 | foldAllButton.firstElementChild.classList.toggle('fa-chevron-down'); |
140 | foldAllButton.firstElementChild.classList.toggle('fa-chevron-up'); | 140 | foldAllButton.firstElementChild.classList.toggle('fa-chevron-up'); |
141 | foldAllButton.title = state === 'down' | ||
142 | ? document.getElementById('translation-fold-all').innerHTML | ||
143 | : document.getElementById('translation-expand-all').innerHTML | ||
141 | }); | 144 | }); |
142 | }); | 145 | }); |
143 | } | 146 | } |
@@ -146,7 +149,7 @@ window.onload = function () { | |||
146 | { | 149 | { |
147 | // Switch fold/expand - up = fold | 150 | // Switch fold/expand - up = fold |
148 | if (button.classList.contains('fa-chevron-up')) { | 151 | if (button.classList.contains('fa-chevron-up')) { |
149 | button.title = 'Expand'; | 152 | button.title = document.getElementById('translation-expand').innerHTML; |
150 | if (description != null) { | 153 | if (description != null) { |
151 | description.style.display = 'none'; | 154 | description.style.display = 'none'; |
152 | } | 155 | } |
@@ -155,7 +158,7 @@ window.onload = function () { | |||
155 | } | 158 | } |
156 | } | 159 | } |
157 | else { | 160 | else { |
158 | button.title = 'Fold'; | 161 | button.title = document.getElementById('translation-fold').innerHTML; |
159 | if (description != null) { | 162 | if (description != null) { |
160 | description.style.display = 'block'; | 163 | description.style.display = 'block'; |
161 | } | 164 | } |
@@ -173,7 +176,7 @@ window.onload = function () { | |||
173 | var deleteLinks = document.querySelectorAll('.confirm-delete'); | 176 | var deleteLinks = document.querySelectorAll('.confirm-delete'); |
174 | [].forEach.call(deleteLinks, function(deleteLink) { | 177 | [].forEach.call(deleteLinks, function(deleteLink) { |
175 | deleteLink.addEventListener('click', function(event) { | 178 | deleteLink.addEventListener('click', function(event) { |
176 | if(! confirm('Are you sure you want to delete this link ?')) { | 179 | if(! confirm(document.getElementById('translation-delete-link').innerHTML)) { |
177 | event.preventDefault(); | 180 | event.preventDefault(); |
178 | } | 181 | } |
179 | }); | 182 | }); |
@@ -618,7 +621,7 @@ function activateFirefoxSocial(node) { | |||
618 | // Keeping the data separated (ie. not in the DOM) so that it's maintainable and diffable. | 621 | // Keeping the data separated (ie. not in the DOM) so that it's maintainable and diffable. |
619 | var data = { | 622 | var data = { |
620 | name: title, | 623 | name: title, |
621 | description: "The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community.", | 624 | description: document.getElementById('translation-delete-link').innerHTML, |
622 | author: "Shaarli", | 625 | author: "Shaarli", |
623 | version: "1.0.0", | 626 | version: "1.0.0", |
624 | 627 | ||
diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html index 685821e3..5dab8e9a 100644 --- a/tpl/default/linklist.html +++ b/tpl/default/linklist.html | |||
@@ -86,7 +86,7 @@ | |||
86 | <div class="pure-g pure-alert pure-alert-success search-result"> | 86 | <div class="pure-g pure-alert pure-alert-success search-result"> |
87 | <div class="pure-u-2-24"></div> | 87 | <div class="pure-u-2-24"></div> |
88 | <div class="pure-u-20-24"> | 88 | <div class="pure-u-20-24"> |
89 | {function="t('%s result', '%s results', $result_count)"} | 89 | {function="sprintf(t('%s result', '%s results', $result_count), $result_count)"} |
90 | {if="!empty($search_term)"} | 90 | {if="!empty($search_term)"} |
91 | {'for'|t} <em><strong>{$search_term}</strong></em> | 91 | {'for'|t} <em><strong>{$search_term}</strong></em> |
92 | {/if} | 92 | {/if} |
@@ -117,6 +117,16 @@ | |||
117 | <div class="pure-g"> | 117 | <div class="pure-g"> |
118 | <div class="pure-u-lg-2-24 pure-u-1-24"></div> | 118 | <div class="pure-u-lg-2-24 pure-u-1-24"></div> |
119 | <div class="pure-u-lg-20-24 pure-u-22-24"> | 119 | <div class="pure-u-lg-20-24 pure-u-22-24"> |
120 | {ignore}Set translation here, for performances{/ignore} | ||
121 | {$strPrivate=t('Private')} | ||
122 | {$strEdit=t('Edit')} | ||
123 | {$strDelete=t('Delete')} | ||
124 | {$strFold=t('Fold')} | ||
125 | {$strEdited=t('Edited: ')} | ||
126 | {$strPermalink=t('Permalink')} | ||
127 | {$strPermalinkLc=t('permalink')} | ||
128 | {$strAddTag=t('Add tag')} | ||
129 | {ignore}End of translations{/ignore} | ||
120 | {loop="links"} | 130 | {loop="links"} |
121 | <div class="anchor" id="{$value.shorturl}"></div> | 131 | <div class="anchor" id="{$value.shorturl}"></div> |
122 | <div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}"> | 132 | <div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}"> |
@@ -125,12 +135,12 @@ | |||
125 | {if="isLoggedIn()"} | 135 | {if="isLoggedIn()"} |
126 | <div class="linklist-item-editbuttons"> | 136 | <div class="linklist-item-editbuttons"> |
127 | {if="$value.private"} | 137 | {if="$value.private"} |
128 | <span class="label label-private">{'Private'|t}</span> | 138 | <span class="label label-private">{$strPrivate}</span> |
129 | {/if} | 139 | {/if} |
130 | <input type="checkbox" class="delete-checkbox" value="{$value.id}"> | 140 | <input type="checkbox" class="delete-checkbox" value="{$value.id}"> |
131 | <!-- FIXME! JS translation --> | 141 | <!-- FIXME! JS translation --> |
132 | <a href="?edit_link={$value.id}" title="{'Edit'|t}"><i class="fa fa-pencil-square-o edit-link"></i></a> | 142 | <a href="?edit_link={$value.id}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link"></i></a> |
133 | <a href="#" title="{'Fold'|t}" class="fold-button"><i class="fa fa-chevron-up"></i></a> | 143 | <a href="#" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up"></i></a> |
134 | </div> | 144 | </div> |
135 | {/if} | 145 | {/if} |
136 | 146 | ||
@@ -164,7 +174,7 @@ | |||
164 | <i class="fa fa-tags"></i> | 174 | <i class="fa fa-tags"></i> |
165 | {$tag_counter=count($value.taglist)} | 175 | {$tag_counter=count($value.taglist)} |
166 | {loop="value.taglist"} | 176 | {loop="value.taglist"} |
167 | <span class="label label-tag" title="Add tag"> | 177 | <span class="label label-tag" title="{$strAddTag}"> |
168 | <a href="?addtag={$value|urlencode}">{$value}</a> | 178 | <a href="?addtag={$value|urlencode}">{$value}</a> |
169 | </span> | 179 | </span> |
170 | {if="$tag_counter - 1 != $counter"}·{/if} | 180 | {if="$tag_counter - 1 != $counter"}·{/if} |
@@ -174,9 +184,9 @@ | |||
174 | 184 | ||
175 | <div class="pure-g"> | 185 | <div class="pure-g"> |
176 | <div class="linklist-item-infos-dateblock pure-u-lg-3-8 pure-u-1"> | 186 | <div class="linklist-item-infos-dateblock pure-u-lg-3-8 pure-u-1"> |
177 | <a href="?{$value.shorturl}" title="{'Permalink'|t}"> | 187 | <a href="?{$value.shorturl}" title="{$strPermalink}"> |
178 | {if="!$hide_timestamps || isLoggedIn()"} | 188 | {if="!$hide_timestamps || isLoggedIn()"} |
179 | {$updated=$value.updated_timestamp ? 'Edited: '. format_date($value.updated) : 'Permalink'} | 189 | {$updated=$value.updated_timestamp ? $strEdited. format_date($value.updated) : $strPermalink} |
180 | <span class="linkdate" title="{$updated}"> | 190 | <span class="linkdate" title="{$updated}"> |
181 | <i class="fa fa-clock-o"></i> | 191 | <i class="fa fa-clock-o"></i> |
182 | {$value.created|format_date} | 192 | {$value.created|format_date} |
@@ -184,7 +194,7 @@ | |||
184 | · | 194 | · |
185 | </span> | 195 | </span> |
186 | {/if} | 196 | {/if} |
187 | {'permalink'|t} | 197 | {$strPermalinkLc} |
188 | </a> | 198 | </a> |
189 | 199 | ||
190 | <div class="pure-u-0 pure-u-lg-visible"> | 200 | <div class="pure-u-0 pure-u-lg-visible"> |
@@ -205,7 +215,7 @@ | |||
205 | </a> | 215 | </a> |
206 | {if="isLoggedIn()"} | 216 | {if="isLoggedIn()"} |
207 | <a href="?delete_link&lf_linkdate={$value.id}&token={$token}" | 217 | <a href="?delete_link&lf_linkdate={$value.id}&token={$token}" |
208 | title="{'Delete'|t}" class="delete-link pure-u-0 pure-u-lg-visible confirm-delete"> | 218 | title="{$strDelete}" class="delete-link pure-u-0 pure-u-lg-visible confirm-delete"> |
209 | <i class="fa fa-trash"></i> | 219 | <i class="fa fa-trash"></i> |
210 | </a> | 220 | </a> |
211 | {/if} | 221 | {/if} |
@@ -221,7 +231,7 @@ | |||
221 | {if="isLoggedIn()"} | 231 | {if="isLoggedIn()"} |
222 | · | 232 | · |
223 | <a href="?delete_link&lf_linkdate={$value.id}&token={$token}" | 233 | <a href="?delete_link&lf_linkdate={$value.id}&token={$token}" |
224 | title="{'Delete'|t}" class="delete-link confirm-delete"> | 234 | title="{$strDelete}" class="delete-link confirm-delete"> |
225 | <i class="fa fa-trash"></i> | 235 | <i class="fa fa-trash"></i> |
226 | </a> | 236 | </a> |
227 | {/if} | 237 | {/if} |
diff --git a/tpl/default/linklist.paging.html b/tpl/default/linklist.paging.html index 41e9fa34..347b3d13 100644 --- a/tpl/default/linklist.paging.html +++ b/tpl/default/linklist.paging.html | |||
@@ -13,7 +13,7 @@ | |||
13 | <a href="?untaggedonly" title="{'Filter untagged links'|t}" | 13 | <a href="?untaggedonly" title="{'Filter untagged links'|t}" |
14 | class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if} | 14 | class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if} |
15 | ><i class="fa fa-tag"></i></a> | 15 | ><i class="fa fa-tag"></i></a> |
16 | <a href="#" class="filter-off fold-all pure-u-lg-0" title="Fold all"> | 16 | <a href="#" class="filter-off fold-all pure-u-lg-0" title="{'Fold all'|t}"> |
17 | <i class="fa fa-chevron-up"></i> | 17 | <i class="fa fa-chevron-up"></i> |
18 | </a> | 18 | </a> |
19 | {loop="$action_plugin"} | 19 | {loop="$action_plugin"} |
@@ -53,7 +53,7 @@ | |||
53 | <form method="GET" class="pure-u-0 pure-u-lg-visible"> | 53 | <form method="GET" class="pure-u-0 pure-u-lg-visible"> |
54 | <input type="text" name="linksperpage" placeholder="133"> | 54 | <input type="text" name="linksperpage" placeholder="133"> |
55 | </form> | 55 | </form> |
56 | <a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" title="Fold all"> | 56 | <a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" title="{'Fold all'|t}"> |
57 | <i class="fa fa-chevron-up"></i> | 57 | <i class="fa fa-chevron-up"></i> |
58 | </a> | 58 | </a> |
59 | </div> | 59 | </div> |
diff --git a/tpl/default/page.footer.html b/tpl/default/page.footer.html index 54b16e8a..659e8c7f 100644 --- a/tpl/default/page.footer.html +++ b/tpl/default/page.footer.html | |||
@@ -8,8 +8,8 @@ | |||
8 | {$version} | 8 | {$version} |
9 | {/if} | 9 | {/if} |
10 | · | 10 | · |
11 | The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community · | 11 | {'The personal, minimalist, super-fast, database free, bookmarking service'|t} {'by the Shaarli community'|t} · |
12 | <a href="doc/html/index.html" rel="nofollow">Documentation</a> | 12 | <a href="doc/html/index.html" rel="nofollow">{'Documentation'|t}</a> |
13 | {loop="$plugins_footer.text"} | 13 | {loop="$plugins_footer.text"} |
14 | {$value} | 14 | {$value} |
15 | {/loop} | 15 | {/loop} |
@@ -27,6 +27,17 @@ | |||
27 | <script src="{$value}#"></script> | 27 | <script src="{$value}#"></script> |
28 | {/loop} | 28 | {/loop} |
29 | 29 | ||
30 | <div id="js-translations" class="hidden"> | ||
31 | <span id="translation-fold">{'Fold'|t}</span> | ||
32 | <span id="translation-fold-all">{'Fold all'|t}</span> | ||
33 | <span id="translation-expand">{'Expand'|t}</span> | ||
34 | <span id="translation-expand-all">{'Expand all'|t}</span> | ||
35 | <span id="translation-delete-link">{'Are you sure you want to delete this link?'|t}</span> | ||
36 | <span id="translation-shaarli-desc"> | ||
37 | {'The personal, minimalist, super-fast, database free, bookmarking service'|t} {'by the Shaarli community'|t} | ||
38 | </span> | ||
39 | </div> | ||
40 | |||
30 | <script src="js/shaarli.js?v={$version_hash}"></script> | 41 | <script src="js/shaarli.js?v={$version_hash}"></script> |
31 | <script src="inc/awesomplete.js?v={$version_hash}#"></script> | 42 | <script src="inc/awesomplete.js?v={$version_hash}#"></script> |
32 | <script src="inc/awesomplete-multiple-tags.js?v={$version_hash}#"></script> | 43 | <script src="inc/awesomplete-multiple-tags.js?v={$version_hash}#"></script> |
diff --git a/tpl/default/pluginsadmin.html b/tpl/default/pluginsadmin.html index 5cc1802f..717cb517 100644 --- a/tpl/default/pluginsadmin.html +++ b/tpl/default/pluginsadmin.html | |||
@@ -116,8 +116,8 @@ | |||
116 | </section> | 116 | </section> |
117 | 117 | ||
118 | <div class="center more"> | 118 | <div class="center more"> |
119 | More plugins available | 119 | {"More plugins available"|t} |
120 | <a href="doc/Community-&-Related-software.html#third-party-plugins">in the documentation</a>. | 120 | <a href="doc/Community-&-Related-software.html#third-party-plugins">{"in the documentation"|t}</a>. |
121 | </div> | 121 | </div> |
122 | <div class="center"> | 122 | <div class="center"> |
123 | <input type="submit" value="{'Save'|t}" name="save"> | 123 | <input type="submit" value="{'Save'|t}" name="save"> |