Merge pull request #871 from ArthurHoaro/feature/translation
Shaarli's translation
This commit is contained in:
commit
d8acf85504
68 changed files with 2744 additions and 280 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -22,6 +22,7 @@ Dockerfile text
|
|||
*.ttf binary
|
||||
*.min.css binary
|
||||
*.min.js binary
|
||||
*.mo binary
|
||||
|
||||
# Exclude from Git archives
|
||||
.editorconfig export-ignore
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,6 +18,7 @@ vendor/
|
|||
# Release archives
|
||||
*.tar.gz
|
||||
*.zip
|
||||
inc/languages/*/LC_MESSAGES/shaarli.mo
|
||||
|
||||
# Development and test resources
|
||||
coverage
|
||||
|
|
|
@ -13,6 +13,8 @@ install:
|
|||
- composer self-update
|
||||
- composer install --prefer-dist
|
||||
- locale -a
|
||||
before_script:
|
||||
- PATH=${PATH//:\.\/node_modules\/\.bin/}
|
||||
script:
|
||||
- make clean
|
||||
- make check_permissions
|
||||
|
|
17
Makefile
17
Makefile
|
@ -130,12 +130,12 @@ check_permissions:
|
|||
# See phpunit.xml for configuration
|
||||
# https://phpunit.de/manual/current/en/appendixes.configuration.html
|
||||
##
|
||||
test:
|
||||
test: translate
|
||||
@echo "-------"
|
||||
@echo "PHPUNIT"
|
||||
@echo "-------"
|
||||
@mkdir -p sandbox coverage
|
||||
@$(BIN)/phpunit --coverage-php coverage/main.cov --testsuite unit-tests
|
||||
@$(BIN)/phpunit --coverage-php coverage/main.cov --bootstrap tests/bootstrap.php --testsuite unit-tests
|
||||
|
||||
locale_test_%:
|
||||
@UT_LOCALE=$*.utf8 \
|
||||
|
@ -168,15 +168,15 @@ composer_dependencies: clean
|
|||
composer install --no-dev --prefer-dist
|
||||
find vendor/ -name ".git" -type d -exec rm -rf {} +
|
||||
|
||||
### generate a release tarball and include 3rd-party dependencies
|
||||
release_tar: composer_dependencies htmldoc
|
||||
### generate a release tarball and include 3rd-party dependencies and translations
|
||||
release_tar: composer_dependencies htmldoc translate
|
||||
git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).tar HEAD
|
||||
tar rvf $(ARCHIVE_VERSION).tar --transform "s|^vendor|$(ARCHIVE_PREFIX)vendor|" vendor/
|
||||
tar rvf $(ARCHIVE_VERSION).tar --transform "s|^doc/html|$(ARCHIVE_PREFIX)doc/html|" doc/html/
|
||||
gzip $(ARCHIVE_VERSION).tar
|
||||
|
||||
### generate a release zip and include 3rd-party dependencies
|
||||
release_zip: composer_dependencies htmldoc
|
||||
### generate a release zip and include 3rd-party dependencies and translations
|
||||
release_zip: composer_dependencies htmldoc translate
|
||||
git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).zip -9 HEAD
|
||||
mkdir -p $(ARCHIVE_PREFIX)/{doc,vendor}
|
||||
rsync -a doc/html/ $(ARCHIVE_PREFIX)doc/html/
|
||||
|
@ -213,3 +213,8 @@ htmldoc:
|
|||
mkdocs build'
|
||||
find doc/html/ -type f -exec chmod a-x '{}' \;
|
||||
rm -r venv
|
||||
|
||||
|
||||
### Generate Shaarli's translation compiled file (.mo)
|
||||
translate:
|
||||
@find inc/languages/ -name shaarli.po -execdir msgfmt shaarli.po -o shaarli.mo \;
|
|
@ -149,12 +149,13 @@ class ApplicationUtils
|
|||
public static function checkPHPVersion($minVersion, $curVersion)
|
||||
{
|
||||
if (version_compare($curVersion, $minVersion) < 0) {
|
||||
throw new Exception(
|
||||
$msg = t(
|
||||
'Your PHP version is obsolete!'
|
||||
.' Shaarli requires at least PHP '.$minVersion.', and thus cannot run.'
|
||||
.' Your PHP version has known security vulnerabilities and should be'
|
||||
.' updated as soon as possible.'
|
||||
. ' Shaarli requires at least PHP %s, and thus cannot run.'
|
||||
. ' Your PHP version has known security vulnerabilities and should be'
|
||||
. ' updated as soon as possible.'
|
||||
);
|
||||
throw new Exception(sprintf($msg, $minVersion));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +180,7 @@ class ApplicationUtils
|
|||
$rainTplDir.'/'.$conf->get('resource.theme'),
|
||||
) as $path) {
|
||||
if (! is_readable(realpath($path))) {
|
||||
$errors[] = '"'.$path.'" directory is not readable';
|
||||
$errors[] = '"'.$path.'" '. t('directory is not readable');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,10 +192,10 @@ class ApplicationUtils
|
|||
$conf->get('resource.raintpl_tmp'),
|
||||
) as $path) {
|
||||
if (! is_readable(realpath($path))) {
|
||||
$errors[] = '"'.$path.'" directory is not readable';
|
||||
$errors[] = '"'.$path.'" '. t('directory is not readable');
|
||||
}
|
||||
if (! is_writable(realpath($path))) {
|
||||
$errors[] = '"'.$path.'" directory is not writable';
|
||||
$errors[] = '"'.$path.'" '. t('directory is not writable');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,10 +213,10 @@ class ApplicationUtils
|
|||
}
|
||||
|
||||
if (! is_readable(realpath($path))) {
|
||||
$errors[] = '"'.$path.'" file is not readable';
|
||||
$errors[] = '"'.$path.'" '. t('file is not readable');
|
||||
}
|
||||
if (! is_writable(realpath($path))) {
|
||||
$errors[] = '"'.$path.'" file is not writable';
|
||||
$errors[] = '"'.$path.'" '. t('file is not writable');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
function purgeCachedPages($pageCacheDir)
|
||||
{
|
||||
if (! is_dir($pageCacheDir)) {
|
||||
$error = 'Cannot purge '.$pageCacheDir.': no directory';
|
||||
$error = sprintf(t('Cannot purge %s: no directory'), $pageCacheDir);
|
||||
error_log($error);
|
||||
return $error;
|
||||
}
|
||||
|
|
|
@ -148,9 +148,9 @@ class FeedBuilder
|
|||
$link['url'] = $pageaddr . $link['url'];
|
||||
}
|
||||
if ($this->usePermalinks === true) {
|
||||
$permalink = '<a href="'. $link['url'] .'" title="Direct link">Direct link</a>';
|
||||
$permalink = '<a href="'. $link['url'] .'" title="'. t('Direct link') .'">'. t('Direct link') .'</a>';
|
||||
} else {
|
||||
$permalink = '<a href="'. $link['guid'] .'" title="Permalink">Permalink</a>';
|
||||
$permalink = '<a href="'. $link['guid'] .'" title="'. t('Permalink') .'">'. t('Permalink') .'</a>';
|
||||
}
|
||||
$link['description'] = format_description($link['description'], '', $pageaddr);
|
||||
$link['description'] .= PHP_EOL .'<br>— '. $permalink;
|
||||
|
|
|
@ -171,7 +171,7 @@ class History
|
|||
}
|
||||
|
||||
if (! is_writable($this->historyFilePath)) {
|
||||
throw new Exception('History file isn\'t readable or writable');
|
||||
throw new Exception(t('History file isn\'t readable or writable'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ class History
|
|||
{
|
||||
$this->history = FileUtils::readFlatDB($this->historyFilePath, []);
|
||||
if ($this->history === false) {
|
||||
throw new Exception('Could not parse history file');
|
||||
throw new Exception(t('Could not parse history file'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace Shaarli;
|
||||
|
||||
use Gettext\GettextTranslator;
|
||||
use Gettext\Merge;
|
||||
use Gettext\Translations;
|
||||
use Gettext\Translator;
|
||||
use Gettext\TranslatorInterface;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
|
||||
/**
|
||||
* Wrapper function for translation which match the API
|
||||
* of gettext()/_() and ngettext().
|
||||
* Class Languages
|
||||
*
|
||||
* Not doing translation for now.
|
||||
* Load Shaarli translations using 'gettext/gettext'.
|
||||
* This class allows to either use PHP gettext extension, or a PHP implementation of gettext,
|
||||
* with a fixed language, or dynamically using autoLocale().
|
||||
*
|
||||
* @param string $text Text to translate.
|
||||
* @param string $nText The plural message ID.
|
||||
* @param int $nb The number of items for plural forms.
|
||||
* Translation files PO/MO files follow gettext standard and must be placed under:
|
||||
* <translation path>/<language>/LC_MESSAGES/<domain>.[po|mo]
|
||||
*
|
||||
* @return String Text translated.
|
||||
* Pros/cons:
|
||||
* - gettext extension is faster
|
||||
* - gettext is very system dependent (PHP extension, the locale must be installed, and web server reloaded)
|
||||
*
|
||||
* Settings:
|
||||
* - translation.mode:
|
||||
* - auto: use default setting (PHP implementation)
|
||||
* - php: use PHP implementation
|
||||
* - gettext: use gettext wrapper
|
||||
* - translation.language:
|
||||
* - auto: use autoLocale() and the language change according to user HTTP headers
|
||||
* - fixed language: e.g. 'fr'
|
||||
* - translation.extensions:
|
||||
* - domain => translation_path: allow plugins and themes to extend the defaut extension
|
||||
* The domain must be unique, and translation path must be relative, and contains the tree mentioned above.
|
||||
*
|
||||
* @package Shaarli
|
||||
*/
|
||||
function t($text, $nText = '', $nb = 0) {
|
||||
if (empty($nText)) {
|
||||
return $text;
|
||||
class Languages
|
||||
{
|
||||
/**
|
||||
* Core translations domain
|
||||
*/
|
||||
const DEFAULT_DOMAIN = 'shaarli';
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* @var ConfigManager
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* Languages constructor.
|
||||
*
|
||||
* @param string $language lang determined by autoLocale(), can be overridden.
|
||||
* @param ConfigManager $conf instance.
|
||||
*/
|
||||
public function __construct($language, $conf)
|
||||
{
|
||||
$this->conf = $conf;
|
||||
$confLanguage = $this->conf->get('translation.language', 'auto');
|
||||
if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) {
|
||||
$this->language = substr($language, 0, 5);
|
||||
} else {
|
||||
$this->language = $confLanguage;
|
||||
}
|
||||
|
||||
if (! extension_loaded('gettext')
|
||||
|| in_array($this->conf->get('translation.mode', 'auto'), ['auto', 'php'])
|
||||
) {
|
||||
$this->initPhpTranslator();
|
||||
} else {
|
||||
$this->initGettextTranslator();
|
||||
}
|
||||
|
||||
// Register default functions (e.g. '__()') to use our Translator
|
||||
$this->translator->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the translator using php gettext extension (gettext dependency act as a wrapper).
|
||||
*/
|
||||
protected function initGettextTranslator ()
|
||||
{
|
||||
$this->translator = new GettextTranslator();
|
||||
$this->translator->setLanguage($this->language);
|
||||
$this->translator->loadDomain(self::DEFAULT_DOMAIN, 'inc/languages');
|
||||
|
||||
foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
|
||||
if ($domain !== self::DEFAULT_DOMAIN) {
|
||||
$this->translator->loadDomain($domain, $translationPath, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the translator using a PHP implementation of gettext.
|
||||
*
|
||||
* Note that if language po file doesn't exist, errors are ignored (e.g. not installed language).
|
||||
*/
|
||||
protected function initPhpTranslator()
|
||||
{
|
||||
$this->translator = new Translator();
|
||||
$translations = new Translations();
|
||||
// Core translations
|
||||
try {
|
||||
/** @var Translations $translations */
|
||||
$translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
|
||||
$translations->setDomain('shaarli');
|
||||
$this->translator->loadTranslations($translations);
|
||||
} catch (\InvalidArgumentException $e) {}
|
||||
|
||||
|
||||
// Extension translations (plugins, themes, etc.).
|
||||
foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
|
||||
if ($domain === self::DEFAULT_DOMAIN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var Translations $extension */
|
||||
$extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po');
|
||||
$extension->setDomain($domain);
|
||||
$this->translator->loadTranslations($extension);
|
||||
} catch (\InvalidArgumentException $e) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a language string is valid.
|
||||
*
|
||||
* @param string $language e.g. 'fr' or 'en_US'
|
||||
*
|
||||
* @return bool true if valid, false otherwise
|
||||
*/
|
||||
protected function isValidLanguage($language)
|
||||
{
|
||||
return preg_match('/^[a-z]{2}(_[A-Z]{2})?/', $language) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of available languages for Shaarli.
|
||||
*
|
||||
* @return array List of available languages, with their label.
|
||||
*/
|
||||
public static function getAvailableLanguages()
|
||||
{
|
||||
return [
|
||||
'auto' => t('Automatic'),
|
||||
'en' => t('English'),
|
||||
'fr' => t('French'),
|
||||
];
|
||||
}
|
||||
$actualForm = $nb > 1 ? $nText : $text;
|
||||
return sprintf($actualForm, $nb);
|
||||
}
|
||||
|
|
|
@ -133,16 +133,16 @@ class LinkDB implements Iterator, Countable, ArrayAccess
|
|||
{
|
||||
// TODO: use exceptions instead of "die"
|
||||
if (!$this->loggedIn) {
|
||||
die('You are not authorized to add a link.');
|
||||
die(t('You are not authorized to add a link.'));
|
||||
}
|
||||
if (!isset($value['id']) || empty($value['url'])) {
|
||||
die('Internal Error: A link should always have an id and URL.');
|
||||
die(t('Internal Error: A link should always have an id and URL.'));
|
||||
}
|
||||
if (($offset !== null && ! is_int($offset)) || ! is_int($value['id'])) {
|
||||
die('You must specify an integer as a key.');
|
||||
die(t('You must specify an integer as a key.'));
|
||||
}
|
||||
if ($offset !== null && $offset !== $value['id']) {
|
||||
die('Array offset and link ID must be equal.');
|
||||
die(t('Array offset and link ID must be equal.'));
|
||||
}
|
||||
|
||||
// If the link exists, we reuse the real offset, otherwise new entry
|
||||
|
@ -248,13 +248,13 @@ class LinkDB implements Iterator, Countable, ArrayAccess
|
|||
$this->links = array();
|
||||
$link = array(
|
||||
'id' => 1,
|
||||
'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone',
|
||||
'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'),
|
||||
'url'=>'https://shaarli.readthedocs.io',
|
||||
'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login.
|
||||
'description'=>t('Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login.
|
||||
|
||||
To learn how to use Shaarli, consult the link "Help/documentation" at the bottom of this page.
|
||||
To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page.
|
||||
|
||||
You use the community supported version of the original Shaarli project, by Sebastien Sauvage.',
|
||||
You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'),
|
||||
'private'=>0,
|
||||
'created'=> new DateTime(),
|
||||
'tags'=>'opensource software'
|
||||
|
@ -264,9 +264,9 @@ You use the community supported version of the original Shaarli project, by Seba
|
|||
|
||||
$link = array(
|
||||
'id' => 0,
|
||||
'title'=>'My secret stuff... - Pastebin.com',
|
||||
'title'=> t('My secret stuff... - Pastebin.com'),
|
||||
'url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=',
|
||||
'description'=>'Shhhh! I\'m a private link only YOU can see. You can delete me too.',
|
||||
'description'=> t('Shhhh! I\'m a private link only YOU can see. You can delete me too.'),
|
||||
'private'=>1,
|
||||
'created'=> new DateTime('1 minute ago'),
|
||||
'tags'=>'secretstuff',
|
||||
|
|
|
@ -444,5 +444,11 @@ class LinkFilter
|
|||
|
||||
class LinkNotFoundException extends Exception
|
||||
{
|
||||
protected $message = 'The link you are trying to reach does not exist or has been deleted.';
|
||||
/**
|
||||
* LinkNotFoundException constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = t('The link you are trying to reach does not exist or has been deleted.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,11 +32,10 @@ class NetscapeBookmarkUtils
|
|||
{
|
||||
// see tpl/export.html for possible values
|
||||
if (! in_array($selection, array('all', 'public', 'private'))) {
|
||||
throw new Exception('Invalid export selection: "'.$selection.'"');
|
||||
throw new Exception(t('Invalid export selection:') .' "'.$selection.'"');
|
||||
}
|
||||
|
||||
$bookmarkLinks = array();
|
||||
|
||||
foreach ($linkDb as $link) {
|
||||
if ($link['private'] != 0 && $selection == 'public') {
|
||||
continue;
|
||||
|
@ -79,14 +78,14 @@ class NetscapeBookmarkUtils
|
|||
$duration=0
|
||||
)
|
||||
{
|
||||
$status = 'File '.$filename.' ('.$filesize.' bytes) ';
|
||||
$status = sprintf(t('File %s (%d bytes) '), $filename, $filesize);
|
||||
if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) {
|
||||
$status .= 'has an unknown file format. Nothing was imported.';
|
||||
$status .= t('has an unknown file format. Nothing was imported.');
|
||||
} else {
|
||||
$status .= 'was successfully processed in '. $duration .' seconds: ';
|
||||
$status .= $importCount.' links imported, ';
|
||||
$status .= $overwriteCount.' links overwritten, ';
|
||||
$status .= $skipCount.' links skipped.';
|
||||
$status .= vsprintf(
|
||||
t('was successfully processed in %d seconds: %d links imported, %d links overwritten, %d links skipped.'),
|
||||
[$duration, $importCount, $overwriteCount, $skipCount]
|
||||
);
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
|
|
@ -159,9 +159,12 @@ class PageBuilder
|
|||
*
|
||||
* @param string $message A messate to display what is not found
|
||||
*/
|
||||
public function render404($message = 'The page you are trying to reach does not exist or has been deleted.')
|
||||
public function render404($message = '')
|
||||
{
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
|
||||
if (empty($message)) {
|
||||
$message = t('The page you are trying to reach does not exist or has been deleted.');
|
||||
}
|
||||
header($_SERVER['SERVER_PROTOCOL'] .' '. t('404 Not Found'));
|
||||
$this->tpl->assign('error_message', $message);
|
||||
$this->renderPage('404');
|
||||
}
|
||||
|
|
|
@ -188,6 +188,9 @@ class PluginManager
|
|||
$metaData[$plugin] = parse_ini_file($metaFile);
|
||||
$metaData[$plugin]['order'] = array_search($plugin, $this->authorizedPlugins);
|
||||
|
||||
if (isset($metaData[$plugin]['description'])) {
|
||||
$metaData[$plugin]['description'] = t($metaData[$plugin]['description']);
|
||||
}
|
||||
// Read parameters and format them into an array.
|
||||
if (isset($metaData[$plugin]['parameters'])) {
|
||||
$params = explode(';', $metaData[$plugin]['parameters']);
|
||||
|
@ -203,7 +206,7 @@ class PluginManager
|
|||
$metaData[$plugin]['parameters'][$param]['value'] = '';
|
||||
// Optional parameter description in parameter.PARAM_NAME=
|
||||
if (isset($metaData[$plugin]['parameter.'. $param])) {
|
||||
$metaData[$plugin]['parameters'][$param]['desc'] = $metaData[$plugin]['parameter.'. $param];
|
||||
$metaData[$plugin]['parameters'][$param]['desc'] = t($metaData[$plugin]['parameter.'. $param]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -237,6 +240,6 @@ class PluginFileNotFoundException extends Exception
|
|||
*/
|
||||
public function __construct($pluginName)
|
||||
{
|
||||
$this->message = 'Plugin "'. $pluginName .'" files not found.';
|
||||
$this->message = sprintf(t('Plugin "%s" files not found.'), $pluginName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ class Updater
|
|||
}
|
||||
|
||||
if ($this->methods === null) {
|
||||
throw new UpdaterException('Couldn\'t retrieve Updater class methods.');
|
||||
throw new UpdaterException(t('Couldn\'t retrieve Updater class methods.'));
|
||||
}
|
||||
|
||||
foreach ($this->methods as $method) {
|
||||
|
@ -482,7 +482,7 @@ class UpdaterException extends Exception
|
|||
}
|
||||
|
||||
if (! empty($this->method)) {
|
||||
$out .= 'An error occurred while running the update '. $this->method . PHP_EOL;
|
||||
$out .= t('An error occurred while running the update ') . $this->method . PHP_EOL;
|
||||
}
|
||||
|
||||
if (! empty($this->previous)) {
|
||||
|
@ -522,11 +522,11 @@ function read_updates_file($updatesFilepath)
|
|||
function write_updates_file($updatesFilepath, $updates)
|
||||
{
|
||||
if (empty($updatesFilepath)) {
|
||||
throw new Exception('Updates file path is not set, can\'t write updates.');
|
||||
throw new Exception(t('Updates file path is not set, can\'t write updates.'));
|
||||
}
|
||||
|
||||
$res = file_put_contents($updatesFilepath, implode(';', $updates));
|
||||
if ($res === false) {
|
||||
throw new Exception('Unable to write updates in '. $updatesFilepath . '.');
|
||||
throw new Exception(t('Unable to write updates in '. $updatesFilepath . '.'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -452,7 +452,7 @@ function get_max_upload_size($limitPost, $limitUpload, $format = true)
|
|||
*/
|
||||
function alphabetical_sort(&$data, $reverse = false, $byKeys = false)
|
||||
{
|
||||
$callback = function($a, $b) use ($reverse) {
|
||||
$callback = function ($a, $b) use ($reverse) {
|
||||
// Collator is part of PHP intl.
|
||||
if (class_exists('Collator')) {
|
||||
$collator = new Collator(setlocale(LC_COLLATE, 0));
|
||||
|
@ -470,3 +470,18 @@ function alphabetical_sort(&$data, $reverse = false, $byKeys = false)
|
|||
usort($data, $callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function for translation which match the API
|
||||
* of gettext()/_() and ngettext().
|
||||
*
|
||||
* @param string $text Text to translate.
|
||||
* @param string $nText The plural message ID.
|
||||
* @param int $nb The number of items for plural forms.
|
||||
* @param string $domain The domain where the translation is stored (default: shaarli).
|
||||
*
|
||||
* @return string Text translated.
|
||||
*/
|
||||
function t($text, $nText = '', $nb = 1, $domain = 'shaarli') {
|
||||
return dn__($domain, $text, $nText, $nb);
|
||||
}
|
||||
|
|
|
@ -22,10 +22,15 @@ class ConfigJson implements ConfigIO
|
|||
$data = json_decode($data, true);
|
||||
if ($data === null) {
|
||||
$errorCode = json_last_error();
|
||||
$error = 'An error occurred while parsing JSON configuration file ('. $filepath .'): error code #';
|
||||
$error .= $errorCode. '<br>➜ <code>' . json_last_error_msg() .'</code>';
|
||||
$error = sprintf(
|
||||
'An error occurred while parsing JSON configuration file (%s): error code #%d',
|
||||
$filepath,
|
||||
$errorCode
|
||||
);
|
||||
$error .= '<br>➜ <code>' . json_last_error_msg() .'</code>';
|
||||
if ($errorCode === JSON_ERROR_SYNTAX) {
|
||||
$error .= '<br>Please check your JSON syntax (without PHP comment tags) using a JSON lint tool such as ';
|
||||
$error .= '<br>';
|
||||
$error .= 'Please check your JSON syntax (without PHP comment tags) using a JSON lint tool such as ';
|
||||
$error .= '<a href="http://jsonlint.com/">jsonlint.com</a>.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
|
@ -44,8 +49,8 @@ class ConfigJson implements ConfigIO
|
|||
if (!file_put_contents($filepath, $data)) {
|
||||
throw new \IOException(
|
||||
$filepath,
|
||||
'Shaarli could not create the config file.
|
||||
Please make sure Shaarli has the right to write in the folder is it installed in.'
|
||||
t('Shaarli could not create the config file. '.
|
||||
'Please make sure Shaarli has the right to write in the folder is it installed in.')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ class ConfigManager
|
|||
public function set($setting, $value, $write = false, $isLoggedIn = false)
|
||||
{
|
||||
if (empty($setting) || ! is_string($setting)) {
|
||||
throw new \Exception('Invalid setting key parameter. String expected, got: '. gettype($setting));
|
||||
throw new \Exception(t('Invalid setting key parameter. String expected, got: '). gettype($setting));
|
||||
}
|
||||
|
||||
// During the ConfigIO transition, map legacy settings to the new ones.
|
||||
|
@ -339,6 +339,10 @@ class ConfigManager
|
|||
$this->setEmpty('redirector.url', '');
|
||||
$this->setEmpty('redirector.encode_url', true);
|
||||
|
||||
$this->setEmpty('translation.language', 'auto');
|
||||
$this->setEmpty('translation.mode', 'php');
|
||||
$this->setEmpty('translation.extensions', []);
|
||||
|
||||
$this->setEmpty('plugins', array());
|
||||
}
|
||||
|
||||
|
|
|
@ -118,8 +118,8 @@ class ConfigPhp implements ConfigIO
|
|||
) {
|
||||
throw new \IOException(
|
||||
$filepath,
|
||||
'Shaarli could not create the config file.
|
||||
Please make sure Shaarli has the right to write in the folder is it installed in.'
|
||||
t('Shaarli could not create the config file. '.
|
||||
'Please make sure Shaarli has the right to write in the folder is it installed in.')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,6 @@ class MissingFieldConfigException extends \Exception
|
|||
public function __construct($field)
|
||||
{
|
||||
$this->field = $field;
|
||||
$this->message = 'Configuration value is required for '. $this->field;
|
||||
$this->message = sprintf(t('Configuration value is required for %s'), $this->field);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@ class PluginConfigOrderException extends \Exception
|
|||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'An error occurred while trying to save plugins loading order.';
|
||||
$this->message = t('An error occurred while trying to save plugins loading order.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@ class UnauthorizedConfigException extends \Exception
|
|||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'You are not authorized to alter config.';
|
||||
$this->message = t('You are not authorized to alter config.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ class IOException extends Exception
|
|||
public function __construct($path, $message = '')
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->message = empty($message) ? 'Error accessing' : $message;
|
||||
$this->message = empty($message) ? t('Error accessing') : $message;
|
||||
$this->message .= ' "' . $this->path .'"';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
"shaarli/netscape-bookmark-parser": "^2.0",
|
||||
"erusev/parsedown": "1.6",
|
||||
"slim/slim": "^3.0",
|
||||
"pubsubhubbub/publisher": "dev-master"
|
||||
"pubsubhubbub/publisher": "dev-master",
|
||||
"gettext/gettext": "^4.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpmd/phpmd" : "@stable",
|
||||
|
|
249
composer.lock
generated
249
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "68beedbfa104c788029b079800cfd6e8",
|
||||
"content-hash": "13b7e1e474fe9264b098ba86face0feb",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
|
@ -76,6 +76,129 @@
|
|||
],
|
||||
"time": "2015-10-04T16:44:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gettext/gettext",
|
||||
"version": "v4.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/oscarotero/Gettext.git",
|
||||
"reference": "4f57f004635cc6311a20815ebfdc0757cb337113"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/oscarotero/Gettext/zipball/4f57f004635cc6311a20815ebfdc0757cb337113",
|
||||
"reference": "4f57f004635cc6311a20815ebfdc0757cb337113",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"gettext/languages": "^2.3",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/view": "*",
|
||||
"phpunit/phpunit": "^4.8|^5.7",
|
||||
"squizlabs/php_codesniffer": "^3.0",
|
||||
"symfony/yaml": "~2",
|
||||
"twig/extensions": "*",
|
||||
"twig/twig": "^1.31|^2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/view": "Is necessary if you want to use the Blade extractor",
|
||||
"symfony/yaml": "Is necessary if you want to use the Yaml extractor/generator",
|
||||
"twig/extensions": "Is necessary if you want to use the Twig extractor",
|
||||
"twig/twig": "Is necessary if you want to use the Twig extractor"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Gettext\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Oscar Otero",
|
||||
"email": "oom@oscarotero.com",
|
||||
"homepage": "http://oscarotero.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP gettext manager",
|
||||
"homepage": "https://github.com/oscarotero/Gettext",
|
||||
"keywords": [
|
||||
"JS",
|
||||
"gettext",
|
||||
"i18n",
|
||||
"mo",
|
||||
"po",
|
||||
"translation"
|
||||
],
|
||||
"time": "2017-08-09T16:59:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gettext/languages",
|
||||
"version": "2.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mlocati/cldr-to-gettext-plural-rules.git",
|
||||
"reference": "49c39e51569963cc917a924b489e7025bfb9d8c7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/49c39e51569963cc917a924b489e7025bfb9d8c7",
|
||||
"reference": "49c39e51569963cc917a924b489e7025bfb9d8c7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4"
|
||||
},
|
||||
"bin": [
|
||||
"bin/export-plural-rules",
|
||||
"bin/export-plural-rules.php"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Gettext\\Languages\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michele Locati",
|
||||
"email": "mlocati@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "gettext languages with plural rules",
|
||||
"homepage": "https://github.com/mlocati/cldr-to-gettext-plural-rules",
|
||||
"keywords": [
|
||||
"cldr",
|
||||
"i18n",
|
||||
"internationalization",
|
||||
"l10n",
|
||||
"language",
|
||||
"languages",
|
||||
"localization",
|
||||
"php",
|
||||
"plural",
|
||||
"plural rules",
|
||||
"plurals",
|
||||
"translate",
|
||||
"translations",
|
||||
"unicode"
|
||||
],
|
||||
"time": "2017-03-23T17:02:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "katzgrau/klogger",
|
||||
"version": "1.2.1",
|
||||
|
@ -371,12 +494,12 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pubsubhubbub/php-publisher.git",
|
||||
"reference": "a5d6a0e1cc9d49101c3904480e5b06cbb8addba7"
|
||||
"reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/a5d6a0e1cc9d49101c3904480e5b06cbb8addba7",
|
||||
"reference": "a5d6a0e1cc9d49101c3904480e5b06cbb8addba7",
|
||||
"url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/0d224daebd504ab61c22fee4db58f8d1fc18945f",
|
||||
"reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -406,7 +529,7 @@
|
|||
"publishers",
|
||||
"pubsubhubbub"
|
||||
],
|
||||
"time": "2016-11-15T06:24:01+00:00"
|
||||
"time": "2017-10-08T10:59:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "shaarli/netscape-bookmark-parser",
|
||||
|
@ -632,16 +755,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "1.0",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
|
||||
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
|
||||
"reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
|
||||
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
|
||||
"reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -682,20 +805,20 @@
|
|||
"reflection",
|
||||
"static analysis"
|
||||
],
|
||||
"time": "2015-12-27T11:43:31+00:00"
|
||||
"time": "2017-09-11T18:02:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "183824db76118b9dddffc7e522b91fa175f75119"
|
||||
"reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/183824db76118b9dddffc7e522b91fa175f75119",
|
||||
"reference": "183824db76118b9dddffc7e522b91fa175f75119",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157",
|
||||
"reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -727,7 +850,7 @@
|
|||
}
|
||||
],
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"time": "2017-08-04T20:55:59+00:00"
|
||||
"time": "2017-08-08T06:39:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
|
@ -844,22 +967,22 @@
|
|||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.7.0",
|
||||
"version": "v1.7.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "93d39f1f7f9326d746203c7c056f300f7f126073"
|
||||
"reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073",
|
||||
"reference": "93d39f1f7f9326d746203c7c056f300f7f126073",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
|
||||
"reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": "^5.3|^7.0",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
|
||||
"sebastian/comparator": "^1.1|^2.0",
|
||||
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
|
||||
},
|
||||
|
@ -870,7 +993,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.6.x-dev"
|
||||
"dev-master": "1.7.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -903,7 +1026,7 @@
|
|||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2017-03-02T20:05:34+00:00"
|
||||
"time": "2017-09-04T11:05:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -1875,20 +1998,20 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v3.3.6",
|
||||
"version": "v3.3.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "54ee12b0dd60f294132cabae6f5da9573d2e5297"
|
||||
"reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/54ee12b0dd60f294132cabae6f5da9573d2e5297",
|
||||
"reference": "54ee12b0dd60f294132cabae6f5da9573d2e5297",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd",
|
||||
"reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"symfony/filesystem": "~2.8|~3.0"
|
||||
},
|
||||
"conflict": {
|
||||
|
@ -1933,20 +2056,20 @@
|
|||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-07-19T07:37:29+00:00"
|
||||
"time": "2017-10-04T18:56:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.8.26",
|
||||
"version": "v2.8.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "32a3c6b3398de5db8ed381f4ef92970c59c2fcdd"
|
||||
"reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/32a3c6b3398de5db8ed381f4ef92970c59c2fcdd",
|
||||
"reference": "32a3c6b3398de5db8ed381f4ef92970c59c2fcdd",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
|
||||
"reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1994,7 +2117,7 @@
|
|||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-07-29T21:26:04+00:00"
|
||||
"time": "2017-10-01T21:00:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
|
@ -2055,20 +2178,20 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v3.3.6",
|
||||
"version": "v3.3.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "8d70987f991481e809c63681ffe8ce3f3fde68a0"
|
||||
"reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8d70987f991481e809c63681ffe8ce3f3fde68a0",
|
||||
"reference": "8d70987f991481e809c63681ffe8ce3f3fde68a0",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1",
|
||||
"reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"conflict": {
|
||||
|
@ -2121,24 +2244,24 @@
|
|||
],
|
||||
"description": "Symfony DependencyInjection Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-07-28T15:27:31+00:00"
|
||||
"time": "2017-10-04T17:15:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v3.3.6",
|
||||
"version": "v3.3.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "427987eb4eed764c3b6e38d52a0f87989e010676"
|
||||
"reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/427987eb4eed764c3b6e38d52a0f87989e010676",
|
||||
"reference": "427987eb4eed764c3b6e38d52a0f87989e010676",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1",
|
||||
"reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
"php": "^5.5.9|>=7.0.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -2170,24 +2293,24 @@
|
|||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-07-11T07:17:58+00:00"
|
||||
"time": "2017-10-03T13:33:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v3.3.6",
|
||||
"version": "v3.3.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "baea7f66d30854ad32988c11a09d7ffd485810c4"
|
||||
"reference": "773e19a491d97926f236942484cb541560ce862d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/baea7f66d30854ad32988c11a09d7ffd485810c4",
|
||||
"reference": "baea7f66d30854ad32988c11a09d7ffd485810c4",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d",
|
||||
"reference": "773e19a491d97926f236942484cb541560ce862d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
"php": "^5.5.9|>=7.0.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -2219,20 +2342,20 @@
|
|||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-06-01T21:01:25+00:00"
|
||||
"time": "2017-10-02T06:42:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.4.0",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "f29dca382a6485c3cbe6379f0c61230167681937"
|
||||
"reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f29dca382a6485c3cbe6379f0c61230167681937",
|
||||
"reference": "f29dca382a6485c3cbe6379f0c61230167681937",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
|
||||
"reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2244,7 +2367,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
"dev-master": "1.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -2278,24 +2401,24 @@
|
|||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2017-06-09T14:24:12+00:00"
|
||||
"time": "2017-10-11T12:05:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.3.6",
|
||||
"version": "v3.3.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed"
|
||||
"reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/ddc23324e6cfe066f3dd34a37ff494fa80b617ed",
|
||||
"reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
|
||||
"reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
"php": "^5.5.9|>=7.0.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "~2.8|~3.0"
|
||||
|
@ -2333,7 +2456,7 @@
|
|||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-07-23T12:43:26+00:00"
|
||||
"time": "2017-10-05T14:43:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/fdomdocument",
|
||||
|
|
|
@ -36,6 +36,7 @@ In most cases, download Shaarli from the [releases](https://github.com/shaarli/S
|
|||
$ mkdir -p /path/to/shaarli && cd /path/to/shaarli/
|
||||
$ git clone -b v0.9 https://github.com/shaarli/Shaarli.git .
|
||||
$ composer install --no-dev --prefer-dist
|
||||
$ make translate
|
||||
```
|
||||
|
||||
## Stable version
|
||||
|
@ -83,13 +84,14 @@ $ git clone https://github.com/shaarli/Shaarli.git -b master /path/to/shaarli/
|
|||
# install/update third-party dependencies
|
||||
$ cd /path/to/shaarli
|
||||
$ composer install --no-dev --prefer-dist
|
||||
$ make translate
|
||||
```
|
||||
|
||||
## Finish Installation
|
||||
|
||||
Once Shaarli is downloaded and files have been placed at the correct location, open it this location your favorite browser.
|
||||
|
||||
![install screenshot](http://i.imgur.com/wuMpDSN.png)
|
||||
![install screenshot](images/install-shaarli.png)
|
||||
|
||||
Setup your Shaarli installation, and it's ready to use!
|
||||
|
||||
|
|
|
@ -39,3 +39,4 @@ Extension | Required? | Usage
|
|||
[`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing
|
||||
[`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`)
|
||||
[`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way
|
||||
[`php-gettext`](http://php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster)
|
||||
|
|
|
@ -81,6 +81,20 @@ _These settings should not be edited_
|
|||
- **page_cache**: Shaarli's internal cache directory.
|
||||
- **ban_file**: Banned IP file path.
|
||||
|
||||
### Translation
|
||||
|
||||
- **language**: translation language (also see [Translations](Translations))
|
||||
- **auto** (default): The translation language is chosen from the browser locale.
|
||||
It means that the language can be different for 2 different visitors depending on their locale.
|
||||
- **en**: Use the English translation.
|
||||
- **fr**: Use the French translation.
|
||||
- **mode**:
|
||||
- **auto** or **php** (default): Use the PHP implementation of gettext (slower)
|
||||
- **gettext**: Use PHP builtin gettext extension
|
||||
(faster, but requires `php-gettext` to be installed and to reload the web server on update)
|
||||
- **extension**: Translation extensions for custom themes or plugins.
|
||||
Must be an associative array: `translation domain => translation path`.
|
||||
|
||||
### Updates
|
||||
|
||||
- **check_updates**: Enable or disable update check to the git repository.
|
||||
|
@ -211,6 +225,13 @@ _These settings should not be edited_
|
|||
"plugins": {
|
||||
"WALLABAG_URL": "http://demo.wallabag.org",
|
||||
"WALLABAG_VERSION": "1"
|
||||
},
|
||||
"translation": {
|
||||
"language": "fr",
|
||||
"mode": "php",
|
||||
"extensions": {
|
||||
"demo": "plugins/demo_plugin/languages/"
|
||||
}
|
||||
}
|
||||
} ?>
|
||||
```
|
||||
|
|
152
doc/md/Translations.md
Normal file
152
doc/md/Translations.md
Normal file
|
@ -0,0 +1,152 @@
|
|||
## Translations
|
||||
|
||||
Shaarli supports [gettext](https://www.gnu.org/software/gettext/manual/gettext.html) translations
|
||||
since `>= v0.9.2`.
|
||||
|
||||
Note that only the `default` theme supports translations.
|
||||
|
||||
### Contributing
|
||||
|
||||
We encourage the community to contribute to Shaarli's translation either by improving existing
|
||||
translations or submitting a new language.
|
||||
|
||||
Contributing to the translation does not require development skill.
|
||||
|
||||
Please submit a pull request with the `.po` file updated/created. Note that the compiled file (`.mo`)
|
||||
is not stored on the repository, and is generated during the release process.
|
||||
|
||||
### How to
|
||||
|
||||
First, install [Poedit](https://poedit.net/) tool.
|
||||
|
||||
Poedit will extract strings to translate from the PHP source code.
|
||||
|
||||
**Important**: due to the usage of a template engine, it's important to generate PHP cache files to extract
|
||||
every translatable string.
|
||||
|
||||
You can either use [this script](https://gist.github.com/ArthurHoaro/5d0323f758ab2401ef444a53f54e9a07) (recommended)
|
||||
or visit every template page in your browser to generate cache files, while logged in.
|
||||
|
||||
Here is a list :
|
||||
|
||||
```
|
||||
http://<replace_domain>/
|
||||
http://<replace_domain>/?nonope
|
||||
http://<replace_domain>/?do=addlink
|
||||
http://<replace_domain>/?do=changepasswd
|
||||
http://<replace_domain>/?do=changetag
|
||||
http://<replace_domain>/?do=configure
|
||||
http://<replace_domain>/?do=tools
|
||||
http://<replace_domain>/?do=daily
|
||||
http://<replace_domain>/?post
|
||||
http://<replace_domain>/?do=export
|
||||
http://<replace_domain>/?do=import
|
||||
http://<replace_domain>/?do=login
|
||||
http://<replace_domain>/?do=picwall
|
||||
http://<replace_domain>/?do=pluginadmin
|
||||
http://<replace_domain>/?do=tagcloud
|
||||
http://<replace_domain>/?do=taglist
|
||||
```
|
||||
|
||||
#### Improve existing translation
|
||||
|
||||
In Poedit, click on "Edit a Translation", and from Shaarli's directory open
|
||||
`inc/languages/<lang>/LC_MESSAGES/shaarli.po`.
|
||||
|
||||
The existing list of translatable strings should have been loaded, then click on the "Update" button.
|
||||
|
||||
You can start editing the translation.
|
||||
|
||||
![poedit-screenshot](images/poedit-1.jpg)
|
||||
|
||||
Save when you're done, then you can submit a pull request containing the updated `shaarli.po`.
|
||||
|
||||
#### Add a new language
|
||||
|
||||
Open Poedit and select "Create New Translation", then from Shaarli's directory open
|
||||
`inc/languages/<lang>/LC_MESSAGES/shaarli.po`.
|
||||
|
||||
Then select the language you want to create.
|
||||
|
||||
Click on `File > Save as...`, and save your file in `<shaarli directory>/inc/language/<new language>/LC_MESSAGES/shaarli.po`.
|
||||
`<new language>` here should be the language code respecting the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-2)
|
||||
format in lowercase (e.g. `de` for German).
|
||||
|
||||
Then click on the "Update" button, and you can start to translate every available string.
|
||||
|
||||
Save when you're done, then you can submit a pull request containing the new `shaarli.po`.
|
||||
|
||||
### Extend Shaarli's translation
|
||||
|
||||
If you're writing a custom theme, or a non official plugin, you might want to use the translation system,
|
||||
but you won't be able to able to override Shaarli's translation.
|
||||
|
||||
However, you can add your own translation domain which extends the main translation list.
|
||||
|
||||
> Note that you can find a live example of translation extension in the `demo_plugin`.
|
||||
|
||||
First, create your translation files tree directory:
|
||||
|
||||
```
|
||||
<your_module>/languages/<ISO 3166-1 alpha-2 language code>/LC_MESSAGES/
|
||||
```
|
||||
|
||||
Your `.po` files must be named like your domain. E.g. if your translation domain is `my_theme`, then your file will be
|
||||
`my_theme.po`.
|
||||
|
||||
Users have to register your extension in their configuration with the parameter
|
||||
`translation.extensions.<domain>: <translation files path>`.
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
if (! $conf->exists('translation.extensions.my_theme')) {
|
||||
$conf->set('translation.extensions.my_theme', '<your_module>/languages/');
|
||||
$conf->write(true);
|
||||
}
|
||||
```
|
||||
|
||||
> Note that the page needs to be reloaded after the registration.
|
||||
|
||||
It is then recommended to create a custom translation function which will call the `t()` function with your domain.
|
||||
For example :
|
||||
|
||||
```php
|
||||
function my_theme_t($text, $nText = '', $nb = 1)
|
||||
{
|
||||
return t($text, $nText, $nb, 'my_theme'); // the last parameter is your translation domain.
|
||||
}
|
||||
```
|
||||
|
||||
All strings which can be translated should be processed through your function:
|
||||
|
||||
```php
|
||||
my_theme_t('Comment');
|
||||
my_theme_t('Comment', 'Comments', 2);
|
||||
```
|
||||
|
||||
Or in templates:
|
||||
|
||||
```php
|
||||
{'Comment'|my_theme_t}
|
||||
{function="my_theme_t('Comment', 'Comments', 2)"}
|
||||
```
|
||||
|
||||
> Note than in template, you need to visit your page at least once to generate a cache file.
|
||||
|
||||
When you're done, open Poedit and load translation strings from sources:
|
||||
|
||||
1. `File > New`
|
||||
2. Choose your language
|
||||
3. Save your `PO` file in `<your_module>/languages/<language code>/LC_MESSAGES/my_theme.po`.
|
||||
4. Go to `Catalog > Properties...`
|
||||
5. Fill the `Translation Properties` tab
|
||||
6. Add your source path in the `Sources Paths` tab
|
||||
7. In the `Sources Keywords` tab uncheck "Also use default keywords" and add the following lines:
|
||||
|
||||
```
|
||||
my_theme_t
|
||||
my_theme_t:1,2
|
||||
```
|
||||
|
||||
Click on the "Update" button and you're free to start your translations!
|
|
@ -39,7 +39,10 @@ We recommend that you use the latest release tarball with the `-full` suffix. It
|
|||
|
||||
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!
|
||||
|
||||
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).
|
||||
If you use translations in gettext mode - meaning you manually changed the default mode -,
|
||||
reload your web server.
|
||||
|
||||
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).
|
||||
|
||||
## Upgrading with Git
|
||||
|
||||
|
@ -72,6 +75,14 @@ Updating dependencies
|
|||
Downloading: 100%
|
||||
```
|
||||
|
||||
Shaarli >= `v0.9.2` supports translations:
|
||||
|
||||
```bash
|
||||
$ make translate
|
||||
```
|
||||
|
||||
If you use translations in gettext mode, reload your web server.
|
||||
|
||||
### Migrating and upgrading from Sebsauvage's repository
|
||||
|
||||
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
|
|||
Downloading: 100%
|
||||
```
|
||||
|
||||
Shaarli >= `v0.9.2` supports translations:
|
||||
|
||||
```bash
|
||||
$ make translate
|
||||
```
|
||||
|
||||
If you use translations in gettext mode, reload your web server.
|
||||
|
||||
Optionally, you can delete information related to the legacy version:
|
||||
|
||||
```bash
|
||||
|
|
BIN
doc/md/images/install-shaarli.png
Normal file
BIN
doc/md/images/install-shaarli.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
doc/md/images/poedit-1.jpg
Normal file
BIN
doc/md/images/poedit-1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
1366
inc/languages/fr/LC_MESSAGES/shaarli.po
Normal file
1366
inc/languages/fr/LC_MESSAGES/shaarli.po
Normal file
File diff suppressed because it is too large
Load diff
91
index.php
91
index.php
|
@ -64,7 +64,6 @@ require_once 'application/FeedBuilder.php';
|
|||
require_once 'application/FileUtils.php';
|
||||
require_once 'application/History.php';
|
||||
require_once 'application/HttpUtils.php';
|
||||
require_once 'application/Languages.php';
|
||||
require_once 'application/LinkDB.php';
|
||||
require_once 'application/LinkFilter.php';
|
||||
require_once 'application/LinkUtils.php';
|
||||
|
@ -76,6 +75,7 @@ require_once 'application/Utils.php';
|
|||
require_once 'application/PluginManager.php';
|
||||
require_once 'application/Router.php';
|
||||
require_once 'application/Updater.php';
|
||||
use \Shaarli\Languages;
|
||||
use \Shaarli\ThemeUtils;
|
||||
use \Shaarli\Config\ConfigManager;
|
||||
|
||||
|
@ -121,8 +121,16 @@ if (isset($_COOKIE['shaarli']) && !is_session_id_valid($_COOKIE['shaarli'])) {
|
|||
}
|
||||
|
||||
$conf = new ConfigManager();
|
||||
|
||||
// Sniff browser language and set date format accordingly.
|
||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
}
|
||||
|
||||
new Languages(setlocale(LC_MESSAGES, 0), $conf);
|
||||
|
||||
$conf->setEmpty('general.timezone', date_default_timezone_get());
|
||||
$conf->setEmpty('general.title', 'Shared links on '. escape(index_url($_SERVER)));
|
||||
$conf->setEmpty('general.title', t('Shared links on '). escape(index_url($_SERVER)));
|
||||
RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl').'/'.$conf->get('resource.theme').'/'; // template directory
|
||||
RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory
|
||||
|
||||
|
@ -144,7 +152,7 @@ if (! is_file($conf->getConfigFileExt())) {
|
|||
$errors = ApplicationUtils::checkResourcePermissions($conf);
|
||||
|
||||
if ($errors != array()) {
|
||||
$message = '<p>Insufficient permissions:</p><ul>';
|
||||
$message = '<p>'. t('Insufficient permissions:') .'</p><ul>';
|
||||
|
||||
foreach ($errors as $error) {
|
||||
$message .= '<li>'.$error.'</li>';
|
||||
|
@ -163,11 +171,6 @@ if (! is_file($conf->getConfigFileExt())) {
|
|||
// a token depending of deployment salt, user password, and the current ip
|
||||
define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt')));
|
||||
|
||||
// Sniff browser language and set date format accordingly.
|
||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking session state (i.e. is the user still logged in)
|
||||
*
|
||||
|
@ -376,7 +379,7 @@ function ban_canLogin($conf)
|
|||
// Process login form: Check if login/password is correct.
|
||||
if (isset($_POST['login']))
|
||||
{
|
||||
if (!ban_canLogin($conf)) die('I said: NO. You are banned for the moment. Go away.');
|
||||
if (!ban_canLogin($conf)) die(t('I said: NO. You are banned for the moment. Go away.'));
|
||||
if (isset($_POST['password'])
|
||||
&& tokenOk($_POST['token'])
|
||||
&& (check_auth($_POST['login'], $_POST['password'], $conf))
|
||||
|
@ -440,7 +443,8 @@ if (isset($_POST['login']))
|
|||
}
|
||||
}
|
||||
}
|
||||
echo '<script>alert("Wrong login/password.");document.location=\'?do=login'.$redir.'\';</script>'; // Redirect to login screen.
|
||||
// Redirect to login screen.
|
||||
echo '<script>alert("'. t("Wrong login/password.") .'");document.location=\'?do=login'.$redir.'\';</script>';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
@ -1100,16 +1104,19 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
if ($targetPage == Router::$PAGE_CHANGEPASSWORD)
|
||||
{
|
||||
if ($conf->get('security.open_shaarli')) {
|
||||
die('You are not supposed to change a password on an Open Shaarli.');
|
||||
die(t('You are not supposed to change a password on an Open Shaarli.'));
|
||||
}
|
||||
|
||||
if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword']))
|
||||
{
|
||||
if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away!
|
||||
if (!tokenOk($_POST['token'])) die(t('Wrong token.')); // Go away!
|
||||
|
||||
// Make sure old password is correct.
|
||||
$oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt'));
|
||||
if ($oldhash!= $conf->get('credentials.hash')) { echo '<script>alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; }
|
||||
if ($oldhash!= $conf->get('credentials.hash')) {
|
||||
echo '<script>alert("'. t('The old password is not correct.') .'");document.location=\'?do=changepasswd\';</script>';
|
||||
exit;
|
||||
}
|
||||
// Save new password
|
||||
// Salt renders rainbow-tables attacks useless.
|
||||
$conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand()));
|
||||
|
@ -1127,7 +1134,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>';
|
||||
exit;
|
||||
}
|
||||
echo '<script>alert("Your password has been changed.");document.location=\'?do=tools\';</script>';
|
||||
echo '<script>alert("'. t('Your password has been changed') .'");document.location=\'?do=tools\';</script>';
|
||||
exit;
|
||||
}
|
||||
else // show the change password form.
|
||||
|
@ -1143,7 +1150,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
if (!empty($_POST['title']) )
|
||||
{
|
||||
if (!tokenOk($_POST['token'])) {
|
||||
die('Wrong token.'); // Go away!
|
||||
die(t('Wrong token.')); // Go away!
|
||||
}
|
||||
$tz = 'UTC';
|
||||
if (!empty($_POST['continent']) && !empty($_POST['city'])
|
||||
|
@ -1163,6 +1170,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
$conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks']));
|
||||
$conf->set('api.enabled', !empty($_POST['enableApi']));
|
||||
$conf->set('api.secret', escape($_POST['apiSecret']));
|
||||
$conf->set('translation.language', escape($_POST['language']));
|
||||
|
||||
try {
|
||||
$conf->write(isLoggedIn());
|
||||
$history->updateSettings();
|
||||
|
@ -1178,7 +1187,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=configure\';</script>';
|
||||
exit;
|
||||
}
|
||||
echo '<script>alert("Configuration was saved.");document.location=\'?do=configure\';</script>';
|
||||
echo '<script>alert("'. t('Configuration was saved.') .'");document.location=\'?do=configure\';</script>';
|
||||
exit;
|
||||
}
|
||||
else // Show the configuration form.
|
||||
|
@ -1200,6 +1209,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
$PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false));
|
||||
$PAGE->assign('api_enabled', $conf->get('api.enabled', true));
|
||||
$PAGE->assign('api_secret', $conf->get('api.secret'));
|
||||
$PAGE->assign('languages', Languages::getAvailableLanguages());
|
||||
$PAGE->assign('language', $conf->get('translation.language'));
|
||||
$PAGE->renderPage('configure');
|
||||
exit;
|
||||
}
|
||||
|
@ -1215,7 +1226,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
}
|
||||
|
||||
if (!tokenOk($_POST['token'])) {
|
||||
die('Wrong token.');
|
||||
die(t('Wrong token.'));
|
||||
}
|
||||
|
||||
$alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), escape($_POST['totag']));
|
||||
|
@ -1225,9 +1236,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
}
|
||||
$delete = empty($_POST['totag']);
|
||||
$redirect = $delete ? 'do=changetag' : 'searchtags='. urlencode(escape($_POST['totag']));
|
||||
$count = count($alteredLinks);
|
||||
$alert = $delete
|
||||
? sprintf(t('The tag was removed from %d links.'), count($alteredLinks))
|
||||
: sprintf(t('The tag was renamed in %d links.'), count($alteredLinks));
|
||||
? sprintf(t('The tag was removed from %d link.', 'The tag was removed from %d links.', $count), $count)
|
||||
: sprintf(t('The tag was renamed in %d link.', 'The tag was renamed in %d links.', $count), $count);
|
||||
echo '<script>alert("'. $alert .'");document.location=\'?'. $redirect .'\';</script>';
|
||||
exit;
|
||||
}
|
||||
|
@ -1244,7 +1256,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
{
|
||||
// Go away!
|
||||
if (! tokenOk($_POST['token'])) {
|
||||
die('Wrong token.');
|
||||
die(t('Wrong token.'));
|
||||
}
|
||||
|
||||
// lf_id should only be present if the link exists.
|
||||
|
@ -1344,7 +1356,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
if ($targetPage == Router::$PAGE_DELETELINK)
|
||||
{
|
||||
if (! tokenOk($_GET['token'])) {
|
||||
die('Wrong token.');
|
||||
die(t('Wrong token.'));
|
||||
}
|
||||
|
||||
$ids = trim($_GET['lf_linkdate']);
|
||||
|
@ -1443,7 +1455,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
|
||||
if ($url == '') {
|
||||
$url = '?' . smallHash($linkdate . $LINKSDB->getNextId());
|
||||
$title = $conf->get('general.default_note_title', 'Note: ');
|
||||
$title = $conf->get('general.default_note_title', t('Note: '));
|
||||
}
|
||||
$url = escape($url);
|
||||
$title = escape($title);
|
||||
|
@ -1550,11 +1562,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
|
|||
// Import bookmarks from an uploaded file
|
||||
if (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size'] == 0) {
|
||||
// The file is too big or some form field may be missing.
|
||||
echo '<script>alert("The file you are trying to upload is probably'
|
||||
.' bigger than what this webserver can accept ('
|
||||
.get_max_upload_size(ini_get('post_max_size'), ini_get('upload_max_filesize')).').'
|
||||
.' Please upload in smaller chunks.");document.location=\'?do='
|
||||
.Router::$PAGE_IMPORT .'\';</script>';
|
||||
$msg = sprintf(
|
||||
t(
|
||||
'The file you are trying to upload is probably bigger than what this webserver can accept'
|
||||
.' (%s). Please upload in smaller chunks.'
|
||||
),
|
||||
get_max_upload_size(ini_get('post_max_size'), ini_get('upload_max_filesize'))
|
||||
);
|
||||
echo '<script>alert("'. $msg .'");document.location=\'?do='.Router::$PAGE_IMPORT .'\';</script>';
|
||||
exit;
|
||||
}
|
||||
if (! tokenOk($_POST['token'])) {
|
||||
|
@ -1962,12 +1977,20 @@ function install($conf)
|
|||
// (Because on some hosts, session.save_path may not be set correctly,
|
||||
// or we may not have write access to it.)
|
||||
if (isset($_GET['test_session']) && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working'))
|
||||
{ // Step 2: Check if data in session is correct.
|
||||
echo '<pre>Sessions do not seem to work correctly on your server.<br>';
|
||||
echo 'Make sure the variable session.save_path is set correctly in your php config, and that you have write access to it.<br>';
|
||||
echo 'It currently points to '.session_save_path().'<br>';
|
||||
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>';
|
||||
echo '<br><a href="?">Click to try again.</a></pre>';
|
||||
{
|
||||
// Step 2: Check if data in session is correct.
|
||||
$msg = t(
|
||||
'<pre>Sessions do not seem to work correctly on your server.<br>'.
|
||||
'Make sure the variable "session.save_path" is set correctly in your PHP config, '.
|
||||
'and that you have write access to it.<br>'.
|
||||
'It currently points to %s.<br>'.
|
||||
'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>'
|
||||
);
|
||||
$msg = sprintf($msg, session_save_path());
|
||||
echo $msg;
|
||||
echo '<br><a href="?">'. t('Click to try again.') .'</a></pre>';
|
||||
die;
|
||||
}
|
||||
if (!isset($_SESSION['session_tested']))
|
||||
|
@ -2000,6 +2023,7 @@ function install($conf)
|
|||
} else {
|
||||
$conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER)));
|
||||
}
|
||||
$conf->set('translation.language', escape($_POST['language']));
|
||||
$conf->set('updates.check_updates', !empty($_POST['updateCheck']));
|
||||
$conf->set('api.enabled', !empty($_POST['enableApi']));
|
||||
$conf->set(
|
||||
|
@ -2031,6 +2055,7 @@ function install($conf)
|
|||
list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get());
|
||||
$PAGE->assign('continents', $continents);
|
||||
$PAGE->assign('cities', $cities);
|
||||
$PAGE->assign('languages', Languages::getAvailableLanguages());
|
||||
$PAGE->renderPage('install');
|
||||
exit;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ pages:
|
|||
- Versioning and Branches: Versioning-and-Branches.md
|
||||
- Security: Security.md
|
||||
- Static analysis: Static-analysis.md
|
||||
- Translations: Translations.md
|
||||
- Theming: Theming.md
|
||||
- Unit tests: Unit-tests.md
|
||||
- Unit tests inside Docker: Unit-tests-Docker.md
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
https://github.com/shaarli/Shaarli/issues/181 - Add Disqus or Isso comments box on a permalink page
|
||||
|
||||
* http://posativ.org/isso/
|
||||
* install debian package https://packages.debian.org/sid/isso
|
||||
* configure server http://posativ.org/isso/docs/configuration/server/
|
||||
* configure client http://posativ.org/isso/docs/configuration/client/
|
||||
* 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)
|
||||
|
||||
|
||||
Problem: by default, Isso thread ID is guessed from the current url (only one thread per page).
|
||||
if we want multiple threads on a single page (shaarli linklist), we must use : the `data-isso-id` client config,
|
||||
with data-isso-id being the permalink of an item.
|
||||
|
||||
`<section data-isso-id="aH7klxW" id="isso-thread"></section>`
|
||||
`data-isso-id: Set a custom thread id, defaults to current URI.`
|
||||
|
||||
Problem: feature is currently broken https://github.com/posativ/isso/issues/27
|
||||
|
||||
Another option, only display isso threads when current URL is a permalink (`\?(A-Z|a-z|0-9|-){7}`) (only show thread
|
||||
when displaying only this link), and just display a "comments" button on each linklist item. Optionally show the comment
|
||||
count on each item using the API (http://posativ.org/isso/docs/extras/api/#get-comment-count). API requests can be done
|
||||
by raintpl `{function` or client-side with js. The former should be faster if isso and shaarli are on ther same server.
|
||||
|
||||
Showing all full isso threads in the linklist would destroy layout
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
http://www.git-attitude.fr/2014/11/04/git-rerere/ for the merge
|
|
@ -26,11 +26,11 @@ function hook_addlink_toolbar_render_header($data)
|
|||
array(
|
||||
'type' => 'text',
|
||||
'name' => 'post',
|
||||
'placeholder' => 'URI',
|
||||
'placeholder' => t('URI'),
|
||||
),
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'value' => 'Add link',
|
||||
'value' => t('Add link'),
|
||||
'class' => 'bigbutton',
|
||||
),
|
||||
),
|
||||
|
@ -40,3 +40,12 @@ function hook_addlink_toolbar_render_header($data)
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function addlink_toolbar_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('Adds the addlink input on the linklist page.');
|
||||
}
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
<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>
|
||||
<span>
|
||||
<a href="https://web.archive.org/web/%s">
|
||||
<img class="linklist-plugin-icon" src="plugins/archiveorg/internetarchive.png" title="%s" alt="archive.org" />
|
||||
</a>
|
||||
</span>
|
||||
|
|
|
@ -20,9 +20,18 @@ function hook_archiveorg_render_linklist($data)
|
|||
if($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) {
|
||||
continue;
|
||||
}
|
||||
$archive = sprintf($archive_html, $value['url']);
|
||||
$archive = sprintf($archive_html, $value['url'], t('View on archive.org'));
|
||||
$value['link_plugin'][] = $archive;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function archiveorg_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('For each link, add an Archive.org icon.');
|
||||
}
|
||||
|
|
|
@ -14,6 +14,26 @@
|
|||
* and check user status with _LOGGEDIN_.
|
||||
*/
|
||||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
|
||||
/**
|
||||
* In the footer hook, there is a working example of a translation extension for Shaarli.
|
||||
*
|
||||
* The extension must be attached to a new translation domain (i.e. NOT 'shaarli').
|
||||
* Use case: any custom theme or non official plugin can use the translation system.
|
||||
*
|
||||
* See the documentation for more information.
|
||||
*/
|
||||
const EXT_TRANSLATION_DOMAIN = 'demo';
|
||||
|
||||
/*
|
||||
* This is not necessary, but it's easier if you don't want Poedit to mix up your translations.
|
||||
*/
|
||||
function demo_plugin_t($text, $nText = '', $nb = 1)
|
||||
{
|
||||
return t($text, $nText, $nb, EXT_TRANSLATION_DOMAIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization function.
|
||||
* It will be called when the plugin is loaded.
|
||||
|
@ -27,6 +47,12 @@ function demo_plugin_init($conf)
|
|||
{
|
||||
$conf->get('toto', 'nope');
|
||||
|
||||
if (! $conf->exists('translation.extensions.demo')) {
|
||||
// Custom translation with the domain 'demo'
|
||||
$conf->set('translation.extensions.demo', 'plugins/demo_plugin/languages/');
|
||||
$conf->write(true);
|
||||
}
|
||||
|
||||
$errors[] = 'This a demo init error.';
|
||||
return $errors;
|
||||
}
|
||||
|
@ -160,7 +186,7 @@ function hook_demo_plugin_render_includes($data)
|
|||
function hook_demo_plugin_render_footer($data)
|
||||
{
|
||||
// footer text
|
||||
$data['text'][] = 'Shaarli is now enhanced by the awesome demo_plugin.';
|
||||
$data['text'][] = '<br>'. demo_plugin_t('Shaarli is now enhanced by the awesome demo_plugin.');
|
||||
|
||||
// Free elements at the end of the page.
|
||||
$data['endofpage'][] = '<marquee id="demo_marquee">' .
|
||||
|
@ -433,3 +459,12 @@ function hook_demo_plugin_render_feed($data)
|
|||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function demo_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('A demo plugin covering all use cases for template designers and plugin developers.');
|
||||
}
|
||||
|
|
BIN
plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.mo
Normal file
BIN
plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.mo
Normal file
Binary file not shown.
21
plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.po
Normal file
21
plugins/demo_plugin/languages/fr/LC_MESSAGES/demo.po
Normal file
|
@ -0,0 +1,21 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Demo plugin\n"
|
||||
"POT-Creation-Date: 2017-08-19 10:45+0200\n"
|
||||
"PO-Revision-Date: 2017-08-19 11:28+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: demo\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.0.2\n"
|
||||
"X-Poedit-Basepath: ../../..\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Poedit-KeywordsList: ;demo_plugin_t:1,2;demo_plugin_t\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: demo_plugin.php:173
|
||||
msgid "Shaarli is now enhanced by the awesome demo_plugin."
|
||||
msgstr "Shaarli est maintenant amélioré avec le fantastique demo_plugin."
|
|
@ -4,10 +4,11 @@
|
|||
* Plugin Isso.
|
||||
*/
|
||||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
|
||||
/**
|
||||
* Display an error everywhere if the plugin is enabled without configuration.
|
||||
*
|
||||
* @param $data array List of links
|
||||
* @param $conf ConfigManager instance
|
||||
*
|
||||
* @return mixed - linklist data with Isso plugin.
|
||||
|
@ -16,8 +17,8 @@ function isso_init($conf)
|
|||
{
|
||||
$issoUrl = $conf->get('plugins.ISSO_SERVER');
|
||||
if (empty($issoUrl)) {
|
||||
$error = 'Isso plugin error: '.
|
||||
'Please define the "ISSO_SERVER" setting in the plugin administration page.';
|
||||
$error = t('Isso plugin error: '.
|
||||
'Please define the "ISSO_SERVER" setting in the plugin administration page.');
|
||||
return array($error);
|
||||
}
|
||||
}
|
||||
|
@ -52,3 +53,13 @@ function hook_isso_render_linklist($data, $conf)
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function isso_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('Let visitor comment your shaares on permalinks with Isso.');
|
||||
t('Isso server URL (without \'http://\')');
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="md_help">
|
||||
Description will be rendered with
|
||||
<a href="http://daringfireball.net/projects/markdown/syntax" title="Markdown syntax documentation">
|
||||
Markdown syntax</a>.
|
||||
%s
|
||||
<a href="http://daringfireball.net/projects/markdown/syntax" title="%s">
|
||||
%s</a>.
|
||||
</div>
|
||||
|
|
|
@ -154,8 +154,13 @@ function hook_markdown_render_includes($data)
|
|||
function hook_markdown_render_editlink($data)
|
||||
{
|
||||
// Load help HTML into a string
|
||||
$data['edit_link_plugin'][] = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html');
|
||||
|
||||
$txt = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html');
|
||||
$translations = [
|
||||
t('Description will be rendered with'),
|
||||
t('Markdown syntax documentation'),
|
||||
t('Markdown syntax'),
|
||||
];
|
||||
$data['edit_link_plugin'][] = vsprintf($txt, $translations);
|
||||
// Add no markdown 'meta-tag' in tag list if it was never used, for autocompletion.
|
||||
if (! in_array(NO_MD_TAG, $data['tags'])) {
|
||||
$data['tags'][NO_MD_TAG] = 0;
|
||||
|
@ -325,3 +330,15 @@ function process_markdown($description, $escape = true, $allowedProtocols = [])
|
|||
|
||||
return $processedDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function markdown_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('Render shaare description with Markdown syntax.<br><strong>Warning</strong>:
|
||||
If your shaared descriptions contained HTML tags before enabling the markdown plugin,
|
||||
enabling it might break your page.
|
||||
See the <a href="https://github.com/shaarli/Shaarli/tree/master/plugins/markdown#html-rendering">README</a>.');
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ function piwik_init($conf)
|
|||
$piwikUrl = $conf->get('plugins.PIWIK_URL');
|
||||
$piwikSiteid = $conf->get('plugins.PIWIK_SITEID');
|
||||
if (empty($piwikUrl) || empty($piwikSiteid)) {
|
||||
$error = 'Piwik plugin error: ' .
|
||||
'Please define PIWIK_URL and PIWIK_SITEID in the plugin administration page.';
|
||||
$error = t('Piwik plugin error: ' .
|
||||
'Please define PIWIK_URL and PIWIK_SITEID in the plugin administration page.');
|
||||
return array($error);
|
||||
}
|
||||
}
|
||||
|
@ -60,3 +60,14 @@ function hook_piwik_render_footer($data, $conf)
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function piwik_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('A plugin that adds Piwik tracking code to Shaarli pages.');
|
||||
t('Piwik URL');
|
||||
t('Piwik site ID');
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ function hook_playvideos_render_header($data)
|
|||
$playvideo = array(
|
||||
'attr' => array(
|
||||
'href' => '#',
|
||||
'title' => 'Video player',
|
||||
'title' => t('Video player'),
|
||||
'id' => 'playvideos',
|
||||
),
|
||||
'html' => '► Play Videos'
|
||||
'html' => '► '. t('Play Videos')
|
||||
);
|
||||
$data['buttons_toolbar'][] = $playvideo;
|
||||
}
|
||||
|
@ -46,3 +46,12 @@ function hook_playvideos_render_footer($data)
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function playvideos_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('Add a button in the toolbar allowing to watch all videos.');
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
|
||||
use pubsubhubbub\publisher\Publisher;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
|
||||
/**
|
||||
* Plugin init function - set the hub to the default appspot one.
|
||||
|
@ -65,7 +66,7 @@ function hook_pubsubhubbub_save_link($data, $conf)
|
|||
$p = new Publisher($conf->get('plugins.PUBSUBHUB_URL'));
|
||||
$p->publish_update($feeds, $httpPost);
|
||||
} catch (Exception $e) {
|
||||
error_log('Could not publish to PubSubHubbub: ' . $e->getMessage());
|
||||
error_log(sprintf(t('Could not publish to PubSubHubbub: %s'), $e->getMessage()));
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
@ -91,11 +92,20 @@ function nocurl_http_post($url, $postString) {
|
|||
$context = stream_context_create($params);
|
||||
$fp = @fopen($url, 'rb', false, $context);
|
||||
if (!$fp) {
|
||||
throw new Exception('Could not post to '. $url);
|
||||
throw new Exception(sprintf(t('Could not post to %s'), $url));
|
||||
}
|
||||
$response = @stream_get_contents($fp);
|
||||
if ($response === false) {
|
||||
throw new Exception('Bad response from the hub '. $url);
|
||||
throw new Exception(sprintf(t('Bad response from the hub %s'), $url));
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function pubsubhubbub_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('Enable PubSubHubbub feed publishing.');
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
description="For each link, add a QRCode icon ."
|
||||
description="For each link, add a QRCode icon."
|
||||
|
|
|
@ -59,3 +59,12 @@ function hook_qrcode_render_includes($data)
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function qrcode_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('For each link, add a QRCode icon.');
|
||||
}
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
<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>
|
||||
<span>
|
||||
<a href="%s%s" target="_blank">
|
||||
<img class="linklist-plugin-icon" src="%s/wallabag/wallabag.png" title="%s" alt="wallabag" />
|
||||
</a>
|
||||
</span>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
require_once 'WallabagInstance.php';
|
||||
use Shaarli\Config\ConfigManager;
|
||||
|
||||
/**
|
||||
* Init function, return an error if the server is not set.
|
||||
|
@ -17,8 +18,8 @@ function wallabag_init($conf)
|
|||
{
|
||||
$wallabagUrl = $conf->get('plugins.WALLABAG_URL');
|
||||
if (empty($wallabagUrl)) {
|
||||
$error = 'Wallabag plugin error: '.
|
||||
'Please define the "WALLABAG_URL" setting in the plugin administration page.';
|
||||
$error = t('Wallabag plugin error: '.
|
||||
'Please define the "WALLABAG_URL" setting in the plugin administration page.');
|
||||
return array($error);
|
||||
}
|
||||
}
|
||||
|
@ -43,12 +44,14 @@ function hook_wallabag_render_linklist($data, $conf)
|
|||
|
||||
$wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html');
|
||||
|
||||
$linkTitle = t('Save to wallabag');
|
||||
foreach ($data['links'] as &$value) {
|
||||
$wallabag = sprintf(
|
||||
$wallabagHtml,
|
||||
$wallabagInstance->getWallabagUrl(),
|
||||
urlencode($value['url']),
|
||||
PluginManager::$PLUGINS_PATH
|
||||
PluginManager::$PLUGINS_PATH,
|
||||
$linkTitle
|
||||
);
|
||||
$value['link_plugin'][] = $wallabag;
|
||||
}
|
||||
|
@ -56,3 +59,14 @@ function hook_wallabag_render_linklist($data, $conf)
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||
*/
|
||||
function wallabag_dummy_translation()
|
||||
{
|
||||
// meta
|
||||
t('For each link, add a QRCode icon.');
|
||||
t('Wallabag API URL');
|
||||
t('Wallabag API version (1 or 2)');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,41 +1,203 @@
|
|||
<?php
|
||||
|
||||
require_once 'application/Languages.php';
|
||||
namespace Shaarli;
|
||||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
|
||||
/**
|
||||
* Class LanguagesTest.
|
||||
*/
|
||||
class LanguagesTest extends PHPUnit_Framework_TestCase
|
||||
class LanguagesTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var string Config file path (without extension).
|
||||
*/
|
||||
protected static $configFile = 'tests/utils/config/configJson';
|
||||
|
||||
/**
|
||||
* @var ConfigManager
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
$this->conf = new ConfigManager(self::$configFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a simple non identified value.
|
||||
*/
|
||||
public function testTranslateSingleNotID()
|
||||
public function testTranslateSingleNotIDGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'abcdé 564 fgK';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a non identified plural form.
|
||||
* Test t() with a simple identified value in gettext mode.
|
||||
*/
|
||||
public function testTranslatePluralNotID()
|
||||
public function testTranslateSingleIDGettext()
|
||||
{
|
||||
$text = '%s sandwich';
|
||||
$nText = '%s sandwiches';
|
||||
$this->assertEquals('0 sandwich', t($text, $nText));
|
||||
$this->assertEquals('1 sandwich', t($text, $nText, 1));
|
||||
$this->assertEquals('2 sandwiches', t($text, $nText, 2));
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'permalink';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a non identified invalid plural form.
|
||||
* Test t() with a non identified plural form in gettext mode.
|
||||
*/
|
||||
public function testTranslatePluralNotIDInvalid()
|
||||
public function testTranslatePluralNotIDGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'sandwich';
|
||||
$nText = 'sandwiches';
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 0));
|
||||
$this->assertEquals('sandwich', t($text, $nText, 1));
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an identified plural form in gettext mode.
|
||||
*/
|
||||
public function testTranslatePluralIDGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'shaare';
|
||||
$nText = 'shaares';
|
||||
// In english, zero is followed by plural form
|
||||
$this->assertEquals('shaares', t($text, $nText, 0));
|
||||
$this->assertEquals('shaare', t($text, $nText, 1));
|
||||
$this->assertEquals('shaares', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a simple non identified value.
|
||||
*/
|
||||
public function testTranslateSingleNotIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'abcdé 564 fgK';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a simple identified value in PHP mode.
|
||||
*/
|
||||
public function testTranslateSingleIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'permalink';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a non identified plural form in PHP mode.
|
||||
*/
|
||||
public function testTranslatePluralNotIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'sandwich';
|
||||
$nText = 'sandwiches';
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 0));
|
||||
$this->assertEquals('sandwich', t($text, $nText, 1));
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an identified plural form in PHP mode.
|
||||
*/
|
||||
public function testTranslatePluralIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'shaare';
|
||||
$nText = 'shaares';
|
||||
// In english, zero is followed by plural form
|
||||
$this->assertEquals('shaares', t($text, $nText, 0));
|
||||
$this->assertEquals('shaare', t($text, $nText, 1));
|
||||
$this->assertEquals('shaares', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an invalid language set in the configuration in gettext mode.
|
||||
*/
|
||||
public function testTranslateWithInvalidConfLanguageGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
$this->conf->set('translation.language', 'nope');
|
||||
new Languages('fr', $this->conf);
|
||||
$text = 'grumble';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an invalid language set in the configuration in PHP mode.
|
||||
*/
|
||||
public function testTranslateWithInvalidConfLanguagePhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
$this->conf->set('translation.language', 'nope');
|
||||
new Languages('fr', $this->conf);
|
||||
$text = 'grumble';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an invalid language set with auto language in gettext mode.
|
||||
*/
|
||||
public function testTranslateWithInvalidAutoLanguageGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('nope', $this->conf);
|
||||
$text = 'grumble';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an invalid language set with auto language in PHP mode.
|
||||
*/
|
||||
public function testTranslateWithInvalidAutoLanguagePhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('nope', $this->conf);
|
||||
$text = 'grumble';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an extension language file in gettext mode
|
||||
*/
|
||||
public function testTranslationExtensionGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
$this->conf->set('translation.extensions.test', 'tests/utils/languages/');
|
||||
new Languages('en', $this->conf);
|
||||
$txt = 'car'; // ignore me poedit
|
||||
$this->assertEquals('car', t($txt, $txt, 1, 'test'));
|
||||
$this->assertEquals('Search', t('Search', 'Search', 1, 'test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an extension language file in PHP mode
|
||||
*/
|
||||
public function testTranslationExtensionPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
$this->conf->set('translation.extensions.test', 'tests/utils/languages/');
|
||||
new Languages('en', $this->conf);
|
||||
$txt = 'car'; // ignore me poedit
|
||||
$this->assertEquals('car', t($txt, $txt, 1, 'test'));
|
||||
$this->assertEquals('Search', t('Search', 'Search', 1, 'test'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -384,18 +384,18 @@ class UtilsTest extends PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testHumanBytes()
|
||||
{
|
||||
$this->assertEquals('2kiB', human_bytes(2 * 1024));
|
||||
$this->assertEquals('2kiB', human_bytes(strval(2 * 1024)));
|
||||
$this->assertEquals('2MiB', human_bytes(2 * (pow(1024, 2))));
|
||||
$this->assertEquals('2MiB', human_bytes(strval(2 * (pow(1024, 2)))));
|
||||
$this->assertEquals('2GiB', human_bytes(2 * (pow(1024, 3))));
|
||||
$this->assertEquals('2GiB', human_bytes(strval(2 * (pow(1024, 3)))));
|
||||
$this->assertEquals('374B', human_bytes(374));
|
||||
$this->assertEquals('374B', human_bytes('374'));
|
||||
$this->assertEquals('232kiB', human_bytes(237481));
|
||||
$this->assertEquals('Unlimited', human_bytes('0'));
|
||||
$this->assertEquals('Unlimited', human_bytes(0));
|
||||
$this->assertEquals('Setting not set', human_bytes(''));
|
||||
$this->assertEquals('2'. t('kiB'), human_bytes(2 * 1024));
|
||||
$this->assertEquals('2'. t('kiB'), human_bytes(strval(2 * 1024)));
|
||||
$this->assertEquals('2'. t('MiB'), human_bytes(2 * (pow(1024, 2))));
|
||||
$this->assertEquals('2'. t('MiB'), human_bytes(strval(2 * (pow(1024, 2)))));
|
||||
$this->assertEquals('2'. t('GiB'), human_bytes(2 * (pow(1024, 3))));
|
||||
$this->assertEquals('2'. t('GiB'), human_bytes(strval(2 * (pow(1024, 3)))));
|
||||
$this->assertEquals('374'. t('B'), human_bytes(374));
|
||||
$this->assertEquals('374'. t('B'), human_bytes('374'));
|
||||
$this->assertEquals('232'. t('kiB'), human_bytes(237481));
|
||||
$this->assertEquals(t('Unlimited'), human_bytes('0'));
|
||||
$this->assertEquals(t('Unlimited'), human_bytes(0));
|
||||
$this->assertEquals(t('Setting not set'), human_bytes(''));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -403,9 +403,9 @@ class UtilsTest extends PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testGetMaxUploadSize()
|
||||
{
|
||||
$this->assertEquals('1MiB', get_max_upload_size(2097152, '1024k'));
|
||||
$this->assertEquals('1MiB', get_max_upload_size('1m', '2m'));
|
||||
$this->assertEquals('100B', get_max_upload_size(100, 100));
|
||||
$this->assertEquals('1'. t('MiB'), get_max_upload_size(2097152, '1024k'));
|
||||
$this->assertEquals('1'. t('MiB'), get_max_upload_size('1m', '2m'));
|
||||
$this->assertEquals('100'. t('B'), get_max_upload_size(100, 100));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
6
tests/bootstrap.php
Normal file
6
tests/bootstrap.php
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
$conf = new \Shaarli\Config\ConfigManager('tests/utils/config/configJson');
|
||||
new \Shaarli\Languages('en', $conf);
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
if (! empty('UT_LOCALE')) {
|
||||
require_once 'tests/bootstrap.php';
|
||||
|
||||
if (! empty(getenv('UT_LOCALE'))) {
|
||||
setlocale(LC_ALL, getenv('UT_LOCALE'));
|
||||
}
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
|
|
175
tests/languages/fr/LanguagesFrTest.php
Normal file
175
tests/languages/fr/LanguagesFrTest.php
Normal file
|
@ -0,0 +1,175 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Shaarli;
|
||||
|
||||
|
||||
use Shaarli\Config\ConfigManager;
|
||||
|
||||
/**
|
||||
* Class LanguagesFrTest
|
||||
*
|
||||
* Test the translation system in PHP and gettext mode with French language.
|
||||
*
|
||||
* @package Shaarli
|
||||
*/
|
||||
class LanguagesFrTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var string Config file path (without extension).
|
||||
*/
|
||||
protected static $configFile = 'tests/utils/config/configJson';
|
||||
|
||||
/**
|
||||
* @var ConfigManager
|
||||
*/
|
||||
protected $conf;
|
||||
|
||||
/**
|
||||
* Init: force French
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
$this->conf = new ConfigManager(self::$configFile);
|
||||
$this->conf->set('translation.language', 'fr');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the locale since gettext seems to mess with it, making it too long
|
||||
*/
|
||||
public static function tearDownAfterClass()
|
||||
{
|
||||
if (! empty(getenv('UT_LOCALE'))) {
|
||||
setlocale(LC_ALL, getenv('UT_LOCALE'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a simple non identified value.
|
||||
*/
|
||||
public function testTranslateSingleNotIDGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'abcdé 564 fgK';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a simple identified value in gettext mode.
|
||||
*/
|
||||
public function testTranslateSingleIDGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'permalink';
|
||||
$this->assertEquals('permalien', t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a non identified plural form in gettext mode.
|
||||
*/
|
||||
public function testTranslatePluralNotIDGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'sandwich';
|
||||
$nText = 'sandwiches';
|
||||
// Not ID, so English fallback, and in english, plural 0
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 0));
|
||||
$this->assertEquals('sandwich', t($text, $nText, 1));
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an identified plural form in gettext mode.
|
||||
*/
|
||||
public function testTranslatePluralIDGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'shaare';
|
||||
$nText = 'shaares';
|
||||
$this->assertEquals('shaare', t($text, $nText, 0));
|
||||
$this->assertEquals('shaare', t($text, $nText, 1));
|
||||
$this->assertEquals('shaares', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a simple non identified value.
|
||||
*/
|
||||
public function testTranslateSingleNotIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'abcdé 564 fgK';
|
||||
$this->assertEquals($text, t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a simple identified value in PHP mode.
|
||||
*/
|
||||
public function testTranslateSingleIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'permalink';
|
||||
$this->assertEquals('permalien', t($text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with a non identified plural form in PHP mode.
|
||||
*/
|
||||
public function testTranslatePluralNotIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'sandwich';
|
||||
$nText = 'sandwiches';
|
||||
// Not ID, so English fallback, and in english, plural 0
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 0));
|
||||
$this->assertEquals('sandwich', t($text, $nText, 1));
|
||||
$this->assertEquals('sandwiches', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an identified plural form in PHP mode.
|
||||
*/
|
||||
public function testTranslatePluralIDPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
new Languages('en', $this->conf);
|
||||
$text = 'shaare';
|
||||
$nText = 'shaares';
|
||||
// In english, zero is followed by plural form
|
||||
$this->assertEquals('shaare', t($text, $nText, 0));
|
||||
$this->assertEquals('shaare', t($text, $nText, 1));
|
||||
$this->assertEquals('shaares', t($text, $nText, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an extension language file in gettext mode
|
||||
*/
|
||||
public function testTranslationExtensionGettext()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'gettext');
|
||||
$this->conf->set('translation.extensions.test', 'tests/utils/languages/');
|
||||
new Languages('en', $this->conf);
|
||||
$txt = 'car'; // ignore me poedit
|
||||
$this->assertEquals('voiture', t($txt, $txt, 1, 'test'));
|
||||
$this->assertEquals('Fouille', t('Search', 'Search', 1, 'test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test t() with an extension language file in PHP mode
|
||||
*/
|
||||
public function testTranslationExtensionPhp()
|
||||
{
|
||||
$this->conf->set('translation.mode', 'php');
|
||||
$this->conf->set('translation.extensions.test', 'tests/utils/languages/');
|
||||
new Languages('en', $this->conf);
|
||||
$txt = 'car'; // ignore me poedit
|
||||
$this->assertEquals('voiture', t($txt, $txt, 1, 'test'));
|
||||
$this->assertEquals('Fouille', t('Search', 'Search', 1, 'test'));
|
||||
}
|
||||
}
|
BIN
tests/utils/languages/fr/LC_MESSAGES/test.mo
Normal file
BIN
tests/utils/languages/fr/LC_MESSAGES/test.mo
Normal file
Binary file not shown.
19
tests/utils/languages/fr/LC_MESSAGES/test.po
Normal file
19
tests/utils/languages/fr/LC_MESSAGES/test.po
Normal file
|
@ -0,0 +1,19 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Extension test\n"
|
||||
"POT-Creation-Date: 2017-05-20 13:54+0200\n"
|
||||
"PO-Revision-Date: 2017-05-20 14:16+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Shaarli\n"
|
||||
"Language: fr_FR\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Generator: Poedit 2.0.1\n"
|
||||
|
||||
msgid "car"
|
||||
msgstr "voiture"
|
||||
|
||||
msgid "Search"
|
||||
msgstr "Fouille"
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</form>
|
||||
|
||||
<p>You can also edit tags in the <a href="?do=taglist&sort=usage">tag list</a>.</p>
|
||||
<p>{'You can also edit tags in the'|t} <a href="?do=taglist&sort=usage">{'tag list'|t}</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
|
|
|
@ -69,6 +69,30 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
|
||||
<div class="form-label">
|
||||
<label for="language">
|
||||
<span class="label-name">{'Language'|t}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-lg-{$ratioInput} pure-u-1">
|
||||
<div class="form-input">
|
||||
<select name="language" id="language" class="align">
|
||||
{loop="$languages"}
|
||||
<option value="{$key}"
|
||||
{if="$key===$language"}
|
||||
selected="selected"
|
||||
{/if}
|
||||
>
|
||||
{$value}
|
||||
</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-{$ratioLabel} pure-u-1 ">
|
||||
<div class="form-label">
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<div class="center" id="import-field">
|
||||
<input type="hidden" name="MAX_FILE_SIZE" value="{$maxfilesize}">
|
||||
<input type="file" name="filetoupload">
|
||||
<p><br>Maximum size allowed: <strong>{$maxfilesizeHuman}</strong></p>
|
||||
<p><br>{'Maximum size allowed:'|t} <strong>{$maxfilesizeHuman}</strong></p>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
|
@ -31,15 +31,15 @@
|
|||
<div class="radio-buttons">
|
||||
<div>
|
||||
<input type="radio" name="privacy" value="default" checked="checked">
|
||||
Use values from the imported file, default to public
|
||||
{'Use values from the imported file, default to public'|t}
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="privacy" value="private">
|
||||
Import all bookmarks as private
|
||||
{'Import all bookmarks as private'|t}
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="privacy" value="public">
|
||||
Import all bookmarks as public
|
||||
{'Import all bookmarks as public'|t}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -65,6 +65,27 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
|
||||
<div class="form-label">
|
||||
<label for="language">
|
||||
<span class="label-name">{'Language'|t}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-lg-{$ratioInput} pure-u-1">
|
||||
<div class="form-input">
|
||||
<select name="language" id="language" class="align">
|
||||
{loop="$languages"}
|
||||
<option value="{$key}">
|
||||
{$value}
|
||||
</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
|
||||
<div class="form-label">
|
||||
|
|
|
@ -138,6 +138,9 @@ window.onload = function () {
|
|||
});
|
||||
foldAllButton.firstElementChild.classList.toggle('fa-chevron-down');
|
||||
foldAllButton.firstElementChild.classList.toggle('fa-chevron-up');
|
||||
foldAllButton.title = state === 'down'
|
||||
? document.getElementById('translation-fold-all').innerHTML
|
||||
: document.getElementById('translation-expand-all').innerHTML
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -146,7 +149,7 @@ window.onload = function () {
|
|||
{
|
||||
// Switch fold/expand - up = fold
|
||||
if (button.classList.contains('fa-chevron-up')) {
|
||||
button.title = 'Expand';
|
||||
button.title = document.getElementById('translation-expand').innerHTML;
|
||||
if (description != null) {
|
||||
description.style.display = 'none';
|
||||
}
|
||||
|
@ -155,7 +158,7 @@ window.onload = function () {
|
|||
}
|
||||
}
|
||||
else {
|
||||
button.title = 'Fold';
|
||||
button.title = document.getElementById('translation-fold').innerHTML;
|
||||
if (description != null) {
|
||||
description.style.display = 'block';
|
||||
}
|
||||
|
@ -173,7 +176,7 @@ window.onload = function () {
|
|||
var deleteLinks = document.querySelectorAll('.confirm-delete');
|
||||
[].forEach.call(deleteLinks, function(deleteLink) {
|
||||
deleteLink.addEventListener('click', function(event) {
|
||||
if(! confirm('Are you sure you want to delete this link ?')) {
|
||||
if(! confirm(document.getElementById('translation-delete-link').innerHTML)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
@ -618,7 +621,7 @@ function activateFirefoxSocial(node) {
|
|||
// Keeping the data separated (ie. not in the DOM) so that it's maintainable and diffable.
|
||||
var data = {
|
||||
name: title,
|
||||
description: "The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community.",
|
||||
description: document.getElementById('translation-delete-link').innerHTML,
|
||||
author: "Shaarli",
|
||||
version: "1.0.0",
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
<div class="pure-g pure-alert pure-alert-success search-result">
|
||||
<div class="pure-u-2-24"></div>
|
||||
<div class="pure-u-20-24">
|
||||
{function="t('%s result', '%s results', $result_count)"}
|
||||
{function="sprintf(t('%s result', '%s results', $result_count), $result_count)"}
|
||||
{if="!empty($search_term)"}
|
||||
{'for'|t} <em><strong>{$search_term}</strong></em>
|
||||
{/if}
|
||||
|
@ -117,6 +117,16 @@
|
|||
<div class="pure-g">
|
||||
<div class="pure-u-lg-2-24 pure-u-1-24"></div>
|
||||
<div class="pure-u-lg-20-24 pure-u-22-24">
|
||||
{ignore}Set translation here, for performances{/ignore}
|
||||
{$strPrivate=t('Private')}
|
||||
{$strEdit=t('Edit')}
|
||||
{$strDelete=t('Delete')}
|
||||
{$strFold=t('Fold')}
|
||||
{$strEdited=t('Edited: ')}
|
||||
{$strPermalink=t('Permalink')}
|
||||
{$strPermalinkLc=t('permalink')}
|
||||
{$strAddTag=t('Add tag')}
|
||||
{ignore}End of translations{/ignore}
|
||||
{loop="links"}
|
||||
<div class="anchor" id="{$value.shorturl}"></div>
|
||||
<div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}">
|
||||
|
@ -125,12 +135,12 @@
|
|||
{if="isLoggedIn()"}
|
||||
<div class="linklist-item-editbuttons">
|
||||
{if="$value.private"}
|
||||
<span class="label label-private">{'Private'|t}</span>
|
||||
<span class="label label-private">{$strPrivate}</span>
|
||||
{/if}
|
||||
<input type="checkbox" class="delete-checkbox" value="{$value.id}">
|
||||
<!-- FIXME! JS translation -->
|
||||
<a href="?edit_link={$value.id}" title="{'Edit'|t}"><i class="fa fa-pencil-square-o edit-link"></i></a>
|
||||
<a href="#" title="{'Fold'|t}" class="fold-button"><i class="fa fa-chevron-up"></i></a>
|
||||
<a href="?edit_link={$value.id}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link"></i></a>
|
||||
<a href="#" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up"></i></a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
@ -164,7 +174,7 @@
|
|||
<i class="fa fa-tags"></i>
|
||||
{$tag_counter=count($value.taglist)}
|
||||
{loop="value.taglist"}
|
||||
<span class="label label-tag" title="Add tag">
|
||||
<span class="label label-tag" title="{$strAddTag}">
|
||||
<a href="?addtag={$value|urlencode}">{$value}</a>
|
||||
</span>
|
||||
{if="$tag_counter - 1 != $counter"}·{/if}
|
||||
|
@ -174,9 +184,9 @@
|
|||
|
||||
<div class="pure-g">
|
||||
<div class="linklist-item-infos-dateblock pure-u-lg-3-8 pure-u-1">
|
||||
<a href="?{$value.shorturl}" title="{'Permalink'|t}">
|
||||
<a href="?{$value.shorturl}" title="{$strPermalink}">
|
||||
{if="!$hide_timestamps || isLoggedIn()"}
|
||||
{$updated=$value.updated_timestamp ? 'Edited: '. format_date($value.updated) : 'Permalink'}
|
||||
{$updated=$value.updated_timestamp ? $strEdited. format_date($value.updated) : $strPermalink}
|
||||
<span class="linkdate" title="{$updated}">
|
||||
<i class="fa fa-clock-o"></i>
|
||||
{$value.created|format_date}
|
||||
|
@ -184,7 +194,7 @@
|
|||
·
|
||||
</span>
|
||||
{/if}
|
||||
{'permalink'|t}
|
||||
{$strPermalinkLc}
|
||||
</a>
|
||||
|
||||
<div class="pure-u-0 pure-u-lg-visible">
|
||||
|
@ -205,7 +215,7 @@
|
|||
</a>
|
||||
{if="isLoggedIn()"}
|
||||
<a href="?delete_link&lf_linkdate={$value.id}&token={$token}"
|
||||
title="{'Delete'|t}" class="delete-link pure-u-0 pure-u-lg-visible confirm-delete">
|
||||
title="{$strDelete}" class="delete-link pure-u-0 pure-u-lg-visible confirm-delete">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
{/if}
|
||||
|
@ -221,7 +231,7 @@
|
|||
{if="isLoggedIn()"}
|
||||
·
|
||||
<a href="?delete_link&lf_linkdate={$value.id}&token={$token}"
|
||||
title="{'Delete'|t}" class="delete-link confirm-delete">
|
||||
title="{$strDelete}" class="delete-link confirm-delete">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
{/if}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<a href="?untaggedonly" title="{'Filter untagged links'|t}"
|
||||
class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if}
|
||||
><i class="fa fa-tag"></i></a>
|
||||
<a href="#" class="filter-off fold-all pure-u-lg-0" title="Fold all">
|
||||
<a href="#" class="filter-off fold-all pure-u-lg-0" title="{'Fold all'|t}">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
{loop="$action_plugin"}
|
||||
|
@ -53,7 +53,7 @@
|
|||
<form method="GET" class="pure-u-0 pure-u-lg-visible">
|
||||
<input type="text" name="linksperpage" placeholder="133">
|
||||
</form>
|
||||
<a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" title="Fold all">
|
||||
<a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" title="{'Fold all'|t}">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
{$version}
|
||||
{/if}
|
||||
·
|
||||
The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community ·
|
||||
<a href="doc/html/index.html" rel="nofollow">Documentation</a>
|
||||
{'The personal, minimalist, super-fast, database free, bookmarking service'|t} {'by the Shaarli community'|t} ·
|
||||
<a href="doc/html/index.html" rel="nofollow">{'Documentation'|t}</a>
|
||||
{loop="$plugins_footer.text"}
|
||||
{$value}
|
||||
{/loop}
|
||||
|
@ -27,6 +27,17 @@
|
|||
<script src="{$value}#"></script>
|
||||
{/loop}
|
||||
|
||||
<div id="js-translations" class="hidden">
|
||||
<span id="translation-fold">{'Fold'|t}</span>
|
||||
<span id="translation-fold-all">{'Fold all'|t}</span>
|
||||
<span id="translation-expand">{'Expand'|t}</span>
|
||||
<span id="translation-expand-all">{'Expand all'|t}</span>
|
||||
<span id="translation-delete-link">{'Are you sure you want to delete this link?'|t}</span>
|
||||
<span id="translation-shaarli-desc">
|
||||
{'The personal, minimalist, super-fast, database free, bookmarking service'|t} {'by the Shaarli community'|t}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<script src="js/shaarli.js?v={$version_hash}"></script>
|
||||
<script src="inc/awesomplete.js?v={$version_hash}#"></script>
|
||||
<script src="inc/awesomplete-multiple-tags.js?v={$version_hash}#"></script>
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
</section>
|
||||
|
||||
<div class="center more">
|
||||
More plugins available
|
||||
<a href="doc/Community-&-Related-software.html#third-party-plugins">in the documentation</a>.
|
||||
{"More plugins available"|t}
|
||||
<a href="doc/Community-&-Related-software.html#third-party-plugins">{"in the documentation"|t}</a>.
|
||||
</div>
|
||||
<div class="center">
|
||||
<input type="submit" value="{'Save'|t}" name="save">
|
||||
|
|
Loading…
Reference in a new issue