diff --git a/miniflux/assets/css/app.css b/miniflux/assets/css/app.css index c612f66..a61064d 100644 --- a/miniflux/assets/css/app.css +++ b/miniflux/assets/css/app.css @@ -127,8 +127,6 @@ form { label { cursor: pointer; display: block; - float: left; - width: 10em; } input { @@ -144,7 +142,8 @@ input[type="text"] { line-height: 15px; width: 250px; font-size: 99%; - margin-bottom: 15px; + margin-bottom: 10px; + margin-top: 5px; } input[type="email"]:focus, @@ -196,14 +195,14 @@ textarea.form-error { .form-errors { color: #b94a48; - margin-left: 10em; + margin-left: 15px; list-style-type: none; } .form-help { font-size: 0.9em; color: brown; - display: inline; + margin-bottom: 15px; } /* alerts */ @@ -346,8 +345,7 @@ nav .active a { .page-header li { font-size: 90%; display: inline; - padding-left: 10px; - padding-right: 10px; + padding-right: 5px; border-right: 1px dotted #ccc; } @@ -488,7 +486,7 @@ nav .active a { /* other pages */ section li { - margin-left: 20px; + margin-left: 15px; list-style-type: square; } diff --git a/miniflux/common.php b/miniflux/common.php index 806aab6..6216aeb 100644 --- a/miniflux/common.php +++ b/miniflux/common.php @@ -3,19 +3,19 @@ require 'check_setup.php'; require 'vendor/password.php'; require 'vendor/PicoTools/Dependency_Injection.php'; +require 'vendor/PicoTools/Translator.php'; require 'vendor/PicoDb/Database.php'; require 'vendor/PicoDb/Table.php'; require 'schema.php'; require 'model.php'; -const DB_VERSION = 2; +const DB_VERSION = 3; const APP_VERSION = 'master'; const APP_USERAGENT = 'Miniflux - http://miniflux.net'; const HTTP_TIMEOUT = 5; -// For future use... function get_db_filename() { return 'data/db.sqlite'; diff --git a/miniflux/index.php b/miniflux/index.php index 2c53592..893adb0 100644 --- a/miniflux/index.php +++ b/miniflux/index.php @@ -25,6 +25,24 @@ Router\before(function($action) { Response\redirect('?action=login'); } + $language = 'en_US'; + + if (isset($_SESSION['user']['language'])) { + + $language = $_SESSION['user']['language']; + } + else if (isset($_COOKIE['language'])) { + + $language = $_COOKIE['language']; + } + + if ($language !== 'en_US') { + + PicoTools\Translator\load($language); + } + + setcookie('language', $language, time()+365*24*3600, dirname($_SERVER['PHP_SELF'])); + Response\csp(array( 'img-src' => '*', 'frame-src' => 'http://www.youtube.com https://www.youtube.com http://player.vimeo.com https://player.vimeo.com' @@ -168,11 +186,11 @@ Router\get_action('remove', function() { if ($id && Model\remove_feed($id)) { - Session\flash('This subscription has been removed successfully'); + Session\flash(t('This subscription has been removed successfully.')); } else { - Session\flash_error('Unable to remove this subscription'); + Session\flash_error(t('Unable to remove this subscription.')); } Response\redirect('?action=feeds'); @@ -230,7 +248,7 @@ Router\get_action('flush-history', function() { Router\get_action('refresh-all', function() { Model\update_feeds(); - Session\flash('Your subscriptions are updated'); + Session\flash(t('Your subscriptions are updated')); Response\redirect('?action=unread'); }); @@ -259,17 +277,16 @@ Router\post_action('add', function() { if (Model\import_feed($_POST['url'])) { - Session\flash('Subscription added successfully.'); + Session\flash(t('Subscription added successfully.')); Response\redirect('?action=feeds'); } else { - Session\flash_error('Unable to find a subscription.'); + Session\flash_error(t('Unable to find a subscription.')); } Response\html(Template\layout('add', array( 'values' => array('url' => $_POST['url']), - 'errors' => array('url' => 'Unable to find a news feed.'), 'menu' => 'feeds' ))); }); @@ -309,14 +326,14 @@ Router\post_action('import', function() { if (Model\import_feeds(Request\file_content('file'))) { - Session\flash('Your feeds are imported.'); + Session\flash(t('Your feeds have been imported.')); } else { - Session\flash_error('Unable to import your OPML file.'); + Session\flash_error(t('Unable to import your OPML file.')); } - Response\redirect('?action=feeds'); + Response\redirect('?action=import'); }); @@ -326,6 +343,7 @@ Router\get_action('config', function() { 'errors' => array(), 'values' => Model\get_config(), 'db_size' => filesize(get_db_filename()), + 'languages' => Model\get_languages(), 'menu' => 'config' ))); }); @@ -340,11 +358,11 @@ Router\post_action('config', function() { if (Model\save_config($values)) { - Session\flash('Your preferences are updated.'); + Session\flash(t('Your preferences are updated.')); } else { - Session\flash_error('Unable to update your preferences.'); + Session\flash_error(t('Unable to update your preferences.')); } Response\redirect('?action=config'); @@ -353,6 +371,8 @@ Router\post_action('config', function() { Response\html(Template\layout('config', array( 'errors' => $errors, 'values' => $values, + 'db_size' => filesize(get_db_filename()), + 'languages' => Model\get_languages(), 'menu' => 'config' ))); }); diff --git a/miniflux/locales/fr_FR/translations.php b/miniflux/locales/fr_FR/translations.php new file mode 100644 index 0000000..c944a0d --- /dev/null +++ b/miniflux/locales/fr_FR/translations.php @@ -0,0 +1,87 @@ + 'Français', + 'English' => 'Anglais', + 'unread' => 'non lus', + 'history' => 'historique', + 'subscriptions' => 'abonnements', + 'Subscriptions' => 'Abonnements', + 'preferences' => 'préférences', + 'Preferences' => 'Préférences', + 'logout' => 'déconnexion', + 'Username' => 'Utilisateur', + 'Password' => 'Mot de passe', + 'Confirmation' => 'Confirmation', + 'Language' => 'Langue', + 'Update' => 'Mettre à jour', + 'More informations' => 'Plus d\'informations', + 'Database' => 'Base de données', + 'Database size:' => 'Taille de la base de données :', + 'Optimize the database' => 'Optimiser la base de données', + '(VACUUM command)' => '(commande SQL VACUUM)', + 'Download the entire database' => 'Télécharger la base de données complète', + '(Gzip compressed Sqlite file)' => '(Fichier Sqlite compressé en Gzip)', + 'Keyboard shortcuts' => 'Raccourcis clavier', + 'Previous item' => 'Élément précédent', + 'Next item' => 'Élément suivant', + 'Mark as read or unread' => 'Marquer comme lu ou non lu', + 'Open original link' => 'Ouvrir le lien original', + 'Open item' => 'Ouvrir un élément', + 'About' => 'A propos', + 'Miniflux version:' => 'Version de Miniflux :', + 'Nothing to read' => 'Rien à lire', + 'Unread items' => 'Éléments non lus', + 'mark all as read' => 'tout marquer comme lu', + 'original link' => 'lien original', + 'mark as read' => 'marquer comme lu', + 'No history' => 'Aucun historique', + 'mark as unread' => 'marquer comme non lu', + 'History' => 'Historique', + 'flush these items' => 'supprimer ces éléments', + 'Item not found' => 'Élément introuvable', + 'Unread items' => 'Éléments non lus', + 'Next' => 'Suivant', + 'Previous' => 'Précédent', + 'Sign in' => 'Connexion', + 'feeds' => 'abonnements', + 'add' => 'ajouter', + 'import' => 'importer', + 'export' => 'exporter', + 'OPML Import' => 'Importation OPML', + 'OPML file' => 'Fichier OPML', + 'Import' => 'Importer', + 'refresh all' => 'actualiser', + 'No subscription' => 'Aucun abonnement', + 'remove' => 'supprimer', + 'refresh' => 'actualiser', + 'feed link' => 'lien du flux', + 'New subscription' => 'Nouvel abonnement', + 'Website or Feed URL' => 'URL du site ou du flux', + 'Add' => 'Ajouter', + 'http://website/' => 'http://siteweb/', + 'Yes' => 'Oui', + 'cancel' => 'annuler', + 'or' => 'ou', + 'Official website:' => 'Site officiel :', + 'Bad username or password' => 'Mauvais utilisateur ou mot de passe', + 'Unable to update your preferences.' => 'Impossible de mettre à jour vos préférences.', + 'Your preferences are updated.' => 'Vos préférences ont été mises à jour.', + 'Unable to import your OPML file.' => 'Impossible d\'importer votre fichier OPML', + 'Your feeds have been imported.' => 'Vos abonnements ont été importés avec succès.', + 'Unable to find a subscription.' => 'Impossible de trouver un abonnement.', + 'Subscription added successfully.' => 'Abonnement ajouté avec succès.', + 'Your subscriptions are updated' => 'Vos abonnements ont été mis à jour', + 'Unable to remove this subscription.' => 'Impossible de supprimer cet abonnement.', + 'This subscription has been removed successfully.' => 'L\'abonnement a été supprimé avec succès.', + 'The user name is required' => 'Le nom d\'utilisateur est obligatoire', + 'The maximum length is 50 characters' => 'La longueur maximale est de 50 caractères', + 'The password is required' => 'Le mot de passe est obligatoire', + 'The minimum length is 6 characters' => 'La longueur minimale est de 6 caractères', + 'The confirmation is required' => 'La confirmation est obligatoire', + 'Passwords doesn\'t match' => 'Les mots de passe ne sont pas identique', + 'Do you really want to remove these items from your history?' => 'Voulez-vous vraiment supprimer les éléments de votre historique ?', + 'Do you really want to remove this subscription: "%s"?' => 'Voulez-vous vraiment supprimer cet abonnement : "%s" ?', + 'Nothing to read, do you want to update your subscriptions?' => + 'Il n\'y a rien à lire, voulez-vous mettre à jour vos abonnements ?' +); \ No newline at end of file diff --git a/miniflux/model.php b/miniflux/model.php index 09873c5..b633f66 100644 --- a/miniflux/model.php +++ b/miniflux/model.php @@ -21,6 +21,15 @@ use PicoFeed\Reader; use PicoFeed\Export; +function get_languages() +{ + return array( + 'en_US' => t('English'), + 'fr_FR' => t('French') + ); +} + + function export_feeds() { $opml = new Export(get_feeds()); @@ -359,7 +368,7 @@ function get_config() { return \PicoTools\singleton('db') ->table('config') - ->columns('username', 'history') + ->columns('username', 'language') ->findOne(); } @@ -368,7 +377,7 @@ function get_user() { return \PicoTools\singleton('db') ->table('config') - ->columns('username', 'password') + ->columns('username', 'password', 'language') ->findOne(); } @@ -376,9 +385,9 @@ function get_user() function validate_login(array $values) { $v = new Validator($values, array( - new Validators\Required('username', 'The user name is required'), - new Validators\MaxLength('username', 'The maximum length is 50 characters', 50), - new Validators\Required('password', 'The password is required') + new Validators\Required('username', t('The user name is required')), + new Validators\MaxLength('username', t('The maximum length is 50 characters'), 50), + new Validators\Required('password', t('The password is required')) )); $result = $v->execute(); @@ -390,12 +399,13 @@ function validate_login(array $values) if ($user && \password_verify($values['password'], $user['password'])) { + unset($user['password']); $_SESSION['user'] = $user; } else { $result = false; - $errors['login'] = 'Bad username or password'; + $errors['login'] = t('Bad username or password'); } } @@ -411,19 +421,19 @@ function validate_config_update(array $values) if (! empty($values['password'])) { $v = new Validator($values, array( - new Validators\Required('username', 'The user name is required'), - new Validators\MaxLength('username', 'The maximum length is 50 characters', 50), - new Validators\Required('password', 'The password is required'), - new Validators\MinLength('password', 'The minimum length is 6 characters', 6), - new Validators\Required('confirmation', 'The confirmation is required'), - new Validators\Equals('password', 'confirmation', 'Passwords doesn\'t match') + new Validators\Required('username', t('The user name is required')), + new Validators\MaxLength('username', t('The maximum length is 50 characters'), 50), + new Validators\Required('password', t('The password is required')), + new Validators\MinLength('password', t('The minimum length is 6 characters'), 6), + new Validators\Required('confirmation', t('The confirmation is required')), + new Validators\Equals('password', 'confirmation', t('Passwords doesn\'t match')) )); } else { $v = new Validator($values, array( - new Validators\Required('username', 'The user name is required'), - new Validators\MaxLength('username', 'The maximum length is 50 characters', 50) + new Validators\Required('username', t('The user name is required')), + new Validators\MaxLength('username', t('The maximum length is 50 characters'), 50) )); } @@ -447,5 +457,8 @@ function save_config(array $values) unset($values['confirmation']); + $_SESSION['user']['language'] = $values['language']; + unset($_COOKIE['language']); + return \PicoTools\singleton('db')->table('config')->update($values); } diff --git a/miniflux/schema.php b/miniflux/schema.php index e446af3..74dd7c1 100644 --- a/miniflux/schema.php +++ b/miniflux/schema.php @@ -3,6 +3,12 @@ namespace Schema; +function version_3($pdo) +{ + $pdo->exec("ALTER TABLE config ADD COLUMN language TEXT DEFAULT 'en_US'"); +} + + function version_2($pdo) { $pdo->exec('ALTER TABLE feeds ADD COLUMN last_modified TEXT'); diff --git a/miniflux/templates/add.php b/miniflux/templates/add.php index 7d4c227..abd1e4f 100644 --- a/miniflux/templates/add.php +++ b/miniflux/templates/add.php @@ -1,16 +1,16 @@
- - + +
- +
\ No newline at end of file diff --git a/miniflux/templates/app_header.php b/miniflux/templates/app_header.php index 4762adf..3cfbda1 100644 --- a/miniflux/templates/app_header.php +++ b/miniflux/templates/app_header.php @@ -18,11 +18,11 @@ diff --git a/miniflux/templates/config.php b/miniflux/templates/config.php index 95c3687..048da99 100644 --- a/miniflux/templates/config.php +++ b/miniflux/templates/config.php @@ -1,51 +1,54 @@
- +
- +
- +
- Don't use the same password everywhere!
+ + +
- +
-

More informations

+

-

Database

+

-

Keyboard shortcuts

+

-

About

+

\ No newline at end of file diff --git a/miniflux/templates/confirm_flush.php b/miniflux/templates/confirm_flush.php index 5a15913..44938cc 100644 --- a/miniflux/templates/confirm_flush.php +++ b/miniflux/templates/confirm_flush.php @@ -1,10 +1,10 @@ -

Do you really want to remove these items from your history?

+

- Yes - or cancel + +
\ No newline at end of file diff --git a/miniflux/templates/confirm_remove.php b/miniflux/templates/confirm_remove.php index 4c48a75..ec40551 100644 --- a/miniflux/templates/confirm_remove.php +++ b/miniflux/templates/confirm_remove.php @@ -1,10 +1,10 @@ -

Do you really want to remove this subscription: ""?

+

- Yes - or cancel + +
\ No newline at end of file diff --git a/miniflux/templates/feeds.php b/miniflux/templates/feeds.php index c39d961..156b354 100644 --- a/miniflux/templates/feeds.php +++ b/miniflux/templates/feeds.php @@ -1,21 +1,21 @@ -

No subscription.

+

-

Nothing to read, do you want to update your subscriptions?

+

update your subscriptions?') ?>

@@ -26,10 +26,10 @@

- | - feed link | - remove | - refresh + | + | + | +

diff --git a/miniflux/templates/import.php b/miniflux/templates/import.php index a81baf3..eca99a7 100644 --- a/miniflux/templates/import.php +++ b/miniflux/templates/import.php @@ -1,16 +1,16 @@
- +
- +
\ No newline at end of file diff --git a/miniflux/templates/login.php b/miniflux/templates/login.php index 66b8fed..e273c79 100644 --- a/miniflux/templates/login.php +++ b/miniflux/templates/login.php @@ -9,7 +9,7 @@ @@ -20,14 +20,14 @@
- +
- +
- +
diff --git a/miniflux/templates/read_item.php b/miniflux/templates/read_item.php index 823c566..6af5719 100644 --- a/miniflux/templates/read_item.php +++ b/miniflux/templates/read_item.php @@ -1,6 +1,6 @@ -

Article not found.

+

@@ -11,7 +11,7 @@

| - +

@@ -20,29 +20,29 @@ diff --git a/miniflux/templates/read_items.php b/miniflux/templates/read_items.php index 1944e81..fdbb038 100644 --- a/miniflux/templates/read_items.php +++ b/miniflux/templates/read_items.php @@ -1,13 +1,13 @@ -

No history.

+

@@ -24,8 +24,8 @@

| - | - mark as unread | + | + | - direct link +

diff --git a/miniflux/templates/unread_items.php b/miniflux/templates/unread_items.php index 1e9dc23..dc50a83 100644 --- a/miniflux/templates/unread_items.php +++ b/miniflux/templates/unread_items.php @@ -1,13 +1,13 @@ -

Nothing to read.

+

@@ -27,7 +27,7 @@

| - mark as read | + | - direct link +

diff --git a/miniflux/vendor/PicoTools/Translator.php b/miniflux/vendor/PicoTools/Translator.php index 40bd653..832635c 100644 --- a/miniflux/vendor/PicoTools/Translator.php +++ b/miniflux/vendor/PicoTools/Translator.php @@ -19,7 +19,7 @@ namespace PicoTools\Translator { $args = \func_get_args(); \array_shift($args); - \array_unshift($args, get($identifier)); + \array_unshift($args, get($identifier, $identifier)); return \call_user_func_array( 'sprintf', @@ -61,6 +61,12 @@ namespace PicoTools\Translator { } + function datetime($format, $timestamp) + { + return strftime($format, $timestamp); + } + + function get($identifier, $default = '') { $locales = container(); @@ -78,6 +84,8 @@ namespace PicoTools\Translator { function load($language) { + setlocale(LC_TIME, $language); + $path = PATH.$language; $locales = array(); @@ -118,4 +126,10 @@ namespace { return call_user_func_array('\PicoTools\Translator\translate', func_get_args()); } + + + function dt() { + + return call_user_func_array('\PicoTools\Translator\datetime', func_get_args()); + } } \ No newline at end of file