Add french locales

This commit is contained in:
Frederic Guillot 2013-04-12 21:08:55 -04:00
parent 58227aa091
commit 222b884aad
18 changed files with 258 additions and 117 deletions

View File

@ -127,8 +127,6 @@ form {
label { label {
cursor: pointer; cursor: pointer;
display: block; display: block;
float: left;
width: 10em;
} }
input { input {
@ -144,7 +142,8 @@ input[type="text"] {
line-height: 15px; line-height: 15px;
width: 250px; width: 250px;
font-size: 99%; font-size: 99%;
margin-bottom: 15px; margin-bottom: 10px;
margin-top: 5px;
} }
input[type="email"]:focus, input[type="email"]:focus,
@ -196,14 +195,14 @@ textarea.form-error {
.form-errors { .form-errors {
color: #b94a48; color: #b94a48;
margin-left: 10em; margin-left: 15px;
list-style-type: none; list-style-type: none;
} }
.form-help { .form-help {
font-size: 0.9em; font-size: 0.9em;
color: brown; color: brown;
display: inline; margin-bottom: 15px;
} }
/* alerts */ /* alerts */
@ -346,8 +345,7 @@ nav .active a {
.page-header li { .page-header li {
font-size: 90%; font-size: 90%;
display: inline; display: inline;
padding-left: 10px; padding-right: 5px;
padding-right: 10px;
border-right: 1px dotted #ccc; border-right: 1px dotted #ccc;
} }
@ -488,7 +486,7 @@ nav .active a {
/* other pages */ /* other pages */
section li { section li {
margin-left: 20px; margin-left: 15px;
list-style-type: square; list-style-type: square;
} }

View File

@ -3,19 +3,19 @@
require 'check_setup.php'; require 'check_setup.php';
require 'vendor/password.php'; require 'vendor/password.php';
require 'vendor/PicoTools/Dependency_Injection.php'; require 'vendor/PicoTools/Dependency_Injection.php';
require 'vendor/PicoTools/Translator.php';
require 'vendor/PicoDb/Database.php'; require 'vendor/PicoDb/Database.php';
require 'vendor/PicoDb/Table.php'; require 'vendor/PicoDb/Table.php';
require 'schema.php'; require 'schema.php';
require 'model.php'; require 'model.php';
const DB_VERSION = 2; const DB_VERSION = 3;
const APP_VERSION = 'master'; const APP_VERSION = 'master';
const APP_USERAGENT = 'Miniflux - http://miniflux.net'; const APP_USERAGENT = 'Miniflux - http://miniflux.net';
const HTTP_TIMEOUT = 5; const HTTP_TIMEOUT = 5;
// For future use...
function get_db_filename() function get_db_filename()
{ {
return 'data/db.sqlite'; return 'data/db.sqlite';

View File

@ -25,6 +25,24 @@ Router\before(function($action) {
Response\redirect('?action=login'); 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( Response\csp(array(
'img-src' => '*', 'img-src' => '*',
'frame-src' => 'http://www.youtube.com https://www.youtube.com http://player.vimeo.com https://player.vimeo.com' '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)) { if ($id && Model\remove_feed($id)) {
Session\flash('This subscription has been removed successfully'); Session\flash(t('This subscription has been removed successfully.'));
} }
else { else {
Session\flash_error('Unable to remove this subscription'); Session\flash_error(t('Unable to remove this subscription.'));
} }
Response\redirect('?action=feeds'); Response\redirect('?action=feeds');
@ -230,7 +248,7 @@ Router\get_action('flush-history', function() {
Router\get_action('refresh-all', function() { Router\get_action('refresh-all', function() {
Model\update_feeds(); Model\update_feeds();
Session\flash('Your subscriptions are updated'); Session\flash(t('Your subscriptions are updated'));
Response\redirect('?action=unread'); Response\redirect('?action=unread');
}); });
@ -259,17 +277,16 @@ Router\post_action('add', function() {
if (Model\import_feed($_POST['url'])) { if (Model\import_feed($_POST['url'])) {
Session\flash('Subscription added successfully.'); Session\flash(t('Subscription added successfully.'));
Response\redirect('?action=feeds'); Response\redirect('?action=feeds');
} }
else { else {
Session\flash_error('Unable to find a subscription.'); Session\flash_error(t('Unable to find a subscription.'));
} }
Response\html(Template\layout('add', array( Response\html(Template\layout('add', array(
'values' => array('url' => $_POST['url']), 'values' => array('url' => $_POST['url']),
'errors' => array('url' => 'Unable to find a news feed.'),
'menu' => 'feeds' 'menu' => 'feeds'
))); )));
}); });
@ -309,14 +326,14 @@ Router\post_action('import', function() {
if (Model\import_feeds(Request\file_content('file'))) { if (Model\import_feeds(Request\file_content('file'))) {
Session\flash('Your feeds are imported.'); Session\flash(t('Your feeds have been imported.'));
} }
else { 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(), 'errors' => array(),
'values' => Model\get_config(), 'values' => Model\get_config(),
'db_size' => filesize(get_db_filename()), 'db_size' => filesize(get_db_filename()),
'languages' => Model\get_languages(),
'menu' => 'config' 'menu' => 'config'
))); )));
}); });
@ -340,11 +358,11 @@ Router\post_action('config', function() {
if (Model\save_config($values)) { if (Model\save_config($values)) {
Session\flash('Your preferences are updated.'); Session\flash(t('Your preferences are updated.'));
} }
else { else {
Session\flash_error('Unable to update your preferences.'); Session\flash_error(t('Unable to update your preferences.'));
} }
Response\redirect('?action=config'); Response\redirect('?action=config');
@ -353,6 +371,8 @@ Router\post_action('config', function() {
Response\html(Template\layout('config', array( Response\html(Template\layout('config', array(
'errors' => $errors, 'errors' => $errors,
'values' => $values, 'values' => $values,
'db_size' => filesize(get_db_filename()),
'languages' => Model\get_languages(),
'menu' => 'config' 'menu' => 'config'
))); )));
}); });

View File

@ -0,0 +1,87 @@
<?php
return array(
'French' => '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 <a href="?action=refresh-all" data-action="refresh-all">update your subscriptions?</a>' =>
'Il n\'y a rien à lire, voulez-vous <a href="?action=refresh-all" data-action="refresh-all">mettre à jour vos abonnements ?</a>'
);

View File

@ -21,6 +21,15 @@ use PicoFeed\Reader;
use PicoFeed\Export; use PicoFeed\Export;
function get_languages()
{
return array(
'en_US' => t('English'),
'fr_FR' => t('French')
);
}
function export_feeds() function export_feeds()
{ {
$opml = new Export(get_feeds()); $opml = new Export(get_feeds());
@ -359,7 +368,7 @@ function get_config()
{ {
return \PicoTools\singleton('db') return \PicoTools\singleton('db')
->table('config') ->table('config')
->columns('username', 'history') ->columns('username', 'language')
->findOne(); ->findOne();
} }
@ -368,7 +377,7 @@ function get_user()
{ {
return \PicoTools\singleton('db') return \PicoTools\singleton('db')
->table('config') ->table('config')
->columns('username', 'password') ->columns('username', 'password', 'language')
->findOne(); ->findOne();
} }
@ -376,9 +385,9 @@ function get_user()
function validate_login(array $values) function validate_login(array $values)
{ {
$v = new Validator($values, array( $v = new Validator($values, array(
new Validators\Required('username', 'The user name is required'), new Validators\Required('username', t('The user name is required')),
new Validators\MaxLength('username', 'The maximum length is 50 characters', 50), new Validators\MaxLength('username', t('The maximum length is 50 characters'), 50),
new Validators\Required('password', 'The password is required') new Validators\Required('password', t('The password is required'))
)); ));
$result = $v->execute(); $result = $v->execute();
@ -390,12 +399,13 @@ function validate_login(array $values)
if ($user && \password_verify($values['password'], $user['password'])) { if ($user && \password_verify($values['password'], $user['password'])) {
unset($user['password']);
$_SESSION['user'] = $user; $_SESSION['user'] = $user;
} }
else { else {
$result = false; $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'])) { if (! empty($values['password'])) {
$v = new Validator($values, array( $v = new Validator($values, array(
new Validators\Required('username', 'The user name is required'), new Validators\Required('username', t('The user name is required')),
new Validators\MaxLength('username', 'The maximum length is 50 characters', 50), new Validators\MaxLength('username', t('The maximum length is 50 characters'), 50),
new Validators\Required('password', 'The password is required'), new Validators\Required('password', t('The password is required')),
new Validators\MinLength('password', 'The minimum length is 6 characters', 6), new Validators\MinLength('password', t('The minimum length is 6 characters'), 6),
new Validators\Required('confirmation', 'The confirmation is required'), new Validators\Required('confirmation', t('The confirmation is required')),
new Validators\Equals('password', 'confirmation', 'Passwords doesn\'t match') new Validators\Equals('password', 'confirmation', t('Passwords doesn\'t match'))
)); ));
} }
else { else {
$v = new Validator($values, array( $v = new Validator($values, array(
new Validators\Required('username', 'The user name is required'), new Validators\Required('username', t('The user name is required')),
new Validators\MaxLength('username', 'The maximum length is 50 characters', 50) new Validators\MaxLength('username', t('The maximum length is 50 characters'), 50)
)); ));
} }
@ -447,5 +457,8 @@ function save_config(array $values)
unset($values['confirmation']); unset($values['confirmation']);
$_SESSION['user']['language'] = $values['language'];
unset($_COOKIE['language']);
return \PicoTools\singleton('db')->table('config')->update($values); return \PicoTools\singleton('db')->table('config')->update($values);
} }

View File

@ -3,6 +3,12 @@
namespace Schema; namespace Schema;
function version_3($pdo)
{
$pdo->exec("ALTER TABLE config ADD COLUMN language TEXT DEFAULT 'en_US'");
}
function version_2($pdo) function version_2($pdo)
{ {
$pdo->exec('ALTER TABLE feeds ADD COLUMN last_modified TEXT'); $pdo->exec('ALTER TABLE feeds ADD COLUMN last_modified TEXT');

View File

@ -1,16 +1,16 @@
<div class="page-header"> <div class="page-header">
<h2>New subscription</h2> <h2><?= t('New subscription') ?></h2>
<ul> <ul>
<li><a href="?action=feeds">feeds</a></li> <li><a href="?action=feeds"><?= t('feeds') ?></a></li>
<li><a href="?action=import">import</a></li> <li><a href="?action=import"><?= t('import') ?></a></li>
<li><a href="?action=export">export</a></li> <li><a href="?action=export"><?= t('export') ?></a></li>
</ul> </ul>
</div> </div>
<form method="post" action="?action=add" autocomplete="off"> <form method="post" action="?action=add" autocomplete="off">
<label for="url">Site or Feed URL</label> <label for="url"><?= t('Website or Feed URL') ?></label>
<input type="text" name="url" id="url" placeholder="http://website/" autofocus required/> <input type="text" name="url" id="url" placeholder="<?= t('http://website/') ?>" autofocus required/>
<div class="form-actions"> <div class="form-actions">
<button type="submit" class="btn btn-blue">Add</button> <button type="submit" class="btn btn-blue"><?= t('Add') ?></button>
</div> </div>
</form> </form>

View File

@ -18,11 +18,11 @@
<nav> <nav>
<a class="logo" href="?">mini<span>flux</span></a> <a class="logo" href="?">mini<span>flux</span></a>
<ul> <ul>
<li <?= isset($menu) && $menu === 'unread' ? 'class="active"' : '' ?>><a href="?action=default">unread</a></li> <li <?= isset($menu) && $menu === 'unread' ? 'class="active"' : '' ?>><a href="?action=default"><?= t('unread') ?></a></li>
<li <?= isset($menu) && $menu === 'history' ? 'class="active"' : '' ?>><a href="?action=history">history</a></li> <li <?= isset($menu) && $menu === 'history' ? 'class="active"' : '' ?>><a href="?action=history"><?= t('history') ?></a></li>
<li <?= isset($menu) && $menu === 'feeds' ? 'class="active"' : '' ?>><a href="?action=feeds">subscriptions</a></li> <li <?= isset($menu) && $menu === 'feeds' ? 'class="active"' : '' ?>><a href="?action=feeds"><?= t('subscriptions') ?></a></li>
<li <?= isset($menu) && $menu === 'config' ? 'class="active"' : '' ?>><a href="?action=config">preferences</a></li> <li <?= isset($menu) && $menu === 'config' ? 'class="active"' : '' ?>><a href="?action=config"><?= t('preferences') ?></a></li>
<li><a href="?action=logout">logout</a></li> <li><a href="?action=logout"><?= t('logout') ?></a></li>
</ul> </ul>
</nav> </nav>
</header> </header>

View File

@ -1,51 +1,54 @@
<div class="page-header"> <div class="page-header">
<h2>Change username and password</h2> <h2><?= t('Preferences') ?></h2>
</div> </div>
<section> <section>
<form method="post" action="?action=config" autocomplete="off"> <form method="post" action="?action=config" autocomplete="off">
<?= Helper\form_label('Username', 'username') ?> <?= Helper\form_label(t('Username'), 'username') ?>
<?= Helper\form_text('username', $values, $errors, array('required')) ?><br/> <?= Helper\form_text('username', $values, $errors, array('required')) ?><br/>
<?= Helper\form_label('Password', 'password') ?> <?= Helper\form_label(t('Password'), 'password') ?>
<?= Helper\form_password('password', $values, $errors) ?><br/> <?= Helper\form_password('password', $values, $errors) ?><br/>
<?= Helper\form_label('Confirmation', 'confirmation') ?> <?= Helper\form_label(t('Confirmation'), 'confirmation') ?>
<?= Helper\form_password('confirmation', $values, $errors) ?><br/> <?= Helper\form_password('confirmation', $values, $errors) ?><br/>
<span class="form-help">Don't use the same password everywhere!</span><br/>
<?= Helper\form_label(t('Language'), 'language') ?>
<?= Helper\form_select('language', $languages, $values, $errors) ?><br/>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="Update" class="btn btn-blue"/> <input type="submit" value="<?= t('Update') ?>" class="btn btn-blue"/>
</div> </div>
</form> </form>
</section> </section>
<div class="page-section"> <div class="page-section">
<h2>More informations</h2> <h2><?= t('More informations') ?></h2>
</div> </div>
<section> <section>
<div class="alert alert-normal"> <div class="alert alert-normal">
<h3>Database</h3> <h3><?= t('Database') ?></h3>
<ul> <ul>
<li>Database size: <?= Helper\format_bytes($db_size) ?></li> <li><?= t('Database size:') ?> <?= Helper\format_bytes($db_size) ?></li>
<li><a href="?action=optimize-db">Optimize the database</a> (VACUUM command)</li> <li><a href="?action=optimize-db"><?= t('Optimize the database') ?></a> <?= t('(VACUUM command)') ?></li>
<li><a href="?action=download-db">Download the entire database</a> (Gzip compressed Sqlite file).</li> <li><a href="?action=download-db"><?= t('Download the entire database') ?></a> <?= t('(Gzip compressed Sqlite file)') ?></li>
</ul> </ul>
</div> </div>
<div class="alert alert-normal"> <div class="alert alert-normal">
<h3>Keyboard shortcuts</h3> <h3><?= t('Keyboard shortcuts') ?></h3>
<ul> <ul>
<li>Previous item = <strong>p</strong></li> <li><?= t('Previous item') ?> = <strong>p</strong></li>
<li>Next item = <strong>n</strong></li> <li><?= t('Next item') ?> = <strong>n</strong></li>
<li>Mark as read or unread = <strong>m</strong></li> <li><?= t('Mark as read or unread') ?> = <strong>m</strong></li>
<li>Open original link = <strong>v</strong></li> <li><?= t('Open original link') ?> = <strong>v</strong></li>
<li>Open item = <strong>o</strong></li> <li><?= t('Open item') ?> = <strong>o</strong></li>
</ul> </ul>
</div> </div>
<div class="alert alert-normal"> <div class="alert alert-normal">
<h3>About</h3> <h3><?= t('About') ?></h3>
<ul> <ul>
<li>Miniflux version: <strong><?= APP_VERSION ?></strong></li> <li><?= t('Miniflux version:') ?> <strong><?= APP_VERSION ?></strong></li>
<li><?= t('Official website:') ?> <a href="http://miniflux.net" target="_blank">http://miniflux.net</a></li>
</ul> </ul>
</div> </div>
</section> </section>

View File

@ -1,10 +1,10 @@
<div class="page-header"> <div class="page-header">
<h2>Confirmation</h2> <h2><?= t('Confirmation') ?></h2>
</div> </div>
<p class="alert alert-info">Do you really want to remove these items from your history?</p> <p class="alert alert-info"><?= t('Do you really want to remove these items from your history?') ?></p>
<div class="form-actions"> <div class="form-actions">
<a href="?action=flush-history" class="btn btn-red">Yes</a> <a href="?action=flush-history" class="btn btn-red"><?= t('Yes') ?></a>
or <a href="?action=history">cancel</a> <?= t('or') ?> <a href="?action=history"><?= t('cancel') ?></a>
</div> </div>

View File

@ -1,10 +1,10 @@
<div class="page-header"> <div class="page-header">
<h2>Confirmation</h2> <h2><?= t('Confirmation') ?></h2>
</div> </div>
<p class="alert alert-info">Do you really want to remove this subscription: "<?= Helper\escape($feed['title']) ?>"?</p> <p class="alert alert-info"><?= t('Do you really want to remove this subscription: "%s"?', Helper\escape($feed['title'])) ?></p>
<div class="form-actions"> <div class="form-actions">
<a href="?action=remove&amp;feed_id=<?= $feed['id'] ?>" class="btn btn-red">Yes</a> <a href="?action=remove&amp;feed_id=<?= $feed['id'] ?>" class="btn btn-red"><?= t('Yes') ?></a>
or <a href="?action=feeds">cancel</a> <?= t('or') ?> <a href="?action=feeds"><?= t('cancel') ?></a>
</div> </div>

View File

@ -1,21 +1,21 @@
<div class="page-header"> <div class="page-header">
<h2>Subscriptions</h2> <h2><?= t('Subscriptions') ?></h2>
<ul> <ul>
<li><a href="?action=add">add</a></li> <li><a href="?action=add"><?= t('add') ?></a></li>
<li><a href="?action=import">import</a></li> <li><a href="?action=import"><?= t('import') ?></a></li>
<li><a href="?action=export">export</a></li> <li><a href="?action=export"><?= t('export') ?></a></li>
<li><a href="?action=refresh-all" data-action="refresh-all">refresh all</a></li> <li><a href="?action=refresh-all" data-action="refresh-all"><?= t('refresh all') ?></a></li>
</ul> </ul>
</div> </div>
<?php if (empty($feeds)): ?> <?php if (empty($feeds)): ?>
<p class="alert alert-info">No subscription.</p> <p class="alert alert-info"><?= t('No subscription') ?></p>
<?php else: ?> <?php else: ?>
<?php if ($nothing_to_read): ?> <?php if ($nothing_to_read): ?>
<p class="alert">Nothing to read, do you want to <a href="?action=refresh-all" data-action="refresh-all">update your subscriptions?</a></p> <p class="alert"><?= t('Nothing to read, do you want to <a href="?action=refresh-all" data-action="refresh-all">update your subscriptions?</a>') ?></p>
<?php endif ?> <?php endif ?>
<section class="items"> <section class="items">
@ -26,10 +26,10 @@
<a href="<?= $feed['site_url'] ?>" rel="noreferrer" target="_blank"><?= Helper\escape($feed['title']) ?></a> <a href="<?= $feed['site_url'] ?>" rel="noreferrer" target="_blank"><?= Helper\escape($feed['title']) ?></a>
</h2> </h2>
<p> <p>
<?= Helper\get_host_from_url($feed['site_url']) ?> | <a href="<?= $feed['site_url'] ?>" rel="noreferrer" target="_blank"><?= Helper\get_host_from_url($feed['site_url']) ?></a> |
<a href="<?= Helper\escape($feed['feed_url']) ?>">feed link</a> | <a href="<?= Helper\escape($feed['feed_url']) ?>" rel="noreferrer" target="_blank"><?= t('feed link') ?></a> |
<a href="?action=confirm-remove&amp;feed_id=<?= $feed['id'] ?>">remove</a> | <a href="?action=confirm-remove&amp;feed_id=<?= $feed['id'] ?>"><?= t('remove') ?></a> |
<a href="?action=refresh-feed&amp;feed_id=<?= $feed['id'] ?>" data-feed-id="<?= $feed['id'] ?>" data-action="refresh-feed">refresh</a> <a href="?action=refresh-feed&amp;feed_id=<?= $feed['id'] ?>" data-feed-id="<?= $feed['id'] ?>" data-action="refresh-feed"><?= t('refresh') ?></a>
</p> </p>
</article> </article>
<?php endforeach ?> <?php endforeach ?>

View File

@ -1,16 +1,16 @@
<div class="page-header"> <div class="page-header">
<h2>OPML Import</h2> <h2><?= t('OPML Import') ?></h2>
<ul> <ul>
<li><a href="?action=feeds">feeds</a></li> <li><a href="?action=feeds"><?= t('feeds') ?></a></li>
<li><a href="?action=add">add</a></li> <li><a href="?action=add"><?= t('add') ?></a></li>
<li><a href="?action=export">export</a></li> <li><a href="?action=export"><?= t('export') ?></a></li>
</ul> </ul>
</div> </div>
<form method="post" action="?action=import" enctype="multipart/form-data"> <form method="post" action="?action=import" enctype="multipart/form-data">
<label for="file">OPML file</label> <label for="file"><?= t('OPML file') ?></label>
<input type="file" name="file" required/> <input type="file" name="file" required/>
<div class="form-actions"> <div class="form-actions">
<button type="submit" class="btn btn-blue">Import</button> <button type="submit" class="btn btn-blue"><?= t('Import') ?></button>
</div> </div>
</form> </form>

View File

@ -9,7 +9,7 @@
<body> <body>
<div class="page-header"> <div class="page-header">
<h1>Login</h1> <h1><?= t('Sign in') ?></h1>
</div> </div>
<?php if (isset($errors['login'])): ?> <?php if (isset($errors['login'])): ?>
@ -20,14 +20,14 @@
<form method="post" action="?action=login"> <form method="post" action="?action=login">
<?= Helper\form_label('Username', 'username') ?> <?= Helper\form_label(t('Username'), 'username') ?>
<?= Helper\form_text('username', $values, $errors, array('autofocus', 'required')) ?><br/> <?= Helper\form_text('username', $values, $errors, array('autofocus', 'required')) ?><br/>
<?= Helper\form_label('Password', 'password') ?> <?= Helper\form_label(t('Password'), 'password') ?>
<?= Helper\form_password('password', $values, $errors, array('required')) ?> <?= Helper\form_password('password', $values, $errors, array('required')) ?>
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="Login" class="btn btn-blue"/> <input type="submit" value="<?= t('Sign in') ?>" class="btn btn-blue"/>
</div> </div>
</form> </form>
</body> </body>

View File

@ -1,6 +1,6 @@
<?php if (empty($item)): ?> <?php if (empty($item)): ?>
<p class="alert alert-info">Article not found.</p> <p class="alert alert-info"><?= t('Item not found') ?></p>
<?php else: ?> <?php else: ?>
@ -11,7 +11,7 @@
<p class="infos"> <p class="infos">
<?= Helper\get_host_from_url($item['url']) ?> | <?= Helper\get_host_from_url($item['url']) ?> |
<?= date('l, j F Y H:i', $item['updated']) ?> <?= dt('%A %e %B %Y %k:%M', $item['updated']) ?>
</p> </p>
<?= $item['content'] ?> <?= $item['content'] ?>
@ -20,29 +20,29 @@
<nav> <nav>
<span class="nav-left"> <span class="nav-left">
<?php if ($item_nav['previous']): ?> <?php if ($item_nav['previous']): ?>
<a href="?action=read&amp;id=<?= urlencode($item_nav['previous']['id']) ?>" id="previous-item">« Previous</a> <a href="?action=read&amp;id=<?= urlencode($item_nav['previous']['id']) ?>" id="previous-item">« <?= t('Previous') ?></a>
<?php else: ?> <?php else: ?>
« Previous « <?= t('Previous') ?>
<?php endif ?> <?php endif ?>
</span> </span>
<span class="nav-middle"> <span class="nav-middle">
<?php if ($item_nav['previous'] && $item_nav['next']): ?> <?php if ($item_nav['previous'] && $item_nav['next']): ?>
<a href="?action=default#item-<?= urlencode($item_nav['next']['id']) ?>">Unread items</a> <a href="?action=default#item-<?= urlencode($item_nav['next']['id']) ?>"><?= t('Unread items') ?></a>
<?php elseif ($item_nav['previous'] && ! $item_nav['next']): ?> <?php elseif ($item_nav['previous'] && ! $item_nav['next']): ?>
<a href="?action=default#item-<?= urlencode($item_nav['previous']['id']) ?>">Unread items</a> <a href="?action=default#item-<?= urlencode($item_nav['previous']['id']) ?>"><?= t('Unread items') ?></a>
<?php elseif (! $item_nav['previous'] && $item_nav['next']): ?> <?php elseif (! $item_nav['previous'] && $item_nav['next']): ?>
<a href="?action=default#item-<?= urlencode($item_nav['next']['id']) ?>">Unread items</a> <a href="?action=default#item-<?= urlencode($item_nav['next']['id']) ?>"><?= t('Unread items') ?></a>
<?php elseif (! $item_nav['previous'] && ! $item_nav['next']): ?> <?php elseif (! $item_nav['previous'] && ! $item_nav['next']): ?>
<a href="?action=default">Unread items</a> <a href="?action=default"><?= t('Unread items') ?></a>
<?php endif ?> <?php endif ?>
</span> </span>
<span class="nav-right"> <span class="nav-right">
<?php if ($item_nav['next']): ?> <?php if ($item_nav['next']): ?>
<a href="?action=read&amp;id=<?= urlencode($item_nav['next']['id']) ?>" id="next-item">Next »</a> <a href="?action=read&amp;id=<?= urlencode($item_nav['next']['id']) ?>" id="next-item"><?= t('Next') ?> »</a>
<?php else: ?> <?php else: ?>
Next » <?= t('Next') ?> »
<?php endif ?> <?php endif ?>
</span> </span>
</nav> </nav>

View File

@ -1,13 +1,13 @@
<?php if (empty($items)): ?> <?php if (empty($items)): ?>
<p class="alert alert-info">No history.</p> <p class="alert alert-info"><?= t('No history') ?></p>
<?php else: ?> <?php else: ?>
<div class="page-header"> <div class="page-header">
<h2>History</h2> <h2><?= t('History') ?></h2>
<ul> <ul>
<li><a href="?action=confirm-flush-history">flush</a></li> <li><a href="?action=confirm-flush-history"><?= t('flush these items') ?></a></li>
</ul> </ul>
</div> </div>
@ -24,8 +24,8 @@
</h2> </h2>
<p> <p>
<?= Helper\get_host_from_url($item['url']) ?> | <?= Helper\get_host_from_url($item['url']) ?> |
<?= date('l, j F Y H:i', $item['updated']) ?> | <?= dt('%A %e %B %Y %k:%M', $item['updated']) ?> |
<a href="?action=mark-item-unread&amp;id=<?= urlencode($item['id']) ?>">mark as unread</a> | <a href="?action=mark-item-unread&amp;id=<?= urlencode($item['id']) ?>"><?= t('mark as unread') ?></a> |
<a <a
href="<?= $item['url'] ?>" href="<?= $item['url'] ?>"
id="original-<?= urlencode($item['id']) ?>" id="original-<?= urlencode($item['id']) ?>"
@ -34,7 +34,7 @@
data-item-id="<?= urlencode($item['id']) ?>" data-item-id="<?= urlencode($item['id']) ?>"
data-action="mark-read" data-action="mark-read"
> >
direct link <?= t('original link') ?>
</a> </a>
</p> </p>
</article> </article>

View File

@ -1,13 +1,13 @@
<?php if (empty($items)): ?> <?php if (empty($items)): ?>
<p class="alert alert-info">Nothing to read.</p> <p class="alert alert-info"><?= t('Nothing to read') ?></p>
<?php else: ?> <?php else: ?>
<div class="page-header"> <div class="page-header">
<h2>Unread items</h2> <h2><?= t('Unread items') ?></h2>
<ul> <ul>
<li><a href="?action=mark-as-read">mark all as read</a></li> <li><a href="?action=mark-as-read"><?= t('mark all as read') ?></a></li>
</ul> </ul>
</div> </div>
@ -27,7 +27,7 @@
</p> </p>
<p> <p>
<?= Helper\get_host_from_url($item['url']) ?> | <?= Helper\get_host_from_url($item['url']) ?> |
<a href="?action=mark-item-read&amp;id=<?= urlencode($item['id']) ?>">mark as read</a> | <a href="?action=mark-item-read&amp;id=<?= urlencode($item['id']) ?>"><?= t('mark as read') ?></a> |
<a <a
href="<?= $item['url'] ?>" href="<?= $item['url'] ?>"
id="original-<?= urlencode($item['id']) ?>" id="original-<?= urlencode($item['id']) ?>"
@ -36,7 +36,7 @@
data-item-id="<?= urlencode($item['id']) ?>" data-item-id="<?= urlencode($item['id']) ?>"
data-action="mark-read" data-action="mark-read"
> >
direct link <?= t('original link') ?>
</a> </a>
</p> </p>
</article> </article>

View File

@ -19,7 +19,7 @@ namespace PicoTools\Translator {
$args = \func_get_args(); $args = \func_get_args();
\array_shift($args); \array_shift($args);
\array_unshift($args, get($identifier)); \array_unshift($args, get($identifier, $identifier));
return \call_user_func_array( return \call_user_func_array(
'sprintf', 'sprintf',
@ -61,6 +61,12 @@ namespace PicoTools\Translator {
} }
function datetime($format, $timestamp)
{
return strftime($format, $timestamp);
}
function get($identifier, $default = '') function get($identifier, $default = '')
{ {
$locales = container(); $locales = container();
@ -78,6 +84,8 @@ namespace PicoTools\Translator {
function load($language) function load($language)
{ {
setlocale(LC_TIME, $language);
$path = PATH.$language; $path = PATH.$language;
$locales = array(); $locales = array();
@ -118,4 +126,10 @@ namespace {
return call_user_func_array('\PicoTools\Translator\translate', func_get_args()); return call_user_func_array('\PicoTools\Translator\translate', func_get_args());
} }
function dt() {
return call_user_func_array('\PicoTools\Translator\datetime', func_get_args());
}
} }