From 09602acc5f754c3e814b4b7de9d9d4d283ed45ff Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 15 Jun 2014 17:49:23 +0200 Subject: Add two wrappers (_t() and _i()) - _t() is a wrapper for Minz_Translate::t() - Improve coding style of Translate.php - _i() is a wrapper for FreshRSS::icon() - queries.phtml shows how they work - It is a lot easier to read files with these functions :) --- lib/Minz/Translate.php | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'lib/Minz/Translate.php') diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index e14f783f7..df48350e9 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -18,28 +18,28 @@ class Minz_Translate { * $translates est le tableau de correspondance * $key => $traduction */ - private static $translates = array (); + private static $translates = array(); /** * Inclus le fichier de langue qui va bien * l'enregistre dans $translates */ - public static function init () { - $l = Minz_Configuration::language (); - self::$language = Minz_Session::param ('language', $l); + public static function init() { + $l = Minz_Configuration::language(); + self::$language = Minz_Session::param('language', $l); $l_path = APP_PATH . '/i18n/' . self::$language . '.php'; - if (file_exists ($l_path)) { - self::$translates = include ($l_path); + if (file_exists($l_path)) { + self::$translates = include($l_path); } } /** * Alias de init */ - public static function reset () { - self::init (); + public static function reset() { + self::init(); } /** @@ -48,24 +48,32 @@ class Minz_Translate { * @return la valeur correspondante à la clé * > si non présente dans le tableau, on retourne la clé elle-même */ - public static function t ($key) { + public static function t($key) { $translate = $key; - if (isset (self::$translates[$key])) { + if (isset(self::$translates[$key])) { $translate = self::$translates[$key]; } - $args = func_get_args (); + $args = func_get_args(); unset($args[0]); - return vsprintf ($translate, $args); + return vsprintf($translate, $args); } /** * Retourne la langue utilisée actuellement * @return la langue */ - public static function language () { + public static function language() { return self::$language; } } + +function _t($key) { + $args = func_get_args(); + unset($args[0]); + array_unshift($args, $key); + + return call_user_func_array("Minz_Translate::t", $args); +} -- cgit v1.2.3 From 35be1769de28df3fff1a26e40d1d6b1e587a2847 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 1 Aug 2014 20:20:25 +0200 Subject: Basic protection against XSRF using Referer https://github.com/marienfressinaud/FreshRSS/issues/554 Also edited the error controler to use the log message passed in Minz_Error::error(). --- app/Controllers/errorController.php | 52 +++++++++++++++++++++++-------------- app/FreshRSS.php | 11 +++++++- app/views/error/index.phtml | 13 ++-------- lib/Minz/Translate.php | 2 +- 4 files changed, 45 insertions(+), 33 deletions(-) (limited to 'lib/Minz/Translate.php') diff --git a/app/Controllers/errorController.php b/app/Controllers/errorController.php index dc9a2ee25..922650b3d 100644 --- a/app/Controllers/errorController.php +++ b/app/Controllers/errorController.php @@ -1,26 +1,38 @@ view->code = 'Error 403 - Forbidden'; - break; - case 404: - $this->view->code = 'Error 404 - Not found'; - break; - case 500: - $this->view->code = 'Error 500 - Internal Server Error'; - break; - case 503: - $this->view->code = 'Error 503 - Service Unavailable'; - break; - default: - $this->view->code = 'Error 404 - Not found'; + public function indexAction() { + switch (Minz_Request::param('code')) { + case 403: + $this->view->code = 'Error 403 - Forbidden'; + break; + case 404: + $this->view->code = 'Error 404 - Not found'; + break; + case 500: + $this->view->code = 'Error 500 - Internal Server Error'; + break; + case 503: + $this->view->code = 'Error 503 - Service Unavailable'; + break; + default: + $this->view->code = 'Error 404 - Not found'; } - - $this->view->logs = Minz_Request::param ('logs'); - - Minz_View::prependTitle ($this->view->code . ' · '); + + $errors = Minz_Request::param('logs', array()); + $this->view->errorMessage = trim(implode($errors)); + if ($this->view->errorMessage == '') { + switch(Minz_Request::param('code')) { + case 403: + $this->view->errorMessage = Minz_Translate::t('forbidden_access'); + break; + case 404: + default: + $this->view->errorMessage = Minz_Translate::t('page_not_found'); + break; + } + } + + Minz_View::prependTitle($this->view->code . ' · '); } } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 84cf3429b..cd6048f75 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -6,6 +6,16 @@ class FreshRSS extends Minz_FrontController { } $loginOk = $this->accessControl(Minz_Session::param('currentUser', '')); $this->loadParamsView(); + if (Minz_Request::isPost() && !empty($_SERVER['HTTP_REFERER']) && + Minz_Request::getDomainName() !== parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)) { + $loginOk = false; //Basic protection against XSRF attacks + Minz_Error::error( + 403, + array('error' => array(Minz_Translate::t('access_denied') . ' [HTTP_REFERER=' . + htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']')) + ); + } + Minz_View::_param('loginOk', $loginOk); $this->loadStylesAndScripts($loginOk); //TODO: Do not load that when not needed, e.g. some Ajax requests $this->loadNotifications(); } @@ -95,7 +105,6 @@ class FreshRSS extends Minz_FrontController { break; } } - Minz_View::_param ('loginOk', $loginOk); return $loginOk; } diff --git a/app/views/error/index.phtml b/app/views/error/index.phtml index 6a09c3aa2..ef4fbd39d 100644 --- a/app/views/error/index.phtml +++ b/app/views/error/index.phtml @@ -1,18 +1,9 @@

code; ?>

-

-
- + errorMessage; ?>
+

diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index df48350e9..8c2f90041 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -75,5 +75,5 @@ function _t($key) { unset($args[0]); array_unshift($args, $key); - return call_user_func_array("Minz_Translate::t", $args); + return call_user_func_array('Minz_Translate::t', $args); } -- cgit v1.2.3 From aa232d8fd52cf548c0b2e7d96e026e684eadda53 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 3 Dec 2014 16:45:51 +0100 Subject: Update the i18n system. Follow recommendations from https://github.com/FreshRSS/FreshRSS/issues/334 --- app/i18n/en.php | 533 ----------------------------------------------- app/i18n/en/admin.php | 92 ++++++++ app/i18n/en/conf.php | 7 + app/i18n/en/feedback.php | 14 ++ app/i18n/en/gen.php | 487 +++++++++++++++++++++++++++++++++++++++++++ app/i18n/en/index.php | 5 + app/i18n/en/install.php | 5 + app/i18n/en/sub.php | 10 + app/i18n/fr.php | 533 ----------------------------------------------- app/i18n/fr/admin.php | 92 ++++++++ app/i18n/fr/conf.php | 7 + app/i18n/fr/feedback.php | 14 ++ app/i18n/fr/gen.php | 487 +++++++++++++++++++++++++++++++++++++++++++ app/i18n/fr/index.php | 5 + app/i18n/fr/install.php | 5 + app/i18n/fr/sub.php | 10 + lib/Minz/Translate.php | 114 +++++++--- 17 files changed, 1320 insertions(+), 1100 deletions(-) delete mode 100644 app/i18n/en.php create mode 100644 app/i18n/en/admin.php create mode 100644 app/i18n/en/conf.php create mode 100644 app/i18n/en/feedback.php create mode 100644 app/i18n/en/gen.php create mode 100644 app/i18n/en/index.php create mode 100644 app/i18n/en/install.php create mode 100644 app/i18n/en/sub.php delete mode 100644 app/i18n/fr.php create mode 100644 app/i18n/fr/admin.php create mode 100644 app/i18n/fr/conf.php create mode 100644 app/i18n/fr/feedback.php create mode 100644 app/i18n/fr/gen.php create mode 100644 app/i18n/fr/index.php create mode 100644 app/i18n/fr/install.php create mode 100644 app/i18n/fr/sub.php (limited to 'lib/Minz/Translate.php') diff --git a/app/i18n/en.php b/app/i18n/en.php deleted file mode 100644 index a35a6ccf1..000000000 --- a/app/i18n/en.php +++ /dev/null @@ -1,533 +0,0 @@ - '\\A\\p\\r\\i\\l', - 'Aug' => '\\A\\u\\g\\u\\s\\t', - 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', - 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', - 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', - 'Jul' => '\\J\\u\\l\\y', - 'Jun' => '\\J\\u\\n\\e', - 'Mar' => '\\M\\a\\r\\c\\h', - 'May' => '\\M\\a\\y', - 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', - 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', - 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', - 'about' => 'About', - 'about_freshrss' => 'About FreshRSS', - 'access_denied' => 'You don’t have permission to access this page', - 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', - 'activate_sharing' => 'Activate sharing', - 'actualize' => 'Actualize', - 'add_category' => 'Add a category', - 'add_query' => 'Add a query', - 'add_rss_feed' => 'Add a RSS feed', - 'admin.check_install.cache.nok' => 'Check permissions on ./data/cache directory. HTTP server must have rights to write into', - 'admin.check_install.cache.ok' => 'Permissions on cache directory are good.', - 'admin.check_install.categories.nok' => 'Category table is bad configured.', - 'admin.check_install.categories.ok' => 'Category table is ok.', - 'admin.check_install.connection.nok' => 'Connection to the database cannot being established.', - 'admin.check_install.connection.ok' => 'Connection to the database is ok.', - 'admin.check_install.ctype.nok' => 'You lack a required library for character type checking (php-ctype).', - 'admin.check_install.ctype.ok' => 'You have the required library for character type checking (ctype).', - 'admin.check_install.curl.nok' => 'You lack cURL (php5-curl package).', - 'admin.check_install.curl.ok' => 'You have cURL extension.', - 'admin.check_install.data.nok' => 'Check permissions on ./data directory. HTTP server must have rights to write into', - 'admin.check_install.data.ok' => 'Permissions on data directory are good.', - 'admin.check_install.database' => 'Database installation', - 'admin.check_install.dom.nok' => 'You lack a required library to browse the DOM (php-xml package).', - 'admin.check_install.dom.ok' => 'You have the required library to browse the DOM.', - 'admin.check_install.entries.nok' => 'Entry table is bad configured.', - 'admin.check_install.entries.ok' => 'Entry table is ok.', - 'admin.check_install.favicons.nok' => 'Check permissions on ./data/favicons directory. HTTP server must have rights to write into', - 'admin.check_install.favicons.ok' => 'Permissions on favicons directory are good.', - 'admin.check_install.feeds.nok' => 'Feed table is bad configured.', - 'admin.check_install.feeds.ok' => 'Feed table is ok.', - 'admin.check_install.files' => 'File installation', - 'admin.check_install.json.nok' => 'You lack JSON (php5-json package).', - 'admin.check_install.json.ok' => 'You have JSON extension.', - 'admin.check_install.logs.nok' => 'Check permissions on ./data/logs directory. HTTP server must have rights to write into', - 'admin.check_install.logs.ok' => 'Permissions on logs directory are good.', - 'admin.check_install.minz.nok' => 'You lack the Minz framework.', - 'admin.check_install.minz.ok' => 'You have the Minz framework.', - 'admin.check_install.pcre.nok' => 'You lack a required library for regular expressions (php-pcre).', - 'admin.check_install.pcre.ok' => 'You have the required library for regular expressions (PCRE).', - 'admin.check_install.pdo.nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo.ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', - 'admin.check_install.persona.nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', - 'admin.check_install.persona.ok' => 'Permissions on Mozilla Persona directory are good.', - 'admin.check_install.php' => 'PHP installation', - 'admin.check_install.php.nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', - 'admin.check_install.php.ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', - 'admin.check_install.tables.nok' => 'There is one or more lacking tables in the database.', - 'admin.check_install.tables.ok' => 'Tables are existing in the database.', - 'admin.check_install.tokens.nok' => 'Check permissions on ./data/tokens directory. HTTP server must have rights to write into', - 'admin.check_install.tokens.ok' => 'Permissions on tokens directory are good.', - 'admin.check_install.zip.nok' => 'You lack ZIP extension (php5-zip package).', - 'admin.check_install.zip.ok' => 'You have ZIP extension.', - 'admin.users.articles_and_size' => '%s articles (%s)', - 'administration' => 'Manage', - 'advanced' => 'Advanced', - 'after_onread' => 'After “mark all as read”,', - 'agpl3' => 'AGPL 3', - 'all_feeds' => 'All feeds', - 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', - 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', - 'already_subscribed' => 'You have already subscribed to %s', - 'api_enabled' => 'Allow API access (required for mobile apps)', - 'apr' => 'apr', - 'april' => 'Apr', - 'archiving_configuration' => 'Archiving', - 'archiving_configuration_help' => 'More options are available in the individual stream settings', - 'article' => 'Article', - 'article_icons' => 'Article icons', - 'article_open_on_website' => 'when article is opened on its original website', - 'article_published_on' => 'This article originally appeared on %s', - 'article_published_on_author' => 'This article originally appeared on %s by %s', - 'article_viewed' => 'when article is viewed', - 'articles' => 'articles', - 'articles_per_page' => 'Number of articles per page', - 'articles_to_display' => 'Articles to display', - 'ask_empty' => 'Clear?', - 'attention' => 'Attention!', - 'aug' => 'aug', - 'august' => 'Aug', - 'auth_form' => 'Web form (traditional, requires JavaScript)', - 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', - 'auth_form_set' => 'Form is now your default authentication system.', - 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', - 'auth_none' => 'None (dangerous)', - 'auth_not_persona' => 'Only Persona system can be reset.', - 'auth_persona' => 'Mozilla Persona (modern, requires JavaScript)', - 'auth_reset' => 'Authentication reset', - 'auth_token' => 'Authentication token', - 'auth_type' => 'Authentication method', - 'auth_will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', - 'author' => 'Author', - 'auto_load_more' => 'Load next articles at the page bottom', - 'auto_read_when' => 'Mark article as read…', - 'auto_share' => 'Share', - 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', - 'back_to_rss_feeds' => '← Go back to your RSS feeds', - 'bad_opml_file' => 'Your OPML file is invalid', - 'base_url' => 'Base URL', - 'bdd' => 'Database', - 'bdd_conf_is_ko' => 'Verify your database information.', - 'bdd_conf_is_ok' => 'Database configuration has been saved.', - 'bdd_configuration' => 'Database configuration', - 'bdd_type' => 'Type of database', - 'before_one_day' => 'Before one day', - 'before_one_week' => 'Before one week', - 'before_yesterday' => 'Before yesterday', - 'blank_to_disable' => 'Leave blank to disable', - 'blogotext' => 'Blogotext', - 'bookmark' => 'Subscribe (FreshRSS bookmark)', - 'bottom_line' => 'Bottom line', - 'bugs_reports' => 'Bugs reports', - 'by' => 'by', - 'by_author' => 'By %s', - 'by_default' => 'By default', - 'by_email' => 'By email', - 'by_feed' => 'by feed', - 'cache_is_ok' => 'Permissions on cache directory are good', - 'can_not_be_deleted' => 'Cannot be deleted', - 'cancel' => 'Cancel', - 'categories' => 'Categories', - 'categories_management' => 'Categories management', - 'categories_updated' => 'Categories have been updated', - 'categorize' => 'Store in a category', - 'category' => 'Category', - 'category_created' => 'Category %s has been created.', - 'category_deleted' => 'Category has been deleted.', - 'category_emptied' => 'Category has been emptied', - 'category_empty' => 'Empty category', - 'category_name_exists' => 'Category name already exists.', - 'category_no_id' => 'You must precise the id of the category.', - 'category_no_name' => 'Category name cannot be empty.', - 'category_not_delete_default' => 'You cannot delete the default category!', - 'category_not_exist' => 'The category does not exist!', - 'category_number' => 'Category n°%d', - 'category_updated' => 'Category has been updated.', - 'change_value' => 'You should change this value by any other', - 'checks' => 'Checks', - 'choose_language' => 'Choose a language for FreshRSS', - 'clear_logs' => 'Clear the logs', - 'collapse_article' => 'Collapse', - 'conf.users.articles_and_size' => '%s articles (%s)', - 'configuration' => 'Configuration', - 'configuration_updated' => 'Configuration has been updated', - 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', - 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', - 'congratulations' => 'Congratulations!', - 'content_width' => 'Content width', - 'create' => 'Create', - 'create_user' => 'Create new user', - 'credits' => 'Credits', - 'credits_content' => 'Some design elements come from Bootstrap although FreshRSS doesn’t use this framework. Icons come from GNOME project. Open Sans font police has been created by Steve Matteson. Favicons are collected with getFavicon API. FreshRSS is based on Minz, a PHP framework.', - 'css_path_on_website' => 'Articles CSS path on original website', - 'ctype_is_nok' => 'You lack a required library for character type checking (php-ctype)', - 'ctype_is_ok' => 'You have the required library for character type checking (ctype)', - 'curl_is_nok' => 'You lack cURL (php5-curl package)', - 'curl_is_ok' => 'You have version %s of cURL', - 'current_user' => 'Current user', - 'damn' => 'Damn!', - 'data_is_ok' => 'Permissions on data directory are good', - 'dec' => 'dec', - 'december' => 'Dec', - 'default_category' => 'Uncategorized', - 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', - 'default_view' => 'Default view', - 'delete' => 'Delete', - 'delete_articles_every' => 'Remove articles after', - 'diaspora' => 'Diaspora*', - 'display' => 'Display', - 'display_articles_unfolded' => 'Show articles unfolded by default', - 'display_categories_unfolded' => 'Show categories folded by default', - 'display_configuration' => 'Display', - 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', - 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', - 'dom_is_ok' => 'You have the required library to browse the DOM', - 'email' => 'Email', - 'error_occurred' => 'An error occurred', - 'error_occurred_update' => 'Nothing was changed', - 'explain_token' => 'Allows to access RSS output of the default user without authentication.
%s?output=rss&token=%s', - 'export' => 'Export', - 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', - 'export_opml' => 'Export list of feeds (OPML)', - 'export_starred' => 'Export your favourites', - 'facebook' => 'Facebook', - 'favicons_is_ok' => 'Permissions on favicons directory are good', - 'favorite_feeds' => 'Favourites (%s)', - 'feb' => 'feb', - 'february' => 'Feb', - 'feed' => 'Feed', - 'feed_actualized' => '%s has been updated', - 'feed_added' => 'RSS feed %s has been added', - 'feed_deleted' => 'Feed has been deleted', - 'feed_description' => 'Description', - 'feed_empty' => 'This feed is empty. Please verify that it is still maintained.', - 'feed_in_error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.', - 'feed_list' => 'List of %s articles', - 'feed_not_added' => '%s could not be added', - 'feed_updated' => 'Feed has been updated', - 'feed_url' => 'Feed URL', - 'feed_validator' => 'Check the validity of the feed', - 'feedback.login.error' => 'Login is invalid', - 'feedback.login.success' => 'You are connected', - 'feedback.logout.success' => 'You are disconnected', - 'feedback.user_profile.updated' => 'Your profile has been modified', - 'feeds' => 'Feeds', - 'feeds_actualized' => 'RSS feeds have been updated', - 'feeds_imported' => 'Your feeds have been imported and will now be updated', - 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', - 'feeds_marked_read' => 'Feeds have been marked as read', - 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', - 'file_cannot_be_uploaded' => 'File cannot be uploaded!', - 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', - 'file_to_import' => 'File to import
(OPML, Json or Zip)', - 'file_to_import_no_zip' => 'File to import
(OPML or Json)', - 'filter' => 'Filter', - 'finish_installation' => 'Complete installation', - 'first' => 'First', - 'first_article' => 'Skip to the first article', - 'fix_errors_before' => 'Fix errors before skip to the next step.', - 'focus_search' => 'Access search box', - 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', - 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', - 'freshrss' => 'FreshRSS', - 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like Kriss Feed or Leed. It is light and easy to take in hand while being powerful and configurable tool.', - 'freshrss_installation' => 'Installation · FreshRSS', - 'fri' => 'Fri', - 'g+' => 'Google+', - 'gen.menu.admin' => 'Administration', - 'gen.menu.authentication' => 'Authentication', - 'gen.menu.check_install' => 'Installation checking', - 'gen.menu.user_management' => 'Manage users', - 'gen.menu.user_profile' => 'Profile', - 'gen.title.authentication' => 'Authentication', - 'gen.title.check_install' => 'Installation checking', - 'gen.title.global_view' => 'Global view', - 'gen.title.user_management' => 'Manage users', - 'gen.title.user_profile' => 'Profile', - 'general_conf_is_ok' => 'General configuration has been saved.', - 'general_configuration' => 'General configuration', - 'github_or_email' => 'on Github or by mail', - 'global_view' => 'Global view', - 'help' => 'Display documentation', - 'hide_read_feeds' => 'Hide categories & feeds with no unread article (does not work with “Show all articles” configuration)', - 'host' => 'Host', - 'html5_notif_timeout' => 'HTML5 notification timeout', - 'http_auth' => 'HTTP (for advanced users with HTTPS)', - 'http_authentication' => 'HTTP Authentication', - 'http_password' => 'HTTP password', - 'http_referer_is_nok' => 'Please check that you are not altering your HTTP REFERER.', - 'http_referer_is_ok' => 'Your HTTP REFERER is known and corresponds to your server.', - 'http_username' => 'HTTP username', - 'img_with_lazyload' => 'Use "lazy load" mode to load pictures', - 'import' => 'Import', - 'import_export' => 'Import / export', - 'informations' => 'Information', - 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', - 'installation_is_ok' => 'The installation process was successful.
The final step will now attempt to delete any file and database backup created during the update process.
You may choose to skip this step by deleting ./data/do-install.txt manually.', - 'installation_step' => 'Installation — step %d · FreshRSS', - 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', - 'invalid_login' => 'Login is invalid', - 'invalid_url' => 'URL %s is invalid', - 'is_admin' => 'is administrator', - 'jan' => 'jan', - 'january' => 'Jan', - 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', - 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', - 'javascript_should_be_activated' => 'JavaScript must be enabled', - 'jul' => 'jul', - 'july' => 'Jul', - 'jump_next' => 'jump to next unread sibling (feed or category)', - 'jun' => 'jun', - 'june' => 'Jun', - 'keep_history' => 'Minimum number of articles to keep', - 'keep_logged_in' => 'Keep me logged in (1 month)', - 'language' => 'Language', - 'language_defined' => 'Language has been defined.', - 'last' => 'Last', - 'last_3_month' => 'Last three months', - 'last_6_month' => 'Last six months', - 'last_article' => 'Skip to the last article', - 'last_month' => 'Last month', - 'last_week' => 'Last week', - 'last_year' => 'Last year', - 'lead_developer' => 'Lead developer', - 'license' => 'License', - 'load_more' => 'Load more articles', - 'log_is_ok' => 'Permissions on logs directory are good', - 'login' => 'Login', - 'login_configuration' => 'Login', - 'login_persona_problem' => 'Connection problem with Persona?', - 'login_required' => 'Login required:', - 'login_with_persona' => 'Login with Persona', - 'logout' => 'Logout', - 'logs' => 'Logs', - 'logs_empty' => 'Log file is empty', - 'main_stream' => 'Main stream', - 'mar' => 'mar', - 'march' => 'Mar', - 'mark_all_read' => 'Mark all as read', - 'mark_cat_read' => 'Mark category as read', - 'mark_favorite' => 'Mark as favourite', - 'mark_feed_read' => 'Mark feed as read', - 'mark_read' => 'Mark as read', - 'may' => 'May', - 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', - 'minz_is_ok' => 'You have the Minz framework', - 'mon' => 'Mon', - 'month' => 'months', - 'more_information' => 'More information', - 'n_entries_deleted' => '%d articles have been deleted', - 'n_feeds_actualized' => '%d feeds have been updated', - 'new_article' => 'There are new available articles, click to refresh the page.', - 'new_category' => 'New category', - 'newer_first' => 'Newer first', - 'next' => 'Next', - 'next_article' => 'Skip to the next article', - 'next_page' => 'Skip to the next page', - 'next_step' => 'Go to the next step', - 'no' => 'No', - 'no_feed_actualized' => 'No RSS feed has been updated', - 'no_feed_to_display' => 'There is no article to show.', - 'no_feed_to_refresh' => 'There is no feed to refresh…', - 'no_query' => 'You haven’t created any user query yet.', - 'no_query_filter' => 'No filter', - 'no_rss_feed' => 'No RSS feed', - 'no_selected_feed' => 'No feed selected.', - 'no_update' => 'No update to apply', - 'no_zip_extension' => 'Zip extension is not present on your server.', - 'normal_view' => 'Normal view', - 'not_read' => '%d unread', - 'not_reads' => '%d unread', - 'not_yet_implemented' => 'Not yet implemented', - 'nothing_to_load' => 'There are no more articles', - 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS: new articles!', - 'nov' => 'nov', - 'november' => 'Nov', - 'number_articles' => '%d articles', - 'number_divided_when_reader' => 'Divided by 2 in the reading view.', - 'number_feeds' => '%d feeds', - 'oct' => 'oct', - 'october' => 'Oct', - 'ok' => 'Ok!', - 'older_first' => 'Oldest first', - 'oops' => 'Oops!', - 'optimization_complete' => 'Optimization complete', - 'optimize_bdd' => 'Optimize database', - 'optimize_todo_sometimes' => 'To do occasionally to reduce the size of the database', - 'or' => 'or', - 'page_not_found' => 'You are looking for a page which doesn’t exist', - 'password' => 'Password', - 'password_api' => 'Password API
(e.g., for mobile apps)', - 'password_form' => 'Password
(for the Web-form login method)', - 'pcre_is_nok' => 'You lack a required library for regular expressions (php-pcre)', - 'pcre_is_ok' => 'You have the required library for regular expressions (PCRE)', - 'pdo_is_nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite)', - 'pdo_is_ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite)', - 'persona_connection_email' => 'Login mail address
(for Mozilla Persona)', - 'persona_is_ok' => 'Permissions on Mozilla Persona directory are good', - 'php_is_nok' => 'Your PHP version is %s but FreshRSS requires at least version %s', - 'php_is_ok' => 'Your PHP version is %s, which is compatible with FreshRSS', - 'prefix' => 'Table prefix', - 'previous' => 'Previous', - 'previous_article' => 'Skip to the previous article', - 'previous_page' => 'Skip to the previous page', - 'print' => 'Print', - 'project_website' => 'Project website', - 'public' => 'Public', - 'publication_date' => 'Date of publication', - 'purge_completed' => 'Purge completed (%d articles deleted)', - 'purge_now' => 'Purge now', - 'queries' => 'User queries', - 'query_created' => 'Query "%s" has been created.', - 'query_deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.', - 'query_filter' => 'Filter applied:', - 'query_get_all' => 'Display all articles', - 'query_get_category' => 'Display "%s" category', - 'query_get_favorite' => 'Display favorite articles', - 'query_get_feed' => 'Display "%s" feed', - 'query_number' => 'Query n°%d', - 'query_order_asc' => 'Display oldest articles first', - 'query_order_desc' => 'Display newest articles first', - 'query_search' => 'Search for "%s"', - 'query_state_0' => 'Display all articles', - 'query_state_1' => 'Display read articles', - 'query_state_2' => 'Display unread articles', - 'query_state_3' => 'Display all articles', - 'query_state_4' => 'Display favorite articles', - 'query_state_5' => 'Display read favorite articles', - 'query_state_6' => 'Display unread favorite articles', - 'query_state_7' => 'Display favorite articles', - 'query_state_8' => 'Display not favorite articles', - 'query_state_9' => 'Display read not favorite articles', - 'query_state_10' => 'Display unread not favorite articles', - 'query_state_11' => 'Display not favorite articles', - 'query_state_12' => 'Display all articles', - 'query_state_13' => 'Display read articles', - 'query_state_14' => 'Display unread articles', - 'query_state_15' => 'Display all articles', - 'random_string' => 'Random string', - 'reader_view' => 'Reading view', - 'reading_configuration' => 'Reading', - 'reading_confirm' => 'Display a confirmation dialog on “mark all as read” actions', - 'refresh' => 'Refresh', - 'related_tags' => 'Related tags', - 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', - 'rss_feed_management' => 'RSS feeds management', - 'rss_feeds_of' => 'RSS feed of %s', - 'rss_view' => 'RSS feed', - 'sat' => 'Sat', - 'save' => 'Save', - 'scroll' => 'while scrolling', - 'search' => 'Search words or #tags', - 'search_short' => 'Search', - 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', - 'see_on_website' => 'See on original website', - 'see_website' => 'See website', - 'sep' => 'sep', - 'september' => 'Sep', - 'shaarli' => 'Shaarli', - 'share' => 'Share', - 'share_name' => 'Share name to display', - 'share_url' => 'Share URL to use', - 'sharing' => 'Sharing', - 'sharing_management' => 'Sharing options management', - 'shift_for_all_read' => '+ shift to mark all articles as read', - 'shortcuts' => 'Shortcuts', - 'shortcuts_article_action' => 'Article actions', - 'shortcuts_navigation' => 'Navigation', - 'shortcuts_navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.
With the "Alt" modifier, navigation shortcuts apply on categories.', - 'shortcuts_other_action' => 'Other actions', - 'shortcuts_updated' => 'Shortcuts have been updated', - 'show_adaptive' => 'Adjust showing', - 'show_all_articles' => 'Show all articles', - 'show_favorite' => 'Show only favorites', - 'show_in_all_flux' => 'Show in main stream', - 'show_not_favorite' => 'Show all but favorites', - 'show_not_reads' => 'Show only unread', - 'show_read' => 'Show only read', - 'sort_order' => 'Sort order', - 'starred_list' => 'List of favourite articles', - 'stats' => 'Statistics', - 'stats_entry_count' => 'Entry count', - 'stats_entry_per_category' => 'Entries per category', - 'stats_entry_per_day' => 'Entries per day (last 30 days)', - 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', - 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', - 'stats_entry_per_month' => 'Per month (average: %.2f messages)', - 'stats_entry_repartition' => 'Entries repartition', - 'stats_feed_per_category' => 'Feeds per category', - 'stats_idle' => 'Idle feeds', - 'stats_main' => 'Main statistics', - 'stats_no_idle' => 'There is no idle feed!', - 'stats_percent_of_total' => '%% of total', - 'stats_repartition' => 'Articles repartition', - 'stats_top_feed' => 'Top ten feeds', - 'status_favorites' => 'Favourites', - 'status_read' => 'Read', - 'status_total' => 'Total', - 'status_unread' => 'Unread', - 'steps' => 'Steps', - 'sticky_post' => 'Stick the article to the top when opened', - 'sub.categories.over_max' => 'You have reached your limit of categories (%d)', - 'sub.feeds.over_max' => 'You have reached your limit of feeds (%d)', - 'submit' => 'Submit', - 'subscription_management' => 'Subscriptions management', - 'sun' => 'Sun', - 'theme' => 'Theme', - 'think_to_add' => 'You may add some feeds.', - 'this_is_the_end' => 'This is the end', - 'thu' => 'Thu', - 'title' => 'Title', - 'today' => 'Today', - 'top_line' => 'Top line', - 'truncate' => 'Delete all articles', - 'ttl' => 'Do not automatically refresh more often than', - 'tue' => 'Tue', - 'twitter' => 'Twitter', - 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', - 'update' => 'Update', - 'update_apply' => 'Apply', - 'update_can_apply' => 'An update is available.', - 'update_check' => 'Check for new updates', - 'update_end' => 'Update process is completed, now you can go to the final step.', - 'update_finished' => 'Update completed!', - 'update_last' => 'Last verification: %s', - 'update_long' => 'This can take a long time, depending on the size of your database. You may have to wait for this page to time out (~5 minutes) and then refresh this page.', - 'update_problem' => 'The update process has encountered an error: %s', - 'update_server_not_found' => 'Update server cannot be found. [%s]', - 'update_start' => 'Start update process', - 'update_system' => 'Update system', - 'updated' => 'Modifications have been updated', - 'upon_reception' => 'upon reception of the article', - 'user_created' => 'User %s has been created', - 'user_deleted' => 'User %s has been deleted', - 'user_filter' => 'Access user filters', - 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', - 'username' => 'Username', - 'username_admin' => 'Administrator username', - 'users' => 'Users', - 'users_list' => 'List of users', - 'version' => 'Version', - 'version_update' => 'Update', - 'wallabag' => 'wallabag', - 'website' => 'Website', - 'website_url' => 'Website URL', - 'wed' => 'Wed', - 'width_large' => 'Large', - 'width_medium' => 'Medium', - 'width_no_limit' => 'No limit', - 'width_thin' => 'Thin', - 'yes' => 'Yes', - 'yesterday' => 'Yesterday', - 'your_diaspora_pod' => 'Your Diaspora* pod', - 'your_favorites' => 'Your favourites', - 'your_rss_feeds' => 'Your RSS feeds', - 'your_shaarli' => 'Your Shaarli', - 'your_wallabag' => 'Your wallabag', - 'zip_error' => 'An error occured during Zip import.', -); \ No newline at end of file diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php new file mode 100644 index 000000000..74f01ae06 --- /dev/null +++ b/app/i18n/en/admin.php @@ -0,0 +1,92 @@ + array( + 'cache' => array( + 'nok' => 'Check permissions on ./data/cache directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on cache directory are good.', + ), + 'categories' => array( + 'nok' => 'Category table is bad configured.', + 'ok' => 'Category table is ok.', + ), + 'connection' => array( + 'nok' => 'Connection to the database cannot being established.', + 'ok' => 'Connection to the database is ok.', + ), + 'ctype' => array( + 'nok' => 'You lack a required library for character type checking (php-ctype).', + 'ok' => 'You have the required library for character type checking (ctype).', + ), + 'curl' => array( + 'nok' => 'You lack cURL (php5-curl package).', + 'ok' => 'You have cURL extension.', + ), + 'data' => array( + 'nok' => 'Check permissions on ./data directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on data directory are good.', + ), + 'database' => 'Database installation', + 'dom' => array( + 'nok' => 'You lack a required library to browse the DOM (php-xml package).', + 'ok' => 'You have the required library to browse the DOM.', + ), + 'entries' => array( + 'nok' => 'Entry table is bad configured.', + 'ok' => 'Entry table is ok.', + ), + 'favicons' => array( + 'nok' => 'Check permissions on ./data/favicons directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on favicons directory are good.', + ), + 'feeds' => array( + 'nok' => 'Feed table is bad configured.', + 'ok' => 'Feed table is ok.', + ), + 'files' => 'File installation', + 'json' => array( + 'nok' => 'You lack JSON (php5-json package).', + 'ok' => 'You have JSON extension.', + ), + 'logs' => array( + 'nok' => 'Check permissions on ./data/logs directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on logs directory are good.', + ), + 'minz' => array( + 'nok' => 'You lack the Minz framework.', + 'ok' => 'You have the Minz framework.', + ), + 'pcre' => array( + 'nok' => 'You lack a required library for regular expressions (php-pcre).', + 'ok' => 'You have the required library for regular expressions (PCRE).', + ), + 'pdo' => array( + 'nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', + 'ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', + ), + 'persona' => array( + 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on Mozilla Persona directory are good.', + ), + 'php' => array( + '_' => 'PHP installation', + 'nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', + 'ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', + ), + 'tables' => array( + 'nok' => 'There is one or more lacking tables in the database.', + 'ok' => 'Tables are existing in the database.', + ), + 'tokens' => array( + 'nok' => 'Check permissions on ./data/tokens directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on tokens directory are good.', + ), + 'zip' => array( + 'nok' => 'You lack ZIP extension (php5-zip package).', + 'ok' => 'You have ZIP extension.', + ), + ), + 'users' => array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php new file mode 100644 index 000000000..460804774 --- /dev/null +++ b/app/i18n/en/conf.php @@ -0,0 +1,7 @@ + array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php new file mode 100644 index 000000000..b3866f1dc --- /dev/null +++ b/app/i18n/en/feedback.php @@ -0,0 +1,14 @@ + array( + 'error' => 'Login is invalid', + 'success' => 'You are connected', + ), + 'logout' => array( + 'success' => 'You are disconnected', + ), + 'user_profile' => array( + 'updated' => 'Your profile has been modified', + ), +); diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php new file mode 100644 index 000000000..9e06357bc --- /dev/null +++ b/app/i18n/en/gen.php @@ -0,0 +1,487 @@ + '\\A\\p\\r\\i\\l', + 'Aug' => '\\A\\u\\g\\u\\s\\t', + 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', + 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', + 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'Jul' => '\\J\\u\\l\\y', + 'Jun' => '\\J\\u\\n\\e', + 'Mar' => '\\M\\a\\r\\c\\h', + 'May' => '\\M\\a\\y', + 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', + 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'about' => 'About', + 'about_freshrss' => 'About FreshRSS', + 'access_denied' => 'You don’t have permission to access this page', + 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', + 'activate_sharing' => 'Activate sharing', + 'actualize' => 'Actualize', + 'add_category' => 'Add a category', + 'add_query' => 'Add a query', + 'add_rss_feed' => 'Add a RSS feed', + 'administration' => 'Manage', + 'advanced' => 'Advanced', + 'after_onread' => 'After “mark all as read”,', + 'agpl3' => 'AGPL 3', + 'all_feeds' => 'All feeds', + 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', + 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', + 'already_subscribed' => 'You have already subscribed to %s', + 'api_enabled' => 'Allow API access (required for mobile apps)', + 'apr' => 'apr', + 'april' => 'Apr', + 'archiving_configuration' => 'Archiving', + 'archiving_configuration_help' => 'More options are available in the individual stream settings', + 'article' => 'Article', + 'article_icons' => 'Article icons', + 'article_open_on_website' => 'when article is opened on its original website', + 'article_published_on' => 'This article originally appeared on %s', + 'article_published_on_author' => 'This article originally appeared on %s by %s', + 'article_viewed' => 'when article is viewed', + 'articles' => 'articles', + 'articles_per_page' => 'Number of articles per page', + 'articles_to_display' => 'Articles to display', + 'ask_empty' => 'Clear?', + 'attention' => 'Attention!', + 'aug' => 'aug', + 'august' => 'Aug', + 'auth_form' => 'Web form (traditional, requires JavaScript)', + 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', + 'auth_form_set' => 'Form is now your default authentication system.', + 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', + 'auth_none' => 'None (dangerous)', + 'auth_not_persona' => 'Only Persona system can be reset.', + 'auth_persona' => 'Mozilla Persona (modern, requires JavaScript)', + 'auth_reset' => 'Authentication reset', + 'auth_token' => 'Authentication token', + 'auth_type' => 'Authentication method', + 'auth_will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', + 'author' => 'Author', + 'auto_load_more' => 'Load next articles at the page bottom', + 'auto_read_when' => 'Mark article as read…', + 'auto_share' => 'Share', + 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', + 'back_to_rss_feeds' => '← Go back to your RSS feeds', + 'bad_opml_file' => 'Your OPML file is invalid', + 'base_url' => 'Base URL', + 'bdd' => 'Database', + 'bdd_conf_is_ko' => 'Verify your database information.', + 'bdd_conf_is_ok' => 'Database configuration has been saved.', + 'bdd_configuration' => 'Database configuration', + 'bdd_type' => 'Type of database', + 'before_one_day' => 'Before one day', + 'before_one_week' => 'Before one week', + 'before_yesterday' => 'Before yesterday', + 'blank_to_disable' => 'Leave blank to disable', + 'blogotext' => 'Blogotext', + 'bookmark' => 'Subscribe (FreshRSS bookmark)', + 'bottom_line' => 'Bottom line', + 'bugs_reports' => 'Bugs reports', + 'by' => 'by', + 'by_author' => 'By %s', + 'by_default' => 'By default', + 'by_email' => 'By email', + 'by_feed' => 'by feed', + 'cache_is_ok' => 'Permissions on cache directory are good', + 'can_not_be_deleted' => 'Cannot be deleted', + 'cancel' => 'Cancel', + 'categories' => 'Categories', + 'categories_management' => 'Categories management', + 'categories_updated' => 'Categories have been updated', + 'categorize' => 'Store in a category', + 'category' => 'Category', + 'category_created' => 'Category %s has been created.', + 'category_deleted' => 'Category has been deleted.', + 'category_emptied' => 'Category has been emptied', + 'category_empty' => 'Empty category', + 'category_name_exists' => 'Category name already exists.', + 'category_no_id' => 'You must precise the id of the category.', + 'category_no_name' => 'Category name cannot be empty.', + 'category_not_delete_default' => 'You cannot delete the default category!', + 'category_not_exist' => 'The category does not exist!', + 'category_number' => 'Category n°%d', + 'category_updated' => 'Category has been updated.', + 'change_value' => 'You should change this value by any other', + 'checks' => 'Checks', + 'choose_language' => 'Choose a language for FreshRSS', + 'clear_logs' => 'Clear the logs', + 'collapse_article' => 'Collapse', + 'configuration' => 'Configuration', + 'configuration_updated' => 'Configuration has been updated', + 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', + 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', + 'congratulations' => 'Congratulations!', + 'content_width' => 'Content width', + 'create' => 'Create', + 'create_user' => 'Create new user', + 'credits' => 'Credits', + 'credits_content' => 'Some design elements come from Bootstrap although FreshRSS doesn’t use this framework. Icons come from GNOME project. Open Sans font police has been created by Steve Matteson. Favicons are collected with getFavicon API. FreshRSS is based on Minz, a PHP framework.', + 'css_path_on_website' => 'Articles CSS path on original website', + 'ctype_is_nok' => 'You lack a required library for character type checking (php-ctype)', + 'ctype_is_ok' => 'You have the required library for character type checking (ctype)', + 'curl_is_nok' => 'You lack cURL (php5-curl package)', + 'curl_is_ok' => 'You have version %s of cURL', + 'current_user' => 'Current user', + 'damn' => 'Damn!', + 'data_is_ok' => 'Permissions on data directory are good', + 'dec' => 'dec', + 'december' => 'Dec', + 'default_category' => 'Uncategorized', + 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', + 'default_view' => 'Default view', + 'delete' => 'Delete', + 'delete_articles_every' => 'Remove articles after', + 'diaspora' => 'Diaspora*', + 'display' => 'Display', + 'display_articles_unfolded' => 'Show articles unfolded by default', + 'display_categories_unfolded' => 'Show categories folded by default', + 'display_configuration' => 'Display', + 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', + 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', + 'dom_is_ok' => 'You have the required library to browse the DOM', + 'email' => 'Email', + 'error_occurred' => 'An error occurred', + 'error_occurred_update' => 'Nothing was changed', + 'explain_token' => 'Allows to access RSS output of the default user without authentication.
%s?output=rss&token=%s', + 'export' => 'Export', + 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', + 'export_opml' => 'Export list of feeds (OPML)', + 'export_starred' => 'Export your favourites', + 'facebook' => 'Facebook', + 'favicons_is_ok' => 'Permissions on favicons directory are good', + 'favorite_feeds' => 'Favourites (%s)', + 'feb' => 'feb', + 'february' => 'Feb', + 'feed' => 'Feed', + 'feed_actualized' => '%s has been updated', + 'feed_added' => 'RSS feed %s has been added', + 'feed_deleted' => 'Feed has been deleted', + 'feed_description' => 'Description', + 'feed_empty' => 'This feed is empty. Please verify that it is still maintained.', + 'feed_in_error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.', + 'feed_list' => 'List of %s articles', + 'feed_not_added' => '%s could not be added', + 'feed_updated' => 'Feed has been updated', + 'feed_url' => 'Feed URL', + 'feed_validator' => 'Check the validity of the feed', + 'feeds' => 'Feeds', + 'feeds_actualized' => 'RSS feeds have been updated', + 'feeds_imported' => 'Your feeds have been imported and will now be updated', + 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', + 'feeds_marked_read' => 'Feeds have been marked as read', + 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', + 'file_cannot_be_uploaded' => 'File cannot be uploaded!', + 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', + 'file_to_import' => 'File to import
(OPML, Json or Zip)', + 'file_to_import_no_zip' => 'File to import
(OPML or Json)', + 'filter' => 'Filter', + 'finish_installation' => 'Complete installation', + 'first' => 'First', + 'first_article' => 'Skip to the first article', + 'fix_errors_before' => 'Fix errors before skip to the next step.', + 'focus_search' => 'Access search box', + 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', + 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', + 'freshrss' => 'FreshRSS', + 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like Kriss Feed or Leed. It is light and easy to take in hand while being powerful and configurable tool.', + 'freshrss_installation' => 'Installation · FreshRSS', + 'fri' => 'Fri', + 'g+' => 'Google+', + 'menu' => array( + 'admin' => 'Administration', + 'authentication' => 'Authentication', + 'check_install' => 'Installation checking', + 'user_management' => 'Manage users', + 'user_profile' => 'Profile', + ), + 'title' => array( + '_' => 'Title', + 'authentication' => 'Authentication', + 'check_install' => 'Installation checking', + 'global_view' => 'Global view', + 'user_management' => 'Manage users', + 'user_profile' => 'Profile', + ), + 'general_conf_is_ok' => 'General configuration has been saved.', + 'general_configuration' => 'General configuration', + 'github_or_email' => 'on Github or by mail', + 'global_view' => 'Global view', + 'help' => 'Display documentation', + 'hide_read_feeds' => 'Hide categories & feeds with no unread article (does not work with “Show all articles” configuration)', + 'host' => 'Host', + 'html5_notif_timeout' => 'HTML5 notification timeout', + 'http_auth' => 'HTTP (for advanced users with HTTPS)', + 'http_authentication' => 'HTTP Authentication', + 'http_password' => 'HTTP password', + 'http_referer_is_nok' => 'Please check that you are not altering your HTTP REFERER.', + 'http_referer_is_ok' => 'Your HTTP REFERER is known and corresponds to your server.', + 'http_username' => 'HTTP username', + 'img_with_lazyload' => 'Use "lazy load" mode to load pictures', + 'import' => 'Import', + 'import_export' => 'Import / export', + 'informations' => 'Information', + 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', + 'installation_is_ok' => 'The installation process was successful.
The final step will now attempt to delete any file and database backup created during the update process.
You may choose to skip this step by deleting ./data/do-install.txt manually.', + 'installation_step' => 'Installation — step %d · FreshRSS', + 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', + 'invalid_login' => 'Login is invalid', + 'invalid_url' => 'URL %s is invalid', + 'is_admin' => 'is administrator', + 'jan' => 'jan', + 'january' => 'Jan', + 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', + 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', + 'javascript_should_be_activated' => 'JavaScript must be enabled', + 'jul' => 'jul', + 'july' => 'Jul', + 'jump_next' => 'jump to next unread sibling (feed or category)', + 'jun' => 'jun', + 'june' => 'Jun', + 'keep_history' => 'Minimum number of articles to keep', + 'keep_logged_in' => 'Keep me logged in (1 month)', + 'language' => 'Language', + 'language_defined' => 'Language has been defined.', + 'last' => 'Last', + 'last_3_month' => 'Last three months', + 'last_6_month' => 'Last six months', + 'last_article' => 'Skip to the last article', + 'last_month' => 'Last month', + 'last_week' => 'Last week', + 'last_year' => 'Last year', + 'lead_developer' => 'Lead developer', + 'license' => 'License', + 'load_more' => 'Load more articles', + 'log_is_ok' => 'Permissions on logs directory are good', + 'login' => 'Login', + 'login_configuration' => 'Login', + 'login_persona_problem' => 'Connection problem with Persona?', + 'login_required' => 'Login required:', + 'login_with_persona' => 'Login with Persona', + 'logout' => 'Logout', + 'logs' => 'Logs', + 'logs_empty' => 'Log file is empty', + 'main_stream' => 'Main stream', + 'mar' => 'mar', + 'march' => 'Mar', + 'mark_all_read' => 'Mark all as read', + 'mark_cat_read' => 'Mark category as read', + 'mark_favorite' => 'Mark as favourite', + 'mark_feed_read' => 'Mark feed as read', + 'mark_read' => 'Mark as read', + 'may' => 'May', + 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', + 'minz_is_ok' => 'You have the Minz framework', + 'mon' => 'Mon', + 'month' => 'months', + 'more_information' => 'More information', + 'n_entries_deleted' => '%d articles have been deleted', + 'n_feeds_actualized' => '%d feeds have been updated', + 'new_article' => 'There are new available articles, click to refresh the page.', + 'new_category' => 'New category', + 'newer_first' => 'Newer first', + 'next' => 'Next', + 'next_article' => 'Skip to the next article', + 'next_page' => 'Skip to the next page', + 'next_step' => 'Go to the next step', + 'no' => 'No', + 'no_feed_actualized' => 'No RSS feed has been updated', + 'no_feed_to_display' => 'There is no article to show.', + 'no_feed_to_refresh' => 'There is no feed to refresh…', + 'no_query' => 'You haven’t created any user query yet.', + 'no_query_filter' => 'No filter', + 'no_rss_feed' => 'No RSS feed', + 'no_selected_feed' => 'No feed selected.', + 'no_update' => 'No update to apply', + 'no_zip_extension' => 'Zip extension is not present on your server.', + 'normal_view' => 'Normal view', + 'not_read' => '%d unread', + 'not_reads' => '%d unread', + 'not_yet_implemented' => 'Not yet implemented', + 'nothing_to_load' => 'There are no more articles', + 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS: new articles!', + 'nov' => 'nov', + 'november' => 'Nov', + 'number_articles' => '%d articles', + 'number_divided_when_reader' => 'Divided by 2 in the reading view.', + 'number_feeds' => '%d feeds', + 'oct' => 'oct', + 'october' => 'Oct', + 'ok' => 'Ok!', + 'older_first' => 'Oldest first', + 'oops' => 'Oops!', + 'optimization_complete' => 'Optimization complete', + 'optimize_bdd' => 'Optimize database', + 'optimize_todo_sometimes' => 'To do occasionally to reduce the size of the database', + 'or' => 'or', + 'page_not_found' => 'You are looking for a page which doesn’t exist', + 'password' => 'Password', + 'password_api' => 'Password API
(e.g., for mobile apps)', + 'password_form' => 'Password
(for the Web-form login method)', + 'pcre_is_nok' => 'You lack a required library for regular expressions (php-pcre)', + 'pcre_is_ok' => 'You have the required library for regular expressions (PCRE)', + 'pdo_is_nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite)', + 'pdo_is_ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite)', + 'persona_connection_email' => 'Login mail address
(for Mozilla Persona)', + 'persona_is_ok' => 'Permissions on Mozilla Persona directory are good', + 'php_is_nok' => 'Your PHP version is %s but FreshRSS requires at least version %s', + 'php_is_ok' => 'Your PHP version is %s, which is compatible with FreshRSS', + 'prefix' => 'Table prefix', + 'previous' => 'Previous', + 'previous_article' => 'Skip to the previous article', + 'previous_page' => 'Skip to the previous page', + 'print' => 'Print', + 'project_website' => 'Project website', + 'public' => 'Public', + 'publication_date' => 'Date of publication', + 'purge_completed' => 'Purge completed (%d articles deleted)', + 'purge_now' => 'Purge now', + 'queries' => 'User queries', + 'query_created' => 'Query "%s" has been created.', + 'query_deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.', + 'query_filter' => 'Filter applied:', + 'query_get_all' => 'Display all articles', + 'query_get_category' => 'Display "%s" category', + 'query_get_favorite' => 'Display favorite articles', + 'query_get_feed' => 'Display "%s" feed', + 'query_number' => 'Query n°%d', + 'query_order_asc' => 'Display oldest articles first', + 'query_order_desc' => 'Display newest articles first', + 'query_search' => 'Search for "%s"', + 'query_state_0' => 'Display all articles', + 'query_state_1' => 'Display read articles', + 'query_state_2' => 'Display unread articles', + 'query_state_3' => 'Display all articles', + 'query_state_4' => 'Display favorite articles', + 'query_state_5' => 'Display read favorite articles', + 'query_state_6' => 'Display unread favorite articles', + 'query_state_7' => 'Display favorite articles', + 'query_state_8' => 'Display not favorite articles', + 'query_state_9' => 'Display read not favorite articles', + 'query_state_10' => 'Display unread not favorite articles', + 'query_state_11' => 'Display not favorite articles', + 'query_state_12' => 'Display all articles', + 'query_state_13' => 'Display read articles', + 'query_state_14' => 'Display unread articles', + 'query_state_15' => 'Display all articles', + 'random_string' => 'Random string', + 'reader_view' => 'Reading view', + 'reading_configuration' => 'Reading', + 'reading_confirm' => 'Display a confirmation dialog on “mark all as read” actions', + 'refresh' => 'Refresh', + 'related_tags' => 'Related tags', + 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', + 'rss_feed_management' => 'RSS feeds management', + 'rss_feeds_of' => 'RSS feed of %s', + 'rss_view' => 'RSS feed', + 'sat' => 'Sat', + 'save' => 'Save', + 'scroll' => 'while scrolling', + 'search' => 'Search words or #tags', + 'search_short' => 'Search', + 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', + 'see_on_website' => 'See on original website', + 'see_website' => 'See website', + 'sep' => 'sep', + 'september' => 'Sep', + 'shaarli' => 'Shaarli', + 'share' => 'Share', + 'share_name' => 'Share name to display', + 'share_url' => 'Share URL to use', + 'sharing' => 'Sharing', + 'sharing_management' => 'Sharing options management', + 'shift_for_all_read' => '+ shift to mark all articles as read', + 'shortcuts' => 'Shortcuts', + 'shortcuts_article_action' => 'Article actions', + 'shortcuts_navigation' => 'Navigation', + 'shortcuts_navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.
With the "Alt" modifier, navigation shortcuts apply on categories.', + 'shortcuts_other_action' => 'Other actions', + 'shortcuts_updated' => 'Shortcuts have been updated', + 'show_adaptive' => 'Adjust showing', + 'show_all_articles' => 'Show all articles', + 'show_favorite' => 'Show only favorites', + 'show_in_all_flux' => 'Show in main stream', + 'show_not_favorite' => 'Show all but favorites', + 'show_not_reads' => 'Show only unread', + 'show_read' => 'Show only read', + 'sort_order' => 'Sort order', + 'starred_list' => 'List of favourite articles', + 'stats' => 'Statistics', + 'stats_entry_count' => 'Entry count', + 'stats_entry_per_category' => 'Entries per category', + 'stats_entry_per_day' => 'Entries per day (last 30 days)', + 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', + 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', + 'stats_entry_per_month' => 'Per month (average: %.2f messages)', + 'stats_entry_repartition' => 'Entries repartition', + 'stats_feed_per_category' => 'Feeds per category', + 'stats_idle' => 'Idle feeds', + 'stats_main' => 'Main statistics', + 'stats_no_idle' => 'There is no idle feed!', + 'stats_percent_of_total' => '%% of total', + 'stats_repartition' => 'Articles repartition', + 'stats_top_feed' => 'Top ten feeds', + 'status_favorites' => 'Favourites', + 'status_read' => 'Read', + 'status_total' => 'Total', + 'status_unread' => 'Unread', + 'steps' => 'Steps', + 'sticky_post' => 'Stick the article to the top when opened', + 'submit' => 'Submit', + 'subscription_management' => 'Subscriptions management', + 'sun' => 'Sun', + 'theme' => 'Theme', + 'think_to_add' => 'You may add some feeds.', + 'this_is_the_end' => 'This is the end', + 'thu' => 'Thu', + 'today' => 'Today', + 'top_line' => 'Top line', + 'truncate' => 'Delete all articles', + 'ttl' => 'Do not automatically refresh more often than', + 'tue' => 'Tue', + 'twitter' => 'Twitter', + 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', + 'update' => 'Update', + 'update_apply' => 'Apply', + 'update_can_apply' => 'An update is available.', + 'update_check' => 'Check for new updates', + 'update_end' => 'Update process is completed, now you can go to the final step.', + 'update_finished' => 'Update completed!', + 'update_last' => 'Last verification: %s', + 'update_long' => 'This can take a long time, depending on the size of your database. You may have to wait for this page to time out (~5 minutes) and then refresh this page.', + 'update_problem' => 'The update process has encountered an error: %s', + 'update_server_not_found' => 'Update server cannot be found. [%s]', + 'update_start' => 'Start update process', + 'update_system' => 'Update system', + 'updated' => 'Modifications have been updated', + 'upon_reception' => 'upon reception of the article', + 'user_created' => 'User %s has been created', + 'user_deleted' => 'User %s has been deleted', + 'user_filter' => 'Access user filters', + 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', + 'username' => 'Username', + 'username_admin' => 'Administrator username', + 'users' => 'Users', + 'users_list' => 'List of users', + 'version' => 'Version', + 'version_update' => 'Update', + 'wallabag' => 'wallabag', + 'website' => 'Website', + 'website_url' => 'Website URL', + 'wed' => 'Wed', + 'width_large' => 'Large', + 'width_medium' => 'Medium', + 'width_no_limit' => 'No limit', + 'width_thin' => 'Thin', + 'yes' => 'Yes', + 'yesterday' => 'Yesterday', + 'your_diaspora_pod' => 'Your Diaspora* pod', + 'your_favorites' => 'Your favourites', + 'your_rss_feeds' => 'Your RSS feeds', + 'your_shaarli' => 'Your Shaarli', + 'your_wallabag' => 'Your wallabag', + 'zip_error' => 'An error occured during Zip import.', +); diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php new file mode 100644 index 000000000..afca37ed3 --- /dev/null +++ b/app/i18n/en/index.php @@ -0,0 +1,5 @@ + array( + 'over_max' => 'You have reached your limit of categories (%d)', + ), + 'feeds' => array( + 'over_max' => 'You have reached your limit of feeds (%d)', + ), +); diff --git a/app/i18n/fr.php b/app/i18n/fr.php deleted file mode 100644 index c29b6c9ac..000000000 --- a/app/i18n/fr.php +++ /dev/null @@ -1,533 +0,0 @@ - '\\a\\v\\r\\i\\l', - 'Aug' => '\\a\\o\\û\\t', - 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', - 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', - 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', - 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', - 'Jun' => '\\j\\u\\i\\n', - 'Mar' => '\\m\\a\\r\\s', - 'May' => '\\m\\a\\i', - 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', - 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', - 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', - 'about' => 'À propos', - 'about_freshrss' => 'À propos de FreshRSS', - 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', - 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.', - 'activate_sharing' => 'Activer le partage', - 'actualize' => 'Actualiser', - 'add_category' => 'Ajouter une catégorie', - 'add_query' => 'Créer un filtre', - 'add_rss_feed' => 'Ajouter un flux RSS', - 'admin.check_install.cache.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/cache. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.cache.ok' => 'Les droits sur le répertoire de cache sont bons.', - 'admin.check_install.categories.nok' => 'La table category est mal configurée.', - 'admin.check_install.categories.ok' => 'La table category est bien configurée.', - 'admin.check_install.connection.nok' => 'La connexion à la base de données est impossible.', - 'admin.check_install.connection.ok' => 'La connexion à la base de données est bonne.', - 'admin.check_install.ctype.nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype).', - 'admin.check_install.ctype.ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype).', - 'admin.check_install.curl.nok' => 'Vous ne disposez pas de cURL (paquet php5-curl).', - 'admin.check_install.curl.ok' => 'Vous disposez de cURL.', - 'admin.check_install.data.nok' => 'Veuillez vérifier les droits sur le répertoire ./data. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.data.ok' => 'Les droits sur le répertoire de data sont bons.', - 'admin.check_install.database' => 'Installation de la base de données', - 'admin.check_install.dom.nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml).', - 'admin.check_install.dom.ok' => 'Vous disposez du nécessaire pour parcourir le DOM.', - 'admin.check_install.entries.nok' => 'La table entry est mal configurée.', - 'admin.check_install.entries.ok' => 'La table entry est bien configurée.', - 'admin.check_install.favicons.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/favicons. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.favicons.ok' => 'Les droits sur le répertoire des favicons sont bons.', - 'admin.check_install.feeds.nok' => 'La table feed est mal configurée.', - 'admin.check_install.feeds.ok' => 'La table feed est bien configurée.', - 'admin.check_install.files' => 'Installation des fichiers', - 'admin.check_install.json.nok' => 'Vous ne disposez pas de JSON (paquet php5-json).', - 'admin.check_install.json.ok' => 'Vous disposez de l\'extension JSON.', - 'admin.check_install.logs.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/logs. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.logs.ok' => 'Les droits sur le répertoire des logs sont bons.', - 'admin.check_install.minz.nok' => 'Vous ne disposez pas de la librairie Minz.', - 'admin.check_install.minz.ok' => 'Vous disposez du framework Minz', - 'admin.check_install.pcre.nok' => 'Il manque une librairie pour les expressions régulières (php-pcre).', - 'admin.check_install.pcre.ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE).', - 'admin.check_install.pdo.nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo.ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', - 'admin.check_install.persona.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.persona.ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', - 'admin.check_install.php' => 'Installation de PHP', - 'admin.check_install.php.nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', - 'admin.check_install.php.ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS.', - 'admin.check_install.tables.nok' => 'Il manque une ou plusieurs tables en base de données.', - 'admin.check_install.tables.ok' => 'Les tables sont bien présentes en base de données.', - 'admin.check_install.tokens.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/tokens. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.tokens.ok' => 'Les droits sur le répertoire des tokens sont bons.', - 'admin.check_install.zip.nok' => 'Vous ne disposez pas de l\'extension ZIP (paquet php5-zip).', - 'admin.check_install.zip.ok' => 'Vous disposez de l\'extension ZIP.', - 'admin.users.articles_and_size' => '%s articles (%s)', - 'administration' => 'Gérer', - 'advanced' => 'Avancé', - 'after_onread' => 'Après “marquer tout comme lu”,', - 'agpl3' => 'AGPL 3', - 'all_feeds' => 'Tous les flux', - 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', - 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', - 'already_subscribed' => 'Vous êtes déjà abonné à %s', - 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', - 'apr' => 'avr.', - 'april' => 'avril', - 'archiving_configuration' => 'Archivage', - 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', - 'article' => 'Article', - 'article_icons' => 'Icônes d’article', - 'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine', - 'article_published_on' => 'Article publié initialement sur %s', - 'article_published_on_author' => 'Article publié initialement sur %s par %s', - 'article_viewed' => 'lorsque l’article est affiché', - 'articles' => 'articles', - 'articles_per_page' => 'Nombre d’articles par page', - 'articles_to_display' => 'Articles à afficher', - 'ask_empty' => 'Vider ?', - 'attention' => 'Attention !', - 'aug' => 'août', - 'august' => 'août', - 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', - 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', - 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', - 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', - 'auth_none' => 'Aucune (dangereux)', - 'auth_not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', - 'auth_persona' => 'Mozilla Persona (moderne, requiert JavaScript)', - 'auth_reset' => 'Réinitialisation de l’authentification', - 'auth_token' => 'Jeton d’identification', - 'auth_type' => 'Méthode d’authentification', - 'auth_will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', - 'author' => 'Auteur', - 'auto_load_more' => 'Charger les articles suivants en bas de page', - 'auto_read_when' => 'Marquer un article comme lu…', - 'auto_share' => 'Partager', - 'auto_share_help' => 'S’il n’y a qu’un mode de partage, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', - 'back_to_rss_feeds' => '← Retour à vos flux RSS', - 'bad_opml_file' => 'Votre fichier OPML n’est pas valide.', - 'base_url' => 'Base de l’URL', - 'bdd' => 'Base de données', - 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', - 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', - 'bdd_configuration' => 'Base de données', - 'bdd_type' => 'Type de base de données', - 'before_one_day' => 'Antérieurs à 1 jour', - 'before_one_week' => 'Antérieurs à 1 semaine', - 'before_yesterday' => 'À partir d’avant-hier', - 'blank_to_disable' => 'Laissez vide pour désactiver', - 'blogotext' => 'Blogotext', - 'bookmark' => 'S’abonner (bookmark FreshRSS)', - 'bottom_line' => 'Ligne du bas', - 'bugs_reports' => 'Rapports de bugs', - 'by' => 'par', - 'by_author' => 'Par %s', - 'by_default' => 'Par défaut', - 'by_email' => 'Par courriel', - 'by_feed' => 'par flux', - 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', - 'can_not_be_deleted' => 'Ne peut pas être supprimée.', - 'cancel' => 'Annuler', - 'categories' => 'Catégories', - 'categories_management' => 'Gestion des catégories', - 'categories_updated' => 'Les catégories ont été mises à jour.', - 'categorize' => 'Ranger dans une catégorie', - 'category' => 'Catégorie', - 'category_created' => 'La catégorie %s a été créée.', - 'category_deleted' => 'La catégorie a été supprimée.', - 'category_emptied' => 'La catégorie a été vidée.', - 'category_empty' => 'Catégorie vide', - 'category_name_exists' => 'Une catégorie possède déjà ce nom.', - 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', - 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', - 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', - 'category_not_exist' => 'Cette catégorie n’existe pas !', - 'category_number' => 'Catégorie n°%d', - 'category_updated' => 'La catégorie a été mise à jour.', - 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', - 'checks' => 'Vérifications', - 'choose_language' => 'Choisissez la langue pour FreshRSS', - 'clear_logs' => 'Effacer les logs', - 'collapse_article' => 'Refermer', - 'conf.users.articles_and_size' => '%s articles (%s)', - 'configuration' => 'Configuration', - 'configuration_updated' => 'La configuration a été mise à jour.', - 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', - 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', - 'congratulations' => 'Félicitations !', - 'content_width' => 'Largeur du contenu', - 'create' => 'Créer', - 'create_user' => 'Créer un nouvel utilisateur', - 'credits' => 'Crédits', - 'credits_content' => 'Des éléments de design sont issus du projet Bootstrap bien que FreshRSS n’utilise pas ce framework. Les icônes sont issues du projet GNOME. La police Open Sans utilisée a été créée par Steve Matteson. Les favicons sont récupérés grâce au site getFavicon. FreshRSS repose sur Minz, un framework PHP.', - 'css_path_on_website' => 'Sélecteur CSS des articles sur le site d’origine', - 'ctype_is_nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype)', - 'ctype_is_ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype)', - 'curl_is_nok' => 'Vous ne disposez pas de cURL (paquet php5-curl)', - 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', - 'current_user' => 'Utilisateur actuel', - 'damn' => 'Arf !', - 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'dec' => 'déc.', - 'december' => 'décembre', - 'default_category' => 'Sans catégorie', - 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', - 'default_view' => 'Vue par défaut', - 'delete' => 'Supprimer', - 'delete_articles_every' => 'Supprimer les articles après', - 'diaspora' => 'Diaspora*', - 'display' => 'Affichage', - 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', - 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', - 'display_configuration' => 'Affichage', - 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', - 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', - 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', - 'email' => 'Courriel', - 'error_occurred' => 'Une erreur est survenue !', - 'error_occurred_update' => 'Rien n’a été modifié !', - 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
%s?output=rss&token=%s', - 'export' => 'Exporter', - 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', - 'export_opml' => 'Exporter la liste des flux (OPML)', - 'export_starred' => 'Exporter les favoris', - 'facebook' => 'Facebook', - 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', - 'favorite_feeds' => 'Favoris (%s)', - 'feb' => 'fév.', - 'february' => 'février', - 'feed' => 'Flux', - 'feed_actualized' => '%s a été mis à jour.', - 'feed_added' => 'Le flux %s a bien été ajouté.', - 'feed_deleted' => 'Le flux a été supprimé.', - 'feed_description' => 'Description', - 'feed_empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.', - 'feed_in_error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.', - 'feed_list' => 'Liste des articles de %s', - 'feed_not_added' => '%s n’a pas pu être ajouté.', - 'feed_updated' => 'Le flux a été mis à jour.', - 'feed_url' => 'URL du flux', - 'feed_validator' => 'Vérifier la valididé du flux', - 'feedback.login.error' => 'L’identifiant est invalide !', - 'feedback.login.success' => 'Vous êtes désormais connecté', - 'feedback.logout.success' => 'Vous avez été déconnecté', - 'feedback.user_profile.updated' => 'Votre profil a été mis à jour', - 'feeds' => 'Flux', - 'feeds_actualized' => 'Les flux ont été mis à jour.', - 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', - 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', - 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', - 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', - 'file_cannot_be_uploaded' => 'Le fichier ne peut pas être téléchargé !', - 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', - 'file_to_import' => 'Fichier à importer
(OPML, Json ou Zip)', - 'file_to_import_no_zip' => 'Fichier à importer
(OPML ou Json)', - 'filter' => 'Filtrer', - 'finish_installation' => 'Terminer l’installation', - 'first' => 'Début', - 'first_article' => 'Passer au premier article', - 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', - 'focus_search' => 'Accéder à la recherche', - 'format_date' => 'j %s Y', - 'format_date_hour' => 'j %s Y \\à H\\:i', - 'freshrss' => 'FreshRSS', - 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de Kriss Feed ou Leed. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.', - 'freshrss_installation' => 'Installation · FreshRSS', - 'fri' => 'ven.', - 'g+' => 'Google+', - 'gen.menu.admin' => 'Administration', - 'gen.menu.authentication' => 'Authentification', - 'gen.menu.check_install' => 'Vérification de l\'installation', - 'gen.menu.user_management' => 'Gestion des utilisateurs', - 'gen.menu.user_profile' => 'Profil', - 'gen.title.authentication' => 'Authentification', - 'gen.title.check_install' => 'Vérification de l\'installation', - 'gen.title.global_view' => 'Vue globale', - 'gen.title.user_management' => 'Gestion des utilisateurs', - 'gen.title.user_profile' => 'Profil', - 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', - 'general_configuration' => 'Configuration générale', - 'github_or_email' => 'sur Github ou par courriel', - 'global_view' => 'Vue globale', - 'help' => 'Afficher la documentation', - 'hide_read_feeds' => 'Cacher les catégories & flux sans article non-lu (ne fonctionne pas avec la configuration “Afficher tous les articles”)', - 'host' => 'Hôte', - 'html5_notif_timeout' => 'Temps d’affichage de la notification HTML5', - 'http_auth' => 'HTTP (pour utilisateurs avancés avec HTTPS)', - 'http_authentication' => 'Authentification HTTP', - 'http_password' => 'Mot de passe HTTP', - 'http_referer_is_nok' => 'Veuillez vérifier que vous ne modifiez pas votre HTTP REFERER.', - 'http_referer_is_ok' => 'Le HTTP REFERER est connu et semble correspondre à votre serveur.', - 'http_username' => 'Identifiant HTTP', - 'img_with_lazyload' => 'Utiliser le mode “chargement différé” pour les images', - 'import' => 'Importer', - 'import_export' => 'Importer / exporter', - 'informations' => 'Informations', - 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', - 'installation_is_ok' => 'L’installation s’est bien passée.
La dernière étape va maintenant tenter de supprimer les fichiers ainsi que d’éventuelles copies de base de données créés durant le processus de mise à jour.
Vous pouvez choisir de sauter cette étape en supprimant ./data/do-install.txt manuellement.', - 'installation_step' => 'Installation — étape %d · FreshRSS', - 'internal_problem_feed' => 'Le flux ne peut pas être ajouté. Consulter les logs de FreshRSS pour plus de détails.', - 'invalid_login' => 'L’identifiant est invalide !', - 'invalid_url' => 'L’url %s est invalide.', - 'is_admin' => 'est administrateur', - 'jan' => 'jan.', - 'january' => 'janvier', - 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', - 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', - 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', - 'jul' => 'jui.', - 'july' => 'juillet', - 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', - 'jun' => 'juin', - 'june' => 'juin', - 'keep_history' => 'Nombre minimum d’articles à conserver', - 'keep_logged_in' => 'Rester connecté (1 mois)', - 'language' => 'Langue', - 'language_defined' => 'La langue a bien été définie.', - 'last' => 'Fin', - 'last_3_month' => 'Depuis les trois derniers mois', - 'last_6_month' => 'Depuis les six derniers mois', - 'last_article' => 'Passer au dernier article', - 'last_month' => 'Depuis le mois dernier', - 'last_week' => 'Depuis la semaine dernière', - 'last_year' => 'Depuis l’année dernière', - 'lead_developer' => 'Développeur principal', - 'license' => 'Licence', - 'load_more' => 'Charger plus d’articles', - 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', - 'login' => 'Connexion', - 'login_configuration' => 'Identification', - 'login_persona_problem' => 'Problème de connexion à Persona ?', - 'login_required' => 'Accès protégé par mot de passe :', - 'login_with_persona' => 'Connexion avec Persona', - 'logout' => 'Déconnexion', - 'logs' => 'Logs', - 'logs_empty' => 'Les logs sont vides.', - 'main_stream' => 'Flux principal', - 'mar' => 'mar.', - 'march' => 'mars', - 'mark_all_read' => 'Tout marquer comme lu', - 'mark_cat_read' => 'Marquer la catégorie comme lue', - 'mark_favorite' => 'Mettre en favori', - 'mark_feed_read' => 'Marquer le flux comme lu', - 'mark_read' => 'Marquer comme lu', - 'may' => 'mai.', - 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', - 'minz_is_ok' => 'Vous disposez du framework Minz', - 'mon' => 'lun.', - 'month' => 'mois', - 'more_information' => 'Plus d’informations', - 'n_entries_deleted' => '%d articles ont été supprimés.', - 'n_feeds_actualized' => '%d flux ont été mis à jour.', - 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', - 'new_category' => 'Nouvelle catégorie', - 'newer_first' => 'Plus récents en premier', - 'next' => 'Suivant', - 'next_article' => 'Passer à l’article suivant', - 'next_page' => 'Passer à la page suivante', - 'next_step' => 'Passer à l’étape suivante', - 'no' => 'Non', - 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', - 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', - 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', - 'no_query' => 'Vous n’avez pas encore créé de filtre.', - 'no_query_filter' => 'Aucun filtre appliqué', - 'no_rss_feed' => 'Aucun flux RSS', - 'no_selected_feed' => 'Aucun flux sélectionné.', - 'no_update' => 'Aucune mise à jour à appliquer', - 'no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur.', - 'normal_view' => 'Vue normale', - 'not_read' => '%d non lu', - 'not_reads' => '%d non lus', - 'not_yet_implemented' => 'Pas encore implémenté', - 'nothing_to_load' => 'Fin des articles', - 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', - 'nov' => 'nov.', - 'november' => 'novembre', - 'number_articles' => '%d articles', - 'number_divided_when_reader' => 'Divisé par 2 dans la vue de lecture.', - 'number_feeds' => '%d flux', - 'oct' => 'oct.', - 'october' => 'octobre', - 'ok' => 'Ok !', - 'older_first' => 'Plus anciens en premier', - 'oops' => 'Oups !', - 'optimization_complete' => 'Optimisation terminée.', - 'optimize_bdd' => 'Optimiser la base de données', - 'optimize_todo_sometimes' => 'À faire de temps en temps pour réduire la taille de la BDD', - 'or' => 'ou', - 'page_not_found' => 'La page que vous cherchez n’existe pas !', - 'password' => 'Mot de passe', - 'password_api' => 'Mot de passe API
(ex. : pour applis mobiles)', - 'password_form' => 'Mot de passe
(pour connexion par formulaire)', - 'pcre_is_nok' => 'Il manque une librairie pour les expressions régulières (php-pcre)', - 'pcre_is_ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE)', - 'pdo_is_nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite)', - 'pdo_is_ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite)', - 'persona_connection_email' => 'Adresse courriel de connexion
(pour Mozilla Persona)', - 'persona_is_ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons', - 'php_is_nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s', - 'php_is_ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS', - 'prefix' => 'Préfixe des tables', - 'previous' => 'Précédent', - 'previous_article' => 'Passer à l’article précédent', - 'previous_page' => 'Passer à la page précédente', - 'print' => 'Imprimer', - 'project_website' => 'Site du projet', - 'public' => 'Public', - 'publication_date' => 'Date de publication', - 'purge_completed' => 'Purge effectuée (%d articles supprimés).', - 'purge_now' => 'Purger maintenant', - 'queries' => 'Filtres utilisateurs', - 'query_created' => 'Le filtre "%s" a bien été créé.', - 'query_deprecated' => 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.', - 'query_filter' => 'Filtres appliqués :', - 'query_get_all' => 'Afficher tous les articles', - 'query_get_category' => 'Afficher la catégorie "%s"', - 'query_get_favorite' => 'Afficher les articles favoris', - 'query_get_feed' => 'Afficher le flux "%s"', - 'query_number' => 'Filtre n°%d', - 'query_order_asc' => 'Afficher les articles les plus anciens en premier', - 'query_order_desc' => 'Afficher les articles les plus récents en premier', - 'query_search' => 'Recherche de "%s"', - 'query_state_0' => 'Afficher tous les articles', - 'query_state_1' => 'Afficher les articles lus', - 'query_state_2' => 'Afficher les articles non lus', - 'query_state_3' => 'Afficher tous les articles', - 'query_state_4' => 'Afficher les articles favoris', - 'query_state_5' => 'Afficher les articles lus et favoris', - 'query_state_6' => 'Afficher les articles non lus et favoris', - 'query_state_7' => 'Afficher les articles favoris', - 'query_state_8' => 'Afficher les articles non favoris', - 'query_state_9' => 'Afficher les articles lus et non favoris', - 'query_state_10' => 'Afficher les articles non lus et non favoris', - 'query_state_11' => 'Afficher les articles non favoris', - 'query_state_12' => 'Afficher tous les articles', - 'query_state_13' => 'Afficher les articles lus', - 'query_state_14' => 'Afficher les articles non lus', - 'query_state_15' => 'Afficher tous les articles', - 'random_string' => 'Chaîne aléatoire', - 'reader_view' => 'Vue lecture', - 'reading_configuration' => 'Lecture', - 'reading_confirm' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', - 'refresh' => 'Actualisation', - 'related_tags' => 'Tags associés', - 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', - 'rss_feed_management' => 'Gestion des flux RSS', - 'rss_feeds_of' => 'Flux RSS de %s', - 'rss_view' => 'Flux RSS', - 'sat' => 'sam.', - 'save' => 'Enregistrer', - 'scroll' => 'au défilement de la page', - 'search' => 'Rechercher des mots ou des #tags', - 'search_short' => 'Rechercher', - 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', - 'see_on_website' => 'Voir sur le site d’origine', - 'see_website' => 'Voir le site', - 'sep' => 'sep.', - 'september' => 'septembre', - 'shaarli' => 'Shaarli', - 'share' => 'Partager', - 'share_name' => 'Nom du partage à afficher', - 'share_url' => 'URL du partage à utiliser', - 'sharing' => 'Partage', - 'sharing_management' => 'Gestion des options de partage', - 'shift_for_all_read' => '+ shift pour marquer tous les articles comme lus', - 'shortcuts' => 'Raccourcis', - 'shortcuts_article_action' => 'Actions associées à l’article courant', - 'shortcuts_navigation' => 'Navigation', - 'shortcuts_navigation_help' => 'Avec le modificateur "Shift", les raccourcis de navigation s’appliquent aux flux.
Avec le modificateur "Alt", les raccourcis de navigation s’appliquent aux catégories.', - 'shortcuts_other_action' => 'Autres actions', - 'shortcuts_updated' => 'Les raccourcis ont été mis à jour.', - 'show_adaptive' => 'Adapter l’affichage', - 'show_all_articles' => 'Afficher tous les articles', - 'show_favorite' => 'Afficher les favoris', - 'show_in_all_flux' => 'Afficher dans le flux principal', - 'show_not_favorite' => 'Afficher tout sauf les favoris', - 'show_not_reads' => 'Afficher les non lus', - 'show_read' => 'Afficher les lus', - 'sort_order' => 'Ordre de tri', - 'starred_list' => 'Liste des articles favoris', - 'stats' => 'Statistiques', - 'stats_entry_count' => 'Nombre d’articles', - 'stats_entry_per_category' => 'Articles par catégorie', - 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', - 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', - 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', - 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', - 'stats_entry_repartition' => 'Répartition des articles', - 'stats_feed_per_category' => 'Flux par catégorie', - 'stats_idle' => 'Flux inactifs', - 'stats_main' => 'Statistiques principales', - 'stats_no_idle' => 'Il n’y a aucun flux inactif !', - 'stats_percent_of_total' => '%% du total', - 'stats_repartition' => 'Répartition des articles', - 'stats_top_feed' => 'Les dix plus gros flux', - 'status_favorites' => 'favoris', - 'status_read' => 'lus', - 'status_total' => 'total', - 'status_unread' => 'non lus', - 'steps' => 'Étapes', - 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', - 'sub.categories.over_max' => 'Vous avez atteint votre limite de catégories (%d)', - 'sub.feeds.over_max' => 'Vous avez atteint votre limite de flux (%d)', - 'submit' => 'Valider', - 'subscription_management' => 'Gestion des abonnements', - 'sun' => 'dim.', - 'theme' => 'Thème', - 'think_to_add' => 'Vous pouvez ajouter des flux.', - 'this_is_the_end' => 'This is the end', - 'thu' => 'jeu.', - 'title' => 'Titre', - 'today' => 'Aujourd’hui', - 'top_line' => 'Ligne du haut', - 'truncate' => 'Supprimer tous les articles', - 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', - 'tue' => 'mar.', - 'twitter' => 'Twitter', - 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', - 'update' => 'Mise à jour', - 'update_apply' => 'Appliquer la mise à jour', - 'update_can_apply' => 'Une mise à jour est disponible.', - 'update_check' => 'Vérifier les mises à jour', - 'update_end' => 'La mise à jour est terminée, vous pouvez maintenant passer à l’étape finale.', - 'update_finished' => 'La mise à jour est terminée !', - 'update_last' => 'Dernière vérification : %s', - 'update_long' => 'Ce processus peut prendre longtemps, selon la taille de votre base de données. Vous aurez peut-être à attendre que cette page dépasse son temps maximum d’exécution (~5 minutes) puis à la recharger.', - 'update_problem' => 'La mise à jour a rencontré un problème : %s', - 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', - 'update_start' => 'Lancer la mise à jour', - 'update_system' => 'Système de mise à jour', - 'updated' => 'Modifications enregistrées.', - 'upon_reception' => 'dès la réception du nouvel article', - 'user_created' => 'L’utilisateur %s a été créé.', - 'user_deleted' => 'L’utilisateur %s a été supprimé.', - 'user_filter' => 'Accéder aux filtres utilisateur', - 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', - 'username' => 'Nom d’utilisateur', - 'username_admin' => 'Nom d’utilisateur administrateur', - 'users' => 'Utilisateurs', - 'users_list' => 'Liste des utilisateurs', - 'version' => 'Version', - 'version_update' => 'Mise à jour', - 'wallabag' => 'wallabag', - 'website' => 'Site Internet', - 'website_url' => 'URL du site', - 'wed' => 'mer.', - 'width_large' => 'Large', - 'width_medium' => 'Moyenne', - 'width_no_limit' => 'Pas de limite', - 'width_thin' => 'Fine', - 'yes' => 'Oui', - 'yesterday' => 'Hier', - 'your_diaspora_pod' => 'Votre pod Diaspora*', - 'your_favorites' => 'Vos favoris', - 'your_rss_feeds' => 'Vos flux RSS', - 'your_shaarli' => 'Votre Shaarli', - 'your_wallabag' => 'Votre wallabag', - 'zip_error' => 'Une erreur est survenue durant l’import du fichier Zip.', -); \ No newline at end of file diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php new file mode 100644 index 000000000..ad1fae6c0 --- /dev/null +++ b/app/i18n/fr/admin.php @@ -0,0 +1,92 @@ + array( + 'cache' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/cache. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire de cache sont bons.', + ), + 'categories' => array( + 'nok' => 'La table category est mal configurée.', + 'ok' => 'La table category est bien configurée.', + ), + 'connection' => array( + 'nok' => 'La connexion à la base de données est impossible.', + 'ok' => 'La connexion à la base de données est bonne.', + ), + 'ctype' => array( + 'nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype).', + 'ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype).', + ), + 'curl' => array( + 'nok' => 'Vous ne disposez pas de cURL (paquet php5-curl).', + 'ok' => 'Vous disposez de cURL.', + ), + 'data' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire de data sont bons.', + ), + 'database' => 'Installation de la base de données', + 'dom' => array( + 'nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml).', + 'ok' => 'Vous disposez du nécessaire pour parcourir le DOM.', + ), + 'entries' => array( + 'nok' => 'La table entry est mal configurée.', + 'ok' => 'La table entry est bien configurée.', + ), + 'favicons' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/favicons. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire des favicons sont bons.', + ), + 'feeds' => array( + 'nok' => 'La table feed est mal configurée.', + 'ok' => 'La table feed est bien configurée.', + ), + 'files' => 'Installation des fichiers', + 'json' => array( + 'nok' => 'Vous ne disposez pas de JSON (paquet php5-json).', + 'ok' => 'Vous disposez de l\'extension JSON.', + ), + 'logs' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/logs. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire des logs sont bons.', + ), + 'minz' => array( + 'nok' => 'Vous ne disposez pas de la librairie Minz.', + 'ok' => 'Vous disposez du framework Minz', + ), + 'pcre' => array( + 'nok' => 'Il manque une librairie pour les expressions régulières (php-pcre).', + 'ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE).', + ), + 'pdo' => array( + 'nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', + 'ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', + ), + 'persona' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', + ), + 'php' => array( + '_' => 'Installation de PHP', + 'nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', + 'ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS.', + ), + 'tables' => array( + 'nok' => 'Il manque une ou plusieurs tables en base de données.', + 'ok' => 'Les tables sont bien présentes en base de données.', + ), + 'tokens' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/tokens. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire des tokens sont bons.', + ), + 'zip' => array( + 'nok' => 'Vous ne disposez pas de l\'extension ZIP (paquet php5-zip).', + 'ok' => 'Vous disposez de l\'extension ZIP.', + ), + ), + 'users' => array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php new file mode 100644 index 000000000..460804774 --- /dev/null +++ b/app/i18n/fr/conf.php @@ -0,0 +1,7 @@ + array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php new file mode 100644 index 000000000..f4bb7cccf --- /dev/null +++ b/app/i18n/fr/feedback.php @@ -0,0 +1,14 @@ + array( + 'error' => 'L’identifiant est invalide !', + 'success' => 'Vous êtes désormais connecté', + ), + 'logout' => array( + 'success' => 'Vous avez été déconnecté', + ), + 'user_profile' => array( + 'updated' => 'Votre profil a été mis à jour', + ), +); diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php new file mode 100644 index 000000000..8a4a9750b --- /dev/null +++ b/app/i18n/fr/gen.php @@ -0,0 +1,487 @@ + '\\a\\v\\r\\i\\l', + 'Aug' => '\\a\\o\\û\\t', + 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', + 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', + 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', + 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', + 'Jun' => '\\j\\u\\i\\n', + 'Mar' => '\\m\\a\\r\\s', + 'May' => '\\m\\a\\i', + 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', + 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', + 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', + 'about' => 'À propos', + 'about_freshrss' => 'À propos de FreshRSS', + 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', + 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.', + 'activate_sharing' => 'Activer le partage', + 'actualize' => 'Actualiser', + 'add_category' => 'Ajouter une catégorie', + 'add_query' => 'Créer un filtre', + 'add_rss_feed' => 'Ajouter un flux RSS', + 'administration' => 'Gérer', + 'advanced' => 'Avancé', + 'after_onread' => 'Après “marquer tout comme lu”,', + 'agpl3' => 'AGPL 3', + 'all_feeds' => 'Tous les flux', + 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', + 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', + 'already_subscribed' => 'Vous êtes déjà abonné à %s', + 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', + 'apr' => 'avr.', + 'april' => 'avril', + 'archiving_configuration' => 'Archivage', + 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', + 'article' => 'Article', + 'article_icons' => 'Icônes d’article', + 'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine', + 'article_published_on' => 'Article publié initialement sur %s', + 'article_published_on_author' => 'Article publié initialement sur %s par %s', + 'article_viewed' => 'lorsque l’article est affiché', + 'articles' => 'articles', + 'articles_per_page' => 'Nombre d’articles par page', + 'articles_to_display' => 'Articles à afficher', + 'ask_empty' => 'Vider ?', + 'attention' => 'Attention !', + 'aug' => 'août', + 'august' => 'août', + 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', + 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', + 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', + 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', + 'auth_none' => 'Aucune (dangereux)', + 'auth_not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', + 'auth_persona' => 'Mozilla Persona (moderne, requiert JavaScript)', + 'auth_reset' => 'Réinitialisation de l’authentification', + 'auth_token' => 'Jeton d’identification', + 'auth_type' => 'Méthode d’authentification', + 'auth_will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', + 'author' => 'Auteur', + 'auto_load_more' => 'Charger les articles suivants en bas de page', + 'auto_read_when' => 'Marquer un article comme lu…', + 'auto_share' => 'Partager', + 'auto_share_help' => 'S’il n’y a qu’un mode de partage, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', + 'back_to_rss_feeds' => '← Retour à vos flux RSS', + 'bad_opml_file' => 'Votre fichier OPML n’est pas valide.', + 'base_url' => 'Base de l’URL', + 'bdd' => 'Base de données', + 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', + 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', + 'bdd_configuration' => 'Base de données', + 'bdd_type' => 'Type de base de données', + 'before_one_day' => 'Antérieurs à 1 jour', + 'before_one_week' => 'Antérieurs à 1 semaine', + 'before_yesterday' => 'À partir d’avant-hier', + 'blank_to_disable' => 'Laissez vide pour désactiver', + 'blogotext' => 'Blogotext', + 'bookmark' => 'S’abonner (bookmark FreshRSS)', + 'bottom_line' => 'Ligne du bas', + 'bugs_reports' => 'Rapports de bugs', + 'by' => 'par', + 'by_author' => 'Par %s', + 'by_default' => 'Par défaut', + 'by_email' => 'Par courriel', + 'by_feed' => 'par flux', + 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', + 'can_not_be_deleted' => 'Ne peut pas être supprimée.', + 'cancel' => 'Annuler', + 'categories' => 'Catégories', + 'categories_management' => 'Gestion des catégories', + 'categories_updated' => 'Les catégories ont été mises à jour.', + 'categorize' => 'Ranger dans une catégorie', + 'category' => 'Catégorie', + 'category_created' => 'La catégorie %s a été créée.', + 'category_deleted' => 'La catégorie a été supprimée.', + 'category_emptied' => 'La catégorie a été vidée.', + 'category_empty' => 'Catégorie vide', + 'category_name_exists' => 'Une catégorie possède déjà ce nom.', + 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', + 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', + 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', + 'category_not_exist' => 'Cette catégorie n’existe pas !', + 'category_number' => 'Catégorie n°%d', + 'category_updated' => 'La catégorie a été mise à jour.', + 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', + 'checks' => 'Vérifications', + 'choose_language' => 'Choisissez la langue pour FreshRSS', + 'clear_logs' => 'Effacer les logs', + 'collapse_article' => 'Refermer', + 'configuration' => 'Configuration', + 'configuration_updated' => 'La configuration a été mise à jour.', + 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', + 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', + 'congratulations' => 'Félicitations !', + 'content_width' => 'Largeur du contenu', + 'create' => 'Créer', + 'create_user' => 'Créer un nouvel utilisateur', + 'credits' => 'Crédits', + 'credits_content' => 'Des éléments de design sont issus du projet Bootstrap bien que FreshRSS n’utilise pas ce framework. Les icônes sont issues du projet GNOME. La police Open Sans utilisée a été créée par Steve Matteson. Les favicons sont récupérés grâce au site getFavicon. FreshRSS repose sur Minz, un framework PHP.', + 'css_path_on_website' => 'Sélecteur CSS des articles sur le site d’origine', + 'ctype_is_nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype)', + 'ctype_is_ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype)', + 'curl_is_nok' => 'Vous ne disposez pas de cURL (paquet php5-curl)', + 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', + 'current_user' => 'Utilisateur actuel', + 'damn' => 'Arf !', + 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', + 'dec' => 'déc.', + 'december' => 'décembre', + 'default_category' => 'Sans catégorie', + 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', + 'default_view' => 'Vue par défaut', + 'delete' => 'Supprimer', + 'delete_articles_every' => 'Supprimer les articles après', + 'diaspora' => 'Diaspora*', + 'display' => 'Affichage', + 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', + 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', + 'display_configuration' => 'Affichage', + 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', + 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', + 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', + 'email' => 'Courriel', + 'error_occurred' => 'Une erreur est survenue !', + 'error_occurred_update' => 'Rien n’a été modifié !', + 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
%s?output=rss&token=%s', + 'export' => 'Exporter', + 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', + 'export_opml' => 'Exporter la liste des flux (OPML)', + 'export_starred' => 'Exporter les favoris', + 'facebook' => 'Facebook', + 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', + 'favorite_feeds' => 'Favoris (%s)', + 'feb' => 'fév.', + 'february' => 'février', + 'feed' => 'Flux', + 'feed_actualized' => '%s a été mis à jour.', + 'feed_added' => 'Le flux %s a bien été ajouté.', + 'feed_deleted' => 'Le flux a été supprimé.', + 'feed_description' => 'Description', + 'feed_empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.', + 'feed_in_error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.', + 'feed_list' => 'Liste des articles de %s', + 'feed_not_added' => '%s n’a pas pu être ajouté.', + 'feed_updated' => 'Le flux a été mis à jour.', + 'feed_url' => 'URL du flux', + 'feed_validator' => 'Vérifier la valididé du flux', + 'feeds' => 'Flux', + 'feeds_actualized' => 'Les flux ont été mis à jour.', + 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', + 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', + 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', + 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', + 'file_cannot_be_uploaded' => 'Le fichier ne peut pas être téléchargé !', + 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', + 'file_to_import' => 'Fichier à importer
(OPML, Json ou Zip)', + 'file_to_import_no_zip' => 'Fichier à importer
(OPML ou Json)', + 'filter' => 'Filtrer', + 'finish_installation' => 'Terminer l’installation', + 'first' => 'Début', + 'first_article' => 'Passer au premier article', + 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', + 'focus_search' => 'Accéder à la recherche', + 'format_date' => 'j %s Y', + 'format_date_hour' => 'j %s Y \\à H\\:i', + 'freshrss' => 'FreshRSS', + 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de Kriss Feed ou Leed. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.', + 'freshrss_installation' => 'Installation · FreshRSS', + 'fri' => 'ven.', + 'g+' => 'Google+', + 'menu' => array( + 'admin' => 'Administration', + 'authentication' => 'Authentification', + 'check_install' => 'Vérification de l’installation', + 'user_management' => 'Gestion des utilisateurs', + 'user_profile' => 'Profil', + ), + 'title' => array( + '_' => 'Titre', + 'authentication' => 'Authentification', + 'check_install' => 'Vérification de l’installation', + 'global_view' => 'Vue globale', + 'user_management' => 'Gestion des utilisateurs', + 'user_profile' => 'Profil', + ), + 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', + 'general_configuration' => 'Configuration générale', + 'github_or_email' => 'sur Github ou par courriel', + 'global_view' => 'Vue globale', + 'help' => 'Afficher la documentation', + 'hide_read_feeds' => 'Cacher les catégories & flux sans article non-lu (ne fonctionne pas avec la configuration “Afficher tous les articles”)', + 'host' => 'Hôte', + 'html5_notif_timeout' => 'Temps d’affichage de la notification HTML5', + 'http_auth' => 'HTTP (pour utilisateurs avancés avec HTTPS)', + 'http_authentication' => 'Authentification HTTP', + 'http_password' => 'Mot de passe HTTP', + 'http_referer_is_nok' => 'Veuillez vérifier que vous ne modifiez pas votre HTTP REFERER.', + 'http_referer_is_ok' => 'Le HTTP REFERER est connu et semble correspondre à votre serveur.', + 'http_username' => 'Identifiant HTTP', + 'img_with_lazyload' => 'Utiliser le mode “chargement différé” pour les images', + 'import' => 'Importer', + 'import_export' => 'Importer / exporter', + 'informations' => 'Informations', + 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', + 'installation_is_ok' => 'L’installation s’est bien passée.
La dernière étape va maintenant tenter de supprimer les fichiers ainsi que d’éventuelles copies de base de données créés durant le processus de mise à jour.
Vous pouvez choisir de sauter cette étape en supprimant ./data/do-install.txt manuellement.', + 'installation_step' => 'Installation — étape %d · FreshRSS', + 'internal_problem_feed' => 'Le flux ne peut pas être ajouté. Consulter les logs de FreshRSS pour plus de détails.', + 'invalid_login' => 'L’identifiant est invalide !', + 'invalid_url' => 'L’url %s est invalide.', + 'is_admin' => 'est administrateur', + 'jan' => 'jan.', + 'january' => 'janvier', + 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', + 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', + 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', + 'jul' => 'jui.', + 'july' => 'juillet', + 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', + 'jun' => 'juin', + 'june' => 'juin', + 'keep_history' => 'Nombre minimum d’articles à conserver', + 'keep_logged_in' => 'Rester connecté (1 mois)', + 'language' => 'Langue', + 'language_defined' => 'La langue a bien été définie.', + 'last' => 'Fin', + 'last_3_month' => 'Depuis les trois derniers mois', + 'last_6_month' => 'Depuis les six derniers mois', + 'last_article' => 'Passer au dernier article', + 'last_month' => 'Depuis le mois dernier', + 'last_week' => 'Depuis la semaine dernière', + 'last_year' => 'Depuis l’année dernière', + 'lead_developer' => 'Développeur principal', + 'license' => 'Licence', + 'load_more' => 'Charger plus d’articles', + 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', + 'login' => 'Connexion', + 'login_configuration' => 'Identification', + 'login_persona_problem' => 'Problème de connexion à Persona ?', + 'login_required' => 'Accès protégé par mot de passe :', + 'login_with_persona' => 'Connexion avec Persona', + 'logout' => 'Déconnexion', + 'logs' => 'Logs', + 'logs_empty' => 'Les logs sont vides.', + 'main_stream' => 'Flux principal', + 'mar' => 'mar.', + 'march' => 'mars', + 'mark_all_read' => 'Tout marquer comme lu', + 'mark_cat_read' => 'Marquer la catégorie comme lue', + 'mark_favorite' => 'Mettre en favori', + 'mark_feed_read' => 'Marquer le flux comme lu', + 'mark_read' => 'Marquer comme lu', + 'may' => 'mai.', + 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', + 'minz_is_ok' => 'Vous disposez du framework Minz', + 'mon' => 'lun.', + 'month' => 'mois', + 'more_information' => 'Plus d’informations', + 'n_entries_deleted' => '%d articles ont été supprimés.', + 'n_feeds_actualized' => '%d flux ont été mis à jour.', + 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', + 'new_category' => 'Nouvelle catégorie', + 'newer_first' => 'Plus récents en premier', + 'next' => 'Suivant', + 'next_article' => 'Passer à l’article suivant', + 'next_page' => 'Passer à la page suivante', + 'next_step' => 'Passer à l’étape suivante', + 'no' => 'Non', + 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', + 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', + 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', + 'no_query' => 'Vous n’avez pas encore créé de filtre.', + 'no_query_filter' => 'Aucun filtre appliqué', + 'no_rss_feed' => 'Aucun flux RSS', + 'no_selected_feed' => 'Aucun flux sélectionné.', + 'no_update' => 'Aucune mise à jour à appliquer', + 'no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur.', + 'normal_view' => 'Vue normale', + 'not_read' => '%d non lu', + 'not_reads' => '%d non lus', + 'not_yet_implemented' => 'Pas encore implémenté', + 'nothing_to_load' => 'Fin des articles', + 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', + 'nov' => 'nov.', + 'november' => 'novembre', + 'number_articles' => '%d articles', + 'number_divided_when_reader' => 'Divisé par 2 dans la vue de lecture.', + 'number_feeds' => '%d flux', + 'oct' => 'oct.', + 'october' => 'octobre', + 'ok' => 'Ok !', + 'older_first' => 'Plus anciens en premier', + 'oops' => 'Oups !', + 'optimization_complete' => 'Optimisation terminée.', + 'optimize_bdd' => 'Optimiser la base de données', + 'optimize_todo_sometimes' => 'À faire de temps en temps pour réduire la taille de la BDD', + 'or' => 'ou', + 'page_not_found' => 'La page que vous cherchez n’existe pas !', + 'password' => 'Mot de passe', + 'password_api' => 'Mot de passe API
(ex. : pour applis mobiles)', + 'password_form' => 'Mot de passe
(pour connexion par formulaire)', + 'pcre_is_nok' => 'Il manque une librairie pour les expressions régulières (php-pcre)', + 'pcre_is_ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE)', + 'pdo_is_nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite)', + 'pdo_is_ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite)', + 'persona_connection_email' => 'Adresse courriel de connexion
(pour Mozilla Persona)', + 'persona_is_ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons', + 'php_is_nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s', + 'php_is_ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS', + 'prefix' => 'Préfixe des tables', + 'previous' => 'Précédent', + 'previous_article' => 'Passer à l’article précédent', + 'previous_page' => 'Passer à la page précédente', + 'print' => 'Imprimer', + 'project_website' => 'Site du projet', + 'public' => 'Public', + 'publication_date' => 'Date de publication', + 'purge_completed' => 'Purge effectuée (%d articles supprimés).', + 'purge_now' => 'Purger maintenant', + 'queries' => 'Filtres utilisateurs', + 'query_created' => 'Le filtre "%s" a bien été créé.', + 'query_deprecated' => 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.', + 'query_filter' => 'Filtres appliqués :', + 'query_get_all' => 'Afficher tous les articles', + 'query_get_category' => 'Afficher la catégorie "%s"', + 'query_get_favorite' => 'Afficher les articles favoris', + 'query_get_feed' => 'Afficher le flux "%s"', + 'query_number' => 'Filtre n°%d', + 'query_order_asc' => 'Afficher les articles les plus anciens en premier', + 'query_order_desc' => 'Afficher les articles les plus récents en premier', + 'query_search' => 'Recherche de "%s"', + 'query_state_0' => 'Afficher tous les articles', + 'query_state_1' => 'Afficher les articles lus', + 'query_state_2' => 'Afficher les articles non lus', + 'query_state_3' => 'Afficher tous les articles', + 'query_state_4' => 'Afficher les articles favoris', + 'query_state_5' => 'Afficher les articles lus et favoris', + 'query_state_6' => 'Afficher les articles non lus et favoris', + 'query_state_7' => 'Afficher les articles favoris', + 'query_state_8' => 'Afficher les articles non favoris', + 'query_state_9' => 'Afficher les articles lus et non favoris', + 'query_state_10' => 'Afficher les articles non lus et non favoris', + 'query_state_11' => 'Afficher les articles non favoris', + 'query_state_12' => 'Afficher tous les articles', + 'query_state_13' => 'Afficher les articles lus', + 'query_state_14' => 'Afficher les articles non lus', + 'query_state_15' => 'Afficher tous les articles', + 'random_string' => 'Chaîne aléatoire', + 'reader_view' => 'Vue lecture', + 'reading_configuration' => 'Lecture', + 'reading_confirm' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', + 'refresh' => 'Actualisation', + 'related_tags' => 'Tags associés', + 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', + 'rss_feed_management' => 'Gestion des flux RSS', + 'rss_feeds_of' => 'Flux RSS de %s', + 'rss_view' => 'Flux RSS', + 'sat' => 'sam.', + 'save' => 'Enregistrer', + 'scroll' => 'au défilement de la page', + 'search' => 'Rechercher des mots ou des #tags', + 'search_short' => 'Rechercher', + 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', + 'see_on_website' => 'Voir sur le site d’origine', + 'see_website' => 'Voir le site', + 'sep' => 'sep.', + 'september' => 'septembre', + 'shaarli' => 'Shaarli', + 'share' => 'Partager', + 'share_name' => 'Nom du partage à afficher', + 'share_url' => 'URL du partage à utiliser', + 'sharing' => 'Partage', + 'sharing_management' => 'Gestion des options de partage', + 'shift_for_all_read' => '+ shift pour marquer tous les articles comme lus', + 'shortcuts' => 'Raccourcis', + 'shortcuts_article_action' => 'Actions associées à l’article courant', + 'shortcuts_navigation' => 'Navigation', + 'shortcuts_navigation_help' => 'Avec le modificateur "Shift", les raccourcis de navigation s’appliquent aux flux.
Avec le modificateur "Alt", les raccourcis de navigation s’appliquent aux catégories.', + 'shortcuts_other_action' => 'Autres actions', + 'shortcuts_updated' => 'Les raccourcis ont été mis à jour.', + 'show_adaptive' => 'Adapter l’affichage', + 'show_all_articles' => 'Afficher tous les articles', + 'show_favorite' => 'Afficher les favoris', + 'show_in_all_flux' => 'Afficher dans le flux principal', + 'show_not_favorite' => 'Afficher tout sauf les favoris', + 'show_not_reads' => 'Afficher les non lus', + 'show_read' => 'Afficher les lus', + 'sort_order' => 'Ordre de tri', + 'starred_list' => 'Liste des articles favoris', + 'stats' => 'Statistiques', + 'stats_entry_count' => 'Nombre d’articles', + 'stats_entry_per_category' => 'Articles par catégorie', + 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', + 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', + 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', + 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', + 'stats_entry_repartition' => 'Répartition des articles', + 'stats_feed_per_category' => 'Flux par catégorie', + 'stats_idle' => 'Flux inactifs', + 'stats_main' => 'Statistiques principales', + 'stats_no_idle' => 'Il n’y a aucun flux inactif !', + 'stats_percent_of_total' => '%% du total', + 'stats_repartition' => 'Répartition des articles', + 'stats_top_feed' => 'Les dix plus gros flux', + 'status_favorites' => 'favoris', + 'status_read' => 'lus', + 'status_total' => 'total', + 'status_unread' => 'non lus', + 'steps' => 'Étapes', + 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', + 'submit' => 'Valider', + 'subscription_management' => 'Gestion des abonnements', + 'sun' => 'dim.', + 'theme' => 'Thème', + 'think_to_add' => 'Vous pouvez ajouter des flux.', + 'this_is_the_end' => 'This is the end', + 'thu' => 'jeu.', + 'today' => 'Aujourd’hui', + 'top_line' => 'Ligne du haut', + 'truncate' => 'Supprimer tous les articles', + 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', + 'tue' => 'mar.', + 'twitter' => 'Twitter', + 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', + 'update' => 'Mise à jour', + 'update_apply' => 'Appliquer la mise à jour', + 'update_can_apply' => 'Une mise à jour est disponible.', + 'update_check' => 'Vérifier les mises à jour', + 'update_end' => 'La mise à jour est terminée, vous pouvez maintenant passer à l’étape finale.', + 'update_finished' => 'La mise à jour est terminée !', + 'update_last' => 'Dernière vérification : %s', + 'update_long' => 'Ce processus peut prendre longtemps, selon la taille de votre base de données. Vous aurez peut-être à attendre que cette page dépasse son temps maximum d’exécution (~5 minutes) puis à la recharger.', + 'update_problem' => 'La mise à jour a rencontré un problème : %s', + 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', + 'update_start' => 'Lancer la mise à jour', + 'update_system' => 'Système de mise à jour', + 'updated' => 'Modifications enregistrées.', + 'upon_reception' => 'dès la réception du nouvel article', + 'user_created' => 'L’utilisateur %s a été créé.', + 'user_deleted' => 'L’utilisateur %s a été supprimé.', + 'user_filter' => 'Accéder aux filtres utilisateur', + 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', + 'username' => 'Nom d’utilisateur', + 'username_admin' => 'Nom d’utilisateur administrateur', + 'users' => 'Utilisateurs', + 'users_list' => 'Liste des utilisateurs', + 'version' => 'Version', + 'version_update' => 'Mise à jour', + 'wallabag' => 'wallabag', + 'website' => 'Site Internet', + 'website_url' => 'URL du site', + 'wed' => 'mer.', + 'width_large' => 'Large', + 'width_medium' => 'Moyenne', + 'width_no_limit' => 'Pas de limite', + 'width_thin' => 'Fine', + 'yes' => 'Oui', + 'yesterday' => 'Hier', + 'your_diaspora_pod' => 'Votre pod Diaspora*', + 'your_favorites' => 'Vos favoris', + 'your_rss_feeds' => 'Vos flux RSS', + 'your_shaarli' => 'Votre Shaarli', + 'your_wallabag' => 'Votre wallabag', + 'zip_error' => 'Une erreur est survenue durant l’import du fichier Zip.', +); diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php new file mode 100644 index 000000000..afca37ed3 --- /dev/null +++ b/app/i18n/fr/index.php @@ -0,0 +1,5 @@ + array( + 'over_max' => 'Vous avez atteint votre limite de catégories (%d)', + ), + 'feeds' => array( + 'over_max' => 'Vous avez atteint votre limite de flux (%d)', + ), +); diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index 8c2f90041..084bd7e07 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -5,71 +5,117 @@ */ /** - * La classe Translate se charge de la traduction - * Utilise les fichiers du répertoire /app/i18n/ + * This class is used for the internationalization. + * It uses files in `./app/i18n/` */ class Minz_Translate { /** - * $language est la langue à afficher + * $lang_name is the name of the current language to use. */ - private static $language; - + private static $lang_name; + + /** + * $lang_path is the pathname of i18n files (e.g. ./app/i18n/en/). + */ + private static $lang_path; + /** - * $translates est le tableau de correspondance - * $key => $traduction + * $translates is a cache for i18n translation. */ private static $translates = array(); - + /** - * Inclus le fichier de langue qui va bien - * l'enregistre dans $translates + * Load $lang_name and $lang_path based on configuration and selected language. */ public static function init() { $l = Minz_Configuration::language(); - self::$language = Minz_Session::param('language', $l); - - $l_path = APP_PATH . '/i18n/' . self::$language . '.php'; - - if (file_exists($l_path)) { - self::$translates = include($l_path); - } + self::$lang_name = Minz_Session::param('language', $l); + self::$lang_path = APP_PATH . '/i18n/' . self::$lang_name . '/'; } - + /** - * Alias de init + * Alias for init(). */ public static function reset() { self::init(); } - + /** - * Traduit une clé en sa valeur du tableau $translates - * @param $key la clé à traduire - * @return la valeur correspondante à la clé - * > si non présente dans le tableau, on retourne la clé elle-même + * Translate a key into its corresponding value based on selected language. + * @param $key the key to translate. + * @param additional parameters for variable keys. + * @return the value corresponding to the key. + * If no value is found, return the key itself. */ public static function t($key) { - $translate = $key; - - if (isset(self::$translates[$key])) { - $translate = self::$translates[$key]; + $group = explode('.', $key); + + if (count($group) < 2) { + // Minz_Log::debug($key . ' is not in a valid format'); + $top_level = 'gen'; + } else { + $top_level = array_shift($group); } + $filename = self::$lang_path . $top_level . '.php'; + + // Try to load the i18n file if it's not done yet. + if (!isset(self::$translates[$top_level])) { + if (!file_exists($filename)) { + Minz_Log::debug($top_level . ' is not a valid top level key'); + return $key; + } + + self::$translates[$top_level] = include($filename); + } + + // Go through the i18n keys to get the correct translation value. + $translates = self::$translates[$top_level]; + $size_group = count($group); + $level_processed = 0; + $translation_value = $key; + foreach ($group as $i18n_level) { + $level_processed++; + if (!isset($translates[$i18n_level])) { + Minz_Log::debug($key . ' is not a valid key'); + return $key; + } + + if ($level_processed < $size_group) { + $translates = $translates[$i18n_level]; + } else { + $translation_value = $translates[$i18n_level]; + } + } + + if (is_array($translation_value)) { + if (isset($translation_value['_'])) { + $translation_value = $translation_value['_']; + } else { + Minz_Log::debug($key . ' is not a valid key'); + return $key; + } + } + + // Get the facultative arguments to replace i18n variables. $args = func_get_args(); unset($args[0]); - - return vsprintf($translate, $args); + + return vsprintf($translation_value, $args); } - + /** - * Retourne la langue utilisée actuellement - * @return la langue + * Return the current language. */ public static function language() { - return self::$language; + return self::$lang_name; } } + +/** + * Alias for Minz_Translate::t() + */ function _t($key) { $args = func_get_args(); unset($args[0]); -- cgit v1.2.3 From aa54f437950eb05d719d10b8be4e0f2648951845 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 10 Dec 2014 22:57:43 +0100 Subject: Verbose for unvalid key format --- lib/Minz/Translate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/Minz/Translate.php') diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index 084bd7e07..e7efb8665 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -51,7 +51,7 @@ class Minz_Translate { $group = explode('.', $key); if (count($group) < 2) { - // Minz_Log::debug($key . ' is not in a valid format'); + Minz_Log::debug($key . ' is not in a valid format'); $top_level = 'gen'; } else { $top_level = array_shift($group); -- cgit v1.2.3 From 26da4aa448906f857a252507b34d369a386043c6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 18 Dec 2014 18:59:13 +0100 Subject: Update Minz_Translation - Give possibility to register new i18n files - Add a extension->registerTranslates() method - extensions can define new strings or override previous ones Fix https://github.com/FreshRSS/FreshRSS/issues/731 --- lib/Minz/Extension.php | 8 +++++ lib/Minz/Translate.php | 79 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 76 insertions(+), 11 deletions(-) (limited to 'lib/Minz/Translate.php') diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index e7b38448f..a24c718c3 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -178,6 +178,14 @@ class Minz_Extension { Minz_View::addBasePathname($this->path); } + /** + * Register i18n files from ext_dir/i18n/ + */ + public function registerTranslates() { + $i18n_dir = $this->path . '/i18n'; + Minz_Translate::registerPath($i18n_dir); + } + /** * Register a new hook. * diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index e7efb8665..aa96728f2 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -15,9 +15,9 @@ class Minz_Translate { private static $lang_name; /** - * $lang_path is the pathname of i18n files (e.g. ./app/i18n/en/). + * $lang_files is a list of registered i18n files. */ - private static $lang_path; + private static $lang_files = array(); /** * $translates is a cache for i18n translation. @@ -30,7 +30,10 @@ class Minz_Translate { public static function init() { $l = Minz_Configuration::language(); self::$lang_name = Minz_Session::param('language', $l); - self::$lang_path = APP_PATH . '/i18n/' . self::$lang_name . '/'; + self::$lang_files = array(); + self::$translates = array(); + + self::registerPath(APP_PATH . '/i18n'); } /** @@ -40,6 +43,63 @@ class Minz_Translate { self::init(); } + /** + * Register a new path and load i18n files inside. + * + * @param $path a path containing i18n directories (e.g. ./en/, ./fr/). + */ + public static function registerPath($path) { + // We load first i18n files for the current language. + $lang_path = $path . '/' . self::$lang_name; + $list_i18n_files = array_values(array_diff( + scandir($lang_path), + array('..', '.') + )); + + // Each file basename correspond to a top-level i18n key. For each of + // these keys we store the file pathname and mark translations must be + // reloaded (by setting $translates[$i18n_key] to null). + foreach ($list_i18n_files as $i18n_filename) { + $i18n_key = basename($i18n_filename, '.php'); + if (!isset(self::$lang_files[$i18n_key])) { + self::$lang_files[$i18n_key] = array(); + } + self::$lang_files[$i18n_key][] = $lang_path . '/' . $i18n_filename; + self::$translates[$i18n_key] = null; + } + } + + /** + * Load the files associated to $key into $translates. + * + * @param $key the top level i18n key we want to load. + */ + private static function loadKey($key) { + // The top level key is not in $lang_files, it means it does not exist! + if (!isset(self::$lang_files[$key])) { + Minz_Log::debug($key . ' is not a valid top level key'); + return false; + } + + self::$translates[$key] = array(); + + foreach (self::$lang_files[$key] as $lang_pathname) { + $i18n_array = include($lang_pathname); + if (!is_array($i18n_array)) { + Minz_Log::warning('`' . $lang_pathname . '` does not contain a PHP array'); + continue; + } + + // We must avoid to erase previous data so we just override them if + // needed. + self::$translates[$key] = array_replace_recursive( + self::$translates[$key], $i18n_array + ); + } + + return true; + } + /** * Translate a key into its corresponding value based on selected language. * @param $key the key to translate. @@ -57,16 +117,13 @@ class Minz_Translate { $top_level = array_shift($group); } - $filename = self::$lang_path . $top_level . '.php'; - - // Try to load the i18n file if it's not done yet. - if (!isset(self::$translates[$top_level])) { - if (!file_exists($filename)) { - Minz_Log::debug($top_level . ' is not a valid top level key'); + // If $translates[$top_level] is null it means we have to load the + // corresponding files. + if (is_null(self::$translates[$top_level])) { + $res = self::loadKey($top_level); + if (!$res) { return $key; } - - self::$translates[$top_level] = include($filename); } // Go through the i18n keys to get the correct translation value. -- cgit v1.2.3 From 51a71ec4b9d62528054be8faee1576a8fd6d37f6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 5 Jan 2015 16:54:16 +0100 Subject: New configuration system (not working yet) - Use only Minz_Configuration - register() method to load a new configuration file - get() to get a configuration - new exceptions related to configuration - fix a list configuration calls to have FRSS working Current problems to resolve: - How to handle configuration param verifications (i.e. check auth_type is a value from none, http_auth, persona or form) - We must use $conf = Minz_Configuration::get('system'); $general_conf = $conf->general; to access global system configuration which is quite annoying. How to change that? See https://github.com/FreshRSS/FreshRSS/issues/730 --- app/Controllers/authController.php | 36 +- app/FreshRSS.php | 8 +- app/Models/Auth.php | 40 ++- app/Models/Context.php | 4 +- app/Models/Factory.php | 16 +- app/Models/Feed.php | 3 +- app/layout/header.phtml | 13 +- app/layout/layout.phtml | 3 +- app/views/helpers/javascript_vars.phtml | 3 +- data/config.default.php | 32 ++ data/users/_/config.default.php | 66 ++++ lib/Minz/BadConfigurationException.php | 9 - lib/Minz/Configuration.php | 517 ++++++++------------------- lib/Minz/ConfigurationException.php | 8 + lib/Minz/ConfigurationNamespaceException.php | 4 + lib/Minz/ConfigurationParamException.php | 4 + lib/Minz/Error.php | 7 +- lib/Minz/FrontController.php | 26 +- lib/Minz/Log.php | 11 +- lib/Minz/ModelPdo.php | 3 +- lib/Minz/Request.php | 3 +- lib/Minz/Translate.php | 3 +- lib/Minz/View.php | 4 +- p/i/index.php | 2 +- 24 files changed, 384 insertions(+), 441 deletions(-) create mode 100644 data/config.default.php create mode 100644 data/users/_/config.default.php delete mode 100644 lib/Minz/BadConfigurationException.php create mode 100644 lib/Minz/ConfigurationException.php create mode 100644 lib/Minz/ConfigurationNamespaceException.php create mode 100644 lib/Minz/ConfigurationParamException.php (limited to 'lib/Minz/Translate.php') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index ccc32ec0d..f68ea8da5 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -27,6 +27,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; + $system_conf = Minz_Configuration::get('system'); + $general = $system_conf->general; $current_token = FreshRSS_Context::$conf->token; $token = Minz_Request::param('token', $current_token); FreshRSS_Context::$conf->_token($token); @@ -39,18 +41,21 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $auth_type = Minz_Request::param('auth_type', 'none'); $unsafe_autologin = Minz_Request::param('unsafe_autologin', false); $api_enabled = Minz_Request::param('api_enabled', false); - if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType() || - $anon_refresh != Minz_Configuration::allowAnonymousRefresh() || - $unsafe_autologin != Minz_Configuration::unsafeAutologinEnabled() || - $api_enabled != Minz_Configuration::apiEnabled()) { - - Minz_Configuration::_authType($auth_type); - Minz_Configuration::_allowAnonymous($anon); - Minz_Configuration::_allowAnonymousRefresh($anon_refresh); - Minz_Configuration::_enableAutologin($unsafe_autologin); - Minz_Configuration::_enableApi($api_enabled); - $ok &= Minz_Configuration::writeFile(); + if ($anon != $general['allow_anonymous'] || + $auth_type != $general['auth_type'] || + $anon_refresh != $general['allow_anonymous_refresh'] || + $unsafe_autologin != $general['unsafe_autologin_enabled'] || + $api_enabled != $general['api_enabled']) { + + // TODO: test values from form + $general['auth_type'] = $auth_type; + $general['allow_anonymous'] = $anon; + $general['allow_anonymous_refresh'] = $anon_refresh; + $general['unsafe_autologin_enabled'] = $unsafe_autologin; + $general['api_enabled'] = $api_enabled; + + $system_conf->general = $general; + $ok &= $system_conf->save(); } invalidateHttpCache(); @@ -76,7 +81,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } - $auth_type = Minz_Configuration::authType(); + $conf = Minz_Configuration::get('system'); + $auth_type = $conf->general['auth_type']; switch ($auth_type) { case 'form': Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); @@ -114,6 +120,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); + $conf = Minz_Configuration::get('system'); + if (Minz_Request::isPost()) { $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); @@ -154,7 +162,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.auth.login.invalid'), array('c' => 'auth', 'a' => 'login')); } - } elseif (Minz_Configuration::unsafeAutologinEnabled()) { + } elseif ($conf->general['unsafe_autologin_enabled']) { $username = Minz_Request::param('u', ''); $password = Minz_Request::param('p', ''); Minz_Request::_param('p'); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 6114a5d1a..455f2fefd 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -6,6 +6,11 @@ class FreshRSS extends Minz_FrontController { Minz_Session::init('FreshRSS'); } + $current_user = Minz_Session::param('currentUser', '_'); + Minz_Configuration::register('user', + join_path(USERS_PATH, $current_user, 'config.php'), + join_path(USERS_PATH, '_', 'config.default.php')); + // Need to be called just after session init because it initializes // current user. FreshRSS_Auth::init(); @@ -57,7 +62,8 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); - if (Minz_Configuration::authType() === 'persona') { + $conf = Minz_Configuration::get('system'); + if ($conf->general['auth_type'] === 'persona') { // TODO move it in a plugin // Needed for login AND logout with Persona. Minz_View::appendScript('https://login.persona.org/include.js'); diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 2971d65c8..84b4e3721 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -16,7 +16,8 @@ class FreshRSS_Auth { self::$login_ok = Minz_Session::param('loginOk', false); $current_user = Minz_Session::param('currentUser', ''); if ($current_user === '') { - $current_user = Minz_Configuration::defaultUser(); + $conf = Minz_Configuration::get('system'); + $current_user = $conf->general['default_user']; Minz_Session::_param('currentUser', $current_user); } @@ -40,7 +41,9 @@ class FreshRSS_Auth { * @return boolean true if user can be connected, false else. */ private static function accessControl() { - switch (Minz_Configuration::authType()) { + $conf = Minz_Configuration::get('system'); + $auth_type = $conf->general['auth_type']; + switch ($auth_type) { case 'form': $credentials = FreshRSS_FormAuth::getCredentialsFromCookie(); $current_user = ''; @@ -79,22 +82,19 @@ class FreshRSS_Auth { * Gives access to the current user. */ public static function giveAccess() { - $current_user = Minz_Session::param('currentUser'); - try { - $conf = new FreshRSS_Configuration($current_user); - } catch(Minz_Exception $e) { - die($e->getMessage()); - } + $user_conf = Minz_Configuration::get('user'); + $system_conf = Minz_Configuration::get('system'); + $auth_type = $system_conf->general['auth_type']; - switch (Minz_Configuration::authType()) { + switch ($auth_type) { case 'form': - self::$login_ok = Minz_Session::param('passwordHash') === $conf->passwordHash; + self::$login_ok = Minz_Session::param('passwordHash') === $user_conf->passwordHash; break; case 'http_auth': self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0; break; case 'persona': - self::$login_ok = strcasecmp(Minz_Session::param('mail'), $conf->mail_login) === 0; + self::$login_ok = strcasecmp(Minz_Session::param('mail'), $user_conf->mail_login) === 0; break; case 'none': self::$login_ok = true; @@ -114,12 +114,14 @@ class FreshRSS_Auth { * @return boolean true if user has corresponding access, false else. */ public static function hasAccess($scope = 'general') { + $conf = Minz_Configuration::get('system'); + $default_user = $conf->general['default_user']; $ok = self::$login_ok; switch ($scope) { case 'general': break; case 'admin': - $ok &= Minz_Session::param('currentUser') === Minz_Configuration::defaultUser(); + $ok &= Minz_Session::param('currentUser') === $default_user; break; default: $ok = false; @@ -133,9 +135,10 @@ class FreshRSS_Auth { public static function removeAccess() { Minz_Session::_param('loginOk'); self::$login_ok = false; - Minz_Session::_param('currentUser', Minz_Configuration::defaultUser()); + $conf = Minz_Configuration::get('system'); + Minz_Session::_param('currentUser', $conf->general['default_user']); - switch (Minz_Configuration::authType()) { + switch ($conf->general['auth_type']) { case 'form': Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); @@ -151,6 +154,15 @@ class FreshRSS_Auth { // TODO: extensions } } + + /** + * Return if authentication is enabled on this instance of FRSS. + */ + public static function accessNeedLogin() { + $conf = Minz_Configuration::get('system'); + $auth_type = $conf->general['auth_type']; + return $auth_type === 'form' || $auth_type === 'persona'; + } } diff --git a/app/Models/Context.php b/app/Models/Context.php index c8a65063a..9bbad9857 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -41,10 +41,10 @@ class FreshRSS_Context { */ public static function init() { // Init configuration. - $current_user = Minz_Session::param('currentUser'); try { - self::$conf = new FreshRSS_Configuration($current_user); + self::$conf = Minz_Configuration::get('user'); } catch(Minz_Exception $e) { + $current_user = Minz_Session::param('currentUser', '_'); Minz_Log::error('Cannot load configuration file of user `' . $current_user . '`'); die($e->getMessage()); } diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 91cb84998..db09d155d 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -3,8 +3,8 @@ class FreshRSS_Factory { public static function createFeedDao($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_FeedDAOSQLite($username); } else { return new FreshRSS_FeedDAO($username); @@ -12,8 +12,8 @@ class FreshRSS_Factory { } public static function createEntryDao($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_EntryDAOSQLite($username); } else { return new FreshRSS_EntryDAO($username); @@ -21,8 +21,8 @@ class FreshRSS_Factory { } public static function createStatsDAO($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_StatsDAOSQLite($username); } else { return new FreshRSS_StatsDAO($username); @@ -30,8 +30,8 @@ class FreshRSS_Factory { } public static function createDatabaseDAO($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_DatabaseDAOSQLite($username); } else { return new FreshRSS_DatabaseDAO($username); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 8f4b60097..071eafdf6 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -39,8 +39,9 @@ class FreshRSS_Feed extends Minz_Model { } public function hash() { + $conf = Minz_Configuration::get('system'); if ($this->hash === null) { - $this->hash = hash('crc32b', Minz_Configuration::salt() . $this->url); + $this->hash = hash('crc32b', $conf->general['salt'] . $this->url); } return $this->hash; } diff --git a/app/layout/header.phtml b/app/layout/header.phtml index ba13c2a45..2f16b5f63 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -1,5 +1,8 @@ - +
diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 1827d6c26..656fbe9bc 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -10,6 +10,7 @@ renderHelper('javascript_vars'); ?> //]]> "> - + diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 6577e0109..02f2014ee 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -1,6 +1,7 @@ "use strict"; mark_when; $mail = Minz_Session::param('mail', false); $auto_actualize = Minz_Session::param('actualize_feeds', false); @@ -29,7 +30,7 @@ echo 'var context={', 'does_lazyload:', FreshRSS_Context::$conf->lazyload ? 'true' : 'false', ',', 'sticky_post:', FreshRSS_Context::isStickyPostEnabled() ? 'true' : 'false', ',', 'html5_notif_timeout:', FreshRSS_Context::$conf->html5_notif_timeout, ',', - 'auth_type:"', Minz_Configuration::authType(), '",', + 'auth_type:"', $conf->general['auth_type'], '",', 'current_user_mail:', $mail ? ('"' . $mail . '"') : 'null', ',', 'current_view:"', Minz_Request::param('output', 'normal'), '"', "},\n"; diff --git a/data/config.default.php b/data/config.default.php new file mode 100644 index 000000000..a69d8050b --- /dev/null +++ b/data/config.default.php @@ -0,0 +1,32 @@ + array( + 'environment' => 'production', + 'salt' => '', + 'base_url' => '', + 'language' => 'en', + 'title' => 'FreshRSS', + 'default_user' => '_', + 'allow_anonymous' => false, + 'allow_anonymous_refresh' => false, + 'auth_type' => 'none', + 'api_enabled' => false, + 'unsafe_autologin_enabled' => false, + ), + 'limits' => array( + 'cache_duration' => 800, + 'timeout' => 10, + 'max_inactivity' => PHP_INT_MAX, + 'max_feeds' => 16384, + 'max_categories' => 16384, + ), + 'db' => array( + 'type' => 'sqlite', + 'host' => '', + 'user' => '', + 'password' => '', + 'base' => '', + 'prefix' => '', + ), +); diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php new file mode 100644 index 000000000..56d54b293 --- /dev/null +++ b/data/users/_/config.default.php @@ -0,0 +1,66 @@ + 'en', + 'old_entries' => 3, + 'keep_history_default' => 0, + 'ttl_default' => 3600, + 'mail_login' => '', + 'token' => '', + 'passwordHash' => '', + 'apiPasswordHash' => '', + 'posts_per_page' => 20, + 'view_mode' => 'normal', + 'default_view' => 'adaptive', + 'default_state' => FreshRSS_Entry::STATE_NOT_READ, + 'auto_load_more' => true, + 'display_posts' => false, + 'display_categories' => false, + 'hide_read_feeds' => true, + 'onread_jump_next' => true, + 'lazyload' => true, + 'sticky_post' => true, + 'reading_confirm' => false, + 'auto_remove_article' => false, + 'sort_order' => 'DESC', + 'anon_access' => false, + 'mark_when' => array ( + 'article' => true, + 'site' => true, + 'scroll' => false, + 'reception' => false, + ), + 'theme' => 'Origine', + 'content_width' => 'thin', + 'shortcuts' => array ( + 'mark_read' => 'r', + 'mark_favorite' => 'f', + 'go_website' => 'space', + 'next_entry' => 'j', + 'prev_entry' => 'k', + 'first_entry' => 'home', + 'last_entry' => 'end', + 'collapse_entry' => 'c', + 'load_more' => 'm', + 'auto_share' => 's', + 'focus_search' => 'a', + 'user_filter' => 'u', + 'help' => 'f1', + 'close_dropdown' => 'escape', + ), + 'topline_read' => true, + 'topline_favorite' => true, + 'topline_date' => true, + 'topline_link' => true, + 'bottomline_read' => true, + 'bottomline_favorite' => true, + 'bottomline_sharing' => true, + 'bottomline_tags' => true, + 'bottomline_date' => true, + 'bottomline_link' => true, + 'sharing' => array ( + ), + 'queries' => array ( + ), + 'html5_notif_timeout' => 0, +); diff --git a/lib/Minz/BadConfigurationException.php b/lib/Minz/BadConfigurationException.php deleted file mode 100644 index a7b77d687..000000000 --- a/lib/Minz/BadConfigurationException.php +++ /dev/null @@ -1,9 +0,0 @@ - -*/ /** - * La classe Configuration permet de gérer la configuration de l'application + * Manage configuration for the application. */ class Minz_Configuration { - const CONF_PATH_NAME = '/config.php'; - /** - * VERSION est la version actuelle de MINZ + * The list of configurations. */ - const VERSION = '1.3.1.freshrss'; // version spéciale FreshRSS + private static $config_list = array(); /** - * valeurs possibles pour l'"environment" - * SILENT rend l'application muette (pas de log) - * PRODUCTION est recommandée pour une appli en production - * (log les erreurs critiques) - * DEVELOPMENT log toutes les erreurs + * Add a new configuration to the list of configuration. + * + * @param $namespace the name of the current configuration + * @param $config_filename the filename of the configuration + * @param $default_filename a filename containing default values for the configuration + * @throws Minz_ConfigurationNamespaceException if the namespace already exists. */ - const SILENT = 0; - const PRODUCTION = 1; - const DEVELOPMENT = 2; + public static function register($namespace, $config_filename, $default_filename = null) { + if (isset(self::$config_list[$namespace])) { + throw new Minz_ConfigurationNamespaceException( + $namespace . ' namespace already exists' + ); + } + + self::$config_list[$namespace] = new Minz_Configuration( + $namespace, $config_filename, $default_filename + ); + } /** - * définition des variables de configuration - * $salt une chaîne de caractères aléatoires (obligatoire) - * $environment gère le niveau d'affichage pour log et erreurs - * $base_url le chemin de base pour accéder à l'application - * $title le nom de l'application - * $language la langue par défaut de l'application - * $db paramètres pour la base de données (tableau) - * - host le serveur de la base - * - user nom d'utilisateur - * - password mot de passe de l'utilisateur - * - base le nom de la base de données + * Parse a file and return its data. + * + * If the file does not contain a valid PHP code returning an array, an + * empty array is returned anyway. + * + * @param $filename the name of the file to parse. + * @return an array of values + * @throws Minz_FileNotExistException if the file does not exist. */ - private static $salt = ''; - private static $environment = Minz_Configuration::PRODUCTION; - private static $base_url = ''; - private static $title = ''; - private static $language = 'en'; - private static $default_user = ''; - private static $allow_anonymous = false; - private static $allow_anonymous_refresh = false; - private static $auth_type = 'none'; - private static $api_enabled = false; - private static $unsafe_autologin_enabled = false; - - private static $db = array ( - 'type' => 'mysql', - 'host' => '', - 'user' => '', - 'password' => '', - 'base' => '', - 'prefix' => '', - ); - - const MAX_SMALL_INT = 16384; - private static $limits = array( - 'cache_duration' => 800, //SimplePie cache duration in seconds - 'timeout' => 10, //SimplePie timeout in seconds - 'max_inactivity' => PHP_INT_MAX, //Time in seconds after which a user who has not used the account is considered inactive (no auto-refresh of feeds). - 'max_feeds' => Minz_Configuration::MAX_SMALL_INT, - 'max_categories' => Minz_Configuration::MAX_SMALL_INT, - ); + public static function parseFile($filename) { + if (!file_exists($filename)) { + throw new Minz_FileNotExistException($filename); + } - /* - * Getteurs - */ - public static function salt () { - return self::$salt; + $data = @include($filename); + if (is_array($data)) { + return $data; + } else { + return array(); + } } - public static function environment ($str = false) { - $env = self::$environment; - if ($str) { - switch (self::$environment) { - case self::SILENT: - $env = 'silent'; - break; - case self::DEVELOPMENT: - $env = 'development'; - break; - case self::PRODUCTION: - default: - $env = 'production'; - } + /** + * Return the configuration related to a given namespace. + * + * @param $namespace the name of the configuration to get. + * @return a Minz_Configuration object + * @throws Minz_ConfigurationNamespaceException if the namespace does not exist. + */ + public static function get($namespace) { + if (!isset(self::$config_list[$namespace])) { + throw new Minz_ConfigurationNamespaceException( + $namespace . ' namespace does not exist' + ); } - return $env; - } - public static function baseUrl () { - return self::$base_url; - } - public static function title () { - return self::$title; - } - public static function language () { - return self::$language; - } - public static function dataBase () { - return self::$db; - } - public static function limits() { - return self::$limits; - } - public static function defaultUser () { - return self::$default_user; - } - public static function allowAnonymous() { - return self::$allow_anonymous; - } - public static function allowAnonymousRefresh() { - return self::$allow_anonymous_refresh; - } - public static function authType() { - return self::$auth_type; - } - public static function needsLogin() { - return self::$auth_type !== 'none'; - } - public static function canLogIn() { - return self::$auth_type === 'form' || self::$auth_type === 'persona'; - } - public static function apiEnabled() { - return self::$api_enabled; - } - public static function unsafeAutologinEnabled() { - return self::$unsafe_autologin_enabled; + return self::$config_list[$namespace]; } - public static function _allowAnonymous($allow = false) { - self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); - } - public static function _allowAnonymousRefresh($allow = false) { - self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous(); - } - public static function _authType($value) { - $value = strtolower($value); - switch ($value) { - case 'form': - case 'http_auth': - case 'persona': - case 'none': - self::$auth_type = $value; - break; - } - self::_allowAnonymous(self::$allow_anonymous); - } + /** + * The namespace of the current configuration. + */ + private $namespace = ''; - public static function _enableApi($value = false) { - self::$api_enabled = (bool)$value; - } - public static function _enableAutologin($value = false) { - self::$unsafe_autologin_enabled = (bool)$value; - } + /** + * The filename for the current configuration. + */ + private $config_filename = ''; + + /** + * The filename for the current default values, null by default. + */ + private $default_filename = null; + + /** + * The configuration values, an empty array by default. + */ + private $data = array(); + + /** + * The default values, an empty array by default. + */ + private $data_default = array(); /** - * Initialise les variables de configuration - * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + * Create a new Minz_Configuration object. + * + * @param $namespace the name of the current configuration. + * @param $config_filename the file containing configuration values. + * @param $default_filename the file containing default values, null by default. */ - public static function init () { + private function __construct($namespace, $config_filename, $default_filename = null) { + $this->namespace = $namespace; + $this->config_filename = $config_filename; + try { - self::parseFile (); - self::setReporting (); + $this->data = self::parseFile($this->config_filename); } catch (Minz_FileNotExistException $e) { - throw $e; - } catch (Minz_BadConfigurationException $e) { - throw $e; + if (is_null($default_filename)) { + throw $e; + } } - } - public static function writeFile() { - $ini_array = array( - 'general' => array( - 'environment' => self::environment(true), - 'salt' => self::$salt, - 'base_url' => self::$base_url, - 'title' => self::$title, - 'default_user' => self::$default_user, - 'allow_anonymous' => self::$allow_anonymous, - 'allow_anonymous_refresh' => self::$allow_anonymous_refresh, - 'auth_type' => self::$auth_type, - 'api_enabled' => self::$api_enabled, - 'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled, - ), - 'limits' => self::$limits, - 'db' => self::$db, - ); - @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php'); - $result = file_put_contents(DATA_PATH . self::CONF_PATH_NAME, "default_filename = $default_filename; + if (!is_null($this->default_filename)) { + $this->data_default = self::parseFile($this->default_filename); } - return (bool)$result; } /** - * Parse un fichier de configuration - * @exception Minz_PermissionDeniedException si le CONF_PATH_NAME n'est pas accessible - * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + * Return the value of the given param. + * + * @param $key the name of the param. + * @param $default default value to return if key does not exist. + * @return the value corresponding to the key. + * @throws Minz_ConfigurationParamException if the param does not exist */ - private static function parseFile () { - $ini_array = include(DATA_PATH . self::CONF_PATH_NAME); - - if (!is_array($ini_array)) { - throw new Minz_PermissionDeniedException ( - DATA_PATH . self::CONF_PATH_NAME, - Minz_Exception::ERROR + public function param($key, $default = null) { + if (isset($this->data[$key])) { + return $this->data[$key]; + } elseif (!is_null($default)) { + return $default; + } elseif (isset($this->data_default[$key])) { + return $this->data_default[$key]; + } else { + throw new Minz_ConfigurationParamException( + $key . ' param does not exist' ); } + } - // [general] est obligatoire - if (!isset ($ini_array['general'])) { - throw new Minz_BadConfigurationException ( - '[general]', - Minz_Exception::ERROR - ); - } - $general = $ini_array['general']; + /** + * A wrapper for param(). + */ + public function __get($key) { + return $this->param($key); + } - // salt est obligatoire - if (!isset ($general['salt'])) { - if (isset($general['sel_application'])) { //v0.6 - $general['salt'] = $general['sel_application']; - } else { - throw new Minz_BadConfigurationException ( - 'salt', - Minz_Exception::ERROR - ); - } + /** + * Set or remove a param. + * + * @param $key the param name to set. + * @param $value the value to set. If null, the key is removed from the configuration. + */ + public function _param($key, $value = null) { + if (isset($this->data[$key]) && is_null($value)) { + unset($this->data[$key]); + } else { + $this->data[$key] = $value; } - self::$salt = $general['salt']; - - if (isset ($general['environment'])) { - switch ($general['environment']) { - case 'silent': - self::$environment = Minz_Configuration::SILENT; - break; - case 'development': - self::$environment = Minz_Configuration::DEVELOPMENT; - break; - case 'production': - self::$environment = Minz_Configuration::PRODUCTION; - break; - default: - if ($general['environment'] >= 0 && - $general['environment'] <= 2) { - // fallback 0.7-beta - self::$environment = $general['environment']; - } else { - throw new Minz_BadConfigurationException ( - 'environment', - Minz_Exception::ERROR - ); - } - } + } - } - if (isset ($general['base_url'])) { - self::$base_url = $general['base_url']; - } + /** + * A wrapper for _param(). + */ + public function __set($key, $value) { + $this->_param($key, $value); + } - if (isset ($general['title'])) { - self::$title = $general['title']; - } - if (isset ($general['language'])) { - self::$language = $general['language']; - } - if (isset ($general['default_user'])) { - self::$default_user = $general['default_user']; - } - if (isset ($general['auth_type'])) { - self::_authType($general['auth_type']); - } - if (isset ($general['allow_anonymous'])) { - self::$allow_anonymous = ( - ((bool)($general['allow_anonymous'])) && - ($general['allow_anonymous'] !== 'no') - ); - } - if (isset ($general['allow_anonymous_refresh'])) { - self::$allow_anonymous_refresh = ( - ((bool)($general['allow_anonymous_refresh'])) && - ($general['allow_anonymous_refresh'] !== 'no') - ); - } - if (isset ($general['api_enabled'])) { - self::$api_enabled = ( - ((bool)($general['api_enabled'])) && - ($general['api_enabled'] !== 'no') - ); - } - if (isset ($general['unsafe_autologin_enabled'])) { - self::$unsafe_autologin_enabled = ( - ((bool)($general['unsafe_autologin_enabled'])) && - ($general['unsafe_autologin_enabled'] !== 'no') - ); - } + /** + * Save the current configuration in the configuration file. + */ + public function save() { + $back_filename = $this->config_filename . '.bak.php'; + @rename($this->config_filename, $back_filename); - if (isset($ini_array['limits'])) { - $limits = $ini_array['limits']; - if (isset($limits['cache_duration'])) { - $v = intval($limits['cache_duration']); - if ($v > 0) { - self::$limits['cache_duration'] = $v; - } - } - if (isset($limits['timeout'])) { - $v = intval($limits['timeout']); - if ($v > 0) { - self::$limits['timeout'] = $v; - } - } - if (isset($limits['max_inactivity'])) { - $v = intval($limits['max_inactivity']); - if ($v > 0) { - self::$limits['max_inactivity'] = $v; - } - } - if (isset($limits['max_feeds'])) { - $v = intval($limits['max_feeds']); - if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { - self::$limits['max_feeds'] = $v; - } - } - if (isset($limits['max_categories'])) { - $v = intval($limits['max_categories']); - if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { - self::$limits['max_categories'] = $v; - } - } + if (file_put_contents($this->config_filename, + "data, true) . ';', + LOCK_EX) === false) { + return false; } - // Base de données - if (isset ($ini_array['db'])) { - $db = $ini_array['db']; - if (empty($db['type'])) { - throw new Minz_BadConfigurationException ( - 'type', - Minz_Exception::ERROR - ); - } - switch ($db['type']) { - case 'mysql': - if (empty($db['host'])) { - throw new Minz_BadConfigurationException ( - 'host', - Minz_Exception::ERROR - ); - } - if (empty($db['user'])) { - throw new Minz_BadConfigurationException ( - 'user', - Minz_Exception::ERROR - ); - } - if (!isset($db['password'])) { - throw new Minz_BadConfigurationException ( - 'password', - Minz_Exception::ERROR - ); - } - if (empty($db['base'])) { - throw new Minz_BadConfigurationException ( - 'base', - Minz_Exception::ERROR - ); - } - self::$db['host'] = $db['host']; - self::$db['user'] = $db['user']; - self::$db['password'] = $db['password']; - self::$db['base'] = $db['base']; - if (isset($db['prefix'])) { - self::$db['prefix'] = $db['prefix']; - } - break; - case 'sqlite': - self::$db['host'] = ''; - self::$db['user'] = ''; - self::$db['password'] = ''; - self::$db['base'] = ''; - self::$db['prefix'] = ''; - break; - default: - throw new Minz_BadConfigurationException ( - 'type', - Minz_Exception::ERROR - ); - break; - } - self::$db['type'] = $db['type']; + // Clear PHP 5.5+ cache for include + if (function_exists('opcache_invalidate')) { + opcache_invalidate($this->config_filename); } - } - private static function setReporting() { - switch (self::$environment) { - case self::PRODUCTION: - error_reporting(E_ALL); - ini_set('display_errors','Off'); - ini_set('log_errors', 'On'); - break; - case self::DEVELOPMENT: - error_reporting(E_ALL); - ini_set('display_errors','On'); - ini_set('log_errors', 'On'); - break; - case self::SILENT: - error_reporting(0); - break; - } + return true; } } diff --git a/lib/Minz/ConfigurationException.php b/lib/Minz/ConfigurationException.php new file mode 100644 index 000000000..f294c3341 --- /dev/null +++ b/lib/Minz/ConfigurationException.php @@ -0,0 +1,8 @@ + en fonction de l'environment */ private static function processLogs ($logs) { - $env = Minz_Configuration::environment (); + $conf = Minz_Configuration::get('system'); + $env = $conf->general['environment']; $logs_ok = array (); $error = array (); $warning = array (); @@ -98,10 +99,10 @@ class Minz_Error { $notice = $logs['notice']; } - if ($env == Minz_Configuration::PRODUCTION) { + if ($env == 'production') { $logs_ok = $error; } - if ($env == Minz_Configuration::DEVELOPMENT) { + if ($env == 'development') { $logs_ok = array_merge ($error, $warning, $notice); } diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index 3dac1e438..974cf4260 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -31,9 +31,12 @@ class Minz_FrontController { */ public function __construct () { try { - Minz_Configuration::init (); + Minz_Configuration::register('system', + DATA_PATH . '/config.php', + DATA_PATH . '/config.default.php'); + $this->setReporting(); - Minz_Request::init (); + Minz_Request::init(); $url = $this->buildUrl(); $url['params'] = array_merge ( @@ -110,4 +113,23 @@ class Minz_FrontController { } exit ('### Application problem ###
'."\n".$txt); } + + private function setReporting() { + $conf = Minz_Configuration::get('system'); + switch($conf->general['environment']) { + case 'production': + error_reporting(E_ALL); + ini_set('display_errors','Off'); + ini_set('log_errors', 'On'); + break; + case 'development': + error_reporting(E_ALL); + ini_set('display_errors','On'); + ini_set('log_errors', 'On'); + break; + case 'silent': + error_reporting(0); + break; + } + } } diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index d19edc1dc..2063efe7e 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -31,10 +31,15 @@ class Minz_Log { * @param $file_name fichier de log */ public static function record ($information, $level, $file_name = null) { - $env = Minz_Configuration::environment (); + try { + $conf = Minz_Configuration::get('system'); + $env = $conf->general['environment']; + } catch (Minz_ConfigurationException $e) { + $env = 'production'; + } - if (! ($env === Minz_Configuration::SILENT - || ($env === Minz_Configuration::PRODUCTION + if (! ($env === 'silent' + || ($env === 'production' && ($level >= Minz_Log::NOTICE)))) { if ($file_name === null) { $file_name = join_path(USERS_PATH, Minz_Session::param('currentUser', '_'), 'log.txt'); diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 118d89ad2..ac7a1bed7 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -44,7 +44,8 @@ class Minz_ModelPdo { return; } - $db = Minz_Configuration::dataBase(); + $conf = Minz_Configuration::get('system'); + $db = $conf->db; if ($currentUser === null) { $currentUser = Minz_Session::param('currentUser', '_'); diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index 4b97a3caf..5f2f6a858 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -96,7 +96,8 @@ class Minz_Request { * @return la base de l'url */ public static function getBaseUrl() { - $defaultBaseUrl = Minz_Configuration::baseUrl(); + $conf = Minz_Configuration::get('system'); + $defaultBaseUrl = $conf->general['base_url']; if (!empty($defaultBaseUrl)) { return $defaultBaseUrl; } elseif (isset($_SERVER['REQUEST_URI'])) { diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index e7efb8665..7525e95cc 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -28,7 +28,8 @@ class Minz_Translate { * Load $lang_name and $lang_path based on configuration and selected language. */ public static function init() { - $l = Minz_Configuration::language(); + $conf = Minz_Configuration::get('system'); + $l = $conf->general['language']; self::$lang_name = Minz_Session::param('language', $l); self::$lang_path = APP_PATH . '/i18n/' . self::$lang_name . '/'; } diff --git a/lib/Minz/View.php b/lib/Minz/View.php index b40448491..24ad630d0 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -28,7 +28,9 @@ class Minz_View { public function __construct () { $this->change_view(Minz_Request::controllerName(), Minz_Request::actionName()); - self::$title = Minz_Configuration::title (); + + $conf = Minz_Configuration::get('system'); + self::$title = $conf->general['title']; } /** diff --git a/p/i/index.php b/p/i/index.php index 009d56bc3..d3fc0b37c 100755 --- a/p/i/index.php +++ b/p/i/index.php @@ -33,7 +33,7 @@ if (file_exists(DATA_PATH . '/do-install.txt')) { $currentUser = Minz_Session::param('currentUser', ''); $dateLastModification = $currentUser === '' ? time() : max( @filemtime(join_path(USERS_PATH, $currentUser, 'log.txt')), - @filemtime(join_path(DATA_PATH . 'config.php')) + @filemtime(join_path(DATA_PATH, 'config.php')) ); if (httpConditional($dateLastModification, 0, 0, false, PHP_COMPRESSION, true)) { exit(); //No need to send anything -- cgit v1.2.3 From d3a93ea2905ae50a2365d293f9f3ef3e51bf5f30 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 6 Jan 2015 18:53:36 +0100 Subject: BREAKING FEATURE: Remove general in config General attribute has been removed from system config. Now subattributes (e.g. environment, salt, title, etc.) are directly accessible. YOU HAVE TO FIX YOUR ./data/config.php file! - Remove the general array - Values inside this array must be kept - To see what it must look like, please have a look to ./data/config.default.php (but keep your values!!). See https://github.com/FreshRSS/FreshRSS/issues/730 --- app/Controllers/authController.php | 28 +++++++++++++--------------- app/Controllers/feedController.php | 2 +- app/Controllers/indexController.php | 6 +++--- app/Controllers/javascriptController.php | 2 +- app/Controllers/userController.php | 4 ++-- app/FreshRSS.php | 2 +- app/Models/Auth.php | 14 +++++++------- app/Models/Feed.php | 4 ++-- app/layout/header.phtml | 6 ++---- app/layout/layout.phtml | 2 +- app/views/helpers/javascript_vars.phtml | 3 +-- data/config.default.php | 24 +++++++++++------------- lib/Minz/Error.php | 2 +- lib/Minz/FrontController.php | 2 +- lib/Minz/Log.php | 2 +- lib/Minz/Request.php | 2 +- lib/Minz/Translate.php | 2 +- lib/Minz/View.php | 2 +- 18 files changed, 51 insertions(+), 58 deletions(-) (limited to 'lib/Minz/Translate.php') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 3a1ad4605..4ae9ff7fb 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -27,7 +27,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; - $general = FreshRSS_Context::$system_conf->general; $current_token = FreshRSS_Context::$user_conf->token; $token = Minz_Request::param('token', $current_token); FreshRSS_Context::$user_conf->_token($token); @@ -40,20 +39,19 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $auth_type = Minz_Request::param('auth_type', 'none'); $unsafe_autologin = Minz_Request::param('unsafe_autologin', false); $api_enabled = Minz_Request::param('api_enabled', false); - if ($anon != $general['allow_anonymous'] || - $auth_type != $general['auth_type'] || - $anon_refresh != $general['allow_anonymous_refresh'] || - $unsafe_autologin != $general['unsafe_autologin_enabled'] || - $api_enabled != $general['api_enabled']) { + if ($anon != FreshRSS_Context::$system_conf->allow_anonymous || + $auth_type != FreshRSS_Context::$system_conf->auth_type || + $anon_refresh != FreshRSS_Context::$system_conf->allow_anonymous_refresh || + $unsafe_autologin != FreshRSS_Context::$system_conf->unsafe_autologin_enabled || + $api_enabled != FreshRSS_Context::$system_conf->api_enabled) { // TODO: test values from form - $general['auth_type'] = $auth_type; - $general['allow_anonymous'] = $anon; - $general['allow_anonymous_refresh'] = $anon_refresh; - $general['unsafe_autologin_enabled'] = $unsafe_autologin; - $general['api_enabled'] = $api_enabled; + FreshRSS_Context::$system_conf->auth_type = $auth_type; + FreshRSS_Context::$system_conf->allow_anonymous = $anon; + FreshRSS_Context::$system_conf->allow_anonymous_refresh = $anon_refresh; + FreshRSS_Context::$system_conf->unsafe_autologin_enabled = $unsafe_autologin; + FreshRSS_Context::$system_conf->api_enabled = $api_enabled; - $system_conf->general = $general; $ok &= $system_conf->save(); } @@ -80,7 +78,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } - $auth_type = FreshRSS_Context::$system_conf->general['auth_type']; + $auth_type = FreshRSS_Context::$system_conf->auth_type; switch ($auth_type) { case 'form': Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); @@ -160,7 +158,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.auth.login.invalid'), array('c' => 'auth', 'a' => 'login')); } - } elseif (FreshRSS_Context::$system_conf->general['unsafe_autologin_enabled']) { + } elseif (FreshRSS_Context::$system_conf->unsafe_autologin_enabled) { $username = Minz_Request::param('u', ''); $password = Minz_Request::param('p', ''); Minz_Request::_param('p'); @@ -301,7 +299,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $this->view->no_form = false; // Enable changement of auth only if Persona! - if (FreshRSS_Context::$system_conf->general['auth_type'] != 'persona') { + if (FreshRSS_Context::$system_conf->auth_type != 'persona') { $this->view->message = array( 'status' => 'bad', 'title' => _t('gen.short.damn'), diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index df1e559bc..c22669361 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -18,7 +18,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $token_param = Minz_Request::param('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName(); - $allow_anonymous_refresh = FreshRSS_Context::$system_conf->general['allow_anonymous_refresh']; + $allow_anonymous_refresh = FreshRSS_Context::$system_conf->allow_anonymous_refresh; if ($action !== 'actualize' || !($allow_anonymous_refresh || $token_is_ok)) { Minz_Error::error(403); diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index d948504cc..c53d3223e 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -20,7 +20,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action displays the normal view of FreshRSS. */ public function normalAction() { - $allow_anonymous = FreshRSS_Context::$system_conf->general['allow_anonymous']; + $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous; if (!FreshRSS_Auth::hasAccess() && !$allow_anonymous) { Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); return; @@ -83,7 +83,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action displays the global view of FreshRSS. */ public function globalAction() { - $allow_anonymous = FreshRSS_Context::$system_conf->general['allow_anonymous']; + $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous; if (!FreshRSS_Auth::hasAccess() && !$allow_anonymous) { Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); return; @@ -111,7 +111,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action displays the RSS feed of FreshRSS. */ public function rssAction() { - $allow_anonymous = FreshRSS_Context::$system_conf->general['allow_anonymous']; + $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous; $token = FreshRSS_Context::$user_conf->token; $token_param = Minz_Request::param('token', ''); $token_is_ok = ($token != '' && $token === $token_param); diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index dd9aa6189..acd3fef69 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -28,7 +28,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { $user = isset($_GET['user']) ? $_GET['user'] : ''; if (ctype_alnum($user)) { try { - $salt = FreshRSS_Context::$system_conf->general['salt']; + $salt = FreshRSS_Context::$system_conf->salt; $conf = new FreshRSS_Configuration($user); $s = $conf->passwordHash; if (strlen($s) >= 60) { diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index be2ae943e..bfc2dfb3b 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -118,7 +118,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { $ok = ($new_user_name != '') && ctype_alnum($new_user_name); if ($ok) { - $default_user = FreshRSS_Context::$system_conf->general['default_user']; + $default_user = FreshRSS_Context::$system_conf->default_user; $ok &= (strcasecmp($new_user_name, $default_user) !== 0); //It is forbidden to alter the default user $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive @@ -188,7 +188,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { $user_data = join_path(DATA_PATH, 'users', $username); if ($ok) { - $default_user = FreshRSS_Context::$system_conf->general['default_user']; + $default_user = FreshRSS_Context::$system_conf->default_user; $ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user } if ($ok) { diff --git a/app/FreshRSS.php b/app/FreshRSS.php index b22bfdb4b..a53174394 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -62,7 +62,7 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); - if (FreshRSS_Context::$system_conf->general['auth_type'] === 'persona') { + if (FreshRSS_Context::$system_conf->auth_type === 'persona') { // TODO move it in a plugin // Needed for login AND logout with Persona. Minz_View::appendScript('https://login.persona.org/include.js'); diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 84b4e3721..05ec61d0e 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -17,7 +17,7 @@ class FreshRSS_Auth { $current_user = Minz_Session::param('currentUser', ''); if ($current_user === '') { $conf = Minz_Configuration::get('system'); - $current_user = $conf->general['default_user']; + $current_user = $conf->default_user; Minz_Session::_param('currentUser', $current_user); } @@ -42,7 +42,7 @@ class FreshRSS_Auth { */ private static function accessControl() { $conf = Minz_Configuration::get('system'); - $auth_type = $conf->general['auth_type']; + $auth_type = $conf->auth_type; switch ($auth_type) { case 'form': $credentials = FreshRSS_FormAuth::getCredentialsFromCookie(); @@ -84,7 +84,7 @@ class FreshRSS_Auth { public static function giveAccess() { $user_conf = Minz_Configuration::get('user'); $system_conf = Minz_Configuration::get('system'); - $auth_type = $system_conf->general['auth_type']; + $auth_type = $system_conf->auth_type; switch ($auth_type) { case 'form': @@ -115,7 +115,7 @@ class FreshRSS_Auth { */ public static function hasAccess($scope = 'general') { $conf = Minz_Configuration::get('system'); - $default_user = $conf->general['default_user']; + $default_user = $conf->default_user; $ok = self::$login_ok; switch ($scope) { case 'general': @@ -136,9 +136,9 @@ class FreshRSS_Auth { Minz_Session::_param('loginOk'); self::$login_ok = false; $conf = Minz_Configuration::get('system'); - Minz_Session::_param('currentUser', $conf->general['default_user']); + Minz_Session::_param('currentUser', $conf->default_user); - switch ($conf->general['auth_type']) { + switch ($conf->auth_type) { case 'form': Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); @@ -160,7 +160,7 @@ class FreshRSS_Auth { */ public static function accessNeedLogin() { $conf = Minz_Configuration::get('system'); - $auth_type = $conf->general['auth_type']; + $auth_type = $conf->auth_type; return $auth_type === 'form' || $auth_type === 'persona'; } } diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 071eafdf6..86cbb783e 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -39,9 +39,9 @@ class FreshRSS_Feed extends Minz_Model { } public function hash() { - $conf = Minz_Configuration::get('system'); if ($this->hash === null) { - $this->hash = hash('crc32b', $conf->general['salt'] . $this->url); + $salt = FreshRSS_Context::$system_conf->salt; + $this->hash = hash('crc32b', $salt . $this->url); } return $this->hash; } diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 2f16b5f63..97e24a1d9 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -1,7 +1,5 @@