diff --git a/README b/README index 0136016a1..30cd56226 100644 --- a/README +++ b/README @@ -49,9 +49,12 @@ SÉCURITÉ ET CONSEILS 3. Le fichier `/public/index.php` défini les chemins d'accès aux répertoires clés de l'application. Si vous les bougez, tout se passe ici. - 4. Vous pouvez ajouter une tâche CRON sur l'url de mise à jour des flux - (clic droit sur le bouton d'actualisation puis "Copier l'adresse du - lien") pour que celle-ci se fasse de manière transparente + 4. Vous pouvez ajouter une tâche CRON sur le script d'actualisation des + flux. Il s'agit d'un script PHP à exécuter avec la commande `php`. + Par exemple, pour exécuter le script toutes les heures : + 0 * * * * php /chemin/vers/freshrss/actualize_script.php >/dev/null 2>&1 + Veuillez cependant vérifier que le fichier PUBLIC_PATH/data/Configuration.array.php + soit accessible en lecture / écriture par l'exécuteur du script CHANGELOG ========= diff --git a/actualize_script.php b/actualize_script.php new file mode 100755 index 000000000..76bbe2e4f --- /dev/null +++ b/actualize_script.php @@ -0,0 +1,27 @@ +init (); +$front_controller->run (); diff --git a/app/App_FrontController.php b/app/App_FrontController.php index 5a66ae1dd..77261280e 100644 --- a/app/App_FrontController.php +++ b/app/App_FrontController.php @@ -11,9 +11,12 @@ class App_FrontController extends FrontController { $this->loadModels (); Session::init (); // lancement de la session doit se faire après chargement des modèles sinon bug (pourquoi ?) + $this->loadParamsView (); $this->loadStylesAndScripts (); $this->loadNotifications (); + + Translate::init (); } private function loadLibs () { @@ -25,11 +28,14 @@ class App_FrontController extends FrontController { private function loadModels () { include (APP_PATH . '/models/Exception/FeedException.php'); + include (APP_PATH . '/models/Exception/EntriesGetterException.php'); include (APP_PATH . '/models/RSSConfiguration.php'); include (APP_PATH . '/models/Days.php'); include (APP_PATH . '/models/Category.php'); include (APP_PATH . '/models/Feed.php'); include (APP_PATH . '/models/Entry.php'); + include (APP_PATH . '/models/EntriesGetter.php'); + include (APP_PATH . '/models/RSSPaginator.php'); } private function loadParamsView () { @@ -38,9 +44,12 @@ class App_FrontController extends FrontController { $entryDAO = new EntryDAO (); View::_param ('nb_not_read', $entryDAO->countNotRead ()); + + Session::_param ('language', $this->conf->language ()); } private function loadStylesAndScripts () { + View::appendStyle (Url::display ('/theme/fallback.css')); View::appendStyle (Url::display ('/theme/global.css')); View::appendStyle (Url::display ('/theme/freshrss.css')); if (login_is_conf ($this->conf)) { diff --git a/app/controllers/apiController.php b/app/controllers/apiController.php index bc08386b5..025908f3e 100755 --- a/app/controllers/apiController.php +++ b/app/controllers/apiController.php @@ -20,11 +20,11 @@ class apiController extends ActionController { $notes = $e->notes (); if ($notes == '') { $feed = $e->feed (true); - $notes = 'Article publié initialement sur ' . $feed->name () . ''; if($author != '') { - $notes .= ' par ' . $author; + $notes = Translate::t ('article_published_on_author', $feed->website (), $feed->name (), $author); + } else { + $notes = Translate::t ('article_published_on', $feed->website (), $feed->name ()); } - $notes .= ', mis en favoris dans FreshRSS'; } $id = $e->id (); diff --git a/app/controllers/configureController.php b/app/controllers/configureController.php index 18a56c066..2f56da177 100755 --- a/app/controllers/configureController.php +++ b/app/controllers/configureController.php @@ -5,14 +5,17 @@ class configureController extends ActionController { if (login_is_conf ($this->view->conf) && !is_logged ()) { Error::error ( 403, - array ('error' => array ('Vous n\'avez pas le droit d\'accéder à cette page')) + array ('error' => array (Translate::t ('access_denied'))) ); } } public function categorizeAction () { + $feedDAO = new FeedDAO (); $catDAO = new CategoryDAO (); $catDAO->checkDefault (); + $defaultCategory = $catDAO->getDefault (); + $defaultId = $defaultCategory->id (); if (Request::isPost ()) { $cats = Request::param ('categories', array ()); @@ -27,7 +30,8 @@ class configureController extends ActionController { 'color' => $cat->color () ); $catDAO->updateCategory ($ids[$key], $values); - } elseif ($ids[$key] != '000000') { + } elseif ($ids[$key] != $defaultId) { + $feedDAO->changeCategory ($ids[$key], $defaultId); $catDAO->deleteCategory ($ids[$key]); } } @@ -48,7 +52,7 @@ class configureController extends ActionController { // notif $notif = array ( 'type' => 'good', - 'content' => 'Les catégories ont été mises à jour' + 'content' => Translate::t ('categories_updated') ); Session::_param ('notification', $notif); @@ -58,7 +62,7 @@ class configureController extends ActionController { $this->view->categories = $catDAO->listCategories (); $this->view->defaultCategory = $catDAO->getDefault (); - View::prependTitle ('Gestion des catégories - '); + View::prependTitle (Translate::t ('categories_management') . ' - '); } public function feedAction () { @@ -80,7 +84,7 @@ class configureController extends ActionController { if (!$this->view->flux) { Error::error ( 404, - array ('error' => array ('La page que vous cherchez n\'existe pas')) + array ('error' => array (Translate::t ('page_not_found'))) ); } else { $catDAO = new CategoryDAO (); @@ -90,11 +94,19 @@ class configureController extends ActionController { $cat = Request::param ('category', 0); $path = Request::param ('path_entries', ''); $priority = Request::param ('priority', 0); + $user = Request::param ('http_user', ''); + $pass = Request::param ('http_pass', ''); + + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } $values = array ( 'category' => $cat, 'pathEntries' => $path, - 'priority' => $priority + 'priority' => $priority, + 'httpAuth' => $httpAuth ); if ($feedDAO->updateFeed ($id, $values)) { @@ -102,12 +114,12 @@ class configureController extends ActionController { $notif = array ( 'type' => 'good', - 'content' => 'Le flux a été mis à jour' + 'content' => Translate::t ('feed_updated') ); } else { $notif = array ( 'type' => 'bad', - 'content' => 'Une erreur est survenue lors de la mise à jour' + 'content' => Translate::t ('error_occurred_update') ); } @@ -115,15 +127,16 @@ class configureController extends ActionController { Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); } - View::prependTitle ('Gestion des flux RSS - ' . $this->view->flux->name () . ' - '); + View::prependTitle (Translate::t ('rss_feed_management') . ' - ' . $this->view->flux->name () . ' - '); } } else { - View::prependTitle ('Gestion des flux RSS - '); + View::prependTitle (Translate::t ('rss_feed_management') . ' - '); } } public function displayAction () { if (Request::isPost ()) { + $language = Request::param ('language', 'en'); $nb = Request::param ('posts_per_page', 10); $view = Request::param ('default_view', 'all'); $display = Request::param ('display_posts', 'no'); @@ -135,6 +148,7 @@ class configureController extends ActionController { $openPage = Request::param ('mark_open_page', 'no'); $urlShaarli = Request::param ('shaarli', ''); + $this->view->conf->_language ($language); $this->view->conf->_postsPerPage (intval ($nb)); $this->view->conf->_defaultView ($view); $this->view->conf->_displayPosts ($display); @@ -149,6 +163,7 @@ class configureController extends ActionController { $this->view->conf->_urlShaarli ($urlShaarli); $values = array ( + 'language' => $this->view->conf->language (), 'posts_per_page' => $this->view->conf->postsPerPage (), 'default_view' => $this->view->conf->defaultView (), 'display_posts' => $this->view->conf->displayPosts (), @@ -164,28 +179,31 @@ class configureController extends ActionController { Session::_param ('conf', $this->view->conf); Session::_param ('mail', $this->view->conf->mailLogin ()); + Session::_param ('language', $this->view->conf->language ()); + Translate::reset (); + // notif $notif = array ( 'type' => 'good', - 'content' => 'La configuration a été mise à jour' + 'content' => Translate::t ('configuration_updated') ); Session::_param ('notification', $notif); Request::forward (array ('c' => 'configure', 'a' => 'display'), true); } - View::prependTitle ('Gestion générale et affichage - '); + View::prependTitle (Translate::t ('general_and_reading_management') . ' - '); } public function importExportAction () { $this->view->req = Request::param ('q'); if ($this->view->req == 'export') { - View::_title ('feeds_opml.xml'); + View::_title ('freshrss_feeds.opml'); $this->view->_useLayout (false); header('Content-Type: text/xml; charset=utf-8'); - header('Content-disposition: attachment; filename=feeds_opml.xml'); + header('Content-disposition: attachment; filename=freshrss_feeds.opml'); $feedDAO = new FeedDAO (); $catDAO = new CategoryDAO (); @@ -199,8 +217,11 @@ class configureController extends ActionController { $this->view->categories = $list; } elseif ($this->view->req == 'import' && Request::isPost ()) { if ($_FILES['file']['error'] == 0) { + // on parse le fichier OPML pour récupérer les catégories et les flux associés list ($categories, $feeds) = opml_import (file_get_contents ($_FILES['file']['tmp_name'])); + // On redirige vers le controller feed qui va se charger d'insérer les flux en BDD + // les flux sont mis au préalable dans des variables de Request Request::_param ('q', 'null'); Request::_param ('categories', $categories); Request::_param ('feeds', $feeds); @@ -210,9 +231,11 @@ class configureController extends ActionController { $feedDAO = new FeedDAO (); $this->view->feeds = $feedDAO->listFeeds (); + + // au niveau de la vue, permet de ne pas voir un flux sélectionné dans la liste $this->view->flux = false; - View::prependTitle ('Importation et exportation OPML - '); + View::prependTitle (Translate::t ('import_export_opml') . ' - '); } public function shortcutAction () { @@ -251,13 +274,13 @@ class configureController extends ActionController { // notif $notif = array ( 'type' => 'good', - 'content' => 'Les raccourcis ont été mis à jour' + 'content' => Translate::t ('shortcuts_updated') ); Session::_param ('notification', $notif); Request::forward (array ('c' => 'configure', 'a' => 'shortcut'), true); } - View::prependTitle ('Gestion des raccourcis - '); + View::prependTitle (Translate::t ('shortcuts_management') . ' - '); } } diff --git a/app/controllers/entryController.php b/app/controllers/entryController.php index e3c4fe165..35f3150ea 100755 --- a/app/controllers/entryController.php +++ b/app/controllers/entryController.php @@ -5,7 +5,7 @@ class entryController extends ActionController { if (login_is_conf ($this->view->conf) && !is_logged ()) { Error::error ( 403, - array ('error' => array ('Vous n\'avez pas le droit d\'accéder à cette page')) + array ('error' => array (Translate::t ('access_denied'))) ); } @@ -63,7 +63,7 @@ class entryController extends ActionController { // notif $notif = array ( 'type' => 'good', - 'content' => 'Les flux ont été marqués comme lu' + 'content' => Translate::t ('feeds_marked_read') ); Session::_param ('notification', $notif); } else { @@ -130,12 +130,12 @@ class entryController extends ActionController { if ($entryDAO->updateEntry ($id, $values)) { $notif = array ( 'type' => 'good', - 'content' => 'Modifications enregistrées' + 'content' => Translate::t ('updated') ); } else { $notif = array ( 'type' => 'bad', - 'content' => 'Une erreur est survenue' + 'content' => Translate::t ('error_occured') ); } Session::_param ('notification', $notif); @@ -157,7 +157,7 @@ class entryController extends ActionController { if ($not_found) { Error::error ( 404, - array ('error' => array ('La page que vous cherchez n\'existe pas')) + array ('error' => array (Translate::t ('page_not_found'))) ); } else { $this->view->entry = $entry; diff --git a/app/controllers/feedController.php b/app/controllers/feedController.php index c67609d57..77f1787d0 100755 --- a/app/controllers/feedController.php +++ b/app/controllers/feedController.php @@ -2,94 +2,114 @@ class feedController extends ActionController { public function firstAction () { + if (login_is_conf ($this->view->conf) && !is_logged ()) { + Error::error ( + 403, + array ('error' => array (Translate::t ('access_denied'))) + ); + } + $catDAO = new CategoryDAO (); $catDAO->checkDefault (); } public function addAction () { - if (login_is_conf ($this->view->conf) && !is_logged ()) { - Error::error ( - 403, - array ('error' => array ('Vous n\'avez pas le droit d\'accéder à cette page')) - ); - } else { - if (Request::isPost ()) { - $url = Request::param ('url_rss'); - $cat = Request::param ('category'); - $params = array (); + if (Request::isPost ()) { + $url = Request::param ('url_rss'); + $cat = Request::param ('category'); + $user = Request::param ('username'); + $pass = Request::param ('password'); + $params = array (); - try { - $feed = new Feed ($url); - $feed->_category ($cat); - $feed->load (); + try { + $feed = new Feed ($url); + $feed->_category ($cat); - $feedDAO = new FeedDAO (); - $values = array ( - 'id' => $feed->id (), - 'url' => $feed->url (), - 'category' => $feed->category (), - 'name' => $feed->name (), - 'website' => $feed->website (), - 'description' => $feed->description (), - 'lastUpdate' => time () + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } + $feed->_httpAuth ($httpAuth); + + $feed->load (); + + $feedDAO = new FeedDAO (); + $values = array ( + 'id' => $feed->id (), + 'url' => $feed->url (), + 'category' => $feed->category (), + 'name' => $feed->name (), + 'website' => $feed->website (), + 'description' => $feed->description (), + 'lastUpdate' => time (), + 'httpAuth' => $feed->httpAuth (), + ); + + if ($feedDAO->searchByUrl ($values['url'])) { + // on est déjà abonné à ce flux + $notif = array ( + 'type' => 'bad', + 'content' => Translate::t ('already_subscribed', $feed->name ()) ); + Session::_param ('notification', $notif); + } elseif (!$feedDAO->addFeed ($values)) { + // problème au niveau de la base de données + $notif = array ( + 'type' => 'bad', + 'content' => Translate::t ('feed_not_added', $feed->name ()) + ); + Session::_param ('notification', $notif); + } else { + $entryDAO = new EntryDAO (); + $entries = $feed->entries (); - if ($feedDAO->searchByUrl ($values['url'])) { - $notif = array ( - 'type' => 'bad', - 'content' => 'Vous êtes déjà abonné à ' . $feed->name () . '' - ); - Session::_param ('notification', $notif); - } elseif ($feedDAO->addFeed ($values)) { - $entryDAO = new EntryDAO (); - $entries = $feed->entries (); + // on calcule la date des articles les plus anciens qu'on accepte + $nb_month_old = $this->view->conf->oldEntries (); + $date_min = time () - (60 * 60 * 24 * 30 * $nb_month_old); - foreach ($entries as $entry) { + // on ajoute les articles en masse sans vérification + foreach ($entries as $entry) { + if ($entry->date (true) >= $date_min) { $values = $entry->toArray (); $entryDAO->addEntry ($values); } - - // notif - $notif = array ( - 'type' => 'good', - 'content' => 'Le flux ' . $feed->name () . ' a bien été ajouté' - ); - Session::_param ('notification', $notif); - $params['id'] = $feed->id (); - } else { - // notif - $notif = array ( - 'type' => 'bad', - 'content' => '' . $feed->name () . ' n\' a pas pu être ajouté' - ); - Session::_param ('notification', $notif); } - } catch (FeedException $e) { - Log::record ($e->getMessage (), Log::ERROR); - $notif = array ( - 'type' => 'bad', - 'content' => 'Un problème interne a été rencontré, le flux n\'a pas pu être ajouté' - ); - Session::_param ('notification', $notif); - } catch (FileNotExistException $e) { - Log::record ($e->getMessage (), Log::ERROR); - // notif - $notif = array ( - 'type' => 'bad', - 'content' => 'Un problème de configuration a empêché l\'ajout du flux. Voir les logs pour plus d\'informations' - ); - Session::_param ('notification', $notif); - } catch (Exception $e) { - // notif - $notif = array ( - 'type' => 'bad', - 'content' => 'L\'url ' . $url . ' est invalide' - ); - Session::_param ('notification', $notif); - } - Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); + // ok, ajout terminé + $notif = array ( + 'type' => 'good', + 'content' => Translate::t ('feed_added', $feed->name ()) + ); + Session::_param ('notification', $notif); + + // permet de rediriger vers la page de conf du flux + $params['id'] = $feed->id (); + } + } catch (BadUrlException $e) { + Log::record ($e->getMessage (), Log::ERROR); + $notif = array ( + 'type' => 'bad', + 'content' => Translate::t ('invalid_url', $url) + ); + Session::_param ('notification', $notif); + } catch (FeedException $e) { + Log::record ($e->getMessage (), Log::ERROR); + $notif = array ( + 'type' => 'bad', + 'content' => Translate::t ('internal_problem_feed') + ); + Session::_param ('notification', $notif); + } catch (FileNotExistException $e) { + // Répertoire de cache n'existe pas + Log::record ($e->getMessage (), Log::ERROR); + $notif = array ( + 'type' => 'bad', + 'content' => Translate::t ('internal_problem_feed') + ); + Session::_param ('notification', $notif); } + + Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); } } @@ -98,6 +118,11 @@ class feedController extends ActionController { $entryDAO = new EntryDAO (); $id = Request::param ('id'); + $force = Request::param ('force', false); + + // on créé la liste des flux à mettre à actualiser + // si on veut mettre un flux à jour spécifiquement, on le met + // dans la liste, mais seul (permet d'automatiser le traitement) $feeds = array (); if ($id) { $feed = $feedDAO->searchById ($id); @@ -108,7 +133,7 @@ class feedController extends ActionController { $feeds = $feedDAO->listFeedsOrderUpdate (); } - // pour ne pas ajouter des entrées trop anciennes + // on calcule la date des articles les plus anciens qu'on accepte $nb_month_old = $this->view->conf->oldEntries (); $date_min = time () - (60 * 60 * 24 * 30 * $nb_month_old); @@ -118,6 +143,11 @@ class feedController extends ActionController { $feed->load (); $entries = $feed->entries (); + // ajout des articles en masse sans se soucier des erreurs + // On ne vérifie pas que l'article n'est pas déjà en BDD + // car demanderait plus de ressources + // La BDD refusera l'ajout de son côté car l'id doit être + // unique foreach ($entries as $entry) { if ($entry->date (true) >= $date_min) { $values = $entry->toArray (); @@ -125,37 +155,45 @@ class feedController extends ActionController { } } + // on indique que le flux vient d'être mis à jour en BDD $feedDAO->updateLastUpdate ($feed->id ()); } catch (FeedException $e) { Log::record ($e->getMessage (), Log::ERROR); + // TODO si on a une erreur ici, il faut mettre + // le flux à jour en BDD (error = 1) (issue #70) } + // On arrête à 10 flux pour ne pas surcharger le serveur + // sauf si le paramètre $force est à vrai $i++; - if ($i >= 10) { + if ($i >= 10 && !$force) { break; } } $entryDAO->cleanOldEntries ($nb_month_old); - // notif $url = array (); if ($i == 1) { + // on a mis un seul flux à jour + // reset permet de récupérer ce flux $feed = reset ($feeds); $notif = array ( 'type' => 'good', - 'content' => '' . $feed->name () . ' a été mis à jour' + 'content' => Translate::t ('feed_actualized', $feed->name ()) ); $url['params'] = array ('get' => 'f_' . $feed->id ()); - } elseif ($i > 0) { + } elseif ($i > 1) { + // plusieurs flux on été mis à jour $notif = array ( 'type' => 'good', - 'content' => $i . ' flux ont été mis à jour' + 'content' => Translate::t ('n_feeds_actualized', $i) ); } else { + // aucun flux n'a été mis à jour, oups $notif = array ( 'type' => 'bad', - 'content' => 'Aucun flux n\'a pu être mis à jour' + 'content' => Translate::t ('no_feed_actualized') ); } @@ -163,123 +201,123 @@ class feedController extends ActionController { Session::_param ('notification', $notif); Request::forward ($url, true); } else { + // Une requête Ajax met un seul flux à jour. + // Comme en principe plusieurs requêtes ont lieu, + // on indique que "plusieurs flux ont été mis à jour". + // Cela permet d'avoir une notification plus proche du + // ressenti utilisateur $notif = array ( 'type' => 'good', - 'content' => 'Les flux ont été mis à jour' + 'content' => Translate::t ('feeds_actualized') ); Session::_param ('notification', $notif); + // et on désactive le layout car ne sert à rien $this->view->_useLayout (false); } } public function massiveImportAction () { - if (login_is_conf ($this->view->conf) && !is_logged ()) { - Error::error ( - 403, - array ('error' => array ('Vous n\'avez pas le droit d\'accéder à cette page')) - ); - } else { - $entryDAO = new EntryDAO (); - $feedDAO = new FeedDAO (); + $entryDAO = new EntryDAO (); + $feedDAO = new FeedDAO (); - $categories = Request::param ('categories', array ()); - $feeds = Request::param ('feeds', array ()); + $categories = Request::param ('categories', array ()); + $feeds = Request::param ('feeds', array ()); - $this->addCategories ($categories); + // on ajoute les catégories en masse dans une fonction à part + $this->addCategories ($categories); - $nb_month_old = $this->view->conf->oldEntries (); - $date_min = time () - (60 * 60 * 24 * 30 * $nb_month_old); + // on calcule la date des articles les plus anciens qu'on accepte + $nb_month_old = $this->view->conf->oldEntries (); + $date_min = time () - (60 * 60 * 24 * 30 * $nb_month_old); - $error = false; - $i = 0; - foreach ($feeds as $feed) { - try { - $feed->load (); + // la variable $error permet de savoir si une erreur est survenue + // Le but est de ne pas arrêter l'import même en cas d'erreur + // L'utilisateur sera mis au courant s'il y a eu des erreurs, mais + // ne connaîtra pas les détails. Ceux-ci seront toutefois logguées + $error = false; + $i = 0; + foreach ($feeds as $feed) { + try { + $feed->load (); - // Enregistrement du flux - $values = array ( - 'id' => $feed->id (), - 'url' => $feed->url (), - 'category' => $feed->category (), - 'name' => $feed->name (), - 'website' => $feed->website (), - 'description' => $feed->description (), - 'lastUpdate' => 0 - ); + $values = array ( + 'id' => $feed->id (), + 'url' => $feed->url (), + 'category' => $feed->category (), + 'name' => $feed->name (), + 'website' => $feed->website (), + 'description' => $feed->description (), + 'lastUpdate' => 0 + ); - if (!$feedDAO->searchByUrl ($values['url'])) { - if (!$feedDAO->addFeed ($values)) { - $error = true; - } + // ajout du flux que s'il n'est pas déjà en BDD + if (!$feedDAO->searchByUrl ($values['url'])) { + if (!$feedDAO->addFeed ($values)) { + $error = true; } - } catch (FeedException $e) { - $error = true; - Log::record ($e->getMessage (), Log::ERROR); } + } catch (FeedException $e) { + $error = true; + Log::record ($e->getMessage (), Log::ERROR); } - - if ($error) { - $res = 'Les flux ont été importés mais des erreurs sont survenus'; - } else { - $res = 'Les flux ont été importés'; - } - $notif = array ( - 'type' => 'good', - 'content' => $res - ); - Session::_param ('notification', $notif); - - Request::forward (array ( - 'c' => 'configure', - 'a' => 'importExport' - ), true); } + + if ($error) { + $res = Translate::t ('feeds_imported_with_errors'); + } else { + $res = Translate::t ('feeds_imported'); + } + + $notif = array ( + 'type' => 'good', + 'content' => $res + ); + Session::_param ('notification', $notif); + + // et on redirige vers la page import/export + Request::forward (array ( + 'c' => 'configure', + 'a' => 'importExport' + ), true); } public function deleteAction () { - if (login_is_conf ($this->view->conf) && !is_logged ()) { - Error::error ( - 403, - array ('error' => array ('Vous n\'avez pas le droit d\'accéder à cette page')) - ); + $type = Request::param ('type', 'feed'); + $id = Request::param ('id'); + + $feedDAO = new FeedDAO (); + if ($type == 'category') { + if ($feedDAO->deleteFeedByCategory ($id)) { + $notif = array ( + 'type' => 'good', + 'content' => Translate::t ('category_emptied') + ); + } else { + $notif = array ( + 'type' => 'bad', + 'content' => Translate::t ('error_occured') + ); + } } else { - $type = Request::param ('type', 'feed'); - $id = Request::param ('id'); - - $feedDAO = new FeedDAO (); - if ($type == 'category') { - if ($feedDAO->deleteFeedByCategory ($id)) { - $notif = array ( - 'type' => 'good', - 'content' => 'La catégorie a été vidée' - ); - } else { - $notif = array ( - 'type' => 'bad', - 'content' => 'Un problème est survenu' - ); - } + if ($feedDAO->deleteFeed ($id)) { + $notif = array ( + 'type' => 'good', + 'content' => Translate::t ('feed_deleted') + ); } else { - if ($feedDAO->deleteFeed ($id)) { - $notif = array ( - 'type' => 'good', - 'content' => 'Le flux a été supprimé' - ); - } else { - $notif = array ( - 'type' => 'bad', - 'content' => 'Un problème est survenu' - ); - } + $notif = array ( + 'type' => 'bad', + 'content' => Translate::t ('error_occured') + ); } + } - Session::_param ('notification', $notif); + Session::_param ('notification', $notif); - if ($type == 'category') { - Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); - } else { - Request::forward (array ('c' => 'configure', 'a' => 'feed'), true); - } + if ($type == 'category') { + Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); + } else { + Request::forward (array ('c' => 'configure', 'a' => 'feed'), true); } } diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index 8fa911631..f4f0b98b3 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -6,117 +6,136 @@ class indexController extends ActionController { private $mode = 'all'; public function indexAction () { - View::appendScript (Url::display ('/scripts/shortcut.js')); - View::appendScript (Url::display (array ('c' => 'javascript', 'a' => 'main'))); - View::appendScript (Url::display (array ('c' => 'javascript', 'a' => 'actualize'))); + if (Request::param ('output') == 'rss') { + $this->view->_useLayout (false); + } else { + View::appendScript (Url::display ('/scripts/shortcut.js')); + View::appendScript (Url::display (array ('c' => 'javascript', 'a' => 'main'))); + View::appendScript (Url::display (array ('c' => 'javascript', 'a' => 'actualize'))); + } $entryDAO = new EntryDAO (); $feedDAO = new FeedDAO (); $catDAO = new CategoryDAO (); - $error = false; + $this->view->cat_aside = $catDAO->listCategories (); + $this->view->nb_favorites = $entryDAO->countFavorites (); + $this->view->nb_total = $entryDAO->count (); - // pour optimiser - $page = Request::param ('page', 1); - $entryDAO->_nbItemsPerPage ($this->view->conf->postsPerPage ()); - $entryDAO->_currentPage ($page); + $this->view->get_c = ''; + $this->view->get_f = ''; - // récupération de la catégorie/flux à filtrer - $this->initFilter (); - // Compte le nombre d'articles non lus en prenant en compte le filtre - $this->countNotRead (); - // mode de vue (tout ou seulement non lus) - $this->initCurrentMode (); - // ordre de listage des flux - $order = Session::param ('order', $this->view->conf->sortOrder ()); - // recherche sur les titres (pour le moment) - $search = Request::param ('search'); - - // Récupère les flux par catégorie, favoris ou tous - if ($this->get['type'] == 'all') { - $entries = $entryDAO->listEntries ($this->mode, $search, $order); - View::prependTitle ('Vos flux RSS - '); - } elseif ($this->get['type'] == 'favoris') { - $entries = $entryDAO->listFavorites ($this->mode, $search, $order); - View::prependTitle ('Vos favoris - '); - } elseif ($this->get['type'] == 'public') { - $entries = $entryDAO->listPublic ($this->mode, $search, $order); - View::prependTitle ('Public - '); - } elseif ($this->get != false) { - if ($this->get['type'] == 'c') { - $cat = $catDAO->searchById ($this->get['filter']); - - if ($cat) { - $entries = $entryDAO->listByCategory ($this->get['filter'], $this->mode, $search, $order); - View::prependTitle ($cat->name () . ' - '); - } else { - $error = true; - } - } elseif ($this->get['type'] == 'f') { - $feed = $feedDAO->searchById ($this->get['filter']); - - if ($feed) { - $entries = $entryDAO->listByFeed ($this->get['filter'], $this->mode, $search, $order); - $this->view->get_c = $feed->category (); - View::prependTitle ($feed->name () . ' - '); - } else { - $error = true; - } - } else { - $error = true; - } - } else { - $error = true; - } - - if ($error) { - Error::error ( - 404, - array ('error' => array ('La page que vous cherchez n\'existe pas')) - ); - } else { - $this->view->mode = $this->mode; - $this->view->order = $order; + $type = $this->getType (); + $error = $this->checkAndProcessType ($type); + if (!$error) { + // On récupère les différents éléments de filtrage + $this->view->state = $state = Request::param ('state', $this->view->conf->defaultView ()); + $filter = Request::param ('search', ''); + $this->view->order = $order = Request::param ('order', $this->view->conf->sortOrder ()); + $nb = Request::param ('nb', $this->view->conf->postsPerPage ()); + $first = Request::param ('next', ''); try { - $this->view->entryPaginator = $entryDAO->getPaginator ($entries); - } catch (CurrentPagePaginationException $e) { } + // EntriesGetter permet de déporter la complexité du filtrage + $getter = new EntriesGetter ($type, $state, $filter, $order, $nb, $first); + $getter->execute (); + $entries = $getter->getPaginator (); - $this->view->cat_aside = $catDAO->listCategories (); - $this->view->nb_favorites = $entryDAO->countFavorites (); - $this->view->nb_total = $entryDAO->count (); + // Si on a récupéré aucun article "non lus" + // on essaye de récupérer tous les articles + if ($state == 'not_read' && $entries->isEmpty ()) { + $this->view->state = 'all'; + $getter->_state ('all'); + $getter->execute (); + $entries = $getter->getPaginator (); + } - if (Request::param ('output', '') == 'rss') { - $this->view->_useLayout (false); + $this->view->entryPaginator = $entries; + } catch(EntriesGetterException $e) { + Log::record ($e->getMessage (), Log::NOTICE); + Error::error ( + 404, + array ('error' => array (Translate::t ('page_not_found'))) + ); } + } else { + Error::error ( + 404, + array ('error' => array (Translate::t ('page_not_found'))) + ); + } + } + + /* + * Détermine le type d'article à récupérer : + * "tous", "favoris", "public", "catégorie" ou "flux" + */ + private function getType () { + $get = Request::param ('get', 'all'); + $typeGet = $get[0]; + $id = substr ($get, 2); + + $type = null; + if ($get == 'all' || $get == 'favoris' || $get == 'public') { + $type = array ( + 'type' => $get, + 'id' => $get + ); + } elseif ($typeGet == 'f' || $typeGet == 'c') { + $type = array ( + 'type' => $typeGet, + 'id' => $id + ); + } + + return $type; + } + /* + * Vérifie que la catégorie / flux sélectionné existe + * + Initialise correctement les variables de vue get_c et get_f + * + Initialise le titre + */ + private function checkAndProcessType ($type) { + if ($type['type'] == 'all') { + View::prependTitle (Translate::t ('your_rss_feeds') . ' - '); + $this->view->get_c = $type['type']; + return false; + } elseif ($type['type'] == 'favoris') { + View::prependTitle (Translate::t ('your_favorites') . ' - '); + $this->view->get_c = $type['type']; + return false; + } elseif ($type['type'] == 'public') { + View::prependTitle (Translate::t ('public') . ' - '); + $this->view->get_c = $type['type']; + return false; + } elseif ($type['type'] == 'c') { + $catDAO = new CategoryDAO (); + $cat = $catDAO->searchById ($type['id']); + if ($cat) { + View::prependTitle ($cat->name () . ' - '); + $this->view->get_c = $type['id']; + return false; + } else { + return true; + } + } elseif ($type['type'] == 'f') { + $feedDAO = new FeedDAO (); + $feed = $feedDAO->searchById ($type['id']); + if ($feed) { + View::prependTitle ($feed->name () . ' - '); + $this->view->get_f = $type['id']; + $this->view->get_c = $feed->category (); + return false; + } else { + return true; + } + } else { + return true; } } public function aboutAction () { - View::prependTitle ('À propos - '); - } - - public function changeModeAction () { - $mode = Request::param ('mode'); - - if ($mode == 'not_read') { - Session::_param ('mode', 'not_read'); - } else { - Session::_param ('mode', 'all'); - } - - Request::forward (array (), true); - } - public function changeOrderAction () { - $order = Request::param ('order'); - - if ($order == 'low_to_high') { - Session::_param ('order', 'low_to_high'); - } else { - Session::_param ('order', 'high_to_low'); - } - - Request::forward (array (), true); + View::prependTitle (Translate::t ('about') . ' - '); } public function loginAction () { @@ -143,7 +162,7 @@ class indexController extends ActionController { } else { $res = array (); $res['status'] = 'failure'; - $res['reason'] = 'L\'identifiant est invalide'; + $res['reason'] = Translate::t ('invalid_login'); } $this->view->res = json_encode ($res); @@ -153,82 +172,4 @@ class indexController extends ActionController { $this->view->_useLayout (false); Session::_param ('mail'); } - - private function initFilter () { - $get = Request::param ('get'); - $this->view->get_c = false; - $this->view->get_f = false; - - $typeGet = $get[0]; - $filter = substr ($get, 2); - - if ($get == 'favoris') { - $this->view->get_c = $get; - - $this->get = array ( - 'type' => $get, - 'filter' => $get - ); - } elseif ($get == 'public') { - $this->view->get_c = $get; - - $this->get = array ( - 'type' => $get, - 'filter' => $get - ); - } elseif ($get == false) { - $this->get = array ( - 'type' => 'all', - 'filter' => 'all' - ); - } else { - if ($typeGet == 'f') { - $this->view->get_f = $filter; - - $this->get = array ( - 'type' => $typeGet, - 'filter' => $filter - ); - } elseif ($typeGet == 'c') { - $this->view->get_c = $filter; - - $this->get = array ( - 'type' => $typeGet, - 'filter' => $filter - ); - } else { - $this->get = false; - } - } - } - - private function countNotRead () { - $entryDAO = new EntryDAO (); - - if ($this->get != false) { - if ($this->get['type'] == 'all') { - $this->nb_not_read = $this->view->nb_not_read; - } elseif ($this->get['type'] == 'favoris') { - $this->nb_not_read = $entryDAO->countNotReadFavorites (); - } elseif ($this->get['type'] == 'c') { - $this->nb_not_read = $entryDAO->countNotReadByCat ($this->get['filter']); - } elseif ($this->get['type'] == 'f') { - $this->nb_not_read = $entryDAO->countNotReadByFeed ($this->get['filter']); - } - } - } - - private function initCurrentMode () { - $default_view = $this->view->conf->defaultView (); - $mode = Session::param ('mode'); - if ($mode == false) { - if ($default_view == 'not_read' && $this->nb_not_read < 1) { - $mode = 'all'; - } else { - $mode = $default_view; - } - } - - $this->mode = $mode; - } } diff --git a/app/i18n/en.php b/app/i18n/en.php new file mode 100644 index 000000000..a78604c3e --- /dev/null +++ b/app/i18n/en.php @@ -0,0 +1,270 @@ + 'Login', + 'logout' => 'Logout', + 'search' => 'Search words or #tags', + + 'configuration' => 'Configuration', + 'general_and_reading' => 'General and reading', + 'categories' => 'Categories', + 'category' => 'Category', + 'shortcuts' => 'Shortcuts', + 'about' => 'About', + + 'your_rss_feeds' => 'Your RSS feeds', + 'add_rss_feed' => 'Add a RSS feed', + 'no_rss_feed' => 'No RSS feed', + 'import_export_opml' => 'Import / export (OPML)', + + 'subscription_management' => 'Subscriptions management', + 'all_feeds' => 'All (%d)', + 'favorite_feeds' => 'Favorites (%d)', + 'not_read' => '%d unread', + 'not_reads' => '%d unread', + + 'filter' => 'Filter', + 'see_website' => 'See website', + 'administration' => 'Manage', + 'actualize' => 'Actualize', + + 'mark_read' => 'Mark as read', + 'mark_favorite' => 'Mark as favorite', + 'mark_all_read' => 'Mark all as read', + 'mark_feed_read' => 'Mark feed as read', + 'mark_cat_read' => 'Mark category as read', + 'before_one_day' => 'Before one day', + 'before_one_week' => 'Before one week', + 'display' => 'Display', + 'show_all_articles' => 'Show all articles', + 'show_not_reads' => 'Show only unread', + 'older_first' => 'Oldest first', + 'newer_first' => 'Newer first', + + // CONTROLLERS + 'article_published_on' => 'This article originally appeared on %s', + 'article_published_on_author' => 'This article originally appeared on %s by %s', + + 'access_denied' => 'You don\'t have permission to access this page', + 'page_not_found' => 'You are looking for a page which doesn\'t exist', + 'error_occurred' => 'An error occured', + 'error_occurred_update' => 'An error occured during update', + + 'default_category' => 'Uncategorized', + 'categories_updated' => 'Categories have been updated', + 'categories_management' => 'Categories management', + 'feed_updated' => 'Feed has been updated', + 'rss_feed_management' => 'RSS feeds management', + 'configuration_updated' => 'Configuration has been updated', + 'general_and_reading_management'=> 'General and reading management', + 'shortcuts_updated' => 'Shortcuts have been updated', + 'shortcuts_management' => 'Shortcuts management', + 'feeds_marked_read' => 'Feeds have been marked as read', + 'updated' => 'Modifications have been updated', + + 'already_subscribed' => 'You have already subscribed to %s', + 'feed_added' => 'RSS feed %s has been added', + 'feed_not_added' => '%s could not be added', + 'internal_problem_feed' => 'An internal problem occured, RSS feed could not be added', + 'invalid_url' => 'URL %s is invalid', + 'feed_actualized' => '%s has been updated', + 'n_feeds_actualized' => '%d feeds have been updated', + 'feeds_actualized' => 'RSS feeds have been updated', + 'no_feed_actualized' => 'No RSS feed has been updated', + 'feeds_imported_with_errors' => 'Feeds have been imported but errors occured', + 'feeds_imported' => 'Feeds have been imported', + 'category_emptied' => 'Category has been emptied', + 'feed_deleted' => 'Feed has been deleted', + + 'your_rss_feeds' => 'Your RSS feeds', + 'your_favorites' => 'Your favorites', + 'public' => 'Public', + 'invalid_login' => 'Login is invalid', + + // VIEWS + 'save' => 'Save', + 'delete' => 'Delete', + 'cancel' => 'Cancel', + + 'back_to_rss_feeds' => '← Go back to your RSS feeds', + 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', + 'category_number' => 'Category n°%d', + 'ask_empty' => 'Clear ?', + 'number_feeds' => '%d feeds', + 'can_not_be_deleted' => 'Can not be deleted', + 'add_category' => 'Add a category', + 'new_category' => 'New category', + + 'javascript_for_shortcuts' => 'Javascript must be enabled in order to use shortcuts', + 'javascript_should_be_activated'=> 'Javascript must be enabled', + 'shift_for_all_read' => '+ shift to mark all articles as read', + 'see_on_website' => 'See article on its original website', + 'next_article' => 'Skip to the next article', + 'shift_for_last' => '+ shift to skip to the last article of page', + 'previous_article' => 'Skip to the previous article', + 'shift_for_first' => '+ shift to skip to the first article of page', + 'next_page' => 'Skip to the next page', + 'previous_page' => 'Skip to the previous page', + + 'file_to_import' => 'File to import', + 'import' => 'Import', + 'export' => 'Export', + 'or' => 'or', + + 'informations' => 'Informations', + 'website_url' => 'Website URL', + 'feed_url' => 'Feed URL', + 'number_articles' => 'Number of articles', + 'categorize' => 'Store in a category', + 'advanced' => 'Advanced', + 'show_in_all_flux' => 'Show in principal stream', + 'yes' => 'Yes', + 'no' => 'No', + 'css_path_on_website' => 'Articles CSS path on original website', + 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', + 'http_authentication' => 'HTTP Authentication', + 'http_username' => 'HTTP username', + 'http_password' => 'HTTP password', + 'blank_to_disable' => 'Leave blank to disable', + 'not_yet_implemented' => 'Not yet implemented', + 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', + 'no_selected_feed' => 'No feed selected.', + 'think_to_add' => 'Think to add RSS feeds!', + + 'general_configuration' => 'General configuration', + 'language' => 'Language', + 'delete_articles_every' => 'Remove articles every', + 'month' => 'months', + 'persona_connection_email' => 'Login mail address (use Persona)', + 'reading_configuration' => 'Reading configuration', + 'articles_per_page' => 'Number of articles per page', + 'default_view' => 'Default view', + 'sort_order' => 'Sort order', + 'display_articles_unfolded' => 'Show articles unfolded by default', + 'auto_read_when' => 'Mark automatically as read when', + 'article_selected' => 'Article is selected', + 'article_open_on_website' => 'Article is opened on its original website', + 'page_loaded' => 'Page is loaded', + 'your_shaarli' => 'Your Shaarli', + 'sharing' => 'Sharing', + 'share' => 'Share', + 'by_email' => 'By mail', + 'on_shaarli' => 'On your Shaarli', + + 'note' => 'Note', + 'add_note' => 'Add a note', + 'update_note' => 'Update your note', + 'ask_public_article' => 'Public article?', + 'article' => 'Article', + 'title' => 'Title', + 'author' => 'Author', + 'publication_date' => 'Date of publication', + + 'load_more' => 'Load more articles', + 'nothing_to_load' => 'There is no more articles', + + 'rss_feeds_of' => 'RSS feed of %s', + + 'refresh' => 'Refresh', + + 'today' => 'Today', + 'yesterday' => 'Yesterday', + 'before_yesterday' => 'Before yesterday', + 'by_author' => 'By %s', + 'related_tags' => 'Related tags', + 'no_feed_to_display' => 'No feed to show.', + + 'about_freshrss' => 'About FreshRSS', + 'project_website' => 'Project website', + 'lead_developer' => 'Lead developer', + 'website' => 'Website', + 'bugs_reports' => 'Bugs reports', + 'github_or_email' => 'on Github or by mail', + 'license' => 'License', + 'agpl3' => 'AGPL 3', + 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like RSSLounge, TinyTinyRSS or Leed. It is light and easy to take in hand while being powerful and configurable tool. Objective is to provide a serious alternative to Google Reader.', + '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 used has been created by Steve Matteson. Favicons are collected with getFavicon API. FreshRSS is based on Minz, a PHP framework.', + + // DATE + 'january' => 'january', + 'february' => 'february', + 'march' => 'march', + 'april' => 'april', + 'may' => 'may', + 'june' => 'june', + 'july' => 'july', + 'august' => 'august', + 'september' => 'september', + 'october' => 'october', + 'november' => 'november', + 'december' => 'december', + // special format for date() function + 'Jan' => '\J\a\n\u\a\r\y', + 'Feb' => '\F\e\b\r\u\a\r\y', + 'Mar' => '\M\a\r\c\h', + 'Apr' => '\A\p\r\i\l', + 'May' => '\M\a\y', + 'Jun' => '\J\u\n\e', + 'Jul' => '\J\u\l\y', + 'Aug' => '\A\u\g\u\s\t', + 'Sep' => '\S\e\p\t\e\m\b\e\r', + 'Oct' => '\O\c\t\o\b\e\r', + 'Nov' => '\N\o\v\e\m\b\e\r', + 'Dec' => '\D\e\c\e\m\b\e\r', + // format for date() function, %s allows to indicate month in letter + 'format_date' => '%s dS Y', + 'format_date_hour' => '%s dS Y \a\t H\.i', + + // INSTALLATION + 'freshrss_installation' => 'Installation - FreshRSS', + 'freshrss' => 'FreshRSS', + 'installation_step' => 'Installation - step %d', + 'steps' => 'Steps', + 'checks' => 'Checks', + 'bdd_configuration' => 'Database configuration', + 'this_is_the_end' => 'This is the end', + + 'ok' => 'Ok!', + 'congratulations' => 'Congratulations!', + 'attention' => 'Attention!', + 'damn' => 'Damn!', + 'oops' => 'Oops!', + 'next_step' => 'Go to the next step', + + 'language_defined' => 'Language has been defined.', + 'choose_language' => 'Choose a language for FreshRSS', + + 'javascript_is_better' => 'FreshRSS is more pleasant with Javascript enabled', + 'php_is_ok' => 'Your PHP version is %s and it\'s compatible with FreshRSS', + 'php_is_nok' => 'Your PHP version is %s. You must have at least version %s', + 'minz_is_ok' => 'You have Minz framework', + 'minz_is_nok' => 'You haven\'t Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', + 'curl_is_ok' => 'You have version %s of cURL', + 'curl_is_nok' => 'You haven\'t cURL', + 'pdomysql_is_ok' => 'You have PDO and its driver for MySQL', + 'pdomysql_is_nok' => 'You haven\'t PDO or its driver for MySQL', + 'cache_is_ok' => 'Permissions on cache directory are good', + 'log_is_ok' => 'Permissions on logs directory are good', + 'conf_is_ok' => 'Permissions on configuration directory are good', + 'data_is_ok' => 'Permissions on data directory are good', + 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', + 'fix_errors_before' => 'Fix errors before skip to the next step.', + + 'general_conf_is_ok' => 'General configuration has been saved.', + 'random_string' => 'Random string', + 'change_value' => 'You should change this value by any other', + 'base_url' => 'Base URL', + 'do_not_change_if_doubt' => 'Don\'t change if you doubt about it', + + 'bdd_conf_is_ok' => 'Database configuration has been saved.', + 'host' => 'Host', + 'username' => 'Username', + 'password' => 'Password', + 'bdd' => 'Database', + + 'installation_is_ok' => 'Installation process is finished. You must delete install.php file to access FreshRSS... or simply click on following button :)', + 'finish_installation' => 'Finish installation', + 'install_not_deleted' => 'Something was going wrong, you muste delete %s file manually.', +); diff --git a/app/i18n/fr.php b/app/i18n/fr.php new file mode 100644 index 000000000..33f094c21 --- /dev/null +++ b/app/i18n/fr.php @@ -0,0 +1,270 @@ + 'Connexion', + 'logout' => 'Déconnexion', + 'search' => 'Rechercher un terme ou des #tags', + + 'configuration' => 'Configuration', + 'general_and_reading' => 'Général et lecture', + 'categories' => 'Catégories', + 'category' => 'Catégorie', + 'shortcuts' => 'Raccourcis', + 'about' => 'À propos', + + 'your_rss_feeds' => 'Vos flux RSS', + 'add_rss_feed' => 'Ajouter un flux RSS', + 'no_rss_feed' => 'Aucun flux RSS', + 'import_export_opml' => 'Importer / exporter (OPML)', + + 'subscription_management' => 'Gestion des abonnements', + 'all_feeds' => 'Tous (%d)', + 'favorite_feeds' => 'Favoris (%d)', + 'not_read' => '%d non lu', + 'not_reads' => '%d non lus', + + 'filter' => 'Filtrer', + 'see_website' => 'Voir le site', + 'administration' => 'Gestion', + 'actualize' => 'Actualiser', + + 'mark_read' => 'Marquer comme lu', + 'mark_favorite' => 'Mettre en favori', + 'mark_all_read' => 'Tout marquer comme lu', + 'mark_feed_read' => 'Marquer le flux comme lu', + 'mark_cat_read' => 'Marquer la catégorie comme lue', + 'before_one_day' => 'Antérieurs à 1 jour', + 'before_one_week' => 'Antérieurs à 1 semaine', + 'display' => 'Affichage', + 'show_all_articles' => 'Afficher tous les articles', + 'show_not_reads' => 'Afficher les non lus', + 'older_first' => 'Plus anciens en premier', + 'newer_first' => 'Plus récents en premier', + + // CONTROLLERS + 'article_published_on' => 'Article publié initialement sur %s', + 'article_published_on_author' => 'Article publié initialement sur %s par %s', + + 'access_denied' => 'Vous n\'avez pas le droit d\'accéder à cette page', + 'page_not_found' => 'La page que vous cherchez n\'existe pas', + 'error_occurred' => 'Une erreur est survenue', + 'error_occurred_update' => 'Une erreur est survenue lors de la mise à jour', + + 'default_category' => 'Sans catégorie', + 'categories_updated' => 'Les catégories ont été mises à jour', + 'categories_management' => 'Gestion des catégories', + 'feed_updated' => 'Le flux a été mis à jour', + 'rss_feed_management' => 'Gestion des flux RSS', + 'configuration_updated' => 'La configuration a été mise à jour', + 'general_and_reading_management'=> 'Gestion générale et affichage', + 'shortcuts_updated' => 'Les raccourcis ont été mis à jour', + 'shortcuts_management' => 'Gestion des raccourcis', + 'feeds_marked_read' => 'Les flux ont été marqués comme lu', + 'updated' => 'Modifications enregistrées', + + 'already_subscribed' => 'Vous êtes déjà abonné à %s', + 'feed_added' => 'Le flux %s a bien été ajouté', + 'feed_not_added' => '%s n\' a pas pu être ajouté', + 'internal_problem_feed' => 'Un problème interne a été rencontré, le flux n\'a pas pu être ajouté', + 'invalid_url' => 'L\'url %s est invalide', + 'feed_actualized' => '%s a été mis à jour', + 'n_feeds_actualized' => '%d flux ont été mis à jour', + 'feeds_actualized' => 'Les flux ont été mis à jour', + 'no_feed_actualized' => 'Aucun flux n\'a pu être mis à jour', + 'feeds_imported_with_errors' => 'Les flux ont été importés mais des erreurs sont survenues', + 'feeds_imported' => 'Les flux ont été importés', + 'category_emptied' => 'La catégorie a été vidée', + 'feed_deleted' => 'Le flux a été supprimé', + + 'your_rss_feeds' => 'Vos flux RSS', + 'your_favorites' => 'Vos favoris', + 'public' => 'Public', + 'invalid_login' => 'L\'identifiant est invalide', + + // VIEWS + 'save' => 'Enregistrer', + 'delete' => 'Supprimer', + 'cancel' => 'Annuler', + + 'back_to_rss_feeds' => '← Retour à vos flux RSS', + 'feeds_moved_category_deleted' => 'Lors de la suppression d\'une catégorie, ses flux seront automatiquement classés dans %s.', + 'category_number' => 'Catégorie n°%d', + 'ask_empty' => 'Vider ?', + 'number_feeds' => '%d flux', + 'can_not_be_deleted' => 'Ne peut pas être supprimée', + 'add_category' => 'Ajouter une catégorie', + 'new_category' => 'Nouvelle catégorie', + + 'javascript_for_shortcuts' => 'Le javascript doit être activé pour pouvoir profiter des raccourcis', + 'javascript_should_be_activated'=> 'Le javascript doit être activé', + 'shift_for_all_read' => '+ shift pour marquer tous les articles comme lus', + 'see_on_website' => 'Voir l\'article sur le site d\'origine', + 'next_article' => 'Passer à l\'article suivant', + 'shift_for_last' => '+ shift pour passer au dernier article de la page', + 'previous_article' => 'Passer à l\'article précédent', + 'shift_for_first' => '+ shift pour passer au premier article de la page', + 'next_page' => 'Passer à la page suivante', + 'previous_page' => 'Passer à la page précédente', + + 'file_to_import' => 'Fichier à importer', + 'import' => 'Importer', + 'export' => 'Exporter', + 'or' => 'ou', + + 'informations' => 'Informations', + 'website_url' => 'URL du site', + 'feed_url' => 'URL du flux', + 'number_articles' => 'Nombre d\'articles', + 'categorize' => 'Ranger dans une catégorie', + 'advanced' => 'Avancé', + 'show_in_all_flux' => 'Afficher dans le flux principal', + 'yes' => 'Oui', + 'no' => 'Non', + 'css_path_on_website' => 'Chemin CSS des articles sur le site d\'origine', + 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', + 'http_authentication' => 'Authentification HTTP', + 'http_username' => 'Identifiant HTTP', + 'http_password' => 'Mot de passe HTTP', + 'blank_to_disable' => 'Laissez vide pour désactiver', + 'not_yet_implemented' => 'Pas encore implémenté', + 'access_protected_feeds' => 'La connexion permet d\'accéder aux flux protégés par une authentification HTTP', + 'no_selected_feed' => 'Aucun flux sélectionné.', + 'think_to_add' => 'Pensez à en ajouter !', + + 'general_configuration' => 'Configuration générale', + 'language' => 'Langue', + 'delete_articles_every' => 'Supprimer les articles tous les', + 'month' => 'mois', + 'persona_connection_email' => 'Adresse mail de connexion (utilise Persona)', + 'reading_configuration' => 'Configuration de lecture', + 'articles_per_page' => 'Nombre d\'articles par page', + 'default_view' => 'Vue par défaut', + 'sort_order' => 'Ordre de tri', + 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', + 'auto_read_when' => 'Marquer automatiquement comme lu lorsque', + 'article_selected' => 'L\'article est sélectionné', + 'article_open_on_website' => 'L\'article est ouvert sur le site d\'origine', + 'page_loaded' => 'La page est chargée', + 'your_shaarli' => 'Votre Shaarli', + 'sharing' => 'Partage', + 'share' => 'Partager', + 'by_email' => 'Par mail', + 'on_shaarli' => 'Sur votre Shaarli', + + 'note' => 'Note', + 'add_note' => 'Ajouter une note', + 'update_note' => 'Modifier votre note', + 'ask_public_article' => 'Article public ?', + 'article' => 'Article', + 'title' => 'Titre', + 'author' => 'Auteur', + 'publication_date' => 'Date de publication', + + 'load_more' => 'Charger plus d\'articles', + 'nothing_to_load' => 'Il n\'y a pas plus d\'article', + + 'rss_feeds_of' => 'Flux RSS de %s', + + 'refresh' => 'Actualisation', + + 'today' => 'Aujourd\'hui', + 'yesterday' => 'Hier', + 'before_yesterday' => 'À partir d\'avant-hier', + 'by_author' => 'Par %s', + 'related_tags' => 'Tags associés', + 'no_feed_to_display' => 'Il n\'y a aucun flux à afficher.', + + 'about_freshrss' => 'À propos de FreshRSS', + 'project_website' => 'Site du projet', + 'lead_developer' => 'Développeur principal', + 'website' => 'Site Internet', + 'bugs_reports' => 'Rapports de bugs', + 'github_or_email' => 'sur Github ou par mail', + 'license' => 'Licence', + 'agpl3' => 'AGPL 3', + 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l\'image de RSSLounge, TinyTinyRSS ou Leed. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable. L\'objectif étant d\'offrir une alternative sérieuse au futur feu-Google Reader.', + '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.', + + // DATE + 'january' => 'janvier', + 'february' => 'février', + 'march' => 'mars', + 'april' => 'avril', + 'may' => 'mai', + 'june' => 'juin', + 'july' => 'juillet', + 'august' => 'août', + 'september' => 'septembre', + 'october' => 'octobre', + 'november' => 'novembre', + 'december' => 'décembre', + // format spécial pour la fonction date() + 'Jan' => '\j\a\n\v\i\e\r', + 'Feb' => '\f\é\v\r\i\e\r', + 'Mar' => '\m\a\r\s', + 'Apr' => '\a\v\r\i\l', + 'May' => '\m\a\i', + 'Jun' => '\j\u\i\n', + 'Jul' => '\j\u\i\l\l\e\t', + 'Aug' => '\a\o\û\t', + 'Sep' => '\s\e\p\t\e\m\b\r\e', + 'Oct' => '\o\c\t\o\b\r\e', + 'Nov' => '\n\o\v\e\m\b\r\e', + 'Dec' => '\d\é\c\e\m\b\r\e', + // format pour la fonction date(), %s permet d'indiquer le mois en toutes lettres + 'format_date' => 'd %s Y', + 'format_date_hour' => '\l\e d %s Y \à H\:i', + + // INSTALLATION + 'freshrss_installation' => 'Installation - FreshRSS', + 'freshrss' => 'FreshRSS', + 'installation_step' => 'Installation - étape %d', + 'steps' => 'Étapes', + 'checks' => 'Vérifications', + 'bdd_configuration' => 'Configuration de la base de données', + 'this_is_the_end' => 'This is the end', + + 'ok' => 'Ok !', + 'congratulations' => 'Félicitations !', + 'attention' => 'Attention !', + 'damn' => 'Arf !', + 'oops' => 'Oups !', + 'next_step' => 'Passer à l\'étape suivante', + + 'language_defined' => 'La langue a bien été définie.', + 'choose_language' => 'Choisissez la langue pour FreshRSS', + + 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec le Javascript d\'activé', + 'php_is_ok' => 'Votre version de PHP est la %s et est compatible avec FreshRSS', + 'php_is_nok' => 'Votre version de PHP est la %s. Vous devriez avoir au moins la version %s', + 'minz_is_ok' => 'Vous disposez du framework Minz', + '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.', + 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', + 'curl_is_nok' => 'Vous ne disposez pas de cURL', + 'pdomysql_is_ok' => 'Vous disposez de PDO et de son driver pour MySQL', + 'pdomysql_is_nok' => 'Vous ne disposez pas de PDO ou de son driver pour MySQL', + 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', + 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', + 'conf_is_ok' => 'Les droits sur le répertoire de configuration sont bons', + 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', + 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d\'écrire dedans', + 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l\'étape suivante.', + + 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', + 'random_string' => 'Chaîne aléatoire', + 'change_value' => 'Vous devriez changer cette valeur par n\'importe quelle autre', + 'base_url' => 'Base de l\'url', + 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', + + 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', + 'host' => 'Hôte', + 'username' => 'Nom utilisateur', + 'password' => 'Mot de passe', + 'bdd' => 'Base de données', + + 'installation_is_ok' => 'L\'installation s\'est bien passée. Il faut maintenant supprimer le fichier install.php pour pouvoir accéder à FreshRSS... ou simplement cliquer sur le bouton ci-dessous :)', + 'finish_installation' => 'Terminer l\'installation', + 'install_not_deleted' => 'Quelque chose s\'est mal passé, vous devez supprimer le fichier %s à la main.', +); diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index ee527d75e..d91aebbdd 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -1,13 +1,13 @@ diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index bd92b3393..158f012d0 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -1,9 +1,9 @@ diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 3a6ecb304..d1fe6b759 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -3,26 +3,21 @@ + 'index', + 'a' => 'index', + 'params' => $params + ); + ?>