From 12266213d098a53c5f005b9afcbbe62771fd580c Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 9 May 2017 18:12:15 +0200 Subject: Shaarli's translation * translation system and unit tests * Translations everywhere Dont use translation merge It is not available with PHP builtin gettext, so it would have lead to inconsistency. --- application/ApplicationUtils.php | 19 +-- application/Cache.php | 2 +- application/FeedBuilder.php | 4 +- application/History.php | 4 +- application/Languages.php | 153 +++++++++++++++++++-- application/LinkDB.php | 20 +-- application/LinkFilter.php | 8 +- application/NetscapeBookmarkUtils.php | 16 +-- application/PageBuilder.php | 7 +- application/PluginManager.php | 7 +- application/Updater.php | 8 +- application/Utils.php | 17 ++- application/config/ConfigJson.php | 15 +- application/config/ConfigManager.php | 6 +- application/config/ConfigPhp.php | 4 +- .../exception/MissingFieldConfigException.php | 2 +- .../exception/PluginConfigOrderException.php | 2 +- .../exception/UnauthorizedConfigException.php | 2 +- application/exceptions/IOException.php | 2 +- 19 files changed, 232 insertions(+), 66 deletions(-) (limited to 'application') diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php index 5643f4a0..911873a0 100644 --- a/application/ApplicationUtils.php +++ b/application/ApplicationUtils.php @@ -149,12 +149,13 @@ class ApplicationUtils 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'); } } diff --git a/application/Cache.php b/application/Cache.php index 5d050165..e5d43e61 100644 --- a/application/Cache.php +++ b/application/Cache.php @@ -13,7 +13,7 @@ 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; } diff --git a/application/FeedBuilder.php b/application/FeedBuilder.php index 7377bcec..3cfaafb4 100644 --- a/application/FeedBuilder.php +++ b/application/FeedBuilder.php @@ -148,9 +148,9 @@ class FeedBuilder $link['url'] = $pageaddr . $link['url']; } if ($this->usePermalinks === true) { - $permalink = 'Direct link'; + $permalink = ''. t('Direct link') .''; } else { - $permalink = 'Permalink'; + $permalink = ''. t('Permalink') .''; } $link['description'] = format_description($link['description'], '', $pageaddr); $link['description'] .= PHP_EOL .'
— '. $permalink; diff --git a/application/History.php b/application/History.php index 5e3b1b72..35ec016a 100644 --- a/application/History.php +++ b/application/History.php @@ -171,7 +171,7 @@ class History } 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')); } } diff --git a/application/Languages.php b/application/Languages.php index c8b0a25a..4ba32f29 100644 --- a/application/Languages.php +++ b/application/Languages.php @@ -1,21 +1,150 @@ //LC_MESSAGES/.[po|mo] * - * @param string $text Text to translate. - * @param string $nText The plural message ID. - * @param int $nb The number of items for plural forms. + * Pros/cons: + * - gettext extension is faster + * - gettext is very system dependent (PHP extension, the locale must be installed, and web server reloaded) * - * @return String Text translated. + * 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 override. + * @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; } - $actualForm = $nb > 1 ? $nText : $text; - return sprintf($actualForm, $nb); } diff --git a/application/LinkDB.php b/application/LinkDB.php index 22c1f0ab..f026a041 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php @@ -133,16 +133,16 @@ class LinkDB implements Iterator, Countable, ArrayAccess { // 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', diff --git a/application/LinkFilter.php b/application/LinkFilter.php index 99ecd1e2..12376e27 100644 --- a/application/LinkFilter.php +++ b/application/LinkFilter.php @@ -444,5 +444,11 @@ class LinkFilter 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.'); + } } diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index 31796367..31a14537 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php @@ -32,11 +32,11 @@ 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(); - +7 foreach ($linkDb as $link) { if ($link['private'] != 0 && $selection == 'public') { continue; @@ -79,14 +79,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; } diff --git a/application/PageBuilder.php b/application/PageBuilder.php index 291860ad..af290671 100644 --- a/application/PageBuilder.php +++ b/application/PageBuilder.php @@ -159,9 +159,12 @@ class PageBuilder * * @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'); } diff --git a/application/PluginManager.php b/application/PluginManager.php index 59ece4fa..cf603845 100644 --- a/application/PluginManager.php +++ b/application/PluginManager.php @@ -188,6 +188,9 @@ class PluginManager $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); } } diff --git a/application/Updater.php b/application/Updater.php index 72b2def0..723a7a81 100644 --- a/application/Updater.php +++ b/application/Updater.php @@ -73,7 +73,7 @@ class Updater } 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 . '.')); } } diff --git a/application/Utils.php b/application/Utils.php index 4a2f5561..27eaafc5 100644 --- a/application/Utils.php +++ b/application/Utils.php @@ -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); +} diff --git a/application/config/ConfigJson.php b/application/config/ConfigJson.php index 9ef2ef56..8c8d5610 100644 --- a/application/config/ConfigJson.php +++ b/application/config/ConfigJson.php @@ -22,10 +22,15 @@ class ConfigJson implements ConfigIO $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. '
' . json_last_error_msg() .''; + $error = sprintf( + 'An error occurred while parsing JSON configuration file (%s): error code #%d', + $filepath, + $errorCode + ); + $error .= '
' . json_last_error_msg() .''; if ($errorCode === JSON_ERROR_SYNTAX) { - $error .= '
Please check your JSON syntax (without PHP comment tags) using a JSON lint tool such as '; + $error .= '
'; + $error .= 'Please check your JSON syntax (without PHP comment tags) using a JSON lint tool such as '; $error .= 'jsonlint.com.'; } 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.') ); } } diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php index 7ff2fe67..9e4c9f63 100644 --- a/application/config/ConfigManager.php +++ b/application/config/ConfigManager.php @@ -132,7 +132,7 @@ class ConfigManager 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()); } diff --git a/application/config/ConfigPhp.php b/application/config/ConfigPhp.php index 2633824d..2f66e8e0 100644 --- a/application/config/ConfigPhp.php +++ b/application/config/ConfigPhp.php @@ -118,8 +118,8 @@ class ConfigPhp implements ConfigIO ) { 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.') ); } } diff --git a/application/config/exception/MissingFieldConfigException.php b/application/config/exception/MissingFieldConfigException.php index 6346c6a9..9e0a9359 100644 --- a/application/config/exception/MissingFieldConfigException.php +++ b/application/config/exception/MissingFieldConfigException.php @@ -18,6 +18,6 @@ class MissingFieldConfigException extends \Exception 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); } } diff --git a/application/config/exception/PluginConfigOrderException.php b/application/config/exception/PluginConfigOrderException.php index f9d68750..f82ec26e 100644 --- a/application/config/exception/PluginConfigOrderException.php +++ b/application/config/exception/PluginConfigOrderException.php @@ -12,6 +12,6 @@ class PluginConfigOrderException extends \Exception */ 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.'); } } diff --git a/application/config/exception/UnauthorizedConfigException.php b/application/config/exception/UnauthorizedConfigException.php index 79672c1b..72311fae 100644 --- a/application/config/exception/UnauthorizedConfigException.php +++ b/application/config/exception/UnauthorizedConfigException.php @@ -13,6 +13,6 @@ class UnauthorizedConfigException extends \Exception */ public function __construct() { - $this->message = 'You are not authorized to alter config.'; + $this->message = t('You are not authorized to alter config.'); } } diff --git a/application/exceptions/IOException.php b/application/exceptions/IOException.php index b563b23d..18e46b77 100644 --- a/application/exceptions/IOException.php +++ b/application/exceptions/IOException.php @@ -16,7 +16,7 @@ class IOException extends Exception 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 .'"'; } } -- cgit v1.2.3 From f39580c6fd171b849cec5832b4912182696341f2 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Thu, 25 May 2017 13:26:05 +0200 Subject: Add language selection in the configure page of the default theme --- application/Languages.php | 16 +++++++++++++++- application/NetscapeBookmarkUtils.php | 1 - 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'application') diff --git a/application/Languages.php b/application/Languages.php index 4ba32f29..357c7524 100644 --- a/application/Languages.php +++ b/application/Languages.php @@ -62,7 +62,7 @@ class Languages /** * Languages constructor. * - * @param string $language lang determined by autoLocale(), can be override. + * @param string $language lang determined by autoLocale(), can be overridden. * @param ConfigManager $conf instance. */ public function __construct($language, $conf) @@ -147,4 +147,18 @@ class Languages { 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'), + ]; + } } diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index 31a14537..dd7057f8 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php @@ -36,7 +36,6 @@ class NetscapeBookmarkUtils } $bookmarkLinks = array(); -7 foreach ($linkDb as $link) { if ($link['private'] != 0 && $selection == 'public') { continue; -- cgit v1.2.3 From 6a65bc579810e3688a63a7c3b0e720dc0f5456b0 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 19 Aug 2017 10:53:19 +0200 Subject: Translations : Working demo example of translation extension --- application/Utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'application') diff --git a/application/Utils.php b/application/Utils.php index 27eaafc5..2f38a8de 100644 --- a/application/Utils.php +++ b/application/Utils.php @@ -480,7 +480,7 @@ function alphabetical_sort(&$data, $reverse = false, $byKeys = false) * @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. + * @return string Text translated. */ function t($text, $nText = '', $nb = 1, $domain = 'shaarli') { return dn__($domain, $text, $nText, $nb); -- cgit v1.2.3