1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/freshrss_ynh.git synced 2024-09-03 18:36:33 +02:00

update sources to 1.2

This commit is contained in:
Clément 2015-11-06 16:54:20 +01:00
parent 9570274f13
commit 9d2f5fc4da
144 changed files with 5562 additions and 992 deletions

View file

@ -4,9 +4,4 @@ FreshRSS for YunoHost
* Site officiel : http://freshrss.org * Site officiel : http://freshrss.org
Changelog: Changelog:
* Update to FreshRSS 1.0 * Update to FreshRSS 1.2
* Admin user no more mandatory
* Only the data directory belongs to www-data
TODO:
* Finish Yunohost theme

View file

@ -1,5 +1,84 @@
# Changelog # Changelog
## 2015-11-03 FreshRSS 1.2.0 / 1.3.0-beta
* Features
* Share with Movim [#992](https://github.com/FreshRSS/FreshRSS/issues/992)
* New option to allow robots / search engines [#938](https://github.com/FreshRSS/FreshRSS/issues/938)
* Security
* Invalid logins now return HTTP 403, to be easier to catch (e.g. fail2ban) [#1015](https://github.com/FreshRSS/FreshRSS/issues/1015)
* UI
* Remove "title" field during installation [#858](https://github.com/FreshRSS/FreshRSS/issues/858)
* Visual alert on categories containing feeds in error [#984](https://github.com/FreshRSS/FreshRSS/pull/984)
* I18n
* Italian [#1003](https://github.com/FreshRSS/FreshRSS/issues/1003)
* Misc.
* Support reverse proxy [#975](https://github.com/FreshRSS/FreshRSS/issues/975)
* Make auto-update server URL alterable [#1019](https://github.com/FreshRSS/FreshRSS/issues/1019)
## 2015-09-12 FreshRSS 1.1.3-beta
* UI
* Configuration page for global settings such as limits [#958](https://github.com/FreshRSS/FreshRSS/pull/958)
* Add feed ID in articles to ease styling [#953](https://github.com/FreshRSS/FreshRSS/issues/953)
* I18n
* Dutch [#949](https://github.com/FreshRSS/FreshRSS/issues/949)
* Bug fixing
* Session cookie bug [#924](https://github.com/FreshRSS/FreshRSS/issues/924)
* Better error handling for PubSubHubbub [#939](https://github.com/FreshRSS/FreshRSS/issues/939)
* Fix tag search link from articles [#970](https://github.com/FreshRSS/FreshRSS/issues/970)
* Fix all quieries deleted when deleting a feed or category [#982](https://github.com/FreshRSS/FreshRSS/pull/982)
## 2015-07-30 FreshRSS 1.1.2-beta
* Features
* Support for PubSubHubbub for instant notifications from compatible Web sites. [#312](https://github.com/FreshRSS/FreshRSS/issues/312)
* cURL options to use a proxy for retrieving feeds. [#897](https://github.com/FreshRSS/FreshRSS/issues/897) [#675](https://github.com/FreshRSS/FreshRSS/issues/675)
* Allow anonymous users to create an account. [#679](https://github.com/FreshRSS/FreshRSS/issues/679)
* Security
* cURL options to verify or not SSL/TLS certificates (now enabled by default). [#897](https://github.com/FreshRSS/FreshRSS/issues/897) [#502](https://github.com/FreshRSS/FreshRSS/issues/502)
* Support for SSL connection to MySQL. [#868](https://github.com/FreshRSS/FreshRSS/issues/868)
* Workaround for browsers that have disabled support for `<form autocomplete="off">`. [#880](https://github.com/FreshRSS/FreshRSS/issues/880)
* UI
* Force UTF-8 for responses. [#870](https://github.com/FreshRSS/FreshRSS/issues/870)
* Increased pagination limit to 500 articles. [#872](https://github.com/FreshRSS/FreshRSS/issues/872)
* Improved UI for installation. [#855](https://github.com/FreshRSS/FreshRSS/issues/855)
* Misc.
* PHP 7 officially supported (~70% speed improvements on early tests). [#889](https://github.com/FreshRSS/FreshRSS/issues/889)
* Restore support for PHP 5.2.1+. [#214a5cc](https://github.com/Alkarex/FreshRSS/commit/214a5cc9a4c2b821961bc21f22b4b08e34b5be68) [#894](https://github.com/FreshRSS/FreshRSS/issues/894)
* Support for data-src for images of articles retrieved via the full-content module. [#877](https://github.com/FreshRSS/FreshRSS/issues/877)
* Add a couple of default feeds for fresh installations. [#886](https://github.com/FreshRSS/FreshRSS/issues/886)
* Changed some log visibilities. [#885](https://github.com/FreshRSS/FreshRSS/issues/885)
* Fix broken links for extension script / style files. [#862](https://github.com/FreshRSS/FreshRSS/issues/862)
* Load default configuration during installation to avoid hard-coded values. [#890](https://github.com/FreshRSS/FreshRSS/issues/890)
* Fix non-consistent behaviour in Minz_Request::getBaseUrl() and introduce Minz_Request::guessBaseUrl(). [#906](https://github.com/FreshRSS/FreshRSS/issues/906)
* Generate `base_url` during the installation and add a `pubsubhubbub_enabled` configuration key. [#865](https://github.com/FreshRSS/FreshRSS/issues/865)
* Load configuration by recursion to overwrite array values. [#923](https://github.com/FreshRSS/FreshRSS/issues/923)
* Cast `$limits` configuration values in integer. [#925](https://github.com/FreshRSS/FreshRSS/issues/925)
* Don't hide errors in configuration. [#920](https://github.com/FreshRSS/FreshRSS/issues/920)
## 2015-05-31 FreshRSS 1.1.1 (beta)
* Features
* New option to detect and mark updated articles as unread.
* Support for internationalized domain name (IDN).
* Improved logic for automatic deletion of old articles.
* API
* Work-around for News+ bug when there is no unread article on the server.
* UI
* New confirmation message when leaving a configuration page without saving the changes.
* Bug fixing
* Corrected bug introduced in previous beta about handling of HTTP 301 (feeds that have changed address)
* Corrected bug in FreshRSS RSS feeds.
* Security
* Sanitize HTTP request header `Host`.
* Misc.
* Attempt to better handle encoded article titles.
## 2015-01-31 FreshRSS 1.0.0 / 1.1.0 (beta) ## 2015-01-31 FreshRSS 1.0.0 / 1.1.0 (beta)
* UI * UI
@ -58,7 +137,7 @@
* Misc. * Misc.
* Add option to remove articles after reading them * Add option to remove articles after reading them
* Add comments * Add comments
* Refactor i18n system to not load unnecessary strings * Refactor i18n system to avoid loading unnecessary strings
* Fix security issue in Minz_Error::error() method * Fix security issue in Minz_Error::error() method
* Fix redirection after refreshing a given feed * Fix redirection after refreshing a given feed
@ -81,7 +160,7 @@
* I18n * I18n
* Introduce a new system for i18n keys (not finished yet) * Introduce a new system for i18n keys (not finished yet)
* Misc. * Misc.
* Fix global view (didn't work anymore) * Fix global view (did not work anymore)
* Add do_post_update for update system * Add do_post_update for update system
* Introduce ```checkInstallAction``` to test if FreshRSS installation is ok * Introduce ```checkInstallAction``` to test if FreshRSS installation is ok
@ -91,7 +170,7 @@
* UI * UI
* Add a space after tag icon * Add a space after tag icon
* Statistics * Statistics
* Add an average per day on the 30 day period graph * Add an average per day on the 30-day period graph
* Add percent of total on top 10 feed * Add percent of total on top 10 feed
* Bug fixes * Bug fixes
* Fix "mark as read" in global view * Fix "mark as read" in global view
@ -140,7 +219,7 @@
* Changed lazyload implementation * Changed lazyload implementation
* Support of HTML5 notifications for new upcoming articles * Support of HTML5 notifications for new upcoming articles
* Add option to stay logged in * Add option to stay logged in
* Bux fixes in export function, add/remove users, keyboard shortcuts, etc. * Bug fixes in export function, add/remove users, keyboard shortcuts, etc.
## 2014-07-21 FreshRSS 0.7.3 ## 2014-07-21 FreshRSS 0.7.3

57
sources/CONTRIBUTING.md Executable file
View file

@ -0,0 +1,57 @@
# How to contribute to FreshRSS?
## Join us on the mailing lists
Do you want to ask us some questions? Do you want to discuss with us? Don't hesitate to subscribe to our mailing lists!
- The first mailing is destined to generic information, it should be adapted to users. [Join mailing@freshrss.org](https://freshrss.org/mailman/listinfo/mailing).
- The second mailing is mainly for developers. [Join dev@freshrss.org](https://freshrss.org/mailman/listinfo/dev)
## Report a bug
You found a bug? Don't panic, here are some steps to report it easily:
1. Search for it on [the bug tracker](https://github.com/FreshRSS/FreshRSS/issues) (don't forget to use the search bar).
2. If you find a similar bug, don't hesitate to post a comment to add more importance to the related ticket.
3. If you didn't find it, [open a new ticket](https://github.com/FreshRSS/FreshRSS/issues/new).
If you have to create a new ticket, try to apply the following advices:
- Give an explicit title to the ticket so it will be easier to find it later.
- Be as exhaustive as possible in the description: what did you do? What is the bug? What are the steps to reproduce the bug?
- We also need some information:
+ Your FreshRSS version (on about page or `constants.php` file)
+ Your server configuration: type of hosting, PHP version
+ Your storage system (MySQL / MariaDB or SQLite)
+ If possible, the related logs (PHP logs and FreshRSS logs under `data/users/your_user/log.txt`)
## Fix a bug
Did you want to fix a bug? To keep a great coordination between collaborators, you will have to follow these indications:
1. Be sure the bug is associated to a ticket and say you work on it.
2. [Fork this project repository](https://help.github.com/articles/fork-a-repo/).
3. [Create a new branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/). The name of the branch must be explicit and being prefixed by the related ticket id. For instance, `783-contributing-file` to fix [ticket #783](https://github.com/FreshRSS/FreshRSS/issues/783).
4. Make your changes to your fork and [send a pull request](https://help.github.com/articles/using-pull-requests/) on the **dev branch**.
If you have to write code, please follow [our coding style recommendations](http://doc2.freshrss.org/en/Developer_documentation/First_steps/Coding_style).
**Tip:** if you are searching for bugs easy to fix, have a look at the « [New comers](https://github.com/FreshRSS/FreshRSS/labels/New%20comers) » ticket label.
## Submit an idea
You have great ideas, yes! Don't be shy and open [a new ticket](https://github.com/FreshRSS/FreshRSS/issues/new) on our bug tracker to ask if we can implement it. The greatest ideas often come from the shyest suggestions!
If your idea is nice, we'll have a look at it.
## Contribute to internationalization (i18n)
If you want to improve internationalization, please open a new ticket first and follow indications from « Fix a bug » section.
Translations are present in the subdirectories of `./app/i18n/`.
We are working on a better way to handle internationalization but don't hesitate to suggest any idea!
## Contribute to documentation
The documentation needs a lot of improvements in order to be more useful to new contributors and we are working on it. If you want to give some help, meet us on [the dedicated repository](https://github.com/FreshRSS/documentation)!

View file

@ -1,39 +0,0 @@
This is a credit file of people who have contributed to FreshRSS with, at least,
one commit on the FreshRSS repository (at https://github.com/FreshRSS/FreshRSS).
Please note a commit on THIS specific file is not considered as a contribution
(too easy!). It's purpose is to show even the smallest contribution is important.
People are sorted by name so please keep this order.
---
Alexandre Alapetite
https://github.com/Alkarex
Alexis Degrugillier
https://github.com/aledeg
Alwaysin
https://github.com/Alwaysin
Amaury Carrade
https://github.com/AmauryCarrade
ealdraed
https://github.com/ealdraed
Luc Didry
https://github.com/ldidry
Marien Fressinaud
dev@marienfressinaud.fr
http://marienfressinaud.fr
https://github.com/marienfressinaud
Nicolas Elie
https://github.com/nicolaselie
plopoyop
https://github.com/plopoyop
tomgue
https://github.com/tomgue

25
sources/CREDITS.md Executable file
View file

@ -0,0 +1,25 @@
This is a credit file of people who have [contributed to FreshRSS](https://github.com/FreshRSS/FreshRSS/graphs/contributors) with, at least,
one commit on the FreshRSS repository (at https://github.com/FreshRSS/FreshRSS).
Please note a commit on THIS specific file is not considered as a contribution
(too easy!). Its purpose is to show that even the smallest contribution is important.
People are sorted by name so please keep this order.
---
* [Alexandre Alapetite](https://github.com/Alkarex): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=Alkarex), [Web](http://alexandre.alapetite.fr/)
* [Alexis Degrugillier](https://github.com/aledeg): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=aledeg)
* [Alwaysin](https://github.com/Alwaysin): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=Alwaysin)
* [Amaury Carrade](https://github.com/AmauryCarrade): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=AmauryCarrade)
* [ealdraed](https://github.com/ealdraed): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=ealdraed)
* [Luc Didry](https://github.com/ldidry): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=ldidry)
* [Marcus Rohrmoser](https://github.com/mro):
[contributions](https://github.com/FreshRSS/FreshRSS/commits?author=mro)
* [Marien Fressinaud](https://github.com/marienfressinaud): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=marienfressinaud), [Web](http://marienfressinaud.fr/)
* [Melvyn Laïly](https://github.com/yaurthek): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=yaurthek)
* [Nicolas Elie](https://github.com/nicolaselie): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=nicolaselie)
* [plopoyop](https://github.com/plopoyop): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=plopoyop)
* [Tets42](https://github.com/Tets42):
[contributions](https://github.com/FreshRSS/FreshRSS/commits?author=Tets42)
* [thomasE1993](https://github.com/thomasE1993):
[contributions](https://github.com/FreshRSS/FreshRSS/commits?author=thomasE1993)
* [tomgue](https://github.com/tomgue): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=tomgue)

View file

@ -6,6 +6,7 @@ FreshRSS est un agrégateur de flux RSS à auto-héberger à limage de [Leed]
Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.
Il permet de gérer plusieurs utilisateurs, et dispose dun mode de lecture anonyme. Il permet de gérer plusieurs utilisateurs, et dispose dun mode de lecture anonyme.
Il supporte [PubSubHubbub](https://code.google.com/p/pubsubhubbub/) pour des notifications instantanées depuis les sites compatibles.
* Site officiel : http://freshrss.org * Site officiel : http://freshrss.org
* Démo : http://demo.freshrss.org/ * Démo : http://demo.freshrss.org/
@ -13,39 +14,73 @@ Il permet de gérer plusieurs utilisateurs, et dispose dun mode de lecture an
![Logo de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_title.png) ![Logo de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_title.png)
# Note sur les branches # Téléchargement
**Ce logiciel est encore en développement !** Veuillez vous assurer d'utiliser la branche qui vous correspond : Voir la [liste des versions](../../releases).
## Note sur les branches
**Ce logiciel est en développement permanent !** Veuillez vous assurer d'utiliser la branche qui vous correspond :
* Utilisez [la branche master](https://github.com/FreshRSS/FreshRSS/tree/master/) si vous visez la stabilité. * Utilisez [la branche master](https://github.com/FreshRSS/FreshRSS/tree/master/) si vous visez la stabilité.
* [La branche beta](https://github.com/FreshRSS/FreshRSS/tree/beta) est celle par défaut : les nouveautés y sont ajoutées environ tous les mois. * [La branche beta](https://github.com/FreshRSS/FreshRSS/tree/beta) est celle par défaut : les nouveautés y sont ajoutées environ tous les mois.
* Pour les développeurs et ceux qui savent ce qu'ils font, [la branche dev](https://github.com/FreshRSS/FreshRSS/tree/dev) vous ouvre les bras ! * Pour les développeurs et ceux qui veulent aider à tester les toutes dernières fonctionnalités, [la branche dev](https://github.com/FreshRSS/FreshRSS/tree/dev) vous ouvre les bras !
# Disclaimer # Avertissements
Cette application a été développée pour sadapter à des besoins personnels et non professionnels. Cette application a été développée pour sadapter principalement à des besoins personnels, et aucune garantie n'est fournie.
Je ne garantis en aucun cas la sécurité de celle-ci, ni son bon fonctionnement. Les demandes de fonctionnalités, rapports de bugs, et autres contributions sont les bienvenues. Privilégiez pour cela des [demandes sur GitHub](https://github.com/FreshRSS/FreshRSS/issues).
Je mengage néanmoins à répondre dans la mesure du possible aux demandes dévolution si celles-ci me semblent justifiées. Nous sommes une communauté amicale.
Privilégiez pour cela des demandes sur GitHub
(https://github.com/FreshRSS/FreshRSS/issues).
# Pré-requis # Prérequis
* Serveur modeste, par exemple sous Linux ou Windows * Serveur modeste, par exemple sous Linux ou Windows
* Fonctionne même sur un Raspberry Pi avec des temps de réponse < 1s (testé sur 150 flux, 22k articles, soit 32Mo de données partiellement compressées) * Fonctionne même sur un Raspberry Pi avec des temps de réponse < 1s (testé sur 150 flux, 22k articles, soit 32Mo de données partiellement compressées)
* Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres) * Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres)
* PHP 5.2.1+ (PHP 5.3.7+ recommandé) * PHP 5.2.1+ (PHP 5.3.7+ recommandé, et PHP 5.5+ pour les performances) (support bêta de PHP 7 avec encore meilleures performances)
* Requis : [PDO_MySQL](http://php.net/pdo-mysql) ou [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (seulement pour accès API sur platformes < 64 bits) * Requis : [PDO_MySQL](http://php.net/pdo-mysql) ou [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](http://php.net/intl.idn) (pour les noms de domaines internationalisés)
* Recommandés : [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [zlib](http://php.net/zlib), [Zip](http://php.net/zip) * Recommandés : [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [zlib](http://php.net/zlib), [Zip](http://php.net/zip)
* MySQL 5.0.3+ (recommandé) ou SQLite 3.7.4+ * MySQL 5.0.3+ (recommandé) ou SQLite 3.7.4+
* Un navigateur Web récent tel Firefox 4+, Chrome, Opera, Safari, Internet Explorer 9+ * Un navigateur Web récent tel Firefox, Chrome, Opera, Safari. [Internet Explorer ne fonctionne plus, mais ce sera corrigé](https://github.com/FreshRSS/FreshRSS/issues/772).
* Fonctionne aussi sur mobile * Fonctionne aussi sur mobile
![Capture décran de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_default-design.png) ![Capture décran de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_default-design.png)
# Installation # Installation
1. Récupérez lapplication FreshRSS via la commande git ou [en téléchargeant larchive](https://github.com/FreshRSS/FreshRSS/archive/master.zip) 1. Récupérez lapplication FreshRSS via la commande git ou [en téléchargeant larchive](../releases)
2. Placez lapplication sur votre serveur (la partie à exposer au Web est le répertoire `./p/`) 2. Placez lapplication sur votre serveur (la partie à exposer au Web est le répertoire `./p/`)
3. Le serveur Web doit avoir les droits décriture dans le répertoire `./data/` 3. Le serveur Web doit avoir les droits décriture dans le répertoire `./data/`
4. Accédez à FreshRSS à travers votre navigateur Web et suivez les instructions dinstallation 4. Accédez à FreshRSS à travers votre navigateur Web et suivez les instructions dinstallation
5. Tout devrait fonctionner :) En cas de problème, nhésitez pas à me contacter. 5. Tout devrait fonctionner :) En cas de problème, nhésitez pas à me contacter.
6. Des paramètres de configuration avancée peuvent être accédés depuis [config.php](./data/config.default.php).
## Exemple dinstallation complète sur Linux Debian/Ubuntu
```sh
# Si vous utilisez le serveur Web Apache (sinon il faut un autre serveur Web)
sudo apt-get install apache2
sudo a2enmod headers expires rewrite ssl
# (optionnel) Si vous voulez un serveur de base de données MySQL
sudo apt-get install mysql-server mysql-client php5-mysql
# Composants principaux (git est optionnel si vous déployez manuellement les fichiers dinstallation)
sudo apt-get install git php5 php5-curl php5-gd php5-intl php5-json php5-gmp php5-sqlite
# Redémarrage du serveur Web
sudo service apache2 restart
# Pour FreshRSS lui-même
cd /usr/share/
sudo git clone https://github.com/FreshRSS/FreshRSS.git
# Mettre les droits daccès pour le serveur Web
cd FreshRSS
sudo chown -R :www-data .
sudo chmod -R g+w ./data/
# Publier FreshRSS dans votre répertoire HTML public
sudo ln -s /usr/share/FreshRSS/p /var/www/html/FreshRSS
# Naviguez vers http://example.net/FreshRSS pour terminer linstallation.
# (Si vous le faite depuis localhost, vous pourrez avoir à ajuster le réglage de votre adresse publique)
# Mettre à jour FreshRSS vers une nouvelle version
cd /usr/share/FreshRSS
sudo git reset --hard
sudo git pull
sudo chown -R :www-data .
sudo chmod -R g+w ./data/
```
# Contrôle daccès # Contrôle daccès
Il est requis pour le mode multi-utilisateur, et recommandé dans tous les cas, de limiter laccès à votre FreshRSS. Au choix : Il est requis pour le mode multi-utilisateur, et recommandé dans tous les cas, de limiter laccès à votre FreshRSS. Au choix :
@ -62,7 +97,7 @@ Cest une bonne idée dutiliser le même utilisateur que votre serveur Web
Par exemple, pour exécuter le script toutes les heures : Par exemple, pour exécuter le script toutes les heures :
``` ```
7 * * * * php /chemin/vers/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1 7 * * * * php /votre-chemin/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1
``` ```
# Conseils # Conseils
@ -74,7 +109,7 @@ Par exemple, pour exécuter le script toutes les heures :
# Sauvegarde # Sauvegarde
* Il faut conserver vos fichiers `./data/config.php` ainsi que `./data/*_user.php` et éventuellement `./data/persona/` * Il faut conserver vos fichiers `./data/config.php` ainsi que `./data/*_user.php` et éventuellement `./data/persona/`
* Vous pouvez exporter votre liste de flux depuis FreshRSS au format OPML * Vous pouvez exporter votre liste de flux depuis FreshRSS au format OPML
* Pour sauvegarder les articles eux-même, vous pouvez utiliser [phpMyAdmin](http://www.phpmyadmin.net) ou les outils de MySQL : * Pour sauvegarder les articles eux-mêmes, vous pouvez utiliser [phpMyAdmin](http://www.phpmyadmin.net) ou les outils de MySQL :
```bash ```bash
mysqldump -u utilisateur -p --databases freshrss > freshrss.sql mysqldump -u utilisateur -p --databases freshrss > freshrss.sql

View file

@ -1,11 +1,12 @@
* [Version française](README.fr.md) * [Version française](README.fr.md)
# FreshRSS # FreshRSS
FreshRSS is a self-hosted RSS feed agregator like [Leed](http://projet.idleman.fr/leed/) or [Kriss Feed](http://tontof.net/kriss/feed/). FreshRSS is a self-hosted RSS feed aggregator such as [Leed](http://projet.idleman.fr/leed/) or [Kriss Feed](http://tontof.net/kriss/feed/).
It is at the same time light-weight, easy to work with, powerful and customizable. It is at the same time lightweight, easy to work with, powerful and customizable.
It is a multi-user application with an anonymous reading mode. It is a multi-user application with an anonymous reading mode.
It supports [PubSubHubbub](https://code.google.com/p/pubsubhubbub/) for instant notifications from compatible Web sites.
* Official website: http://freshrss.org * Official website: http://freshrss.org
* Demo: http://demo.freshrss.org/ * Demo: http://demo.freshrss.org/
@ -13,29 +14,30 @@ It is a multi-user application with an anonymous reading mode.
![FreshRSS logo](http://marienfressinaud.fr/data/images/freshrss/freshrss_title.png) ![FreshRSS logo](http://marienfressinaud.fr/data/images/freshrss/freshrss_title.png)
# Note on branches # Releases
**This application is still in development!** Please use the branch that suits your needs: See the [list of releases](../../releases).
## Note on branches
**This application is under continuous development!** Please use the branch that suits your needs:
* Use [the master branch](https://github.com/FreshRSS/FreshRSS/tree/master/) if you need a stable version. * Use [the master branch](https://github.com/FreshRSS/FreshRSS/tree/master/) if you need a stable version.
* [The beta branch](https://github.com/FreshRSS/FreshRSS/tree/beta) is the default branch: new features are added on a monthly basis. * [The beta branch](https://github.com/FreshRSS/FreshRSS/tree/beta) is the default branch: new features are added on a monthly basis.
* For developers and tech savvy persons, [the dev branch](https://github.com/FreshRSS/FreshRSS/tree/dev) is waiting for you! * For developers and tech savvy persons willing to help testing the latest features, [the dev branch](https://github.com/FreshRSS/FreshRSS/tree/dev) is waiting for you!
# Disclaimer # Disclaimer
This application was developed to fulfill personal needs not professional needs. This application was developed to fulfil personal needs primarily, and comes with absolutely no warranty.
There is no guarantee neither on its security nor its proper functioning. Feature requests, bug reports, and other contributions are welcome. The best way is to [open issues on GitHub](https://github.com/FreshRSS/FreshRSS/issues).
If there is feature requests which I think are good for the project, I'll do my best to include them. We are a friendly community.
The best way is to open issues on GitHub
(https://github.com/FreshRSS/FreshRSS/issues).
# Requirements # Requirements
* Light server running Linux or Windows * Light server running Linux or Windows
* It even works on Raspberry Pi with response time under a second (tested with 150 feeds, 22k articles, or 32Mo of compressed data) * It even works on Raspberry Pi with response time under a second (tested with 150 feeds, 22k articles, or 32Mo of compressed data)
* A web server: Apache2 (recommanded), nginx, lighttpd (not tested on others) * A web server: Apache2 (recommended), nginx, lighttpd (not tested on others)
* PHP 5.2.1+ (PHP 5.3.7+ recommanded) * PHP 5.2.1+ (PHP 5.3.7+ recommended, and PHP 5.5+ for performance) (beta support for PHP 7 with even higher performance)
* Required extensions: [PDO_MySQL](http://php.net/pdo-mysql) or [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (only for API access on platforms under 64 bits) * Required extensions: [PDO_MySQL](http://php.net/pdo-mysql) or [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names)
* Recommanded extensions : [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [zlib](http://php.net/zlib), [Zip](http://php.net/zip) * Recommended extensions: [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [zlib](http://php.net/zlib), [Zip](http://php.net/zip)
* MySQL 5.0.3+ (recommanded) or SQLite 3.7.4+ * MySQL 5.0.3+ (recommended) or SQLite 3.7.4+
* A recent browser like Firefox 4+, Chrome, Opera, Safari, Internet Explorer 9+ * A recent browser like Firefox, Chrome, Opera, Safari. [Internet Explorer currently not supported, but support will come back](https://github.com/FreshRSS/FreshRSS/issues/772).
* Works on mobile * Works on mobile
![FreshRSS screenshot](http://marienfressinaud.fr/data/images/freshrss/freshrss_default-design.png) ![FreshRSS screenshot](http://marienfressinaud.fr/data/images/freshrss/freshrss_default-design.png)
@ -45,7 +47,40 @@ The best way is to open issues on GitHub
2. Dump the application on your server (expose only the `./p/` folder) 2. Dump the application on your server (expose only the `./p/` folder)
3. Add write access on `./data/` folder to the webserver user 3. Add write access on `./data/` folder to the webserver user
4. Access FreshRSS with your browser and follow the installation process 4. Access FreshRSS with your browser and follow the installation process
5. Every thing should be working :) If you encounter any problem, feel free to contact me. 5. Everything should be working :) If you encounter any problem, feel free to contact me.
6. Advanced configuration settings can be seen in [config.php](./data/config.default.php).
## Example of full installation on Linux Debian/Ubuntu
```sh
# If you use an Apache Web server (otherwise you need another Web server)
sudo apt-get install apache2
sudo a2enmod headers expires rewrite ssl
# (Optional) If you want a MySQL database server
sudo apt-get install mysql-server mysql-client php5-mysql
# Main components (git is optional if you manually download the installation files)
sudo apt-get install git php5 php5-curl php5-gd php5-intl php5-json php5-gmp php5-sqlite
# Restart Web server
sudo service apache2 restart
# For FreshRSS itself
cd /usr/share/
sudo git clone https://github.com/FreshRSS/FreshRSS.git
# Set the rights so that your Web browser can access the files
cd FreshRSS
sudo chown -R :www-data .
sudo chmod -R g+w ./data/
# Publish FreshRSS in your public HTML directory
sudo ln -s /usr/share/FreshRSS/p /var/www/html/FreshRSS
# Navigate to http://example.net/FreshRSS to complete the installation.
# (If you do it from localhost, you may have to adjust the setting of your public address later)
# Update to a newer version of FreshRSS
cd /usr/share/FreshRSS
sudo git reset --hard
sudo git pull
sudo chown -R :www-data .
sudo chmod -R g+w ./data/
```
# Access control # Access control
It is needed for the multi-user mode to limit access to FreshRSS. You can: It is needed for the multi-user mode to limit access to FreshRSS. You can:
@ -58,18 +93,18 @@ It is needed for the multi-user mode to limit access to FreshRSS. You can:
# Automatic feed update # Automatic feed update
* You can add a Cron job to launch the update script. * You can add a Cron job to launch the update script.
Check the Cron documentation related to your distribution ([Debian/Ubuntu](https://help.ubuntu.com/community/CronHowto), [Red Hat/Fedora](https://fedoraproject.org/wiki/Administration_Guide_Draft/Cron), [Slackware](http://docs.slackware.com/fr:slackbook:process_control?#cron), [Gentoo](https://wiki.gentoo.org/wiki/Cron), [Arch Linux](https://wiki.archlinux.org/index.php/Cron)…). Check the Cron documentation related to your distribution ([Debian/Ubuntu](https://help.ubuntu.com/community/CronHowto), [Red Hat/Fedora](https://fedoraproject.org/wiki/Administration_Guide_Draft/Cron), [Slackware](http://docs.slackware.com/fr:slackbook:process_control?#cron), [Gentoo](https://wiki.gentoo.org/wiki/Cron), [Arch Linux](https://wiki.archlinux.org/index.php/Cron)…).
Its a good idea to use the web server user . Its a good idea to use the Web server user.
For example, if you want to run the script every hour: For example, if you want to run the script every hour:
``` ```
7 * * * * php /chemin/vers/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1 7 * * * * php /your-path/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1
``` ```
# Advices # Advices
* For a better security, expose only the `./p/` folder on the web. * For a better security, expose only the `./p/` folder on the web.
* Be aware that the `./data/` folder contains all personal data, so it is a bad idea to expose it. * Be aware that the `./data/` folder contains all personal data, so it is a bad idea to expose it.
* The `./constants.php` file defines access to application folder. If you want to customize your installation, every thing happens here. * The `./constants.php` file defines access to application folder. If you want to customize your installation, every thing happens here.
* If you encounter any problem, logs are accessibles from the interface or manually in `./data/log/*.log` files. * If you encounter any problem, logs are accessible from the interface or manually in `./data/log/*.log` files.
# Backup # Backup
* You need to keep `./data/config.php`, `./data/*_user.php` and `./data/persona/` files * You need to keep `./data/config.php`, `./data/*_user.php` and `./data/persona/` files

View file

@ -123,8 +123,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
$conf = get_user_configuration($username); $conf = get_user_configuration($username);
if (is_null($conf)) { if (is_null($conf)) {
Minz_Request::bad(_t('feedback.auth.login.invalid'), Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false);
array('c' => 'auth', 'a' => 'login')); return;
} }
$ok = FreshRSS_FormAuth::checkCredentials( $ok = FreshRSS_FormAuth::checkCredentials(
@ -151,8 +151,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
' user=' . $username . ' user=' . $username .
', nonce=' . $nonce . ', nonce=' . $nonce .
', c=' . $challenge); ', c=' . $challenge);
Minz_Request::bad(_t('feedback.auth.login.invalid'), Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false);
array('c' => 'auth', 'a' => 'login'));
} }
} elseif (FreshRSS_Context::$system_conf->unsafe_autologin_enabled) { } elseif (FreshRSS_Context::$system_conf->unsafe_autologin_enabled) {
$username = Minz_Request::param('u', ''); $username = Minz_Request::param('u', '');
@ -184,8 +183,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
array('c' => 'index', 'a' => 'index')); array('c' => 'index', 'a' => 'index'));
} else { } else {
Minz_Log::warning('Unsafe password mismatch for user ' . $username); Minz_Log::warning('Unsafe password mismatch for user ' . $username);
Minz_Request::bad(_t('feedback.auth.login.invalid'), Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false);
array('c' => 'auth', 'a' => 'login'));
} }
} }
} }
@ -253,7 +251,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
FreshRSS_Auth::giveAccess(); FreshRSS_Auth::giveAccess();
invalidateHttpCache(); invalidateHttpCache();
} else { } else {
Minz_Log::error($reason); Minz_Log::warning($reason);
$res = array(); $res = array();
$res['status'] = 'failure'; $res['status'] = 'failure';
@ -346,4 +344,15 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
} }
} }
} }
/**
* This action gives possibility to a user to create an account.
*/
public function registerAction() {
if (max_registrations_reached()) {
Minz_Error::error(403);
}
Minz_View::prependTitle(_t('gen.auth.registration.title') . ' · ');
}
} }

View file

@ -112,6 +112,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
FreshRSS_Context::$user_conf->sticky_post = Minz_Request::param('sticky_post', false); FreshRSS_Context::$user_conf->sticky_post = Minz_Request::param('sticky_post', false);
FreshRSS_Context::$user_conf->reading_confirm = Minz_Request::param('reading_confirm', false); FreshRSS_Context::$user_conf->reading_confirm = Minz_Request::param('reading_confirm', false);
FreshRSS_Context::$user_conf->auto_remove_article = Minz_Request::param('auto_remove_article', false); FreshRSS_Context::$user_conf->auto_remove_article = Minz_Request::param('auto_remove_article', false);
FreshRSS_Context::$user_conf->mark_updated_article_unread = Minz_Request::param('mark_updated_article_unread', false);
FreshRSS_Context::$user_conf->sort_order = Minz_Request::param('sort_order', 'DESC'); FreshRSS_Context::$user_conf->sort_order = Minz_Request::param('sort_order', 'DESC');
FreshRSS_Context::$user_conf->mark_when = array( FreshRSS_Context::$user_conf->mark_when = array(
'article' => Minz_Request::param('mark_open_article', false), 'article' => Minz_Request::param('mark_open_article', false),
@ -241,13 +242,16 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
* checking if categories and feeds are still in use. * checking if categories and feeds are still in use.
*/ */
public function queriesAction() { public function queriesAction() {
$category_dao = new FreshRSS_CategoryDAO();
$feed_dao = FreshRSS_Factory::createFeedDao();
if (Minz_Request::isPost()) { if (Minz_Request::isPost()) {
$queries = Minz_Request::param('queries', array()); $params = Minz_Request::param('queries', array());
foreach ($queries as $key => $query) { foreach ($params as $key => $query) {
if (!$query['name']) { if (!$query['name']) {
$query['name'] = _t('conf.query.number', $key + 1); $query['name'] = _t('conf.query.number', $key + 1);
} }
$queries[] = new FreshRSS_UserQuery($query, $feed_dao, $category_dao);
} }
FreshRSS_Context::$user_conf->queries = $queries; FreshRSS_Context::$user_conf->queries = $queries;
FreshRSS_Context::$user_conf->save(); FreshRSS_Context::$user_conf->save();
@ -255,62 +259,9 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
Minz_Request::good(_t('feedback.conf.updated'), Minz_Request::good(_t('feedback.conf.updated'),
array('c' => 'configure', 'a' => 'queries')); array('c' => 'configure', 'a' => 'queries'));
} else { } else {
$this->view->query_get = array(); $this->view->queries = array();
$cat_dao = new FreshRSS_CategoryDAO();
$feed_dao = FreshRSS_Factory::createFeedDao();
foreach (FreshRSS_Context::$user_conf->queries as $key => $query) { foreach (FreshRSS_Context::$user_conf->queries as $key => $query) {
if (!isset($query['get'])) { $this->view->queries[$key] = new FreshRSS_UserQuery($query, $feed_dao, $category_dao);
continue;
}
switch ($query['get'][0]) {
case 'c':
$category = $cat_dao->searchById(substr($query['get'], 2));
$deprecated = true;
$cat_name = '';
if ($category) {
$cat_name = $category->name();
$deprecated = false;
}
$this->view->query_get[$key] = array(
'type' => 'category',
'name' => $cat_name,
'deprecated' => $deprecated,
);
break;
case 'f':
$feed = $feed_dao->searchById(substr($query['get'], 2));
$deprecated = true;
$feed_name = '';
if ($feed) {
$feed_name = $feed->name();
$deprecated = false;
}
$this->view->query_get[$key] = array(
'type' => 'feed',
'name' => $feed_name,
'deprecated' => $deprecated,
);
break;
case 's':
$this->view->query_get[$key] = array(
'type' => 'favorite',
'name' => 'favorite',
'deprecated' => false,
);
break;
case 'a':
$this->view->query_get[$key] = array(
'type' => 'all',
'name' => 'all',
'deprecated' => false,
);
break;
}
} }
} }
@ -325,20 +276,56 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
* lean data. * lean data.
*/ */
public function addQueryAction() { public function addQueryAction() {
$whitelist = array('get', 'order', 'name', 'search', 'state'); $category_dao = new FreshRSS_CategoryDAO();
$queries = FreshRSS_Context::$user_conf->queries; $feed_dao = FreshRSS_Factory::createFeedDao();
$query = Minz_Request::params(); $queries = array();
$query['name'] = _t('conf.query.number', count($queries) + 1); foreach (FreshRSS_Context::$user_conf->queries as $key => $query) {
foreach ($query as $key => $value) { $queries[$key] = new FreshRSS_UserQuery($query, $feed_dao, $category_dao);
if (!in_array($key, $whitelist)) {
unset($query[$key]);
}
} }
$queries[] = $query; $params = Minz_Request::params();
$params['url'] = Minz_Url::display(array('params' => $params));
$params['name'] = _t('conf.query.number', count($queries) + 1);
$queries[] = new FreshRSS_UserQuery($params, $feed_dao, $category_dao);
FreshRSS_Context::$user_conf->queries = $queries; FreshRSS_Context::$user_conf->queries = $queries;
FreshRSS_Context::$user_conf->save(); FreshRSS_Context::$user_conf->save();
Minz_Request::good(_t('feedback.conf.query_created', $query['name']), Minz_Request::good(_t('feedback.conf.query_created', $query['name']),
array('c' => 'configure', 'a' => 'queries')); array('c' => 'configure', 'a' => 'queries'));
} }
/**
* This action handles the system configuration page.
*
* It displays the system configuration page.
* If this action is reach through a POST request, it stores all new
* configuration values then sends a notification to the user.
*
* The options available on the page are:
* - user limit (default: 1)
* - user category limit (default: 16384)
* - user feed limit (default: 16384)
*/
public function systemAction() {
if (!FreshRSS_Auth::hasAccess('admin')) {
Minz_Error::error(403);
}
if (Minz_Request::isPost()) {
$limits = FreshRSS_Context::$system_conf->limits;
$limits['max_registrations'] = Minz_Request::param('max-registrations', 1);
$limits['max_feeds'] = Minz_Request::param('max-feeds', 16384);
$limits['max_categories'] = Minz_Request::param('max-categories', 16384);
FreshRSS_Context::$system_conf->limits = $limits;
FreshRSS_Context::$system_conf->title = Minz_Request::param('instance-name', 'FreshRSS');
FreshRSS_Context::$system_conf->auto_update_url = Minz_Request::param('auto-update-url', false);
FreshRSS_Context::$system_conf->save();
invalidateHttpCache();
Minz_Session::_param('notification', array(
'type' => 'good',
'content' => _t('feedback.conf.updated')
));
}
}
} }

View file

@ -98,10 +98,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// HTTP information are useful if feed is protected behind a // HTTP information are useful if feed is protected behind a
// HTTP authentication // HTTP authentication
$user = Minz_Request::param('http_user'); $user = trim(Minz_Request::param('http_user', ''));
$pass = Minz_Request::param('http_pass'); $pass = Minz_Request::param('http_pass', '');
$http_auth = ''; $http_auth = '';
if ($user != '' || $pass != '') { if ($user != '' && $pass != '') { //TODO: Sanitize
$http_auth = $user . ':' . $pass; $http_auth = $user . ':' . $pass;
} }
@ -145,8 +145,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// Call the extension hook // Call the extension hook
$name = $feed->name(); $name = $feed->name();
$feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed);
if (is_null($feed)) { if ($feed === null) {
Minz_Request::bad(_t('feed_not_added', $name), $url_redirect); Minz_Request::bad(_t('feedback.sub.feed.not_added', $name), $url_redirect);
} }
$values = array( $values = array(
@ -168,6 +168,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// Ok, feed has been added in database. Now we have to refresh entries. // Ok, feed has been added in database. Now we have to refresh entries.
$feed->_id($id); $feed->_id($id);
$feed->faviconPrepare(); $feed->faviconPrepare();
//$feed->pubSubHubbubPrepare(); //TODO: prepare PubSubHubbub already when adding the feed
$is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
@ -181,7 +182,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// Use a shared statement and a transaction to improve a LOT the // Use a shared statement and a transaction to improve a LOT the
// performances. // performances.
$prepared_statement = $entryDAO->addEntryPrepare();
$feedDAO->beginTransaction(); $feedDAO->beginTransaction();
foreach ($entries as $entry) { foreach ($entries as $entry) {
// Entries are added without any verification. // Entries are added without any verification.
@ -190,13 +190,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$entry->_isRead($is_read); $entry->_isRead($is_read);
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
if (is_null($entry)) { if ($entry === null) {
// An extension has returned a null value, there is nothing to insert. // An extension has returned a null value, there is nothing to insert.
continue; continue;
} }
$values = $entry->toArray(); $values = $entry->toArray();
$entryDAO->addEntry($values, $prepared_statement); $entryDAO->addEntry($values);
} }
$feedDAO->updateLastUpdate($feed->id()); $feedDAO->updateLastUpdate($feed->id());
$feedDAO->commit(); $feedDAO->commit();
@ -262,12 +262,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
* This action actualizes entries from one or several feeds. * This action actualizes entries from one or several feeds.
* *
* Parameters are: * Parameters are:
* - id (default: false) * - id (default: false): Feed ID
* - url (default: false): Feed URL
* - force (default: false) * - force (default: false)
* If id is not specified, all the feeds are actualized. But if force is * If id and url are not specified, all the feeds are actualized. But if force is
* false, process stops at 10 feeds to avoid time execution problem. * false, process stops at 10 feeds to avoid time execution problem.
*/ */
public function actualizeAction() { public function actualizeAction($simplePiePush = null) {
@set_time_limit(300); @set_time_limit(300);
$feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO = FreshRSS_Factory::createFeedDao();
@ -275,14 +276,15 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
Minz_Session::_param('actualize_feeds', false); Minz_Session::_param('actualize_feeds', false);
$id = Minz_Request::param('id'); $id = Minz_Request::param('id');
$url = Minz_Request::param('url');
$force = Minz_Request::param('force'); $force = Minz_Request::param('force');
// Create a list of feeds to actualize. // Create a list of feeds to actualize.
// If id is set and valid, corresponding feed is added to the list but // If id is set and valid, corresponding feed is added to the list but
// alone in order to automatize further process. // alone in order to automatize further process.
$feeds = array(); $feeds = array();
if ($id) { if ($id || $url) {
$feed = $feedDAO->searchById($id); $feed = $id ? $feedDAO->searchById($id) : $feedDAO->searchByUrl($url);
if ($feed) { if ($feed) {
$feeds[] = $feed; $feeds[] = $feed;
} }
@ -294,25 +296,41 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1);
$date_min = time() - (3600 * 24 * 30 * $nb_month_old); $date_min = time() - (3600 * 24 * 30 * $nb_month_old);
// PubSubHubbub support
$pubsubhubbubEnabledGeneral = FreshRSS_Context::$system_conf->pubsubhubbub_enabled;
$pshbMinAge = time() - (3600 * 24); //TODO: Make a configuration.
$updated_feeds = 0; $updated_feeds = 0;
$is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
foreach ($feeds as $feed) { foreach ($feeds as $feed) {
$url = $feed->url(); //For detection of HTTP 301
$pubSubHubbubEnabled = $pubsubhubbubEnabledGeneral && $feed->pubSubHubbubEnabled();
if ((!$simplePiePush) && (!$id) && $pubSubHubbubEnabled && ($feed->lastUpdate() > $pshbMinAge)) {
//$text = 'Skip pull of feed using PubSubHubbub: ' . $url;
//Minz_Log::debug($text);
//file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
continue; //When PubSubHubbub is used, do not pull refresh so often
}
if (!$feed->lock()) { if (!$feed->lock()) {
Minz_Log::notice('Feed already being actualized: ' . $feed->url()); Minz_Log::notice('Feed already being actualized: ' . $feed->url());
continue; continue;
} }
try { try {
// Load entries if ($simplePiePush) {
$feed->load(false); $feed->loadEntries($simplePiePush); //Used by PubSubHubbub
} else {
$feed->load(false);
}
} catch (FreshRSS_Feed_Exception $e) { } catch (FreshRSS_Feed_Exception $e) {
Minz_Log::notice($e->getMessage()); Minz_Log::warning($e->getMessage());
$feedDAO->updateLastUpdate($feed->id(), 1); $feedDAO->updateLastUpdate($feed->id(), true);
$feed->unlock(); $feed->unlock();
continue; continue;
} }
$url = $feed->url();
$feed_history = $feed->keepHistory(); $feed_history = $feed->keepHistory();
if ($feed_history == -2) { if ($feed_history == -2) {
// TODO: -2 must be a constant! // TODO: -2 must be a constant!
@ -323,49 +341,74 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
// We want chronological order and SimplePie uses reverse order. // We want chronological order and SimplePie uses reverse order.
$entries = array_reverse($feed->entries()); $entries = array_reverse($feed->entries());
if (count($entries) > 0) { if (count($entries) > 0) {
// For this feed, check last n entry GUIDs already in database. $newGuids = array();
$existing_guids = array_fill_keys($entryDAO->listLastGuidsByFeed( foreach ($entries as $entry) {
$feed->id(), count($entries) + 10 $newGuids[] = $entry->guid();
), 1); }
$use_declared_date = empty($existing_guids); // For this feed, check existing GUIDs already in database.
$existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids);
unset($newGuids);
$oldGuids = array();
// Add entries in database if possible. // Add entries in database if possible.
$prepared_statement = $entryDAO->addEntryPrepare();
$feedDAO->beginTransaction();
foreach ($entries as $entry) { foreach ($entries as $entry) {
$entry_date = $entry->date(true); $entry_date = $entry->date(true);
if (isset($existing_guids[$entry->guid()]) || if (isset($existingHashForGuids[$entry->guid()])) {
($feed_history == 0 && $entry_date < $date_min)) { $existingHash = $existingHashForGuids[$entry->guid()];
// This entry already exists in DB or should not be added if (strcasecmp($existingHash, $entry->hash()) === 0 || $existingHash === '00000000000000000000000000000000') {
// considering configuration and date. //This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3
continue; $oldGuids[] = $entry->guid();
} else { //This entry already exists but has been updated
Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() .
', old hash ' . $existingHash . ', new hash ' . $entry->hash());
//TODO: Make an updated/is_read policy by feed, in addition to the global one.
$entry->_isRead(FreshRSS_Context::$user_conf->mark_updated_article_unread ? false : null); //Change is_read according to policy.
if (!$entryDAO->hasTransaction()) {
$entryDAO->beginTransaction();
}
$entryDAO->updateEntry($entry->toArray());
}
} elseif ($feed_history == 0 && $entry_date < $date_min) {
// This entry should not be added considering configuration and date.
$oldGuids[] = $entry->guid();
} else {
if ($entry_date < $date_min) {
$id = min(time(), $entry_date) . uSecString();
$entry->_isRead(true); //Old article that was not in database. Probably an error, so mark as read
} else {
$id = uTimeString();
$entry->_isRead($is_read);
}
$entry->_id($id);
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
if ($entry === null) {
// An extension has returned a null value, there is nothing to insert.
continue;
}
if ($pubSubHubbubEnabled && !$simplePiePush) { //We use push, but have discovered an article by pull!
$text = 'An article was discovered by pull although we use PubSubHubbub!: Feed ' . $url . ' GUID ' . $entry->guid();
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
Minz_Log::warning($text);
$pubSubHubbubEnabled = false;
$feed->pubSubHubbubError(true);
}
if (!$entryDAO->hasTransaction()) {
$entryDAO->beginTransaction();
}
$entryDAO->addEntry($entry->toArray());
} }
$id = uTimeString();
if ($use_declared_date || $entry_date < $date_min) {
// Use declared date at first import.
$id = min(time(), $entry_date) . uSecString();
}
$entry->_id($id);
$entry->_isRead($is_read);
$entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
if (is_null($entry)) {
// An extension has returned a null value, there is nothing to insert.
continue;
}
$values = $entry->toArray();
$entryDAO->addEntry($values, $prepared_statement);
} }
$entryDAO->updateLastSeen($feed->id(), $oldGuids);
} }
if ($feed_history >= 0 && rand(0, 30) === 1) { if ($feed_history >= 0 && rand(0, 30) === 1) {
// TODO: move this function in web cron when available (see entry::purge) // TODO: move this function in web cron when available (see entry::purge)
// Remove old entries once in 30. // Remove old entries once in 30.
if (!$feedDAO->hasTransaction()) { if (!$entryDAO->hasTransaction()) {
$feedDAO->beginTransaction(); $entryDAO->beginTransaction();
} }
$nb = $feedDAO->cleanOldEntries($feed->id(), $nb = $feedDAO->cleanOldEntries($feed->id(),
@ -377,18 +420,37 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
} }
} }
$feedDAO->updateLastUpdate($feed->id(), 0, $feedDAO->hasTransaction()); $feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->hasTransaction());
if ($feedDAO->hasTransaction()) { if ($entryDAO->hasTransaction()) {
$feedDAO->commit(); $entryDAO->commit();
} }
if ($feed->url() !== $url) { if ($feed->hubUrl() && $feed->selfUrl()) { //selfUrl has priority for PubSubHubbub
// HTTP 301 Moved Permanently if ($feed->selfUrl() !== $url) { //https://code.google.com/p/pubsubhubbub/wiki/MovingFeedsOrChangingHubs
$selfUrl = checkUrl($feed->selfUrl());
if ($selfUrl) {
Minz_Log::debug('PubSubHubbub unsubscribe ' . $feed->url());
if (!$feed->pubSubHubbubSubscribe(false)) { //Unsubscribe
Minz_Log::warning('Error while PubSubHubbub unsubscribing from ' . $feed->url());
}
$feed->_url($selfUrl, false);
Minz_Log::notice('Feed ' . $url . ' canonical address moved to ' . $feed->url());
$feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
}
}
}
elseif ($feed->url() !== $url) { // HTTP 301 Moved Permanently
Minz_Log::notice('Feed ' . $url . ' moved permanently to ' . $feed->url()); Minz_Log::notice('Feed ' . $url . ' moved permanently to ' . $feed->url());
$feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); $feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
} }
$feed->faviconPrepare(); $feed->faviconPrepare();
if ($pubsubhubbubEnabledGeneral && $feed->pubSubHubbubPrepare()) {
Minz_Log::notice('PubSubHubbub subscribe ' . $feed->url());
if (!$feed->pubSubHubbubSubscribe(true)) { //Subscribe
Minz_Log::warning('Error while PubSubHubbub subscribing to ' . $feed->url());
}
}
$feed->unlock(); $feed->unlock();
$updated_feeds++; $updated_feeds++;
unset($feed); unset($feed);
@ -411,20 +473,20 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
Minz_Session::_param('notification', $notif); Minz_Session::_param('notification', $notif);
// No layout in ajax request. // No layout in ajax request.
$this->view->_useLayout(false); $this->view->_useLayout(false);
return;
}
// Redirect to the main page with correct notification.
if ($updated_feeds === 1) {
$feed = reset($feeds);
Minz_Request::good(_t('feedback.sub.feed.actualized', $feed->name()), array(
'params' => array('get' => 'f_' . $feed->id())
));
} elseif ($updated_feeds > 1) {
Minz_Request::good(_t('feedback.sub.feed.n_actualized', $updated_feeds), array());
} else { } else {
Minz_Request::good(_t('feedback.sub.feed.no_refresh'), array()); // Redirect to the main page with correct notification.
if ($updated_feeds === 1) {
$feed = reset($feeds);
Minz_Request::good(_t('feedback.sub.feed.actualized', $feed->name()), array(
'params' => array('get' => 'f_' . $feed->id())
));
} elseif ($updated_feeds > 1) {
Minz_Request::good(_t('feedback.sub.feed.n_actualized', $updated_feeds), array());
} else {
Minz_Request::good(_t('feedback.sub.feed.no_refresh'), array());
}
} }
return $updated_feeds;
} }
/** /**

View file

@ -47,7 +47,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$status_file = $file['error']; $status_file = $file['error'];
if ($status_file !== 0) { if ($status_file !== 0) {
Minz_Log::error('File cannot be uploaded. Error code: ' . $status_file); Minz_Log::warning('File cannot be uploaded. Error code: ' . $status_file);
Minz_Request::bad(_t('feedback.import_export.file_cannot_be_uploaded'), Minz_Request::bad(_t('feedback.import_export.file_cannot_be_uploaded'),
array('c' => 'importExport', 'a' => 'index')); array('c' => 'importExport', 'a' => 'index'));
} }
@ -69,7 +69,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
if (!is_resource($zip)) { if (!is_resource($zip)) {
// zip_open cannot open file: something is wrong // zip_open cannot open file: something is wrong
Minz_Log::error('Zip archive cannot be imported. Error code: ' . $zip); Minz_Log::warning('Zip archive cannot be imported. Error code: ' . $zip);
Minz_Request::bad(_t('feedback.import_export.zip_error'), Minz_Request::bad(_t('feedback.import_export.zip_error'),
array('c' => 'importExport', 'a' => 'index')); array('c' => 'importExport', 'a' => 'index'));
} }
@ -77,7 +77,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
while (($zipfile = zip_read($zip)) !== false) { while (($zipfile = zip_read($zip)) !== false) {
if (!is_resource($zipfile)) { if (!is_resource($zipfile)) {
// zip_entry() can also return an error code! // zip_entry() can also return an error code!
Minz_Log::error('Zip file cannot be imported. Error code: ' . $zipfile); Minz_Log::warning('Zip file cannot be imported. Error code: ' . $zipfile);
} else { } else {
$type_zipfile = $this->guessFileType(zip_entry_name($zipfile)); $type_zipfile = $this->guessFileType(zip_entry_name($zipfile));
if ($type_file !== 'unknown') { if ($type_file !== 'unknown') {
@ -361,7 +361,6 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
} }
// Then, articles are imported. // Then, articles are imported.
$prepared_statement = $this->entryDAO->addEntryPrepare();
$this->entryDAO->beginTransaction(); $this->entryDAO->beginTransaction();
foreach ($article_object['items'] as $item) { foreach ($article_object['items'] as $item) {
if (!isset($article_to_feed[$item['id']])) { if (!isset($article_to_feed[$item['id']])) {
@ -396,7 +395,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
} }
$values = $entry->toArray(); $values = $entry->toArray();
$id = $this->entryDAO->addEntry($values, $prepared_statement); $id = $this->entryDAO->addEntry($values);
if (!$error && ($id === false)) { if (!$error && ($id === false)) {
$error = true; $error = true;

View file

@ -137,6 +137,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
} }
// No layout for RSS output. // No layout for RSS output.
$this->view->url = empty($_SERVER['QUERY_STRING']) ? '' : '?' . $_SERVER['QUERY_STRING'];
$this->view->rss_title = FreshRSS_Context::$name . ' | ' . Minz_View::title(); $this->view->rss_title = FreshRSS_Context::$name . ' | ' . Minz_View::title();
$this->view->_useLayout(false); $this->view->_useLayout(false);
header('Content-Type: application/rss+xml; charset=utf-8'); header('Content-Type: application/rss+xml; charset=utf-8');
@ -161,6 +162,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
); );
FreshRSS_Context::_get(Minz_Request::param('get', 'a')); FreshRSS_Context::_get(Minz_Request::param('get', 'a'));
FreshRSS_Context::$state = Minz_Request::param( FreshRSS_Context::$state = Minz_Request::param(
'state', FreshRSS_Context::$user_conf->default_state 'state', FreshRSS_Context::$user_conf->default_state
); );
@ -172,7 +174,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
FreshRSS_Context::$state |= FreshRSS_Entry::STATE_READ; FreshRSS_Context::$state |= FreshRSS_Entry::STATE_READ;
} }
FreshRSS_Context::$search = Minz_Request::param('search', ''); FreshRSS_Context::$search = new FreshRSS_Search(Minz_Request::param('search', ''));
FreshRSS_Context::$order = Minz_Request::param( FreshRSS_Context::$order = Minz_Request::param(
'order', FreshRSS_Context::$user_conf->sort_order 'order', FreshRSS_Context::$user_conf->sort_order
); );

View file

@ -43,7 +43,12 @@ class FreshRSS_javascript_Controller extends Minz_ActionController {
} else { } else {
Minz_Log::notice('Nonce failure due to invalid username!'); Minz_Log::notice('Nonce failure due to invalid username!');
} }
$this->view->nonce = ''; //Failure //Failure: Return random data.
$this->view->salt1 = ''; $this->view->salt1 = sprintf('$2a$%02d$', FreshRSS_user_Controller::BCRYPT_COST);
$alphabet = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for ($i = 22; $i > 0; $i--) {
$this->view->salt1 .= $alphabet[rand(0, 63)];
}
$this->view->nonce = sha1(rand());
} }
} }

View file

@ -77,11 +77,11 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
Minz_View::prependTitle(_t('sub.title.feed_management') . ' · ' . $this->view->feed->name() . ' · '); Minz_View::prependTitle(_t('sub.title.feed_management') . ' · ' . $this->view->feed->name() . ' · ');
if (Minz_Request::isPost()) { if (Minz_Request::isPost()) {
$user = Minz_Request::param('http_user', ''); $user = trim(Minz_Request::param('http_user_feed' . $id, ''));
$pass = Minz_Request::param('http_pass', ''); $pass = Minz_Request::param('http_pass_feed' . $id, '');
$httpAuth = ''; $httpAuth = '';
if ($user != '' || $pass != '') { if ($user != '' && $pass != '') { //TODO: Sanitize
$httpAuth = $user . ':' . $pass; $httpAuth = $user . ':' . $pass;
} }

View file

@ -53,7 +53,8 @@ class FreshRSS_update_Controller extends Minz_ActionController {
return; return;
} }
$c = curl_init(FRESHRSS_UPDATE_WEBSITE); $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '?v=' . FRESHRSS_VERSION;
$c = curl_init($auto_update_url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, true); curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
@ -63,14 +64,14 @@ class FreshRSS_update_Controller extends Minz_ActionController {
curl_close($c); curl_close($c);
if ($c_status !== 200) { if ($c_status !== 200) {
Minz_Log::error( Minz_Log::warning(
'Error during update (HTTP code ' . $c_status . '): ' . $c_error 'Error during update (HTTP code ' . $c_status . '): ' . $c_error
); );
$this->view->message = array( $this->view->message = array(
'status' => 'bad', 'status' => 'bad',
'title' => _t('gen.short.damn'), 'title' => _t('gen.short.damn'),
'body' => _t('feedback.update.server_not_found', FRESHRSS_UPDATE_WEBSITE) 'body' => _t('feedback.update.server_not_found', $auto_update_url)
); );
return; return;
} }

View file

@ -12,9 +12,14 @@ class FreshRSS_user_Controller extends Minz_ActionController {
* This action is called before every other action in that class. It is * This action is called before every other action in that class. It is
* the common boiler plate for every action. It is triggered by the * the common boiler plate for every action. It is triggered by the
* underlying framework. * underlying framework.
*
* @todo clean up the access condition.
*/ */
public function firstAction() { public function firstAction() {
if (!FreshRSS_Auth::hasAccess()) { if (!FreshRSS_Auth::hasAccess() && !(
Minz_Request::actionName() === 'create' &&
!max_registrations_reached()
)) {
Minz_Error::error(403); Minz_Error::error(403);
} }
} }
@ -25,13 +30,17 @@ class FreshRSS_user_Controller extends Minz_ActionController {
public function profileAction() { public function profileAction() {
Minz_View::prependTitle(_t('conf.profile.title') . ' · '); Minz_View::prependTitle(_t('conf.profile.title') . ' · ');
Minz_View::appendScript(Minz_Url::display(
'/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')
));
if (Minz_Request::isPost()) { if (Minz_Request::isPost()) {
$ok = true; $ok = true;
$passwordPlain = Minz_Request::param('passwordPlain', '', true); $passwordPlain = Minz_Request::param('newPasswordPlain', '', true);
if ($passwordPlain != '') { if ($passwordPlain != '') {
Minz_Request::_param('passwordPlain'); //Discard plain-text password ASAP Minz_Request::_param('newPasswordPlain'); //Discard plain-text password ASAP
$_POST['passwordPlain'] = ''; $_POST['newPasswordPlain'] = '';
if (!function_exists('password_hash')) { if (!function_exists('password_hash')) {
include_once(LIB_PATH . '/password_compat.php'); include_once(LIB_PATH . '/password_compat.php');
} }
@ -103,8 +112,24 @@ class FreshRSS_user_Controller extends Minz_ActionController {
$this->view->size_user = $entryDAO->size(); $this->view->size_user = $entryDAO->size();
} }
/**
* This action creates a new user.
*
* Request parameters are:
* - new_user_language
* - new_user_name
* - new_user_passwordPlain
* - new_user_email
* - r (i.e. a redirection url, optional)
*
* @todo clean up this method. Idea: write a method to init a user with basic information.
* @todo handle r redirection in Minz_Request::forward directly?
*/
public function createAction() { public function createAction() {
if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { if (Minz_Request::isPost() && (
FreshRSS_Auth::hasAccess('admin') ||
!max_registrations_reached()
)) {
$db = FreshRSS_Context::$system_conf->db; $db = FreshRSS_Context::$system_conf->db;
require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
@ -175,15 +200,37 @@ class FreshRSS_user_Controller extends Minz_ActionController {
Minz_Session::_param('notification', $notif); Minz_Session::_param('notification', $notif);
} }
Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); $redirect_url = urldecode(Minz_Request::param('r', false, true));
if (!$redirect_url) {
$redirect_url = array('c' => 'user', 'a' => 'manage');
}
Minz_Request::forward($redirect_url, true);
} }
/**
* This action delete an existing user.
*
* Request parameter is:
* - username
*
* @todo clean up this method. Idea: create a User->clean() method.
*/
public function deleteAction() { public function deleteAction() {
if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { $username = Minz_Request::param('username');
$redirect_url = urldecode(Minz_Request::param('r', false, true));
if (!$redirect_url) {
$redirect_url = array('c' => 'user', 'a' => 'manage');
}
$self_deletion = Minz_Session::param('currentUser', '_') === $username;
if (Minz_Request::isPost() && (
FreshRSS_Auth::hasAccess('admin') ||
$self_deletion
)) {
$db = FreshRSS_Context::$system_conf->db; $db = FreshRSS_Context::$system_conf->db;
require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
$username = Minz_Request::param('username');
$ok = ctype_alnum($username); $ok = ctype_alnum($username);
$user_data = join_path(DATA_PATH, 'users', $username); $user_data = join_path(DATA_PATH, 'users', $username);
@ -191,6 +238,16 @@ class FreshRSS_user_Controller extends Minz_ActionController {
$default_user = FreshRSS_Context::$system_conf->default_user; $default_user = FreshRSS_Context::$system_conf->default_user;
$ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user $ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user
} }
if ($ok && $self_deletion) {
// We check the password if it's a self-destruction
$nonce = Minz_Session::param('nonce');
$challenge = Minz_Request::param('challenge', '');
$ok &= FreshRSS_FormAuth::checkCredentials(
$username, FreshRSS_Context::$user_conf->passwordHash,
$nonce, $challenge
);
}
if ($ok) { if ($ok) {
$ok &= is_dir($user_data); $ok &= is_dir($user_data);
} }
@ -200,6 +257,10 @@ class FreshRSS_user_Controller extends Minz_ActionController {
$ok &= recursive_unlink($user_data); $ok &= recursive_unlink($user_data);
//TODO: delete Persona file //TODO: delete Persona file
} }
if ($ok && $self_deletion) {
FreshRSS_Auth::removeAccess();
$redirect_url = array('c' => 'index', 'a' => 'index');
}
invalidateHttpCache(); invalidateHttpCache();
$notif = array( $notif = array(
@ -209,6 +270,6 @@ class FreshRSS_user_Controller extends Minz_ActionController {
Minz_Session::_param('notification', $notif); Minz_Session::_param('notification', $notif);
} }
Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); Minz_Request::forward($redirect_url, true);
} }
} }

View file

@ -1,6 +1,9 @@
<?php <?php
class FreshRSS_BadUrl_Exception extends FreshRSS_Feed_Exception { class FreshRSS_BadUrl_Exception extends FreshRSS_Feed_Exception {
public function __construct($url) { public function __construct($url) {
parent::__construct('`' . $url . '` is not a valid URL'); parent::__construct('`' . $url . '` is not a valid URL');
} }
} }

View file

@ -4,7 +4,5 @@
* An exception raised when a context is invalid * An exception raised when a context is invalid
*/ */
class FreshRSS_Context_Exception extends Exception { class FreshRSS_Context_Exception extends Exception {
public function __construct($message) {
parent::__construct($message);
}
} }

View file

@ -0,0 +1,5 @@
<?php
class FreshRSS_DAO_Exception extends Exception {
}

View file

@ -1,7 +1,5 @@
<?php <?php
class FreshRSS_EntriesGetter_Exception extends Exception { class FreshRSS_EntriesGetter_Exception extends Exception {
public function __construct($message) {
parent::__construct($message);
}
} }

View file

@ -1,6 +1,5 @@
<?php <?php
class FreshRSS_Feed_Exception extends Exception { class FreshRSS_Feed_Exception extends Exception {
public function __construct($message) {
parent::__construct($message);
}
} }

View file

@ -63,10 +63,11 @@ class FreshRSS extends Minz_FrontController {
// Basic protection against XSRF attacks // Basic protection against XSRF attacks
FreshRSS_Auth::removeAccess(); FreshRSS_Auth::removeAccess();
$http_referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; $http_referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
Minz_Translate::init('en'); //TODO: Better choice of fallback language
Minz_Error::error( Minz_Error::error(
403, 403,
array('error' => array( array('error' => array(
_t('access_denied'), _t('feedback.access.denied'),
' [HTTP_REFERER=' . htmlspecialchars($http_referer) . ']' ' [HTTP_REFERER=' . htmlspecialchars($http_referer) . ']'
)) ))
); );

View file

@ -6,6 +6,7 @@ class FreshRSS_Category extends Minz_Model {
private $nbFeed = -1; private $nbFeed = -1;
private $nbNotRead = -1; private $nbNotRead = -1;
private $feeds = null; private $feeds = null;
private $hasFeedsWithError = false;
public function __construct($name = '', $feeds = null) { public function __construct($name = '', $feeds = null) {
$this->_name($name); $this->_name($name);
@ -16,6 +17,7 @@ class FreshRSS_Category extends Minz_Model {
foreach ($feeds as $feed) { foreach ($feeds as $feed) {
$this->nbFeed++; $this->nbFeed++;
$this->nbNotRead += $feed->nbNotRead(); $this->nbNotRead += $feed->nbNotRead();
$this->hasFeedsWithError |= $feed->inError();
} }
} }
} }
@ -51,12 +53,17 @@ class FreshRSS_Category extends Minz_Model {
foreach ($this->feeds as $feed) { foreach ($this->feeds as $feed) {
$this->nbFeed++; $this->nbFeed++;
$this->nbNotRead += $feed->nbNotRead(); $this->nbNotRead += $feed->nbNotRead();
$this->hasFeedsWithError |= $feed->inError();
} }
} }
return $this->feeds; return $this->feeds;
} }
public function hasFeedsWithError() {
return $this->hasFeedsWithError;
}
public function _id($value) { public function _id($value) {
$this->id = $value; $this->id = $value;
} }

View file

@ -1,6 +1,6 @@
<?php <?php
class FreshRSS_CategoryDAO extends Minz_ModelPdo { class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function addCategory($valuesTmp) { public function addCategory($valuesTmp) {
$sql = 'INSERT INTO `' . $this->prefix . 'category`(name) VALUES(?)'; $sql = 'INSERT INTO `' . $this->prefix . 'category`(name) VALUES(?)';
$stm = $this->bd->prepare($sql); $stm = $this->bd->prepare($sql);
@ -13,7 +13,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
return $this->bd->lastInsertId(); return $this->bd->lastInsertId();
} else { } else {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
Minz_Log::error('SQL error addCategory: ' . $info[2] ); Minz_Log::error('SQL error addCategory: ' . $info[2]);
return false; return false;
} }
} }

View file

@ -117,12 +117,11 @@ class FreshRSS_ConfigurationSetter {
private function _queries(&$data, $values) { private function _queries(&$data, $values) {
$data['queries'] = array(); $data['queries'] = array();
foreach ($values as $value) { foreach ($values as $value) {
$value = array_filter($value); if ($value instanceof FreshRSS_UserQuery) {
$params = $value; $data['queries'][] = $value->toArray();
unset($params['name']); } elseif (is_array($value)) {
unset($params['url']); $data['queries'][] = $value;
$value['url'] = Minz_Url::display(array('params' => $params)); }
$data['queries'][] = $value;
} }
} }
@ -192,6 +191,10 @@ class FreshRSS_ConfigurationSetter {
$data['auto_remove_article'] = $this->handleBool($value); $data['auto_remove_article'] = $this->handleBool($value);
} }
private function _mark_updated_article_unread(&$data, $value) {
$data['mark_updated_article_unread'] = $this->handleBool($value);
}
private function _display_categories(&$data, $value) { private function _display_categories(&$data, $value) {
$data['display_categories'] = $this->handleBool($value); $data['display_categories'] = $this->handleBool($value);
} }
@ -351,6 +354,9 @@ class FreshRSS_ConfigurationSetter {
'min' => 0, 'min' => 0,
'max' => $max_small_int, 'max' => $max_small_int,
), ),
'max_registrations' => array(
'min' => 0,
),
); );
foreach ($values as $key => $value) { foreach ($values as $key => $value) {
@ -358,10 +364,11 @@ class FreshRSS_ConfigurationSetter {
continue; continue;
} }
$value = intval($value);
$limits = $limits_keys[$key]; $limits = $limits_keys[$key];
if ( if (
(!isset($limits['min']) || $value > $limits['min']) && (!isset($limits['min']) || $value >= $limits['min']) &&
(!isset($limits['max']) || $value < $limits['max']) (!isset($limits['max']) || $value <= $limits['max'])
) { ) {
$data['limits'][$key] = $value; $data['limits'][$key] = $value;
} }
@ -371,4 +378,12 @@ class FreshRSS_ConfigurationSetter {
private function _unsafe_autologin_enabled(&$data, $value) { private function _unsafe_autologin_enabled(&$data, $value) {
$data['unsafe_autologin_enabled'] = $this->handleBool($value); $data['unsafe_autologin_enabled'] = $this->handleBool($value);
} }
private function _auto_update_url(&$data, $value) {
if (!$value) {
return;
}
$data['auto_update_url'] = $value;
}
} }

View file

@ -10,6 +10,7 @@ class FreshRSS_Context {
public static $categories = array(); public static $categories = array();
public static $name = ''; public static $name = '';
public static $description = '';
public static $total_unread = 0; public static $total_unread = 0;
public static $total_starred = array( public static $total_starred = array(
@ -30,7 +31,7 @@ class FreshRSS_Context {
public static $state = 0; public static $state = 0;
public static $order = 'DESC'; public static $order = 'DESC';
public static $number = 0; public static $number = 0;
public static $search = ''; public static $search;
public static $first_id = ''; public static $first_id = '';
public static $next_id = ''; public static $next_id = '';
public static $id_max = ''; public static $id_max = '';
@ -93,6 +94,13 @@ class FreshRSS_Context {
} }
} }
/**
* Return true if the current request targets a feed (and not a category or all articles), false otherwise.
*/
public static function isFeed() {
return self::$current_get['feed'] != false;
}
/** /**
* Return true if $get parameter correspond to the $current_get attribute. * Return true if $get parameter correspond to the $current_get attribute.
*/ */
@ -146,8 +154,8 @@ class FreshRSS_Context {
self::$state = self::$state | FreshRSS_Entry::STATE_FAVORITE; self::$state = self::$state | FreshRSS_Entry::STATE_FAVORITE;
break; break;
case 'f': case 'f':
// We try to find the corresponding feed. // We try to find the corresponding feed. When allowing robots, always retrieve the full feed including description
$feed = FreshRSS_CategoryDAO::findFeed(self::$categories, $id); $feed = FreshRSS_Context::$system_conf->allow_robots ? null : FreshRSS_CategoryDAO::findFeed(self::$categories, $id);
if ($feed === null) { if ($feed === null) {
$feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO = FreshRSS_Factory::createFeedDao();
$feed = $feedDAO->searchById($id); $feed = $feedDAO->searchById($id);
@ -160,6 +168,7 @@ class FreshRSS_Context {
self::$current_get['feed'] = $id; self::$current_get['feed'] = $id;
self::$current_get['category'] = $feed->category(); self::$current_get['category'] = $feed->category();
self::$name = $feed->name(); self::$name = $feed->name();
self::$description = $feed->description();
self::$get_unread = $feed->nbNotRead(); self::$get_unread = $feed->nbNotRead();
break; break;
case 'c': case 'c':
@ -301,4 +310,5 @@ class FreshRSS_Context {
} }
return false; return false;
} }
} }

View file

@ -14,7 +14,8 @@ class FreshRSS_Entry extends Minz_Model {
private $content; private $content;
private $link; private $link;
private $date; private $date;
private $is_read; private $hash = null;
private $is_read; //Nullable boolean
private $is_favorite; private $is_favorite;
private $feed; private $feed;
private $tags; private $tags;
@ -88,6 +89,14 @@ class FreshRSS_Entry extends Minz_Model {
} }
} }
public function hash() {
if ($this->hash === null) {
//Do not include $this->date because it may be automatically generated when lacking
$this->hash = md5($this->link . $this->title . $this->author . $this->content . $this->tags(true));
}
return $this->hash;
}
public function _id($value) { public function _id($value) {
$this->id = $value; $this->id = $value;
} }
@ -95,23 +104,28 @@ class FreshRSS_Entry extends Minz_Model {
$this->guid = $value; $this->guid = $value;
} }
public function _title($value) { public function _title($value) {
$this->hash = null;
$this->title = $value; $this->title = $value;
} }
public function _author($value) { public function _author($value) {
$this->hash = null;
$this->author = $value; $this->author = $value;
} }
public function _content($value) { public function _content($value) {
$this->hash = null;
$this->content = $value; $this->content = $value;
} }
public function _link($value) { public function _link($value) {
$this->hash = null;
$this->link = $value; $this->link = $value;
} }
public function _date($value) { public function _date($value) {
$this->hash = null;
$value = intval($value); $value = intval($value);
$this->date = $value > 1 ? $value : time(); $this->date = $value > 1 ? $value : time();
} }
public function _isRead($value) { public function _isRead($value) {
$this->is_read = $value; $this->is_read = $value === null ? null : (bool)$value;
} }
public function _isFavorite($value) { public function _isFavorite($value) {
$this->is_favorite = $value; $this->is_favorite = $value;
@ -120,6 +134,7 @@ class FreshRSS_Entry extends Minz_Model {
$this->feed = $value; $this->feed = $value;
} }
public function _tags($value) { public function _tags($value) {
$this->hash = null;
if (!is_array($value)) { if (!is_array($value)) {
$value = array($value); $value = array($value);
} }
@ -182,6 +197,7 @@ class FreshRSS_Entry extends Minz_Model {
'content' => $this->content(), 'content' => $this->content(),
'link' => $this->link(), 'link' => $this->link(),
'date' => $this->date(true), 'date' => $this->date(true),
'hash' => $this->hash(),
'is_read' => $this->isRead(), 'is_read' => $this->isRead(),
'is_favorite' => $this->isFavorite(), 'is_favorite' => $this->isFavorite(),
'id_feed' => $this->feed(), 'id_feed' => $this->feed(),

View file

@ -1,25 +1,78 @@
<?php <?php
class FreshRSS_EntryDAO extends Minz_ModelPdo { class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function isCompressed() { public function isCompressed() {
return parent::$sharedDbType !== 'sqlite'; return parent::$sharedDbType !== 'sqlite';
} }
public function addEntryPrepare() { public function hasNativeHex() {
$sql = 'INSERT INTO `' . $this->prefix . 'entry`(id, guid, title, author, ' return parent::$sharedDbType !== 'sqlite';
. ($this->isCompressed() ? 'content_bin' : 'content')
. ', link, date, is_read, is_favorite, id_feed, tags) '
. 'VALUES(?, ?, ?, ?, '
. ($this->isCompressed() ? 'COMPRESS(?)' : '?')
. ', ?, ?, ?, ?, ?, ?)';
return $this->bd->prepare($sql);
} }
public function addEntry($valuesTmp, $preparedStatement = null) { protected function addColumn($name) {
$stm = $preparedStatement === null ? Minz_Log::debug('FreshRSS_EntryDAO::autoAddColumn: ' . $name);
FreshRSS_EntryDAO::addEntryPrepare() : $hasTransaction = false;
$preparedStatement; try {
$stm = null;
if ($name === 'lastSeen') { //v1.1.1
if (!$this->bd->inTransaction()) {
$this->bd->beginTransaction();
$hasTransaction = true;
}
$stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN lastSeen INT(11) DEFAULT 0');
if ($stm && $stm->execute()) {
$stm = $this->bd->prepare('CREATE INDEX entry_lastSeen_index ON `' . $this->prefix . 'entry`(`lastSeen`);'); //"IF NOT EXISTS" does not exist in MySQL 5.7
if ($stm && $stm->execute()) {
if ($hasTransaction) {
$this->bd->commit();
}
return true;
}
}
if ($hasTransaction) {
$this->bd->rollBack();
}
} elseif ($name === 'hash') { //v1.1.1
$stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN hash BINARY(16)');
return $stm && $stm->execute();
}
} catch (Exception $e) {
Minz_Log::debug('FreshRSS_EntryDAO::autoAddColumn error: ' . $e->getMessage());
if ($hasTransaction) {
$this->bd->rollBack();
}
}
return false;
}
protected function autoAddColumn($errorInfo) {
if (isset($errorInfo[0])) {
if ($errorInfo[0] == '42S22') { //ER_BAD_FIELD_ERROR
foreach (array('lastSeen', 'hash') as $column) {
if (stripos($errorInfo[2], $column) !== false) {
return $this->addColumn($column);
}
}
}
}
return false;
}
private $addEntryPrepared = null;
public function addEntry($valuesTmp) {
if ($this->addEntryPrepared === null) {
$sql = 'INSERT INTO `' . $this->prefix . 'entry` (id, guid, title, author, '
. ($this->isCompressed() ? 'content_bin' : 'content')
. ', link, date, lastSeen, hash, is_read, is_favorite, id_feed, tags) '
. 'VALUES(?, ?, ?, ?, '
. ($this->isCompressed() ? 'COMPRESS(?)' : '?')
. ', ?, ?, ?, '
. ($this->hasNativeHex() ? 'X?' : '?')
. ', ?, ?, ?, ?)';
$this->addEntryPrepared = $this->bd->prepare($sql);
}
$values = array( $values = array(
$valuesTmp['id'], $valuesTmp['id'],
@ -29,55 +82,76 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$valuesTmp['content'], $valuesTmp['content'],
substr($valuesTmp['link'], 0, 1023), substr($valuesTmp['link'], 0, 1023),
$valuesTmp['date'], $valuesTmp['date'],
time(),
$this->hasNativeHex() ? $valuesTmp['hash'] : pack('H*', $valuesTmp['hash']), // X'09AF' hexadecimal literals do not work with SQLite/PDO //hex2bin() is PHP5.4+
$valuesTmp['is_read'] ? 1 : 0, $valuesTmp['is_read'] ? 1 : 0,
$valuesTmp['is_favorite'] ? 1 : 0, $valuesTmp['is_favorite'] ? 1 : 0,
$valuesTmp['id_feed'], $valuesTmp['id_feed'],
substr($valuesTmp['tags'], 0, 1023), substr($valuesTmp['tags'], 0, 1023),
); );
if ($stm && $stm->execute($values)) { if ($this->addEntryPrepared && $this->addEntryPrepared->execute($values)) {
return $this->bd->lastInsertId(); return $this->bd->lastInsertId();
} else { } else {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); $info = $this->addEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->addEntryPrepared->errorInfo();
if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries if ($this->autoAddColumn($info)) {
return $this->addEntry($valuesTmp);
} elseif ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries
Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']); . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']);
} /*else { }
Minz_Log::debug('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']);
}*/
return false; return false;
} }
} }
public function addEntryObject($entry, $conf, $feedHistory) { private $updateEntryPrepared = null;
$existingGuids = array_fill_keys(
$this->listLastGuidsByFeed($entry->feed(), 20), 1 public function updateEntry($valuesTmp) {
if (!isset($valuesTmp['is_read'])) {
$valuesTmp['is_read'] = null;
}
if ($this->updateEntryPrepared === null) {
$sql = 'UPDATE `' . $this->prefix . 'entry` '
. 'SET title=?, author=?, '
. ($this->isCompressed() ? 'content_bin=COMPRESS(?)' : 'content=?')
. ', link=?, date=?, lastSeen=?, hash='
. ($this->hasNativeHex() ? 'X?' : '?')
. ', ' . ($valuesTmp['is_read'] === null ? '' : 'is_read=?, ')
. 'tags=? '
. 'WHERE id_feed=? AND guid=?';
$this->updateEntryPrepared = $this->bd->prepare($sql);
}
$values = array(
substr($valuesTmp['title'], 0, 255),
substr($valuesTmp['author'], 0, 255),
$valuesTmp['content'],
substr($valuesTmp['link'], 0, 1023),
$valuesTmp['date'],
time(),
$this->hasNativeHex() ? $valuesTmp['hash'] : pack('H*', $valuesTmp['hash']),
); );
if ($valuesTmp['is_read'] !== null) {
$nb_month_old = max($conf->old_entries, 1); $values[] = $valuesTmp['is_read'] ? 1 : 0;
$date_min = time() - (3600 * 24 * 30 * $nb_month_old);
$eDate = $entry->date(true);
if ($feedHistory == -2) {
$feedHistory = $conf->keep_history_default;
} }
$values = array_merge($values, array(
substr($valuesTmp['tags'], 0, 1023),
$valuesTmp['id_feed'],
substr($valuesTmp['guid'], 0, 760),
));
if (!isset($existingGuids[$entry->guid()]) && if ($this->updateEntryPrepared && $this->updateEntryPrepared->execute($values)) {
($feedHistory != 0 || $eDate >= $date_min || $entry->isFavorite())) { return $this->bd->lastInsertId();
$values = $entry->toArray(); } else {
$info = $this->updateEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->updateEntryPrepared->errorInfo();
$useDeclaredDate = empty($existingGuids); if ($this->autoAddColumn($info)) {
$values['id'] = ($useDeclaredDate || $eDate < $date_min) ? return $this->updateEntry($valuesTmp);
min(time(), $eDate) . uSecString() : }
uTimeString(); Minz_Log::error('SQL error updateEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while updating entry with GUID ' . $valuesTmp['guid'] . ' in feed ' . $valuesTmp['id_feed']);
return $this->addEntry($values); return false;
} }
// We don't return Entry object to avoid a research in DB
return -1;
} }
/** /**
@ -94,6 +168,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
if (!is_array($ids)) { if (!is_array($ids)) {
$ids = array($ids); $ids = array($ids);
} }
if (count($ids) < 1) {
return 0;
}
$sql = 'UPDATE `' . $this->prefix . 'entry` ' $sql = 'UPDATE `' . $this->prefix . 'entry` '
. 'SET is_favorite=? ' . 'SET is_favorite=? '
. 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)'; . 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)';
@ -296,11 +373,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
* *
* If $idMax equals 0, a deprecated debug message is logged * If $idMax equals 0, a deprecated debug message is logged
* *
* @param integer $id feed ID * @param integer $id_feed feed ID
* @param integer $idMax fail safe article ID * @param integer $idMax fail safe article ID
* @return integer affected rows * @return integer affected rows
*/ */
public function markReadFeed($id, $idMax = 0) { public function markReadFeed($id_feed, $idMax = 0) {
if ($idMax == 0) { if ($idMax == 0) {
$idMax = time() . '000000'; $idMax = time() . '000000';
Minz_Log::debug('Calling markReadFeed(0) is deprecated!'); Minz_Log::debug('Calling markReadFeed(0) is deprecated!');
@ -310,7 +387,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$sql = 'UPDATE `' . $this->prefix . 'entry` ' $sql = 'UPDATE `' . $this->prefix . 'entry` '
. 'SET is_read=1 ' . 'SET is_read=1 '
. 'WHERE id_feed=? AND is_read=0 AND id <= ?'; . 'WHERE id_feed=? AND is_read=0 AND id <= ?';
$values = array($id, $idMax); $values = array($id_feed, $idMax);
$stm = $this->bd->prepare($sql); $stm = $this->bd->prepare($sql);
if (!($stm && $stm->execute($values))) { if (!($stm && $stm->execute($values))) {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
@ -324,7 +401,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$sql = 'UPDATE `' . $this->prefix . 'feed` ' $sql = 'UPDATE `' . $this->prefix . 'feed` '
. 'SET cache_nbUnreads=cache_nbUnreads-' . $affected . 'SET cache_nbUnreads=cache_nbUnreads-' . $affected
. ' WHERE id=?'; . ' WHERE id=?';
$values = array($id); $values = array($id_feed);
$stm = $this->bd->prepare($sql); $stm = $this->bd->prepare($sql);
if (!($stm && $stm->execute($values))) { if (!($stm && $stm->execute($values))) {
$info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
@ -338,7 +415,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
return $affected; return $affected;
} }
public function searchByGuid($feed_id, $id) { public function searchByGuid($id_feed, $guid) {
// un guid est unique pour un flux donné // un guid est unique pour un flux donné
$sql = 'SELECT id, guid, title, author, ' $sql = 'SELECT id, guid, title, author, '
. ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
@ -347,8 +424,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$stm = $this->bd->prepare($sql); $stm = $this->bd->prepare($sql);
$values = array( $values = array(
$feed_id, $id_feed,
$id $guid,
); );
$stm->execute($values); $stm->execute($values);
@ -441,56 +518,50 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
$where .= 'AND e1.id >= ' . $date_min . '000000 '; $where .= 'AND e1.id >= ' . $date_min . '000000 ';
} }
$search = ''; $search = '';
if ($filter !== '') { if ($filter) {
require_once(LIB_PATH . '/lib_date.php'); if ($filter->getIntitle()) {
$filter = trim($filter); $search .= 'AND e1.title LIKE ? ';
$filter = addcslashes($filter, '\\%_'); $values[] = "%{$filter->getIntitle()}%";
$terms = array_unique(explode(' ', $filter)); }
//sort($terms); //Put #tags first //TODO: Put the cheapest filters first if ($filter->getInurl()) {
foreach ($terms as $word) { $search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
$word = trim($word); $values[] = "%{$filter->getInurl()}%";
if (stripos($word, 'intitle:') === 0) { }
$word = substr($word, strlen('intitle:')); if ($filter->getAuthor()) {
$search .= 'AND e1.title LIKE ? '; $search .= 'AND e1.author LIKE ? ';
$values[] = '%' . $word .'%'; $values[] = "%{$filter->getAuthor()}%";
} elseif (stripos($word, 'inurl:') === 0) { }
$word = substr($word, strlen('inurl:')); if ($filter->getMinDate()) {
$search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? '; $search .= 'AND e1.id >= ? ';
$values[] = '%' . $word .'%'; $values[] = "{$filter->getMinDate()}000000";
} elseif (stripos($word, 'author:') === 0) { }
$word = substr($word, strlen('author:')); if ($filter->getMaxDate()) {
$search .= 'AND e1.author LIKE ? '; $search .= 'AND e1.id <= ? ';
$values[] = '%' . $word .'%'; $values[] = "{$filter->getMaxDate()}000000";
} elseif (stripos($word, 'date:') === 0) { }
$word = substr($word, strlen('date:')); if ($filter->getMinPubdate()) {
list($minDate, $maxDate) = parseDateInterval($word); $search .= 'AND e1.date >= ? ';
if ($minDate) { $values[] = $filter->getMinPubdate();
$search .= 'AND e1.id >= ' . $minDate . '000000 '; }
} if ($filter->getMaxPubdate()) {
if ($maxDate) { $search .= 'AND e1.date <= ? ';
$search .= 'AND e1.id <= ' . $maxDate . '000000 '; $values[] = $filter->getMaxPubdate();
} }
} elseif (stripos($word, 'pubdate:') === 0) { if ($filter->getTags()) {
$word = substr($word, strlen('pubdate:')); $tags = $filter->getTags();
list($minDate, $maxDate) = parseDateInterval($word); foreach ($tags as $tag) {
if ($minDate) { $search .= 'AND e1.tags LIKE ? ';
$search .= 'AND e1.date >= ' . $minDate . ' '; $values[] = "%{$tag}%";
} }
if ($maxDate) { }
$search .= 'AND e1.date <= ' . $maxDate . ' '; if ($filter->getSearch()) {
} $search_values = $filter->getSearch();
} else { foreach ($search_values as $search_value) {
if ($word[0] === '#' && isset($word[1])) { $search .= 'AND ' . $this->sqlconcat('e1.title', $this->isCompressed() ? 'UNCOMPRESS(content_bin)' : 'content') . ' LIKE ? ';
$search .= 'AND e1.tags LIKE ? '; $values[] = "%{$search_value}%";
$values[] = '%' . $word .'%';
} else {
$search .= 'AND ' . $this->sqlconcat('e1.title', $this->isCompressed() ? 'UNCOMPRESS(content_bin)' : 'content') . ' LIKE ? ';
$values[] = '%' . $word .'%';
}
} }
} }
} }
return array($values, return array($values,
'SELECT e1.id FROM `' . $this->prefix . 'entry` e1 ' 'SELECT e1.id FROM `' . $this->prefix . 'entry` e1 '
. ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed=f.id ' : '') . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed=f.id ' : '')
@ -527,12 +598,51 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
return $stm->fetchAll(PDO::FETCH_COLUMN, 0); return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
} }
public function listLastGuidsByFeed($id, $n) { public function listHashForFeedGuids($id_feed, $guids) {
$sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n); if (count($guids) < 1) {
return array();
}
$sql = 'SELECT guid, hex(hash) AS hexHash FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
$stm = $this->bd->prepare($sql); $stm = $this->bd->prepare($sql);
$values = array($id); $values = array($id_feed);
$stm->execute($values); $values = array_merge($values, $guids);
return $stm->fetchAll(PDO::FETCH_COLUMN, 0); if ($stm && $stm->execute($values)) {
$result = array();
$rows = $stm->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$result[$row['guid']] = $row['hexHash'];
}
return $result;
} else {
$info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
if ($this->autoAddColumn($info)) {
return $this->listHashForFeedGuids($id_feed, $guids);
}
Minz_Log::error('SQL error listHashForFeedGuids: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while querying feed ' . $id_feed);
return false;
}
}
public function updateLastSeen($id_feed, $guids) {
if (count($guids) < 1) {
return 0;
}
$sql = 'UPDATE `' . $this->prefix . 'entry` SET lastSeen=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
$stm = $this->bd->prepare($sql);
$values = array(time(), $id_feed);
$values = array_merge($values, $guids);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
$info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
if ($this->autoAddColumn($info)) {
return $this->updateLastSeen($id_feed, $guids);
}
Minz_Log::error('SQL error updateLastSeen: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
. ' while updating feed ' . $id_feed);
return false;
}
} }
public function countUnreadRead() { public function countUnreadRead() {

View file

@ -2,6 +2,21 @@
class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO {
protected function autoAddColumn($errorInfo) {
if (empty($errorInfo[0]) || $errorInfo[0] == '42S22') { //ER_BAD_FIELD_ERROR
if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='entry'")) {
$showCreate = $tableInfo->fetchColumn();
Minz_Log::debug('FreshRSS_EntryDAOSQLite::autoAddColumn: ' . $showCreate);
foreach (array('lastSeen', 'hash') as $column) {
if (stripos($showCreate, $column) === false) {
return $this->addColumn($column);
}
}
}
}
return false;
}
protected function sqlConcat($s1, $s2) { protected function sqlConcat($s1, $s2) {
return $s1 . '||' . $s2; return $s1 . '||' . $s2;
} }

View file

@ -19,6 +19,8 @@ class FreshRSS_Feed extends Minz_Model {
private $ttl = -2; private $ttl = -2;
private $hash = null; private $hash = null;
private $lockPath = ''; private $lockPath = '';
private $hubUrl = '';
private $selfUrl = '';
public function __construct($url, $validate=true) { public function __construct($url, $validate=true) {
if ($validate) { if ($validate) {
@ -49,6 +51,12 @@ class FreshRSS_Feed extends Minz_Model {
public function url() { public function url() {
return $this->url; return $this->url;
} }
public function selfUrl() {
return $this->selfUrl;
}
public function hubUrl() {
return $this->hubUrl;
}
public function category() { public function category() {
return $this->category; return $this->category;
} }
@ -96,6 +104,16 @@ class FreshRSS_Feed extends Minz_Model {
public function ttl() { public function ttl() {
return $this->ttl; return $this->ttl;
} }
// public function ttlExpire() {
// $ttl = $this->ttl;
// if ($ttl == -2) { //Default
// $ttl = FreshRSS_Context::$user_conf->ttl_default;
// }
// if ($ttl == -1) { //Never
// $ttl = 64000000; //~2 years. Good enough for PubSubHubbub logic
// }
// return $this->lastUpdate + $ttl;
// }
public function nbEntries() { public function nbEntries() {
if ($this->nbEntries < 0) { if ($this->nbEntries < 0) {
$feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO = FreshRSS_Factory::createFeedDao();
@ -226,6 +244,11 @@ class FreshRSS_Feed extends Minz_Model {
throw new FreshRSS_Feed_Exception(($errorMessage == '' ? 'Feed error' : $errorMessage) . ' [' . $url . ']'); throw new FreshRSS_Feed_Exception(($errorMessage == '' ? 'Feed error' : $errorMessage) . ' [' . $url . ']');
} }
$links = $feed->get_links('self');
$this->selfUrl = isset($links[0]) ? $links[0] : null;
$links = $feed->get_links('hub');
$this->hubUrl = isset($links[0]) ? $links[0] : null;
if ($loadDetails) { if ($loadDetails) {
// si on a utilisé l'auto-discover, notre url va avoir changé // si on a utilisé l'auto-discover, notre url va avoir changé
$subscribe_url = $feed->subscribe_url(false); $subscribe_url = $feed->subscribe_url(false);
@ -240,16 +263,16 @@ class FreshRSS_Feed extends Minz_Model {
$subscribe_url = $feed->subscribe_url(true); $subscribe_url = $feed->subscribe_url(true);
} }
$clean_url = url_remove_credentials($subscribe_url); $clean_url = SimplePie_Misc::url_remove_credentials($subscribe_url);
if ($subscribe_url !== null && $subscribe_url !== $url) { if ($subscribe_url !== null && $subscribe_url !== $url) {
$this->_url($clean_url); $this->_url($clean_url);
} }
if (($mtime === true) ||($mtime > $this->lastUpdate)) { if (($mtime === true) || ($mtime > $this->lastUpdate)) {
Minz_Log::notice('FreshRSS no cache ' . $mtime . ' > ' . $this->lastUpdate . ' for ' . $clean_url); //Minz_Log::debug('FreshRSS no cache ' . $mtime . ' > ' . $this->lastUpdate . ' for ' . $clean_url);
$this->loadEntries($feed); // et on charge les articles du flux $this->loadEntries($feed); // et on charge les articles du flux
} else { } else {
Minz_Log::notice('FreshRSS use cache for ' . $clean_url); //Minz_Log::debug('FreshRSS use cache for ' . $clean_url);
$this->entries = array(); $this->entries = array();
} }
@ -259,7 +282,7 @@ class FreshRSS_Feed extends Minz_Model {
} }
} }
private function loadEntries($feed) { public function loadEntries($feed) {
$entries = array(); $entries = array();
foreach ($feed->get_items() as $item) { foreach ($feed->get_items() as $item) {
@ -333,4 +356,136 @@ class FreshRSS_Feed extends Minz_Model {
function unlock() { function unlock() {
@unlink($this->lockPath); @unlink($this->lockPath);
} }
//<PubSubHubbub>
function pubSubHubbubEnabled() {
$url = $this->selfUrl ? $this->selfUrl : $this->url;
$hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json';
if ($hubFile = @file_get_contents($hubFilename)) {
$hubJson = json_decode($hubFile, true);
if ($hubJson && empty($hubJson['error']) &&
(empty($hubJson['lease_end']) || $hubJson['lease_end'] > time())) {
return true;
}
}
return false;
}
function pubSubHubbubError($error = true) {
$url = $this->selfUrl ? $this->selfUrl : $this->url;
$hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json';
$hubFile = @file_get_contents($hubFilename);
$hubJson = $hubFile ? json_decode($hubFile, true) : array();
if (!isset($hubJson['error']) || $hubJson['error'] !== (bool)$error) {
$hubJson['error'] = (bool)$error;
file_put_contents($hubFilename, json_encode($hubJson));
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t"
. 'Set error to ' . ($error ? 1 : 0) . ' for ' . $url . "\n", FILE_APPEND);
}
return false;
}
function pubSubHubbubPrepare() {
$key = '';
if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl && @is_dir(PSHB_PATH)) {
$path = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl);
$hubFilename = $path . '/!hub.json';
if ($hubFile = @file_get_contents($hubFilename)) {
$hubJson = json_decode($hubFile, true);
if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) {
$text = 'Invalid JSON for PubSubHubbub: ' . $this->url;
Minz_Log::warning($text);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
return false;
}
if ((!empty($hubJson['lease_end'])) && ($hubJson['lease_end'] < (time() + (3600 * 23)))) { //TODO: Make a better policy
$text = 'PubSubHubbub lease ends at '
. date('c', empty($hubJson['lease_end']) ? time() : $hubJson['lease_end'])
. ' and needs renewal: ' . $this->url;
Minz_Log::warning($text);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
$key = $hubJson['key']; //To renew our lease
} elseif (((!empty($hubJson['error'])) || empty($hubJson['lease_end'])) &&
(empty($hubJson['lease_start']) || $hubJson['lease_start'] < time() - (3600 * 23))) { //Do not renew too often
$key = $hubJson['key']; //To renew our lease
}
} else {
@mkdir($path, 0777, true);
$key = sha1($path . FreshRSS_Context::$system_conf->salt . uniqid(mt_rand(), true));
$hubJson = array(
'hub' => $this->hubUrl,
'key' => $key,
);
file_put_contents($hubFilename, json_encode($hubJson));
@mkdir(PSHB_PATH . '/keys/');
file_put_contents(PSHB_PATH . '/keys/' . $key . '.txt', base64url_encode($this->selfUrl));
$text = 'PubSubHubbub prepared for ' . $this->url;
Minz_Log::debug($text);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
}
$currentUser = Minz_Session::param('currentUser');
if (ctype_alnum($currentUser) && !file_exists($path . '/' . $currentUser . '.txt')) {
touch($path . '/' . $currentUser . '.txt');
}
}
return $key;
}
//Parameter true to subscribe, false to unsubscribe.
function pubSubHubbubSubscribe($state) {
if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl) {
$hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl) . '/!hub.json';
$hubFile = @file_get_contents($hubFilename);
if ($hubFile === false) {
Minz_Log::warning('JSON not found for PubSubHubbub: ' . $this->url);
return false;
}
$hubJson = json_decode($hubFile, true);
if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) {
Minz_Log::warning('Invalid JSON for PubSubHubbub: ' . $this->url);
return false;
}
$callbackUrl = checkUrl(FreshRSS_Context::$system_conf->base_url . 'api/pshb.php?k=' . $hubJson['key']);
if ($callbackUrl == '') {
Minz_Log::warning('Invalid callback for PubSubHubbub: ' . $this->url);
return false;
}
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $this->hubUrl,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERAGENT => _t('gen.freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')',
CURLOPT_POSTFIELDS => 'hub.verify=sync'
. '&hub.mode=' . ($state ? 'subscribe' : 'unsubscribe')
. '&hub.topic=' . urlencode($this->selfUrl)
. '&hub.callback=' . urlencode($callbackUrl)
)
);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" .
'PubSubHubbub ' . ($state ? 'subscribe' : 'unsubscribe') . ' to ' . $this->selfUrl .
' with callback ' . $callbackUrl . ': ' . $info['http_code'] . ' ' . $response . "\n", FILE_APPEND);
if (!$state) { //unsubscribe
$hubJson['lease_end'] = time() - 60;
file_put_contents($hubFilename, json_encode($hubJson));
}
if (substr($info['http_code'], 0, 1) == '2') {
return true;
} else {
$hubJson['lease_start'] = time(); //Prevent trying again too soon
$hubJson['error'] = true;
file_put_contents($hubFilename, json_encode($hubJson));
return false;
}
}
return false;
}
//</PubSubHubbub>
} }

View file

@ -1,6 +1,6 @@
<?php <?php
class FreshRSS_FeedDAO extends Minz_ModelPdo { class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function addFeed($valuesTmp) { public function addFeed($valuesTmp) {
$sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)';
$stm = $this->bd->prepare($sql); $stm = $this->bd->prepare($sql);
@ -322,17 +322,20 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
return $affected; return $affected;
} }
public function cleanOldEntries($id, $date_min, $keep = 15) { //Remember to call updateLastUpdate($id) just after public function cleanOldEntries($id, $date_min, $keep = 15) { //Remember to call updateLastUpdate($id) or updateCachedValues() just after
$sql = 'DELETE FROM `' . $this->prefix . 'entry` ' $sql = 'DELETE FROM `' . $this->prefix . 'entry` '
. 'WHERE id_feed = :id_feed AND id <= :id_max AND is_favorite=0 AND id NOT IN ' . 'WHERE id_feed=:id_feed AND id<=:id_max '
. '(SELECT id FROM (SELECT e2.id FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed = :id_feed ORDER BY id DESC LIMIT :keep) keep)'; //Double select MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' . 'AND is_favorite=0 ' //Do not remove favourites
. 'AND lastSeen < (SELECT maxLastSeen FROM (SELECT (MAX(e3.lastSeen)-99) AS maxLastSeen FROM `' . $this->prefix . 'entry` e3 WHERE e3.id_feed=:id_feed) recent) ' //Do not remove the most newly seen articles, plus a few seconds of tolerance
. 'AND id NOT IN (SELECT id FROM (SELECT e2.id FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=:id_feed ORDER BY id DESC LIMIT :keep) keep)'; //Double select: MySQL doesn't support 'LIMIT & IN/ALL/ANY/SOME subquery'
$stm = $this->bd->prepare($sql); $stm = $this->bd->prepare($sql);
$id_max = intval($date_min) . '000000'; if ($stm) {
$id_max = intval($date_min) . '000000';
$stm->bindParam(':id_feed', $id, PDO::PARAM_INT); $stm->bindParam(':id_feed', $id, PDO::PARAM_INT);
$stm->bindParam(':id_max', $id_max, PDO::PARAM_STR); $stm->bindParam(':id_max', $id_max, PDO::PARAM_STR);
$stm->bindParam(':keep', $keep, PDO::PARAM_INT); $stm->bindParam(':keep', $keep, PDO::PARAM_INT);
}
if ($stm && $stm->execute()) { if ($stm && $stm->execute()) {
return $stm->rowCount(); return $stm->rowCount();

View file

@ -21,5 +21,10 @@ class FreshRSS_LogDAO {
public static function truncate() { public static function truncate() {
file_put_contents(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'), ''); file_put_contents(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'), '');
if (FreshRSS_Auth::hasAccess('admin')) {
file_put_contents(join_path(DATA_PATH, 'users', '_', 'log.txt'), '');
file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_api.txt'), '');
file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_pshb.txt'), '');
}
} }
} }

229
sources/app/Models/Search.php Executable file
View file

@ -0,0 +1,229 @@
<?php
require_once(LIB_PATH . '/lib_date.php');
/**
* Contains a search from the search form.
*
* It allows to extract meaningful bits of the search and store them in a
* convenient object
*/
class FreshRSS_Search {
// This contains the user input string
private $raw_input = '';
// The following properties are extracted from the raw input
private $intitle;
private $min_date;
private $max_date;
private $min_pubdate;
private $max_pubdate;
private $inurl;
private $author;
private $tags;
private $search;
public function __construct($input) {
if (strcmp($input, '') == 0) {
return;
}
$this->raw_input = $input;
$input = $this->parseIntitleSearch($input);
$input = $this->parseAuthorSearch($input);
$input = $this->parseInurlSearch($input);
$input = $this->parsePubdateSearch($input);
$input = $this->parseDateSearch($input);
$input = $this->parseTagsSeach($input);
$this->parseSearch($input);
}
public function __toString() {
return $this->getRawInput();
}
public function getRawInput() {
return $this->raw_input;
}
public function getIntitle() {
return $this->intitle;
}
public function getMinDate() {
return $this->min_date;
}
public function getMaxDate() {
return $this->max_date;
}
public function getMinPubdate() {
return $this->min_pubdate;
}
public function getMaxPubdate() {
return $this->max_pubdate;
}
public function getInurl() {
return $this->inurl;
}
public function getAuthor() {
return $this->author;
}
public function getTags() {
return $this->tags;
}
public function getSearch() {
return $this->search;
}
/**
* Parse the search string to find intitle keyword and the search related
* to it.
* The search is the first word following the keyword.
*
* @param string $input
* @return string
*/
private function parseIntitleSearch($input) {
if (preg_match('/intitle:(?P<delim>[\'"])(?P<search>.*)(?P=delim)/U', $input, $matches)) {
$this->intitle = $matches['search'];
return str_replace($matches[0], '', $input);
}
if (preg_match('/intitle:(?P<search>\w*)/', $input, $matches)) {
$this->intitle = $matches['search'];
return str_replace($matches[0], '', $input);
}
return $input;
}
/**
* Parse the search string to find author keyword and the search related
* to it.
* The search is the first word following the keyword except when using
* a delimiter. Supported delimiters are single quote (') and double
* quotes (").
*
* @param string $input
* @return string
*/
private function parseAuthorSearch($input) {
if (preg_match('/author:(?P<delim>[\'"])(?P<search>.*)(?P=delim)/U', $input, $matches)) {
$this->author = $matches['search'];
return str_replace($matches[0], '', $input);
}
if (preg_match('/author:(?P<search>\w*)/', $input, $matches)) {
$this->author = $matches['search'];
return str_replace($matches[0], '', $input);
}
return $input;
}
/**
* Parse the search string to find inurl keyword and the search related
* to it.
* The search is the first word following the keyword except.
*
* @param string $input
* @return string
*/
private function parseInurlSearch($input) {
if (preg_match('/inurl:(?P<search>[^\s]*)/', $input, $matches)) {
$this->inurl = $matches['search'];
return str_replace($matches[0], '', $input);
}
return $input;
}
/**
* Parse the search string to find date keyword and the search related
* to it.
* The search is the first word following the keyword.
*
* @param string $input
* @return string
*/
private function parseDateSearch($input) {
if (preg_match('/date:(?P<search>[^\s]*)/', $input, $matches)) {
list($this->min_date, $this->max_date) = parseDateInterval($matches['search']);
return str_replace($matches[0], '', $input);
}
return $input;
}
/**
* Parse the search string to find pubdate keyword and the search related
* to it.
* The search is the first word following the keyword.
*
* @param string $input
* @return string
*/
private function parsePubdateSearch($input) {
if (preg_match('/pubdate:(?P<search>[^\s]*)/', $input, $matches)) {
list($this->min_pubdate, $this->max_pubdate) = parseDateInterval($matches['search']);
return str_replace($matches[0], '', $input);
}
return $input;
}
/**
* Parse the search string to find tags keyword (# followed by a word)
* and the search related to it.
* The search is the first word following the #.
*
* @param string $input
* @return string
*/
private function parseTagsSeach($input) {
if (preg_match_all('/#(?P<search>[^\s]+)/', $input, $matches)) {
$this->tags = $matches['search'];
return str_replace($matches[0], '', $input);
}
return $input;
}
/**
* Parse the search string to find search values.
* Every word is a distinct search value, except when using a delimiter.
* Supported delimiters are single quote (') and double quotes (").
*
* @param string $input
* @return string
*/
private function parseSearch($input) {
$input = $this->cleanSearch($input);
if (strcmp($input, '') == 0) {
return;
}
if (preg_match_all('/(?P<delim>[\'"])(?P<search>.*)(?P=delim)/U', $input, $matches)) {
$this->search = $matches['search'];
$input = str_replace($matches[0], '', $input);
}
$input = $this->cleanSearch($input);
if (strcmp($input, '') == 0) {
return;
}
if (is_array($this->search)) {
$this->search = array_merge($this->search, explode(' ', $input));
} else {
$this->search = explode(' ', $input);
}
}
/**
* Remove all unnecessary spaces in the search
*
* @param string $input
* @return string
*/
private function cleanSearch($input) {
$input = preg_replace('/\s+/', ' ', $input);
return trim($input);
}
}

View file

@ -0,0 +1,6 @@
<?php
interface FreshRSS_Searchable {
public function searchById($id);
}

View file

@ -152,7 +152,7 @@ class FreshRSS_Share {
* Return the current name of the share option. * Return the current name of the share option.
*/ */
public function name($real = false) { public function name($real = false) {
if ($real || is_null($this->custom_name)) { if ($real || is_null($this->custom_name) || empty($this->custom_name)) {
return $this->name; return $this->name;
} else { } else {
return $this->custom_name; return $this->custom_name;

226
sources/app/Models/UserQuery.php Executable file
View file

@ -0,0 +1,226 @@
<?php
/**
* Contains the description of a user query
*
* It allows to extract the meaningful bits of the query to be manipulated in an
* easy way.
*/
class FreshRSS_UserQuery {
private $deprecated = false;
private $get;
private $get_name;
private $get_type;
private $name;
private $order;
private $search;
private $state;
private $url;
private $feed_dao;
private $category_dao;
/**
* @param array $query
* @param FreshRSS_Searchable $feed_dao
* @param FreshRSS_Searchable $category_dao
*/
public function __construct($query, FreshRSS_Searchable $feed_dao = null, FreshRSS_Searchable $category_dao = null) {
$this->category_dao = $category_dao;
$this->feed_dao = $feed_dao;
if (isset($query['get'])) {
$this->parseGet($query['get']);
}
if (isset($query['name'])) {
$this->name = $query['name'];
}
if (isset($query['order'])) {
$this->order = $query['order'];
}
if (!isset($query['search'])) {
$query['search'] = '';
}
// linked to deeply with the search object, need to use dependency injection
$this->search = new FreshRSS_Search($query['search']);
if (isset($query['state'])) {
$this->state = $query['state'];
}
if (isset($query['url'])) {
$this->url = $query['url'];
}
}
/**
* Convert the current object to an array.
*
* @return array
*/
public function toArray() {
return array_filter(array(
'get' => $this->get,
'name' => $this->name,
'order' => $this->order,
'search' => $this->search->__toString(),
'state' => $this->state,
'url' => $this->url,
));
}
/**
* Parse the get parameter in the query string to extract its name and
* type
*
* @param string $get
*/
private function parseGet($get) {
$this->get = $get;
if (preg_match('/(?P<type>[acfs])(_(?P<id>\d+))?/', $get, $matches)) {
switch ($matches['type']) {
case 'a':
$this->parseAll();
break;
case 'c':
$this->parseCategory($matches['id']);
break;
case 'f':
$this->parseFeed($matches['id']);
break;
case 's':
$this->parseFavorite();
break;
}
}
}
/**
* Parse the query string when it is an "all" query
*/
private function parseAll() {
$this->get_name = 'all';
$this->get_type = 'all';
}
/**
* Parse the query string when it is a "category" query
*
* @param integer $id
* @throws FreshRSS_DAO_Exception
*/
private function parseCategory($id) {
if (is_null($this->category_dao)) {
throw new FreshRSS_DAO_Exception('Category DAO is not loaded in UserQuery');
}
$category = $this->category_dao->searchById($id);
if ($category) {
$this->get_name = $category->name();
} else {
$this->deprecated = true;
}
$this->get_type = 'category';
}
/**
* Parse the query string when it is a "feed" query
*
* @param integer $id
* @throws FreshRSS_DAO_Exception
*/
private function parseFeed($id) {
if (is_null($this->feed_dao)) {
throw new FreshRSS_DAO_Exception('Feed DAO is not loaded in UserQuery');
}
$feed = $this->feed_dao->searchById($id);
if ($feed) {
$this->get_name = $feed->name();
} else {
$this->deprecated = true;
}
$this->get_type = 'feed';
}
/**
* Parse the query string when it is a "favorite" query
*/
private function parseFavorite() {
$this->get_name = 'favorite';
$this->get_type = 'favorite';
}
/**
* Check if the current user query is deprecated.
* It is deprecated if the category or the feed used in the query are
* not existing.
*
* @return boolean
*/
public function isDeprecated() {
return $this->deprecated;
}
/**
* Check if the user query has parameters.
* If the type is 'all', it is considered equal to no parameters
*
* @return boolean
*/
public function hasParameters() {
if ($this->get_type === 'all') {
return false;
}
if ($this->hasSearch()) {
return true;
}
if ($this->state) {
return true;
}
if ($this->order) {
return true;
}
if ($this->get) {
return true;
}
return false;
}
/**
* Check if there is a search in the search object
*
* @return boolean
*/
public function hasSearch() {
return $this->search->getRawInput() != "";
}
public function getGet() {
return $this->get;
}
public function getGetName() {
return $this->get_name;
}
public function getGetType() {
return $this->get_type;
}
public function getName() {
return $this->name;
}
public function getOrder() {
return $this->order;
}
public function getSearch() {
return $this->search;
}
public function getState() {
return $this->state;
}
public function getUrl() {
return $this->url;
}
}

View file

@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS `%1$sfeed` (
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
`website` varchar(255) CHARACTER SET latin1, `website` varchar(255) CHARACTER SET latin1,
`description` text, `description` text,
`lastUpdate` int(11) DEFAULT 0, `lastUpdate` int(11) DEFAULT 0, -- Until year 2038
`priority` tinyint(2) NOT NULL DEFAULT 10, `priority` tinyint(2) NOT NULL DEFAULT 10,
`pathEntries` varchar(511) DEFAULT NULL, `pathEntries` varchar(511) DEFAULT NULL,
`httpAuth` varchar(511) DEFAULT NULL, `httpAuth` varchar(511) DEFAULT NULL,
@ -40,7 +40,9 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` (
`author` varchar(255), `author` varchar(255),
`content_bin` blob, -- v0.7 `content_bin` blob, -- v0.7
`link` varchar(1023) CHARACTER SET latin1 NOT NULL, `link` varchar(1023) CHARACTER SET latin1 NOT NULL,
`date` int(11), `date` int(11), -- Until year 2038
`lastSeen` INT(11) DEFAULT 0, -- v1.1.1, Until year 2038
`hash` BINARY(16), -- v1.1.1
`is_read` boolean NOT NULL DEFAULT 0, `is_read` boolean NOT NULL DEFAULT 0,
`is_favorite` boolean NOT NULL DEFAULT 0, `is_favorite` boolean NOT NULL DEFAULT 0,
`id_feed` SMALLINT, -- v0.7 `id_feed` SMALLINT, -- v0.7
@ -49,11 +51,14 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` (
FOREIGN KEY (`id_feed`) REFERENCES `%1$sfeed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`id_feed`) REFERENCES `%1$sfeed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE KEY (`id_feed`,`guid`), -- v0.7 UNIQUE KEY (`id_feed`,`guid`), -- v0.7
INDEX (`is_favorite`), -- v0.7 INDEX (`is_favorite`), -- v0.7
INDEX (`is_read`) -- v0.7 INDEX (`is_read`), -- v0.7
INDEX `entry_lastSeen_index` (`lastSeen`) -- v1.1.1
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci
ENGINE = INNODB; ENGINE = INNODB;
INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s"); INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s");
INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("http://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "http://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400);
INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS @ GitHub", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400);
'); ');
define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory');

View file

@ -14,7 +14,7 @@ $SQL_CREATE_TABLES = array(
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
`website` varchar(255), `website` varchar(255),
`description` text, `description` text,
`lastUpdate` int(11) DEFAULT 0, `lastUpdate` int(11) DEFAULT 0, -- Until year 2038
`priority` tinyint(2) NOT NULL DEFAULT 10, `priority` tinyint(2) NOT NULL DEFAULT 10,
`pathEntries` varchar(511) DEFAULT NULL, `pathEntries` varchar(511) DEFAULT NULL,
`httpAuth` varchar(511) DEFAULT NULL, `httpAuth` varchar(511) DEFAULT NULL,
@ -38,7 +38,9 @@ $SQL_CREATE_TABLES = array(
`author` varchar(255), `author` varchar(255),
`content` text, `content` text,
`link` varchar(1023) NOT NULL, `link` varchar(1023) NOT NULL,
`date` int(11), `date` int(11), -- Until year 2038
`lastSeen` INT(11) DEFAULT 0, -- v1.1.1, Until year 2038
`hash` BINARY(16), -- v1.1.1
`is_read` boolean NOT NULL DEFAULT 0, `is_read` boolean NOT NULL DEFAULT 0,
`is_favorite` boolean NOT NULL DEFAULT 0, `is_favorite` boolean NOT NULL DEFAULT 0,
`id_feed` SMALLINT, `id_feed` SMALLINT,
@ -50,8 +52,11 @@ $SQL_CREATE_TABLES = array(
'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `%1$sentry`(`is_favorite`);', 'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `%1$sentry`(`is_favorite`);',
'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `%1$sentry`(`is_read`);', 'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `%1$sentry`(`is_read`);',
'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `%1$sentry`(`lastSeen`);', //v1.1.1
'INSERT OR IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s");', 'INSERT OR IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s");',
'INSERT OR IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("http://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "http://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400);',
'INSERT OR IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS releases", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400);',
); );
define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory');

183
sources/app/i18n/cz/admin.php Executable file
View file

@ -0,0 +1,183 @@
<?php
return array(
'auth' => array(
'allow_anonymous' => 'Umožnit anonymně číst články výchozího uživatele (%s)',
'allow_anonymous_refresh' => 'Umožnit anonymní obnovení článků',
'api_enabled' => 'Povolit přístup k <abbr>API</abbr> <small>(vyžadováno mobilními aplikacemi)</small>',
'form' => 'Webový formulář (tradiční, vyžaduje JavaScript)',
'http' => 'HTTP (pro pokročilé uživatele s HTTPS)',
'none' => 'Žádný (nebezpečné)',
'persona' => 'Mozilla Persona (moderní, vyžaduje JavaScript)',
'title' => 'Přihlášení',
'title_reset' => 'Reset přihlášení',
'token' => 'Authentizační token',
'token_help' => 'Umožňuje přístup k RSS kanálu článků výchozího uživatele bez přihlášení:',
'type' => 'Způsob přihlášení',
'unsafe_autologin' => 'Povolit nebezpečné automatické přihlášení přes: ',
),
'check_install' => array(
'cache' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/cache</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře cache jsou v pořádku.',
),
'categories' => array(
'nok' => 'Tabulka kategorií je nastavena špatně.',
'ok' => 'Tabulka kategorií je v pořádku.',
),
'connection' => array(
'nok' => 'Nelze navázat spojení s databází.',
'ok' => 'Připojení k databázi je v pořádku.',
),
'ctype' => array(
'nok' => 'Nemáte požadovanou knihovnu pro ověřování znaků (php-ctype).',
'ok' => 'Máte požadovanou knihovnu pro ověřování znaků (ctype).',
),
'curl' => array(
'nok' => 'Nemáte cURL (balíček php5-curl).',
'ok' => 'Máte rozšíření cURL.',
),
'data' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře data jsou v pořádku.',
),
'database' => 'Instalace databáze',
'dom' => array(
'nok' => 'Nemáte požadovanou knihovnu pro procházení DOM (balíček php-xml).',
'ok' => 'Máte požadovanou knihovnu pro procházení DOM.',
),
'entries' => array(
'nok' => 'Tabulka článků je nastavena špatně.',
'ok' => 'Tabulka kategorií je v pořádku.',
),
'favicons' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/favicons</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře favicons jsou v pořádku.',
),
'feeds' => array(
'nok' => 'Tabulka kanálů je nastavena špatně.',
'ok' => 'Tabulka kanálů je v pořádku.',
),
'files' => 'Instalace souborů',
'json' => array(
'nok' => 'Nemáte JSON (balíček php5-json).',
'ok' => 'Máte rozšíření JSON.',
),
'minz' => array(
'nok' => 'Nemáte framework Minz.',
'ok' => 'Máte framework Minz.',
),
'pcre' => array(
'nok' => 'Nemáte požadovanou knihovnu pro regulární výrazy (php-pcre).',
'ok' => 'Máte požadovanou knihovnu pro regulární výrazy (PCRE).',
),
'pdo' => array(
'nok' => 'Nemáte PDO nebo některý z podporovaných ovladačů (pdo_mysql, pdo_sqlite).',
'ok' => 'Máte PDO a alespoň jeden z podporovaných ovladačů (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/persona</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře Mozilla Persona jsou v pořádku.',
),
'php' => array(
'_' => 'PHP instalace',
'nok' => 'Vaše verze PHP je %s, ale FreshRSS vyžaduje alespoň verzi %s.',
'ok' => 'Vaše verze PHP je %s a je kompatibilní s FreshRSS.',
),
'tables' => array(
'nok' => 'V databázi chybí jedna nevo více tabulek.',
'ok' => 'V databázi jsou všechny tabulky.',
),
'title' => 'Kontrola instalace',
'tokens' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/tokens</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře tokens jsou v pořádku.',
),
'users' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/users</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře users jsou v pořádku.',
),
'zip' => array(
'nok' => 'Nemáte rozšíření ZIP (balíček php5-zip).',
'ok' => 'Máte rozšíření ZIP.',
),
),
'extensions' => array(
'disabled' => 'Vypnuto',
'empty_list' => 'Není naistalováno žádné rozšíření',
'enabled' => 'Zapnuto',
'no_configure_view' => 'Toto rozšíření nemá žádné možnosti nastavení.',
'system' => array(
'_' => 'Systémová rozšíření',
'no_rights' => 'Systémová rozšíření (na ně nemáte oprávnění)',
),
'title' => 'Rozšíření',
'user' => 'Uživatelská rozšíření',
),
'stats' => array(
'_' => 'Statistika',
'all_feeds' => 'Všechny kanály',
'category' => 'Kategorie',
'entry_count' => 'Počet článků',
'entry_per_category' => 'Článků na kategorii',
'entry_per_day' => 'Článků za den (posledních 30 dní)',
'entry_per_day_of_week' => 'Za den v týdnu (průměr: %.2f zprávy)',
'entry_per_hour' => 'Za hodinu (průměr: %.2f zprávy)',
'entry_per_month' => 'Za měsíc (průměr: %.2f zprávy)',
'entry_repartition' => 'Rozdělení článků',
'feed' => 'Kanál',
'feed_per_category' => 'Článků na kategorii',
'idle' => 'Neaktivní kanály',
'main' => 'Přehled',
'main_stream' => 'Všechny kanály',
'menu' => array(
'idle' => 'Neaktivní kanály',
'main' => 'Přehled',
'repartition' => 'Rozdělení článků',
),
'no_idle' => 'Žádné neaktivní kanály!',
'number_entries' => '%d článků',
'percent_of_total' => '%% ze všech',
'repartition' => 'Rozdělení článků',
'status_favorites' => 'Oblíbené',
'status_read' => 'Přečtené',
'status_total' => 'Celkem',
'status_unread' => 'Nepřečtené',
'title' => 'Statistika',
'top_feed' => 'Top ten kanálů',
),
'system' => array(
'_' => 'System configuration', // @todo translate
'auto-update-url' => 'Auto-update server URL', // @todo translate
'instance-name' => 'Instance name', // @todo translate
'max-categories' => 'Categories per user limit', // @todo translate
'max-feeds' => 'Feeds per user limit', // @todo translate
'registration' => array(
'help' => '0 znamená žádná omezení účtu',
'number' => 'Maximální počet účtů',
),
),
'update' => array(
'_' => 'Aktualizace systému',
'apply' => 'Použít',
'check' => 'Zkontrolovat aktualizace',
'current_version' => 'Vaše instalace FreshRSS je verze %s.',
'last' => 'Poslední kontrola: %s',
'none' => 'Žádné nové aktualizace',
'title' => 'Aktualizovat systém',
),
'user' => array(
'articles_and_size' => '%s článků (%s)',
'create' => 'Vytvořit nového uživatele',
'email_persona' => 'Email pro přihlášení<br /><small>(pro <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'language' => 'Jazyk',
'number' => 'Zatím je vytvořen %d účet',
'numbers' => 'Zatím je vytvořeno %d účtů',
'password_form' => 'Heslo<br /><small>(pro přihlášení webovým formulářem)</small>',
'password_format' => 'Alespoň 7 znaků',
'title' => 'Správa uživatelů',
'user_list' => 'Seznam uživatelů',
'username' => 'Přihlašovací jméno',
'users' => 'Uživatelé',
),
);

174
sources/app/i18n/cz/conf.php Executable file
View file

@ -0,0 +1,174 @@
<?php
return array(
'archiving' => array(
'_' => 'Archivace',
'advanced' => 'Pokročilé',
'delete_after' => 'Smazat články starší než',
'help' => 'Více možností je dostupných v nastavení jednotlivých kanálů',
'keep_history_by_feed' => 'Zachovat tento minimální počet článků v každém kanálu',
'optimize' => 'Optimalizovat databázi',
'optimize_help' => 'Občasná údržba zmenší velikost databáze',
'purge_now' => 'Vyčistit nyní',
'title' => 'Archivace',
'ttl' => 'Neaktualizovat častěji než',
),
'display' => array(
'_' => 'Zobrazení',
'icon' => array(
'bottom_line' => 'Spodní řádek',
'entry' => 'Ikony článků',
'publication_date' => 'Datum vydání',
'related_tags' => 'Související tagy',
'sharing' => 'Sdílení',
'top_line' => 'Horní řádek',
),
'language' => 'Jazyk',
'notif_html5' => array(
'seconds' => 'sekund (0 znamená žádný timeout)',
'timeout' => 'Timeout HTML5 notifikací',
),
'theme' => 'Vzhled',
'title' => 'Zobrazení',
'width' => array(
'content' => 'Šířka obsahu',
'large' => 'Velká',
'medium' => 'Střední',
'no_limit' => 'Bez limitu',
'thin' => 'Tenká',
),
),
'query' => array(
'_' => 'Uživatelské dotazy',
'deprecated' => 'Tento dotaz již není platný. Odkazovaná kategorie nebo kanál byly smazány.',
'filter' => 'Filtr aplikován:',
'get_all' => 'Zobrazit všechny články',
'get_category' => 'Zobrazit "%s" kategorii',
'get_favorite' => 'Zobrazit oblíbené články',
'get_feed' => 'Zobrazit "%s" článkek',
'no_filter' => 'Zrušit filtr',
'none' => 'Ještě jste nevytvořil žádný uživatelský dotaz.',
'number' => 'Dotaz n°%d',
'order_asc' => 'Zobrazit nejdříve nejstarší články',
'order_desc' => 'Zobrazit nejdříve nejnovější články',
'search' => 'Hledat "%s"',
'state_0' => 'Zobrazit všechny články',
'state_1' => 'Zobrazit přečtené články',
'state_2' => 'Zobrazit nepřečtené články',
'state_3' => 'Zobrazit všechny články',
'state_4' => 'Zobrazit oblíbené články',
'state_5' => 'Zobrazit oblíbené přečtené články',
'state_6' => 'Zobrazit oblíbené nepřečtené články',
'state_7' => 'Zobrazit oblíbené články',
'state_8' => 'Zobrazit všechny články vyjma oblíbených',
'state_9' => 'Zobrazit všechny přečtené články vyjma oblíbených',
'state_10' => 'Zobrazit všechny nepřečtené články vyjma oblíbených',
'state_11' => 'Zobrazit všechny články vyjma oblíbených',
'state_12' => 'Zobrazit všechny články',
'state_13' => 'Zobrazit přečtené články',
'state_14' => 'Zobrazit nepřečtené články',
'state_15' => 'Zobrazit všechny články',
'title' => 'Uživatelské dotazy',
),
'profile' => array(
'_' => 'Správa profilu',
'delete' => array(
'_' => 'Smazání účtu',
'warn' => 'Váš účet bude smazán spolu se všemi souvisejícími daty',
),
'email_persona' => 'Email pro přihlášení<br /><small>(pro <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'password_api' => 'Password API<br /><small>(tzn. pro mobilní aplikace)</small>',
'password_form' => 'Heslo<br /><small>(pro přihlášení webovým formulářem)</small>',
'password_format' => 'Alespoň 7 znaků',
'title' => 'Profil',
),
'reading' => array(
'_' => 'Čtení',
'after_onread' => 'Po “označit vše jako přečtené”,',
'articles_per_page' => 'Počet článků na stranu',
'auto_load_more' => 'Načítat další články dole na stránce',
'auto_remove_article' => 'Po přečtení články schovat',
'mark_updated_article_unread' => 'Označte aktualizované položky jako nepřečtené',
'confirm_enabled' => 'Vyžadovat potvrzení pro akci “označit vše jako přečtené”',
'display_articles_unfolded' => 'Ve výchozím stavu zobrazovat články otevřené',
'display_categories_unfolded' => 'Ve výchozím stavu zobrazovat kategorie zavřené',
'hide_read_feeds' => 'Schovat kategorie a kanály s nulovým počtem nepřečtených článků (nefunguje s nastavením “Zobrazit všechny články”)',
'img_with_lazyload' => 'Použít "lazy load" mód pro načítaní obrázků',
'jump_next' => 'skočit na další nepřečtený (kanál nebo kategorii)',
'number_divided_when_reader' => 'V režimu “Čtení” děleno dvěma.',
'read' => array(
'article_open_on_website' => 'když je otevřen původní web s článkem',
'article_viewed' => 'během čtení článku',
'scroll' => 'během skrolování',
'upon_reception' => 'po načtení článku',
'when' => 'Označit článek jako přečtený…',
),
'show' => array(
'_' => 'Počet zobrazených článků',
'adaptive' => 'Vyberte zobrazení',
'all_articles' => 'Zobrazit všechny články',
'unread' => 'Zobrazit jen nepřečtené',
),
'sort' => array(
'_' => 'Řazení',
'newer_first' => 'Nejdříve nejnovější',
'older_first' => 'Nejdříve nejstarší',
),
'sticky_post' => 'Při otevření posunout článek nahoru',
'title' => 'Čtení',
'view' => array(
'default' => 'Výchozí',
'global' => 'Přehled',
'normal' => 'Normální',
'reader' => 'Čtení',
),
),
'sharing' => array(
'_' => 'Sdílení',
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'more_information' => 'Více informací',
'print' => 'Tisk',
'shaarli' => 'Shaarli',
'share_name' => 'Jméno pro zobrazení',
'share_url' => 'Jakou URL použít pro sdílení',
'title' => 'Sdílení',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'shortcut' => array(
'_' => 'Zkratky',
'article_action' => 'Články - akce',
'auto_share' => 'Sdílet',
'auto_share_help' => 'Je-li nastavena pouze jedna možnost sdílení, bude použita. Další možnosti jsou dostupné pomocí jejich čísla.',
'close_dropdown' => 'Zavřít menu',
'collapse_article' => 'Srolovat',
'first_article' => 'Skočit na první článek',
'focus_search' => 'Hledání',
'help' => 'Zobrazit documentaci',
'javascript' => 'Pro použití zkratek musí být povolen JavaScript',
'last_article' => 'Skočit na poslední článek',
'load_more' => 'Načíst více článků',
'mark_read' => 'Označit jako přečtené',
'mark_favorite' => 'Označit jako oblíbené',
'navigation' => 'Navigace',
'navigation_help' => 'Pomocí přepínače "Shift" fungují navigační zkratky v rámci kanálů.<br/>Pomocí přepínače "Alt" fungují v rámci kategorií.',
'next_article' => 'Skočit na další článek',
'other_action' => 'Ostatní akce',
'previous_article' => 'Skočit na předchozí článek',
'see_on_website' => 'Navštívit původní webovou stránku',
'shift_for_all_read' => '+ <code>shift</code> označí vše jako přečtené',
'title' => 'Zkratky',
'user_filter' => 'Aplikovat uživatelské filtry',
'user_filter_help' => 'Je-li nastaven pouze jeden filtr, bude použit. Další filtry jsou dostupné pomocí jejich čísla.',
),
'user' => array(
'articles_and_size' => '%s článků (%s)',
'current' => 'Aktuální uživatel',
'is_admin' => 'je administrátor',
'users' => 'Uživatelé',
),
);

110
sources/app/i18n/cz/feedback.php Executable file
View file

@ -0,0 +1,110 @@
<?php
return array(
'admin' => array(
'optimization_complete' => 'Optimalizace dokončena',
),
'access' => array(
'denied' => 'Nemáte oprávnění přistupovat na tuto stránku',
'not_found' => 'Tato stránka neexistuje',
),
'auth' => array(
'form' => array(
'not_set' => 'Nastal problém s konfigurací přihlašovacího systému. Zkuste to prosím později.',
'set' => 'Webový formulář je nyní výchozí přihlašovací systém.',
),
'login' => array(
'invalid' => 'Login není platný',
'success' => 'Jste přihlášen',
),
'logout' => array(
'success' => 'Jste odhlášen',
),
'no_password_set' => 'Heslo administrátora nebylo nastaveno. Tato funkce není k dispozici.',
'not_persona' => 'Resetovat lze pouze systém Persona.',
),
'conf' => array(
'error' => 'Během ukládání nastavení došlo k chybě',
'query_created' => 'Dotaz "%s" byl vytvořen.',
'shortcuts_updated' => 'Zkratky byly aktualizovány',
'updated' => 'Nastavení bylo aktualizováno',
),
'extensions' => array(
'already_enabled' => '%s je již zapnut',
'disable' => array(
'ko' => '%s nelze vypnout. Pro více detailů <a href="%s">zkontrolujte logy FressRSS</a>.',
'ok' => '%s je nyní vypnut',
),
'enable' => array(
'ko' => '%s nelze zapnout. Pro více detailů <a href="%s">zkontrolujte logy FressRSS</a>.',
'ok' => '%s je nyní zapnut',
),
'no_access' => 'Nemáte přístup k %s',
'not_enabled' => '%s není ještě zapnut',
'not_found' => '%s neexistuje',
),
'import_export' => array(
'export_no_zip_extension' => 'Na serveru není naistalována podpora zip. Zkuste prosím exportovat soubory jeden po druhém.',
'feeds_imported' => 'Vaše kanály byly naimportovány a nyní budou aktualizovány',
'feeds_imported_with_errors' => 'Vaše kanály byly naimportovány, došlo ale k nějakým chybám',
'file_cannot_be_uploaded' => 'Soubor nelze nahrát!',
'no_zip_extension' => 'Na serveru není naistalována podpora zip.',
'zip_error' => 'Během importu zip souboru došlo k chybě.',
),
'sub' => array(
'actualize' => 'Aktualizovat',
'category' => array(
'created' => 'Kategorie %s byla vytvořena.',
'deleted' => 'Kategorie byla smazána.',
'emptied' => 'Kategorie byla vyprázdněna',
'error' => 'Kategorii nelze aktualizovat',
'name_exists' => 'Název kategorie již existuje.',
'no_id' => 'Musíte upřesnit id kategorie.',
'no_name' => 'Název kategorie nemůže být prázdný.',
'not_delete_default' => 'Nelze smazat výchozí kategorii!',
'not_exist' => 'Tato kategorie neexistuje!',
'over_max' => 'Dosáhl jste maximálního počtu kategorií (%d)',
'updated' => 'Kategorie byla aktualizována.',
),
'feed' => array(
'actualized' => '<em>%s</em> bylo aktualizováno',
'actualizeds' => 'RSS kanály byly aktualizovány',
'added' => 'RSS kanál <em>%s</em> byl přidán',
'already_subscribed' => 'Již jste přihlášen k odběru <em>%s</em>',
'deleted' => 'Kanál byl smazán',
'error' => 'Kanál nelze aktualizovat',
'internal_problem' => 'RSS kanál nelze přidat. Pro detaily <a href="%s">zkontrolujte logy FressRSS</a>.',
'invalid_url' => 'URL <em>%s</em> není platné',
'marked_read' => 'Kanály byly označeny jako přečtené',
'n_actualized' => '%d kanálů bylo aktualizováno',
'n_entries_deleted' => '%d článků bylo smazáno',
'no_refresh' => 'Nelze obnovit žádné kanály…',
'not_added' => '<em>%s</em> nemůže být přidán',
'over_max' => 'Dosáhl jste maximálního počtu kanálů (%d)',
'updated' => 'Kanál byl aktualizován',
),
'purge_completed' => 'Vyprázdněno (smazáno %d článků)',
),
'update' => array(
'can_apply' => 'FreshRSS bude nyní upgradováno na <strong>verzi %s</strong>.',
'error' => 'Během upgrade došlo k chybě: %s',
'file_is_nok' => 'Zkontrolujte oprávnění adresáře <em>%s</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'finished' => 'Upgrade hotov!',
'none' => 'Novější verze není k dispozici',
'server_not_found' => 'Nelze nalézt server s instalačním souborem. [%s]',
),
'user' => array(
'created' => array(
'_' => 'Uživatel %s byl vytvořen',
'error' => 'Uživatele %s nelze vytvořit',
),
'deleted' => array(
'_' => 'Uživatel %s byl smazán',
'error' => 'Uživatele %s nelze smazat',
),
),
'profile' => array(
'error' => 'Váš profil nelze změnit',
'updated' => 'Váš profil byl změněn',
),
);

180
sources/app/i18n/cz/gen.php Executable file
View file

@ -0,0 +1,180 @@
<?php
return array(
'action' => array(
'actualize' => 'Aktualizovat',
'back_to_rss_feeds' => '← Zpět na seznam RSS kanálů',
'cancel' => 'Zrušit',
'create' => 'Vytvořit',
'disable' => 'Zakázat',
'empty' => 'Vyprázdnit',
'enable' => 'Povolit',
'export' => 'Export',
'filter' => 'Filtrovat',
'import' => 'Import',
'manage' => 'Spravovat',
'mark_read' => 'Označit jako přečtené',
'mark_favorite' => 'Označit jako oblíbené',
'remove' => 'Odstranit',
'see_website' => 'Navštívit WWW stránku',
'submit' => 'Odeslat',
'truncate' => 'Smazat všechny články',
),
'auth' => array(
'email' => 'Email',
'keep_logged_in' => 'Zapamatovat přihlášení <small>(1 měsíc)</small>',
'login' => 'Login',
'login_persona' => 'Přihlášení pomocí Persona',
'login_persona_problem' => 'Problém s připojením k Persona?',
'logout' => 'Odhlášení',
'password' => array(
'_' => 'Heslo',
'format' => '<small>Alespoň 7 znaků</small>',
),
'registration' => array(
'_' => 'Nový účet',
'ask' => 'Vytvořit účet?',
'title' => 'Vytvoření účtu',
),
'reset' => 'Reset přihlášení',
'username' => array(
'_' => 'Uživatel',
'admin' => 'Název administrátorského účtu',
'format' => '<small>maximálně 16 alfanumerických znaků</small>',
),
'will_reset' => 'Přihlašovací systém bude vyresetován: místo sytému Persona bude použito přihlášení formulářem.',
),
'date' => array(
'Apr' => '\\D\\u\\b\\e\\n',
'Aug' => '\\S\\r\\p\\e\\n',
'Dec' => '\\P\\r\\o\\s\\i\\n\\e\\c',
'Feb' => '\\Ú\\n\\o\\r',
'Jan' => '\\L\\e\\d\\e\\n',
'Jul' => '\\Č\\e\\r\\v\\e\\n\\e\\c',
'Jun' => '\\Č\\e\\r\\v\\e\\n',
'Mar' => '\\B\\ř\\e\\z\\e\\n',
'May' => '\\K\\v\\ě\\t\\e\\n',
'Nov' => '\\L\\i\\s\\t\\o\\p\\a\\d',
'Oct' => '\\Ř\\í\\j\\e\\n',
'Sep' => '\\Z\\á\\ř\\í',
'apr' => 'dub',
'april' => 'Dub',
'aug' => 'srp',
'august' => 'Srp',
'before_yesterday' => 'Předevčírem',
'dec' => 'pro',
'december' => 'Pro',
'feb' => 'úno',
'february' => 'Úno',
'format_date' => 'j\\. %s Y',
'format_date_hour' => 'j\\. %s Y \\v H\\:i',
'fri' => 'Pá',
'jan' => 'led',
'january' => 'Led',
'jul' => 'čvn',
'july' => 'Čvn',
'jun' => 'čer',
'june' => 'Čer',
'last_3_month' => 'Minulé tři měsíce',
'last_6_month' => 'Minulých šest měsíců',
'last_month' => 'Minulý měsíc',
'last_week' => 'Minulý týden',
'last_year' => 'Minulý rok',
'mar' => 'bře',
'march' => 'Bře',
'may' => 'Kvě',
'mon' => 'Po',
'month' => 'měsíce',
'nov' => 'lis',
'november' => 'Lis',
'oct' => 'říj',
'october' => 'Říj',
'sat' => 'So',
'sep' => 'zář',
'september' => 'Zář',
'sun' => 'Ne',
'thu' => 'Čt',
'today' => 'Dnes',
'tue' => 'Út',
'wed' => 'St',
'yesterday' => 'Včera',
),
'freshrss' => array(
'_' => 'FreshRSS',
'about' => 'O FreshRSS',
),
'js' => array(
'category_empty' => 'Prázdná kategorie',
'confirm_action' => 'Jste si jist, že chcete provést tuto akci? Změny nelze vrátit zpět!',
'confirm_action_feed_cat' => 'Jste si jist, že chcete provést tuto akci? Přijdete o související oblíbené položky a uživatelské dotazy. Změny nelze vrátit zpět!',
'feedback' => array(
'body_new_articles' => 'Je \\d nových článků k přečtení v FreshRSS.',
'request_failed' => 'Požadavek selhal, což může být způsobeno problémy s připojení k internetu.',
'title_new_articles' => 'FreshRSS: nové články!',
),
'new_article' => 'Jsou k dispozici nové články, stránku obnovíte kliknutím zde.',
'should_be_activated' => 'JavaScript musí být povolen',
),
'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch',
'en' => 'English',
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
),
'menu' => array(
'about' => 'O aplikaci',
'admin' => 'Administrace',
'archiving' => 'Archivace',
'authentication' => 'Přihlášení',
'check_install' => 'Ověření instalace',
'configuration' => 'Nastavení',
'display' => 'Zobrazení',
'extensions' => 'Rozšíření',
'logs' => 'Logy',
'queries' => 'Uživatelské dotazy',
'reading' => 'Čtení',
'search' => 'Hledat výraz nebo #tagy',
'sharing' => 'Sdílení',
'shortcuts' => 'Zkratky',
'stats' => 'Statistika',
'system' => 'System configuration',// @todo translate
'update' => 'Aktualizace',
'user_management' => 'Správa uživatelů',
'user_profile' => 'Profil',
),
'pagination' => array(
'first' => 'První',
'last' => 'Poslední',
'load_more' => 'Načíst více článků',
'mark_all_read' => 'Označit vše jako přečtené',
'next' => 'Další',
'nothing_to_load' => 'Žádné nové články',
'previous' => 'Předchozí',
),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'movim' => 'Movim',
'print' => 'Tisk',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'short' => array(
'attention' => 'Upozornění!',
'blank_to_disable' => 'Zakázat - ponechte prázdné',
'by_author' => 'Od <em>%s</em>',
'by_default' => 'Výchozí',
'damn' => 'Sakra!',
'default_category' => 'Nezařazeno',
'no' => 'Ne',
'ok' => 'Ok!',
'or' => 'nebo',
'yes' => 'Ano',
),
);

61
sources/app/i18n/cz/index.php Executable file
View file

@ -0,0 +1,61 @@
<?php
return array(
'about' => array(
'_' => 'O FreshRSS',
'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
'bugs_reports' => 'Hlášení chyb',
'credits' => 'Poděkování',
'credits_content' => 'Některé designové prvky pocházejí z <a href="http://twitter.github.io/bootstrap/">Bootstrap</a>, FreshRSS ale tuto platformu nevyužívá. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Ikony</a> pocházejí z <a href="https://www.gnome.org/">GNOME projektu</a>. Font <em>Open Sans</em> vytvořil <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a>. Favicony jsou shromažďovány pomocí <a href="https://getfavicon.appspot.com/">getFavicon API</a>. FreshRSS je založen na PHP framework <a href="https://github.com/marienfressinaud/MINZ">Minz</a>.',
'freshrss_description' => 'FreshRSS je čtečka RSS kanálů určená k provozu na vlastním serveru, podobná <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> nebo <a href="http://projet.idleman.fr/leed/">Leed</a>. Je to nenáročný a jednoduchý, zároveň ale mocný a konfigurovatelný nástroj.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">na Github</a>',
'license' => 'Licence',
'project_website' => 'Stránka projektu',
'title' => 'O FreshRSS',
'version' => 'Verze',
'website' => 'Webové stránka',
),
'feed' => array(
'add' => 'Můžete přidat kanály.',
'empty' => 'Žádné články k zobrazení.',
'rss_of' => 'RSS kanál %s',
'title' => 'RSS kanály',
'title_global' => 'Přehled',
'title_fav' => 'Oblíbené',
),
'log' => array(
'_' => 'Logy',
'clear' => 'Vymazat logy',
'empty' => 'Log je prázdný',
'title' => 'Logy',
),
'menu' => array(
'about' => 'O FreshRSS',
'add_query' => 'Vytvořit dotaz',
'before_one_day' => 'Den nazpět',
'before_one_week' => 'Před týdnem',
'favorites' => 'Oblíbené (%s)',
'global_view' => 'Přehled',
'main_stream' => 'Všechny kanály',
'mark_all_read' => 'Označit vše jako přečtené',
'mark_cat_read' => 'Označit kategorii jako přečtenou',
'mark_feed_read' => 'Označit kanál jako přečtený',
'newer_first' => 'Nové nejdříve',
'non-starred' => 'Zobrazit vše vyjma oblíbených',
'normal_view' => 'Normální',
'older_first' => 'Nejstarší nejdříve',
'queries' => 'Uživatelské dotazy',
'read' => 'Zobrazovat přečtené',
'reader_view' => 'Čtení',
'rss_view' => 'RSS kanál',
'search_short' => 'Hledat',
'starred' => 'Zobrazit oblíbené',
'stats' => 'Statistika',
'subscription' => 'Správa subskripcí',
'unread' => 'Zobrazovat nepřečtené',
),
'share' => 'Sdílet',
'tag' => array(
'related' => 'Související tagy',
),
);

113
sources/app/i18n/cz/install.php Executable file
View file

@ -0,0 +1,113 @@
<?php
return array(
'action' => array(
'finish' => 'Dokončit instalaci',
'fix_errors_before' => 'Chyby prosím před přechodem na další krok opravte.',
'keep_install' => 'Zachovat předchozí instalaci',
'next_step' => 'Přejít na další krok',
'reinstall' => 'Reinstalovat FreshRSS',
),
'auth' => array(
'email_persona' => 'Email pro přihlášení<br /><small>(pro <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'form' => 'Webový formulář (tradiční, vyžaduje JavaScript)',
'http' => 'HTTP (pro pokročilé uživatele s HTTPS)',
'none' => 'Žádný (nebezpečné)',
'password_form' => 'Heslo<br /><small>(pro přihlášení webovým formulářem)</small>',
'password_format' => 'Alespoň 7 znaků',
'persona' => 'Mozilla Persona (moderní, vyžaduje JavaScript)',
'type' => 'Způsob přihlášení',
),
'bdd' => array(
'_' => 'Databáze',
'conf' => array(
'_' => 'Nastavení databáze',
'ko' => 'Ověřte informace o databázi.',
'ok' => 'Nastavení databáze bylo uloženo.',
),
'host' => 'Hostitel',
'prefix' => 'Prefix tabulky',
'password' => 'Heslo',
'type' => 'Typ databáze',
'username' => 'Uživatel',
),
'check' => array(
'_' => 'Kontrola',
'already_installed' => 'Zjistili jsme, že FreshRSS je již nainstalován!',
'cache' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/cache</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře cache jsou v pořádku.',
),
'ctype' => array(
'nok' => 'Není nainstalována požadovaná knihovna pro ověřování znaků (php-ctype).',
'ok' => 'Je nainstalována požadovaná knihovna pro ověřování znaků (ctype).',
),
'curl' => array(
'nok' => 'Nemáte cURL (balíček php5-curl).',
'ok' => 'Máte rozšíření cURL.',
),
'data' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře data jsou v pořádku.',
),
'dom' => array(
'nok' => 'Nemáte požadovanou knihovnu pro procházení DOM (balíček php-xml).',
'ok' => 'Máte požadovanou knihovnu pro procházení DOM.',
),
'favicons' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/favicons</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře favicons jsou v pořádku.',
),
'http_referer' => array(
'nok' => 'Zkontrolujte prosím že neměníte HTTP REFERER.',
'ok' => 'Váš HTTP REFERER je znám a odpovídá Vašemu serveru.',
),
'minz' => array(
'nok' => 'Nemáte framework Minz.',
'ok' => 'Máte framework Minz.',
),
'pcre' => array(
'nok' => 'Nemáte požadovanou knihovnu pro regulární výrazy (php-pcre).',
'ok' => 'Máte požadovanou knihovnu pro regulární výrazy (PCRE).',
),
'pdo' => array(
'nok' => 'Nemáte PDO nebo některý z podporovaných ovladačů (pdo_mysql, pdo_sqlite).',
'ok' => 'Máte PDO a alespoň jeden z podporovaných ovladačů (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/persona</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře Mozilla Persona jsou v pořádku.',
),
'php' => array(
'nok' => 'Vaše verze PHP je %s, ale FreshRSS vyžaduje alespoň verzi %s.',
'ok' => 'Vaše verze PHP je %s a je kompatibilní s FreshRSS.',
),
'users' => array(
'nok' => 'Zkontrolujte oprávnění adresáře <em>./data/users</em>. HTTP server musí mít do tohoto adresáře práva zápisu',
'ok' => 'Oprávnění adresáře users jsou v pořádku.',
),
),
'conf' => array(
'_' => 'Obecná nastavení',
'ok' => 'Nastavení bylo uloženo.',
),
'congratulations' => 'Gratulujeme!',
'default_user' => 'Jméno výchozího uživatele <small>(maximálně 16 alfanumerických znaků)</small>',
'delete_articles_after' => 'Smazat články starší než',
'fix_errors_before' => 'Chyby prosím před přechodem na další krok opravte.',
'javascript_is_better' => 'Práce s FreshRSS je příjemnější se zapnutým JavaScriptem',
'js' => array(
'confirm_reinstall' => 'Reinstalací FreshRSS ztratíte předchozí konfiguraci. Opravdu chcete pokračovat?',
),
'language' => array(
'_' => 'Jazyk',
'choose' => 'Vyberte jazyk FreshRSS',
'defined' => 'Jazyk byl nastaven.',
),
'not_deleted' => 'Nastala chyba, soubor <em>%s</em> musíte smazat ručně.',
'ok' => 'Instalace byla úspěšná.',
'step' => 'krok %d',
'steps' => 'Kroky',
'title' => 'Instalace · FreshRSS',
'this_is_the_end' => 'Konec',
);

62
sources/app/i18n/cz/sub.php Executable file
View file

@ -0,0 +1,62 @@
<?php
return array(
'category' => array(
'_' => 'Kategorie',
'add' => 'Přidat kategorii',
'empty' => 'Vyprázdit kategorii',
'new' => 'Nová kategorie',
),
'feed' => array(
'add' => 'Přidat RSS kanál',
'advanced' => 'Pokročilé',
'archiving' => 'Archivace',
'auth' => array(
'configuration' => 'Přihlášení',
'help' => 'Umožní přístup k RSS kanálům chráneným HTTP autentizací',
'http' => 'HTTP přihlášení',
'password' => 'Heslo',
'username' => 'Přihlašovací jméno',
),
'css_help' => 'Stáhne zkrácenou verzi RSS kanálů (pozor, náročnější na čas!)',
'css_path' => 'Původní CSS soubor článku z webových stránek',
'description' => 'Popis',
'empty' => 'Kanál je prázdný. Ověřte prosím zda je ještě autorem udržován.',
'error' => 'Vyskytl se problém s kanálem. Ověřte že je vždy dostupný, prosím, a poté jej aktualizujte.',
'in_main_stream' => 'Zobrazit ve “Všechny kanály”',
'informations' => 'Informace',
'keep_history' => 'Zachovat tento minimální počet článků',
'moved_category_deleted' => 'Po smazání kategorie budou v ní obsažené kanály automaticky přesunuty do <em>%s</em>.',
'no_selected' => 'Nejsou označeny žádné kanály.',
'number_entries' => '%d článků',
'stats' => 'Statistika',
'think_to_add' => 'Můžete přidat kanály.',
'title' => 'Název',
'title_add' => 'Přidat RSS kanál',
'ttl' => 'Neobnovovat častěji než',
'url' => 'URL kanálu',
'validator' => 'Zkontrolovat platnost kanálu',
'website' => 'URL webové stránky',
'pubsubhubbub' => 'Okamžité oznámení s PubSubHubbub',
),
'import_export' => array(
'export' => 'Export',
'export_opml' => 'Exportovat seznam kanálů (OPML)',
'export_starred' => 'Exportovat oblíbené',
'feed_list' => 'Seznam %s článků',
'file_to_import' => 'Soubor k importu<br />(OPML, Json nebo Zip)',
'file_to_import_no_zip' => 'Soubor k importu<br />(OPML nebo Json)',
'import' => 'Import',
'starred_list' => 'Seznam oblíbených článků',
'title' => 'Import / export',
),
'menu' => array(
'bookmark' => 'Přihlásit (FreshRSS bookmark)',
'import_export' => 'Import / export',
'subscription_management' => 'Správa subskripcí',
),
'title' => array(
'_' => 'Správa subskripcí',
'feed_management' => 'Správa RSS kanálů',
),
);

View file

@ -19,15 +19,15 @@ return array(
'check_install' => array( 'check_install' => array(
'cache' => array( 'cache' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/cache</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/cache</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/cache</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/cache</em> sind in Ordnung.',
), ),
'categories' => array( 'categories' => array(
'nok' => 'Die Tabelle <em>category</em> ist schlecht konfiguriert.', 'nok' => 'Die Tabelle <em>category</em> ist schlecht konfiguriert.',
'ok' => 'Die Tabelle <em>category</em> ist in Ordnung.', 'ok' => 'Die Tabelle <em>category</em> ist korrekt konfiguriert.',
), ),
'connection' => array( 'connection' => array(
'nok' => 'Verbindung zur Datenbank kann nicht aufgebaut werden.', 'nok' => 'Verbindung zur Datenbank kann nicht aufgebaut werden.',
'ok' => 'Verbindung zur Datenbank ist in Ordnung.', 'ok' => 'Verbindung zur Datenbank konnte aufgebaut werden.',
), ),
'ctype' => array( 'ctype' => array(
'nok' => 'Ihnen fehlt eine benötigte Bibliothek für die Überprüfung von Zeichentypen (php-ctype).', 'nok' => 'Ihnen fehlt eine benötigte Bibliothek für die Überprüfung von Zeichentypen (php-ctype).',
@ -39,7 +39,7 @@ return array(
), ),
'data' => array( 'data' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data</em> sind in Ordnung.',
), ),
'database' => 'Datenbank-Installation', 'database' => 'Datenbank-Installation',
'dom' => array( 'dom' => array(
@ -48,19 +48,19 @@ return array(
), ),
'entries' => array( 'entries' => array(
'nok' => 'Die Tabelle <em>entry</em> ist schlecht konfiguriert.', 'nok' => 'Die Tabelle <em>entry</em> ist schlecht konfiguriert.',
'ok' => 'Die Tabelle <em>entry</em> ist in Ordnung.', 'ok' => 'Die Tabelle <em>entry</em> ist korrekt konfiguriert.',
), ),
'favicons' => array( 'favicons' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/favicons</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/favicons</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/favicons</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/favicons</em> sind in Ordnung.',
), ),
'feeds' => array( 'feeds' => array(
'nok' => 'Die Tabelle <em>feed</em> ist schlecht konfiguriert.', 'nok' => 'Die Tabelle <em>feed</em> ist schlecht konfiguriert.',
'ok' => 'Die Tabelle <em>feed</em> ist in Ordnung.', 'ok' => 'Die Tabelle <em>feed</em> ist korrekt konfiguriert.',
), ),
'files' => 'Datei-Installation', 'files' => 'Datei-Installation',
'json' => array( 'json' => array(
'nok' => 'Ihnen fehlt JSON (Paket php5-json).', 'nok' => 'Ihnen fehlt die JSON-Erweiterung (Paket php5-json).',
'ok' => 'Sie haben die JSON-Erweiterung.', 'ok' => 'Sie haben die JSON-Erweiterung.',
), ),
'minz' => array( 'minz' => array(
@ -77,7 +77,7 @@ return array(
), ),
'persona' => array( 'persona' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/persona</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/persona</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/persona</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/persona</em> sind in Ordnung.',
), ),
'php' => array( 'php' => array(
'_' => 'PHP-Installation', '_' => 'PHP-Installation',
@ -91,11 +91,11 @@ return array(
'title' => 'Installationsüberprüfung', 'title' => 'Installationsüberprüfung',
'tokens' => array( 'tokens' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/tokens</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/tokens</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/tokens</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/tokens</em> sind in Ordnung.',
), ),
'users' => array( 'users' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/users</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/users</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/users</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/users</em> sind in Ordnung.',
), ),
'zip' => array( 'zip' => array(
'nok' => 'Ihnen fehlt die ZIP-Erweiterung (Paket php5-zip).', 'nok' => 'Ihnen fehlt die ZIP-Erweiterung (Paket php5-zip).',
@ -120,22 +120,22 @@ return array(
'category' => 'Kategorie', 'category' => 'Kategorie',
'entry_count' => 'Anzahl der Einträge', 'entry_count' => 'Anzahl der Einträge',
'entry_per_category' => 'Einträge pro Kategorie', 'entry_per_category' => 'Einträge pro Kategorie',
'entry_per_day' => 'Einträge pro Tag (letzte 30 Tage)', 'entry_per_day' => 'Einträge pro Tag (letzten 30 Tage)',
'entry_per_day_of_week' => 'Pro Wochentag (Durchschnitt: %.2f Nachrichten)', 'entry_per_day_of_week' => 'Pro Wochentag (Durchschnitt: %.2f Nachrichten)',
'entry_per_hour' => 'Pro Stunde (Durchschnitt: %.2f Nachrichten)', 'entry_per_hour' => 'Pro Stunde (Durchschnitt: %.2f Nachrichten)',
'entry_per_month' => 'Pro Monat (Durchschnitt: %.2f Nachrichten)', 'entry_per_month' => 'Pro Monat (Durchschnitt: %.2f Nachrichten)',
'entry_repartition' => 'Einträge-Verteilung', 'entry_repartition' => 'Einträge-Verteilung',
'feed' => 'Feed', 'feed' => 'Feed',
'feed_per_category' => 'Feeds pro Kategorie', 'feed_per_category' => 'Feeds pro Kategorie',
'idle' => 'Untätige Feeds', 'idle' => 'Inaktive Feeds',
'main' => 'Haupt-Statistiken', 'main' => 'Haupt-Statistiken',
'main_stream' => 'Haupt-Feeds', 'main_stream' => 'Haupt-Feeds',
'menu' => array( 'menu' => array(
'idle' => 'Untätige Feeds', 'idle' => 'Inaktive Feeds',
'main' => 'Haupt-Statistiken', 'main' => 'Haupt-Statistiken',
'repartition' => 'Artikel-Verteilung', 'repartition' => 'Artikel-Verteilung',
), ),
'no_idle' => 'Es gibt keinen untätigen Feed!', 'no_idle' => 'Es gibt keinen inaktiven Feed!',
'number_entries' => '%d Artikel', 'number_entries' => '%d Artikel',
'percent_of_total' => '%% Gesamt', 'percent_of_total' => '%% Gesamt',
'repartition' => 'Artikel-Verteilung', 'repartition' => 'Artikel-Verteilung',
@ -146,13 +146,24 @@ return array(
'title' => 'Statistiken', 'title' => 'Statistiken',
'top_feed' => 'Top 10-Feeds', 'top_feed' => 'Top 10-Feeds',
), ),
'system' => array(
'_' => 'System configuration', // @todo translate
'auto-update-url' => 'Auto-update server URL', // @todo translate
'instance-name' => 'Instance name', // @todo translate
'max-categories' => 'Categories per user limit', // @todo translate
'max-feeds' => 'Feeds per user limit', // @todo translate
'registration' => array(
'help' => '0 meint, dass es kein Account Limit gibt',
'number' => 'Maximale Anzahl von Accounts',
),
),
'update' => array( 'update' => array(
'_' => 'System aktualisieren', '_' => 'System aktualisieren',
'apply' => 'Anwenden', 'apply' => 'Anwenden',
'check' => 'Auf neue Aktualisierungen prüfen', 'check' => 'Auf neue Aktualisierungen prüfen',
'current_version' => 'Ihre aktuelle Version von FreshRSS ist %s.', 'current_version' => 'Ihre aktuelle Version von FreshRSS ist %s.',
'last' => 'Letzte Überprüfung: %s', 'last' => 'Letzte Überprüfung: %s',
'none' => 'Keine Aktualisierung zum Anwenden', 'none' => 'Keine ausstehende Aktualisierung',
'title' => 'System aktualisieren', 'title' => 'System aktualisieren',
), ),
'user' => array( 'user' => array(
@ -160,6 +171,8 @@ return array(
'create' => 'Neuen Benutzer erstellen', 'create' => 'Neuen Benutzer erstellen',
'email_persona' => 'Anmelde-E-Mail-Adresse<br /><small>(für <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Anmelde-E-Mail-Adresse<br /><small>(für <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'language' => 'Sprache', 'language' => 'Sprache',
'number' => 'Es wurde bis jetzt %d Account erstellt',
'numbers' => 'Es wurden bis jetzt %d Accounts erstellt',
'password_form' => 'Passwort<br /><small>(für die Anmeldemethode per Webformular)</small>', 'password_form' => 'Passwort<br /><small>(für die Anmeldemethode per Webformular)</small>',
'password_format' => 'mindestens 7 Zeichen', 'password_format' => 'mindestens 7 Zeichen',
'title' => 'Benutzer verwalten', 'title' => 'Benutzer verwalten',

View file

@ -5,8 +5,8 @@ return array(
'_' => 'Archivierung', '_' => 'Archivierung',
'advanced' => 'Erweitert', 'advanced' => 'Erweitert',
'delete_after' => 'Entferne Artikel nach', 'delete_after' => 'Entferne Artikel nach',
'help' => 'Weitere Optionen sind in den Einstellungen der individuellen Nachrichten-Feeds vorhanden.', 'help' => 'Weitere Optionen sind in den Einstellungen der individuellen Feeds verfügbar.',
'keep_history_by_feed' => 'Minimale Anzahl an Artikeln, die pro Feed behalten wird', 'keep_history_by_feed' => 'Minimale Anzahl an Artikeln, die pro Feed behalten werden',
'optimize' => 'Datenbank optimieren', 'optimize' => 'Datenbank optimieren',
'optimize_help' => 'Sollte gelegentlich durchgeführt werden, um die Größe der Datenbank zu reduzieren.', 'optimize_help' => 'Sollte gelegentlich durchgeführt werden, um die Größe der Datenbank zu reduzieren.',
'purge_now' => 'Jetzt bereinigen', 'purge_now' => 'Jetzt bereinigen',
@ -32,10 +32,10 @@ return array(
'title' => 'Anzeige', 'title' => 'Anzeige',
'width' => array( 'width' => array(
'content' => 'Inhaltsbreite', 'content' => 'Inhaltsbreite',
'large' => 'Weit', 'large' => 'Gross',
'medium' => 'Mittel', 'medium' => 'Mittel',
'no_limit' => 'Keine Begrenzung', 'no_limit' => 'Keine Begrenzung',
'thin' => 'Schmal', 'thin' => 'Klein',
), ),
), ),
'query' => array( 'query' => array(
@ -72,6 +72,10 @@ return array(
), ),
'profile' => array( 'profile' => array(
'_' => 'Profil-Verwaltung', '_' => 'Profil-Verwaltung',
'delete' => array(
'_' => 'Accountlöschung',
'warn' => 'Dein Account und alle damit bezogenen Daten werden gelöscht.',
),
'email_persona' => 'Anmelde-E-Mail-Adresse<br /><small>(für <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Anmelde-E-Mail-Adresse<br /><small>(für <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'password_api' => 'Passwort-API<br /><small>(z. B. für mobile Anwendungen)</small>', 'password_api' => 'Passwort-API<br /><small>(z. B. für mobile Anwendungen)</small>',
'password_form' => 'Passwort<br /><small>(für die Anmeldemethode per Webformular)</small>', 'password_form' => 'Passwort<br /><small>(für die Anmeldemethode per Webformular)</small>',
@ -84,6 +88,7 @@ return array(
'articles_per_page' => 'Anzahl der Artikel pro Seite', 'articles_per_page' => 'Anzahl der Artikel pro Seite',
'auto_load_more' => 'Die nächsten Artikel am Seitenende laden', 'auto_load_more' => 'Die nächsten Artikel am Seitenende laden',
'auto_remove_article' => 'Artikel nach dem Lesen verstecken', 'auto_remove_article' => 'Artikel nach dem Lesen verstecken',
'mark_updated_article_unread' => 'Markieren Sie aktualisierte Artikel als ungelesen',
'confirm_enabled' => 'Bei der Aktion „Alle als gelesen markieren“ einen Bestätigungsdialog anzeigen', 'confirm_enabled' => 'Bei der Aktion „Alle als gelesen markieren“ einen Bestätigungsdialog anzeigen',
'display_articles_unfolded' => 'Artikel standardmäßig ausgeklappt zeigen', 'display_articles_unfolded' => 'Artikel standardmäßig ausgeklappt zeigen',
'display_categories_unfolded' => 'Kategorien standardmäßig eingeklappt zeigen', 'display_categories_unfolded' => 'Kategorien standardmäßig eingeklappt zeigen',
@ -135,14 +140,14 @@ return array(
'wallabag' => 'wallabag', 'wallabag' => 'wallabag',
), ),
'shortcut' => array( 'shortcut' => array(
'_' => 'Tastaturkürzel', '_' => 'Tastenkombination',
'article_action' => 'Artikelaktionen', 'article_action' => 'Artikelaktionen',
'auto_share' => 'Teilen', 'auto_share' => 'Teilen',
'auto_share_help' => 'Wenn es nur eine Option zum Teilen gibt, wird diese verwendet. Ansonsten sind die Optionen über ihre Nummer erreichbar.', 'auto_share_help' => 'Wenn es nur eine Option zum Teilen gibt, wird diese verwendet. Ansonsten sind die Optionen über ihre Nummer erreichbar.',
'close_dropdown' => 'Menüs schließen', 'close_dropdown' => 'Menüs schließen',
'collapse_article' => 'Zusammenfalten', 'collapse_article' => 'Einklappen',
'first_article' => 'Zum ersten Artikel springen', 'first_article' => 'Zum ersten Artikel springen',
'focus_search' => 'Auf Suchfeld zugreifen', 'focus_search' => 'Auf das Suchfeld zugreifen',
'help' => 'Dokumentation anzeigen', 'help' => 'Dokumentation anzeigen',
'javascript' => 'JavaScript muss aktiviert sein, um Tastaturkürzel benutzen zu können', 'javascript' => 'JavaScript muss aktiviert sein, um Tastaturkürzel benutzen zu können',
'last_article' => 'Zum letzten Artikel springen', 'last_article' => 'Zum letzten Artikel springen',
@ -150,13 +155,13 @@ return array(
'mark_read' => 'Als gelesen markieren', 'mark_read' => 'Als gelesen markieren',
'mark_favorite' => 'Als Favorit markieren', 'mark_favorite' => 'Als Favorit markieren',
'navigation' => 'Navigation', 'navigation' => 'Navigation',
'navigation_help' => 'Mit der "Umschalttaste" finden die Tastaturkürzel auf Feeds Anwendung.<br/>Mit der "Alt-Taste" finden die Tastaturkürzel auf Kategorien Anwendung.', 'navigation_help' => 'Mit der "Umschalttaste" finden die Tastenkombination auf Feeds Anwendung.<br/>Mit der "Alt-Taste" finden die Tastenkombination auf Kategorien Anwendung.',
'next_article' => 'Zum nächsten Artikel springen', 'next_article' => 'Zum nächsten Artikel springen',
'other_action' => 'Andere Aktionen', 'other_action' => 'Andere Aktionen',
'previous_article' => 'Zum vorherigen Artikel springen', 'previous_article' => 'Zum vorherigen Artikel springen',
'see_on_website' => 'Auf der Original-Webseite ansehen', 'see_on_website' => 'Auf der Original-Webseite ansehen',
'shift_for_all_read' => '+ <code>Umschalttaste</code>, um alle Artikel als gelesen zu markieren.', 'shift_for_all_read' => '+ <code>Umschalttaste</code>, um alle Artikel als gelesen zu markieren.',
'title' => 'Tastaturkürzel', 'title' => 'Tastenkombination',
'user_filter' => 'Auf Benutzerfilter zugreifen', 'user_filter' => 'Auf Benutzerfilter zugreifen',
'user_filter_help' => 'Wenn es nur einen Benutzerfilter gibt, wird dieser verwendet. Ansonsten sind die Filter über ihre Nummer erreichbar.', 'user_filter_help' => 'Wenn es nur einen Benutzerfilter gibt, wird dieser verwendet. Ansonsten sind die Filter über ihre Nummer erreichbar.',
), ),

View file

@ -15,19 +15,19 @@ return array(
), ),
'login' => array( 'login' => array(
'invalid' => 'Anmeldung ist ungültig', 'invalid' => 'Anmeldung ist ungültig',
'success' => 'Sie sind verbunden', 'success' => 'Sie sind angemeldet',
), ),
'logout' => array( 'logout' => array(
'success' => 'Sie sind getrennt', 'success' => 'Sie sind abgemeldet',
), ),
'no_password_set' => 'Administrator-Passwort ist nicht gesetzt worden. Dieses Feature ist nicht verfügbar.', 'no_password_set' => 'Administrator-Passwort ist nicht gesetzt worden. Dieses Feature ist nicht verfügbar.',
'not_persona' => 'Nur das Persona-System kann zurückgesetzt werden.', 'not_persona' => 'Nur das Persona-System kann zurückgesetzt werden.',
), ),
'conf' => array( 'conf' => array(
'error' => 'Während des Speicherung der Konfiguration trat ein Fehler auf', 'error' => 'Während der Speicherung der Konfiguration trat ein Fehler auf',
'query_created' => 'Abfrage "%s" ist erstellt worden.', 'query_created' => 'Abfrage "%s" ist erstellt worden.',
'shortcuts_updated' => 'Tastaturkürzel sind aktualisiert worden', 'shortcuts_updated' => 'Die Tastenkombinationen sind aktualisiert worden',
'updated' => 'Konfiguration ist aktualisiert worden', 'updated' => 'Die Konfiguration ist aktualisiert worden',
), ),
'extensions' => array( 'extensions' => array(
'already_enabled' => '%s ist bereits aktiviert', 'already_enabled' => '%s ist bereits aktiviert',
@ -44,44 +44,44 @@ return array(
'not_found' => '%s existiert nicht', 'not_found' => '%s existiert nicht',
), ),
'import_export' => array( 'import_export' => array(
'export_no_zip_extension' => 'Die Zip-Erweiterung fehlt auf Ihrem Server. Bitte versuchen Sie, Dateien eine nach der anderen zu exportieren.', 'export_no_zip_extension' => 'Die Zip-Erweiterung fehlt auf Ihrem Server. Bitte versuchen Sie die Dateien eine nach der anderen zu exportieren.',
'feeds_imported' => 'Ihre Feeds sind importiert worden und werden jetzt aktualisiert', 'feeds_imported' => 'Ihre Feeds sind importiert worden und werden jetzt aktualisiert',
'feeds_imported_with_errors' => 'Ihre Feeds sind importiert worden, aber es traten einige Fehler auf', 'feeds_imported_with_errors' => 'Ihre Feeds sind importiert worden, aber es traten einige Fehler auf',
'file_cannot_be_uploaded' => 'Datei kann nicht hochgeladen werden!', 'file_cannot_be_uploaded' => 'Die Datei kann nicht hochgeladen werden!',
'no_zip_extension' => 'Die Zip-Erweiterung ist auf Ihrem Server nicht vorhanden.', 'no_zip_extension' => 'Die Zip-Erweiterung ist auf Ihrem Server nicht vorhanden.',
'zip_error' => 'Ein Fehler trat während des Zip-Imports auf.', 'zip_error' => 'Ein Fehler trat während des Zip-Imports auf.',
), ),
'sub' => array( 'sub' => array(
'actualize' => 'Aktualisieren', 'actualize' => 'Aktualisieren',
'category' => array( 'category' => array(
'created' => 'Kategorie %s ist erstellt worden.', 'created' => 'Die Kategorie %s ist erstellt worden.',
'deleted' => 'Kategorie ist gelöscht worden.', 'deleted' => 'Die Kategorie ist gelöscht worden.',
'emptied' => 'Kategorie ist geleert worden.', 'emptied' => 'Die Kategorie ist geleert worden.',
'error' => 'Kategorie kann nicht aktualisiert werden', 'error' => 'Die Kategorie kann nicht aktualisiert werden',
'name_exists' => 'Kategorie-Name existiert bereits.', 'name_exists' => 'Der Kategorie-Name existiert bereits.',
'no_id' => 'Sie müssen die ID der Kategorie präzisieren.', 'no_id' => 'Sie müssen die ID der Kategorie präzisieren.',
'no_name' => 'Kategorie-Name kann nicht leer sein.', 'no_name' => 'Der Kategorie-Name kann nicht leer sein.',
'not_delete_default' => 'Sie können die Vorgabe-Kategorie nicht löschen!', 'not_delete_default' => 'Sie können die Vorgabe-Kategorie nicht löschen!',
'not_exist' => 'Die Kategorie existiert nicht!', 'not_exist' => 'Die Kategorie existiert nicht!',
'over_max' => 'Sie haben Ihr Kategorien-Limit erreicht (%d)', 'over_max' => 'Sie haben Ihre Kategorien-Limite erreicht (%d)',
'updated' => 'Kategorie ist aktualisiert worden.', 'updated' => 'Die Kategorie ist aktualisiert worden.',
), ),
'feed' => array( 'feed' => array(
'actualized' => '<em>%s</em> ist aktualisiert worden', 'actualized' => '<em>%s</em> ist aktualisiert worden',
'actualizeds' => 'RSS-Feeds sind aktualisiert worden', 'actualizeds' => 'Die RSS-Feeds sind aktualisiert worden',
'added' => 'RSS-Feed <em>%s</em> ist hinzugefügt worden', 'added' => 'Der RSS-Feed <em>%s</em> ist hinzugefügt worden',
'already_subscribed' => 'Sie haben <em>%s</em> bereits abonniert', 'already_subscribed' => 'Sie haben <em>%s</em> bereits abonniert',
'deleted' => 'Feed ist gelöscht worden', 'deleted' => 'Der Feed ist gelöscht worden',
'error' => 'Feed kann nicht aktualisiert werden', 'error' => 'Der Feed kann nicht aktualisiert werden',
'internal_problem' => 'Der RSS-Feed konnte nicht hinzugefügt werden. Für Details <a href="%s">prüfen Sie die FressRSS-Protokolle</a>.', 'internal_problem' => 'Der RSS-Feed konnte nicht hinzugefügt werden. Für Details <a href="%s">prüfen Sie die FressRSS-Protokolle</a>.',
'invalid_url' => 'URL <em>%s</em> ist ungültig', 'invalid_url' => 'Die URL <em>%s</em> ist ungültig',
'marked_read' => 'Feeds sind als gelesen markiert worden', 'marked_read' => 'Die Feeds sind als gelesen markiert worden',
'n_actualized' => '%d Feeds sind aktualisiert worden', 'n_actualized' => 'Die %d Feeds sind aktualisiert worden',
'n_entries_deleted' => '%d Artikel sind gelöscht worden', 'n_entries_deleted' => 'Die %d Artikel sind gelöscht worden',
'no_refresh' => 'Es gibt keinen Feed zum Aktualisieren…', 'no_refresh' => 'Es gibt keinen Feed zum Aktualisieren…',
'not_added' => '<em>%s</em> konnte nicht hinzugefügt werden', 'not_added' => '<em>%s</em> konnte nicht hinzugefügt werden',
'over_max' => 'Sie haben Ihr Feeds-Limit erreicht (%d)', 'over_max' => 'Sie haben Ihre Feeds-Limite erreicht (%d)',
'updated' => 'Feed ist aktualisiert worden', 'updated' => 'Der Feed ist aktualisiert worden',
), ),
'purge_completed' => 'Bereinigung abgeschlossen (%d Artikel gelöscht)', 'purge_completed' => 'Bereinigung abgeschlossen (%d Artikel gelöscht)',
), ),
@ -91,16 +91,16 @@ return array(
'file_is_nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>%s</em>. Der HTTP-Server muss Schreibrechte besitzen', 'file_is_nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>%s</em>. Der HTTP-Server muss Schreibrechte besitzen',
'finished' => 'Aktualisierung abgeschlossen!', 'finished' => 'Aktualisierung abgeschlossen!',
'none' => 'Keine Aktualisierung zum Anwenden', 'none' => 'Keine Aktualisierung zum Anwenden',
'server_not_found' => 'Aktualisierungs-Server kann nicht gefunden werden. [%s]', 'server_not_found' => 'Der Aktualisierungs-Server kann nicht gefunden werden. [%s]',
), ),
'user' => array( 'user' => array(
'created' => array( 'created' => array(
'_' => 'Benutzer %s ist erstellt worden', '_' => 'Der Benutzer %s ist erstellt worden',
'error' => 'Benutzer %s kann nicht erstellt werden', 'error' => 'Der Benutzer %s kann nicht erstellt werden',
), ),
'deleted' => array( 'deleted' => array(
'_' => 'Benutzer %s ist gelöscht worden', '_' => 'Der Benutzer %s ist gelöscht worden',
'error' => 'Benutzer %s kann nicht gelöscht werden', 'error' => 'Der Benutzer %s kann nicht gelöscht werden',
), ),
), ),
'profile' => array( 'profile' => array(

View file

@ -21,15 +21,27 @@ return array(
'truncate' => 'Alle Artikel löschen', 'truncate' => 'Alle Artikel löschen',
), ),
'auth' => array( 'auth' => array(
'email' => 'E-Mail-Adresse',
'keep_logged_in' => 'Eingeloggt bleiben <small>(1 Monat)</small>', 'keep_logged_in' => 'Eingeloggt bleiben <small>(1 Monat)</small>',
'login' => 'Anmelden', 'login' => 'Anmelden',
'login_persona' => 'Anmelden mit Persona', 'login_persona' => 'Anmelden mit Persona',
'login_persona_problem' => 'Verbindungsproblem mit Persona?', 'login_persona_problem' => 'Verbindungsproblem mit Persona?',
'logout' => 'Abmelden', 'logout' => 'Abmelden',
'password' => 'Passwort', 'password' => array(
'_' => 'Passwort',
'format' => '<small>mindestens 7 Zeichen</small>',
),
'registration' => array(
'_' => 'Neuer Account',
'ask' => 'Erstelle einen Account?',
'title' => 'Accounterstellung',
),
'reset' => 'Zurücksetzen der Authentifizierung', 'reset' => 'Zurücksetzen der Authentifizierung',
'username' => 'Nutzername', 'username' => array(
'username_admin' => 'Administrator-Nutzername', '_' => 'Nutzername',
'admin' => 'Administrator-Nutzername',
'format' => '<small>maximal 16 alphanumerische Zeichen</small>',
),
'will_reset' => 'Authentifikationssystem wird zurückgesetzt: ein Formular wird anstelle von Persona benutzt.', 'will_reset' => 'Authentifikationssystem wird zurückgesetzt: ein Formular wird anstelle von Persona benutzt.',
), ),
'date' => array( 'date' => array(
@ -49,7 +61,7 @@ return array(
'april' => 'April', 'april' => 'April',
'aug' => 'Aug', 'aug' => 'Aug',
'august' => 'August', 'august' => 'August',
'before_yesterday' => 'Vor gestern', 'before_yesterday' => 'Vor vorgestern',
'dec' => 'Dez', 'dec' => 'Dez',
'december' => 'Dezember', 'december' => 'Dezember',
'feb' => 'Feb', 'feb' => 'Feb',
@ -93,7 +105,7 @@ return array(
), ),
'js' => array( 'js' => array(
'category_empty' => 'Kategorie leeren', 'category_empty' => 'Kategorie leeren',
'confirm_action' => 'Sind Sie sicher, dass Sie diese Aktion durchführen wollen? Dies kann nicht abgebrochen werden!', 'confirm_action' => 'Sind Sie sicher, dass Sie diese Aktion durchführen wollen? Diese Aktion kann nicht abgebrochen werden!',
'confirm_action_feed_cat' => 'Sind Sie sicher, dass Sie diese Aktion durchführen wollen? Sie werden zugehörige Favoriten und Benutzerabfragen verlieren. Dies kann nicht abgebrochen werden!', 'confirm_action_feed_cat' => 'Sind Sie sicher, dass Sie diese Aktion durchführen wollen? Sie werden zugehörige Favoriten und Benutzerabfragen verlieren. Dies kann nicht abgebrochen werden!',
'feedback' => array( 'feedback' => array(
'body_new_articles' => 'Es gibt \\d neue Artikel zum Lesen auf FreshRSS.', 'body_new_articles' => 'Es gibt \\d neue Artikel zum Lesen auf FreshRSS.',
@ -104,9 +116,12 @@ return array(
'should_be_activated' => 'JavaScript muss aktiviert sein', 'should_be_activated' => 'JavaScript muss aktiviert sein',
), ),
'lang' => array( 'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch', 'de' => 'Deutsch',
'en' => 'English', 'en' => 'English',
'fr' => 'Français', 'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
), ),
'menu' => array( 'menu' => array(
'about' => 'Über', 'about' => 'Über',
@ -124,6 +139,7 @@ return array(
'sharing' => 'Teilen', 'sharing' => 'Teilen',
'shortcuts' => 'Tastaturkürzel', 'shortcuts' => 'Tastaturkürzel',
'stats' => 'Statistiken', 'stats' => 'Statistiken',
'system' => 'System configuration',// @todo translate
'update' => 'Aktualisieren', 'update' => 'Aktualisieren',
'user_management' => 'Benutzer verwalten', 'user_management' => 'Benutzer verwalten',
'user_profile' => 'Profil', 'user_profile' => 'Profil',
@ -143,6 +159,7 @@ return array(
'email' => 'E-Mail', 'email' => 'E-Mail',
'facebook' => 'Facebook', 'facebook' => 'Facebook',
'g+' => 'Google+', 'g+' => 'Google+',
'movim' => 'Movim',
'print' => 'Drucken', 'print' => 'Drucken',
'shaarli' => 'Shaarli', 'shaarli' => 'Shaarli',
'twitter' => 'Twitter', 'twitter' => 'Twitter',
@ -156,6 +173,7 @@ return array(
'damn' => 'Verdammt!', 'damn' => 'Verdammt!',
'default_category' => 'Unkategorisiert', 'default_category' => 'Unkategorisiert',
'no' => 'Nein', 'no' => 'Nein',
'not_applicable' => 'Nicht verfügbar',
'ok' => 'OK!', 'ok' => 'OK!',
'or' => 'oder', 'or' => 'oder',
'yes' => 'Ja', 'yes' => 'Ja',

View file

@ -17,7 +17,7 @@ return array(
), ),
'feed' => array( 'feed' => array(
'add' => 'Sie können Feeds hinzufügen.', 'add' => 'Sie können Feeds hinzufügen.',
'empty' => 'Es gibt keinen Artikel zum Zeigen.', 'empty' => 'Es gibt keinen Artikel zum Anzeigen.',
'rss_of' => 'RSS-Feed von %s', 'rss_of' => 'RSS-Feed von %s',
'title' => 'Ihre RSS-Feeds', 'title' => 'Ihre RSS-Feeds',
'title_global' => 'Globale Ansicht', 'title_global' => 'Globale Ansicht',

View file

@ -3,8 +3,10 @@
return array( return array(
'action' => array( 'action' => array(
'finish' => 'Installation fertigstellen', 'finish' => 'Installation fertigstellen',
'fix_errors_before' => 'Fehler korrigieren, bevor zum nächsten Schritt gesprungen wird.', 'fix_errors_before' => 'Bitte Fehler korrigieren, bevor zum nächsten Schritt gesprungen wird.',
'next_step' => 'Zum nächsten Schritt gehen', 'keep_install' => 'Vorherige Installation beibehalten (Daten)',
'next_step' => 'Zum nächsten Schritt springen',
'reinstall' => 'Neuinstallation von FreshRSS',
), ),
'auth' => array( 'auth' => array(
'email_persona' => 'Anmelde-E-Mail-Adresse<br /><small>(für <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Anmelde-E-Mail-Adresse<br /><small>(für <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
@ -25,15 +27,16 @@ return array(
), ),
'host' => 'Host', 'host' => 'Host',
'prefix' => 'Tabellen-Präfix', 'prefix' => 'Tabellen-Präfix',
'password' => 'HTTP-Password', 'password' => 'SQL-Password',
'type' => 'Datenbank-Typ', 'type' => 'Datenbank-Typ',
'username' => 'HTTP-Nutzername', 'username' => 'SQL-Nutzername',
), ),
'check' => array( 'check' => array(
'_' => 'Überprüfungen', '_' => 'Überprüfungen',
'already_installed' => 'Wir haben festgestellt, dass FreshRSS bereits installiert wurde!',
'cache' => array( 'cache' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/cache</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/cache</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/cache</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/cache</em> sind in Ordnung.',
), ),
'ctype' => array( 'ctype' => array(
'nok' => 'Ihnen fehlt eine benötigte Bibliothek für die Überprüfung von Zeichentypen (php-ctype).', 'nok' => 'Ihnen fehlt eine benötigte Bibliothek für die Überprüfung von Zeichentypen (php-ctype).',
@ -45,7 +48,7 @@ return array(
), ),
'data' => array( 'data' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data</em> sind in Ordnung.',
), ),
'dom' => array( 'dom' => array(
'nok' => 'Ihnen fehlt eine benötigte Bibliothek um DOM zu durchstöbern (Paket php-xml).', 'nok' => 'Ihnen fehlt eine benötigte Bibliothek um DOM zu durchstöbern (Paket php-xml).',
@ -53,7 +56,7 @@ return array(
), ),
'favicons' => array( 'favicons' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/favicons</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/favicons</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/favicons</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/favicons</em> sind in Ordnung.',
), ),
'http_referer' => array( 'http_referer' => array(
'nok' => 'Bitte stellen Sie sicher, dass Sie Ihren HTTP REFERER nicht abändern.', 'nok' => 'Bitte stellen Sie sicher, dass Sie Ihren HTTP REFERER nicht abändern.',
@ -73,7 +76,7 @@ return array(
), ),
'persona' => array( 'persona' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/persona</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/persona</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/persona</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/persona</em> sind in Ordnung.',
), ),
'php' => array( 'php' => array(
'nok' => 'Ihre PHP-Version ist %s aber FreshRSS benötigt mindestens Version %s.', 'nok' => 'Ihre PHP-Version ist %s aber FreshRSS benötigt mindestens Version %s.',
@ -81,22 +84,25 @@ return array(
), ),
'users' => array( 'users' => array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/users</em>. Der HTTP-Server muss Schreibrechte besitzen.', 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/users</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Berechtigungen des Verzeichnisses <em>./data/users</em> sind in Ordnung.', 'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/users</em> sind in Ordnung.',
), ),
), ),
'conf' => array( 'conf' => array(
'_' => 'Allgemeine Konfiguration', '_' => 'Allgemeine Konfiguration',
'ok' => 'Allgemeine Konfiguration ist gespeichert worden.', 'ok' => 'Die allgemeine Konfiguration ist gespeichert worden.',
), ),
'congratulations' => 'Glückwunsch!', 'congratulations' => 'Glückwunsch!',
'default_user' => 'Nutzername des Standardbenutzers <small>(maximal 16 alphanumerische Zeichen)</small>', 'default_user' => 'Nutzername des Standardbenutzers <small>(maximal 16 alphanumerische Zeichen)</small>',
'delete_articles_after' => 'Entferne Artikel nach', 'delete_articles_after' => 'Entferne Artikel nach',
'fix_errors_before' => 'Fehler korrigieren, bevor zum nächsten Schritt gesprungen wird.', 'fix_errors_before' => 'Bitte den Fehler korrigieren, bevor zum nächsten Schritt gesprungen wird.',
'javascript_is_better' => 'FreshRSS ist ansprechender mit aktiviertem JavaScript', 'javascript_is_better' => 'FreshRSS ist ansprechender mit aktiviertem JavaScript',
'js' => array(
'confirm_reinstall' => 'Du wirst deine vorherige Konfiguration (Daten) verlieren FreshRSS. Bist du sicher, dass du fortfahren willst?',
),
'language' => array( 'language' => array(
'_' => 'Sprache', '_' => 'Sprache',
'choose' => 'Wählen Sie eine Sprache für FreshRSS', 'choose' => 'Wählen Sie eine Sprache für FreshRSS',
'defined' => 'Sprache ist festgelegt worden.', 'defined' => 'Die Sprache ist festgelegt worden.',
), ),
'not_deleted' => 'Etwas ist schiefgelaufen; Sie müssen die Datei <em>%s</em> manuell löschen.', 'not_deleted' => 'Etwas ist schiefgelaufen; Sie müssen die Datei <em>%s</em> manuell löschen.',
'ok' => 'Der Installationsvorgang war erfolgreich.', 'ok' => 'Der Installationsvorgang war erfolgreich.',

View file

@ -37,6 +37,7 @@ return array(
'url' => 'Feed-URL', 'url' => 'Feed-URL',
'validator' => 'Überprüfen Sie die Gültigkeit des Feeds', 'validator' => 'Überprüfen Sie die Gültigkeit des Feeds',
'website' => 'Webseiten-URL', 'website' => 'Webseiten-URL',
'pubsubhubbub' => 'Sofortbenachrichtigung mit PubSubHubbub',
), ),
'import_export' => array( 'import_export' => array(
'export' => 'Exportieren', 'export' => 'Exportieren',

View file

@ -12,7 +12,7 @@ return array(
'title' => 'Authentication', 'title' => 'Authentication',
'title_reset' => 'Authentication reset', 'title_reset' => 'Authentication reset',
'token' => 'Authentication token', 'token' => 'Authentication token',
'token_help' => 'Allows to access RSS output of the default user without authentication:', 'token_help' => 'Allows access to RSS output of the default user without authentication:',
'type' => 'Authentication method', 'type' => 'Authentication method',
'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ',
), ),
@ -146,6 +146,17 @@ return array(
'title' => 'Statistics', 'title' => 'Statistics',
'top_feed' => 'Top ten feeds', 'top_feed' => 'Top ten feeds',
), ),
'system' => array(
'_' => 'System configuration',
'auto-update-url' => 'Auto-update server URL',
'instance-name' => 'Instance name',
'max-categories' => 'Categories per user limit',
'max-feeds' => 'Feeds per user limit',
'registration' => array(
'help' => '0 means that there is no account limit',
'number' => 'Max number of accounts',
),
),
'update' => array( 'update' => array(
'_' => 'Update system', '_' => 'Update system',
'apply' => 'Apply', 'apply' => 'Apply',
@ -160,6 +171,8 @@ return array(
'create' => 'Create new user', 'create' => 'Create new user',
'email_persona' => 'Login mail address<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Login mail address<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'language' => 'Language', 'language' => 'Language',
'number' => 'There is %d account created yet',
'numbers' => 'There are %d accounts created yet',
'password_form' => 'Password<br /><small>(for the Web-form login method)</small>', 'password_form' => 'Password<br /><small>(for the Web-form login method)</small>',
'password_format' => 'At least 7 characters', 'password_format' => 'At least 7 characters',
'title' => 'Manage users', 'title' => 'Manage users',

View file

@ -5,9 +5,9 @@ return array(
'_' => 'Archiving', '_' => 'Archiving',
'advanced' => 'Advanced', 'advanced' => 'Advanced',
'delete_after' => 'Remove articles after', 'delete_after' => 'Remove articles after',
'help' => 'More options are available in the individual stream settings', 'help' => 'More options are available in the individual feed settings',
'keep_history_by_feed' => 'Minimum number of articles to keep by feed', 'keep_history_by_feed' => 'Minimum number of articles to keep by feed',
'optimize' => 'Optimize database', 'optimize' => 'Optimise database',
'optimize_help' => 'To do occasionally to reduce the size of the database', 'optimize_help' => 'To do occasionally to reduce the size of the database',
'purge_now' => 'Purge now', 'purge_now' => 'Purge now',
'title' => 'Archiving', 'title' => 'Archiving',
@ -72,7 +72,11 @@ return array(
), ),
'profile' => array( 'profile' => array(
'_' => 'Profile management', '_' => 'Profile management',
'email_persona' => 'Login mail address<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'delete' => array(
'_' => 'Account deletion',
'warn' => 'Your account and all the related data will be deleted.',
),
'email_persona' => 'Login email address<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'password_api' => 'Password API<br /><small>(e.g., for mobile apps)</small>', 'password_api' => 'Password API<br /><small>(e.g., for mobile apps)</small>',
'password_form' => 'Password<br /><small>(for the Web-form login method)</small>', 'password_form' => 'Password<br /><small>(for the Web-form login method)</small>',
'password_format' => 'At least 7 characters', 'password_format' => 'At least 7 characters',
@ -84,6 +88,7 @@ return array(
'articles_per_page' => 'Number of articles per page', 'articles_per_page' => 'Number of articles per page',
'auto_load_more' => 'Load next articles at the page bottom', 'auto_load_more' => 'Load next articles at the page bottom',
'auto_remove_article' => 'Hide articles after reading', 'auto_remove_article' => 'Hide articles after reading',
'mark_updated_article_unread' => 'Mark updated articles as unread',
'confirm_enabled' => 'Display a confirmation dialog on “mark all as read” actions', 'confirm_enabled' => 'Display a confirmation dialog on “mark all as read” actions',
'display_articles_unfolded' => 'Show articles unfolded by default', 'display_articles_unfolded' => 'Show articles unfolded by default',
'display_categories_unfolded' => 'Show categories folded by default', 'display_categories_unfolded' => 'Show categories folded by default',

View file

@ -2,7 +2,7 @@
return array( return array(
'admin' => array( 'admin' => array(
'optimization_complete' => 'Optimization complete', 'optimization_complete' => 'Optimisation complete',
), ),
'access' => array( 'access' => array(
'denied' => 'You dont have permission to access this page', 'denied' => 'You dont have permission to access this page',
@ -52,7 +52,7 @@ return array(
'zip_error' => 'An error occured during Zip import.', 'zip_error' => 'An error occured during Zip import.',
), ),
'sub' => array( 'sub' => array(
'actualize' => 'Actualize', 'actualize' => 'Actualise',
'category' => array( 'category' => array(
'created' => 'Category %s has been created.', 'created' => 'Category %s has been created.',
'deleted' => 'Category has been deleted.', 'deleted' => 'Category has been deleted.',
@ -86,7 +86,7 @@ return array(
'purge_completed' => 'Purge completed (%d articles deleted)', 'purge_completed' => 'Purge completed (%d articles deleted)',
), ),
'update' => array( 'update' => array(
'can_apply' => 'FreshRSS will be now updated to the <strong>version %s</strong>.', 'can_apply' => 'FreshRSS will now be updated to the <strong>version %s</strong>.',
'error' => 'The update process has encountered an error: %s', 'error' => 'The update process has encountered an error: %s',
'file_is_nok' => 'Check permissions on <em>%s</em> directory. HTTP server must have rights to write into', 'file_is_nok' => 'Check permissions on <em>%s</em> directory. HTTP server must have rights to write into',
'finished' => 'Update completed!', 'finished' => 'Update completed!',

View file

@ -10,7 +10,7 @@ return array(
'empty' => 'Empty', 'empty' => 'Empty',
'enable' => 'Enable', 'enable' => 'Enable',
'export' => 'Export', 'export' => 'Export',
'filter' => 'Filtrer', 'filter' => 'Filter',
'import' => 'Import', 'import' => 'Import',
'manage' => 'Manage', 'manage' => 'Manage',
'mark_read' => 'Mark as read', 'mark_read' => 'Mark as read',
@ -21,15 +21,27 @@ return array(
'truncate' => 'Delete all articles', 'truncate' => 'Delete all articles',
), ),
'auth' => array( 'auth' => array(
'email' => 'Email address',
'keep_logged_in' => 'Keep me logged in <small>(1 month)</small>', 'keep_logged_in' => 'Keep me logged in <small>(1 month)</small>',
'login' => 'Login', 'login' => 'Login',
'login_persona' => 'Login with Persona', 'login_persona' => 'Login with Persona',
'login_persona_problem' => 'Connection problem with Persona?', 'login_persona_problem' => 'Connection problem with Persona?',
'logout' => 'Logout', 'logout' => 'Logout',
'password' => 'Password', 'password' => array(
'_' => 'Password',
'format' => '<small>At least 7 characters</small>',
),
'registration' => array(
'_' => 'New account',
'ask' => 'Create an account?',
'title' => 'Account creation',
),
'reset' => 'Authentication reset', 'reset' => 'Authentication reset',
'username' => 'Username', 'username' => array(
'username_admin' => 'Administrator username', '_' => 'Username',
'admin' => 'Administrator username',
'format' => '<small>maximum 16 alphanumeric characters</small>',
),
'will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', 'will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.',
), ),
'date' => array( 'date' => array(
@ -104,9 +116,12 @@ return array(
'should_be_activated' => 'JavaScript must be enabled', 'should_be_activated' => 'JavaScript must be enabled',
), ),
'lang' => array( 'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch', 'de' => 'Deutsch',
'en' => 'English', 'en' => 'English',
'fr' => 'Français', 'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
), ),
'menu' => array( 'menu' => array(
'about' => 'About', 'about' => 'About',
@ -124,6 +139,7 @@ return array(
'sharing' => 'Sharing', 'sharing' => 'Sharing',
'shortcuts' => 'Shortcuts', 'shortcuts' => 'Shortcuts',
'stats' => 'Statistics', 'stats' => 'Statistics',
'system' => 'System configuration',
'update' => 'Update', 'update' => 'Update',
'user_management' => 'Manage users', 'user_management' => 'Manage users',
'user_profile' => 'Profile', 'user_profile' => 'Profile',
@ -143,19 +159,21 @@ return array(
'email' => 'Email', 'email' => 'Email',
'facebook' => 'Facebook', 'facebook' => 'Facebook',
'g+' => 'Google+', 'g+' => 'Google+',
'movim' => 'Movim',
'print' => 'Print', 'print' => 'Print',
'shaarli' => 'Shaarli', 'shaarli' => 'Shaarli',
'twitter' => 'Twitter', 'twitter' => 'Twitter',
'wallabag' => 'wallabag', 'wallabag' => 'wallabag',
), ),
'short' => array( 'short' => array(
'attention' => 'Attention!', 'attention' => 'Warning!',
'blank_to_disable' => 'Leave blank to disable', 'blank_to_disable' => 'Leave blank to disable',
'by_author' => 'By <em>%s</em>', 'by_author' => 'By <em>%s</em>',
'by_default' => 'By default', 'by_default' => 'By default',
'damn' => 'Damn!', 'damn' => 'Damn!',
'default_category' => 'Uncategorized', 'default_category' => 'Uncategorized',
'no' => 'No', 'no' => 'No',
'not_applicable' => 'Not available',
'ok' => 'Ok!', 'ok' => 'Ok!',
'or' => 'or', 'or' => 'or',
'yes' => 'Yes', 'yes' => 'Yes',

View file

@ -3,11 +3,13 @@
return array( return array(
'action' => array( 'action' => array(
'finish' => 'Complete installation', 'finish' => 'Complete installation',
'fix_errors_before' => 'Fix errors before skip to the next step.', 'fix_errors_before' => 'Please fix errors before skipping to the next step.',
'keep_install' => 'Keep previous installation',
'next_step' => 'Go to the next step', 'next_step' => 'Go to the next step',
'reinstall' => 'Reinstall FreshRSS',
), ),
'auth' => array( 'auth' => array(
'email_persona' => 'Login mail address<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Login email address<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'form' => 'Web form (traditional, requires JavaScript)', 'form' => 'Web form (traditional, requires JavaScript)',
'http' => 'HTTP (for advanced users with HTTPS)', 'http' => 'HTTP (for advanced users with HTTPS)',
'none' => 'None (dangerous)', 'none' => 'None (dangerous)',
@ -31,6 +33,7 @@ return array(
), ),
'check' => array( 'check' => array(
'_' => 'Checks', '_' => 'Checks',
'already_installed' => 'We have detected that FreshRSS is already installed!',
'cache' => array( 'cache' => array(
'nok' => 'Check permissions on <em>./data/cache</em> directory. HTTP server must have rights to write into', 'nok' => 'Check permissions on <em>./data/cache</em> directory. HTTP server must have rights to write into',
'ok' => 'Permissions on cache directory are good.', 'ok' => 'Permissions on cache directory are good.',
@ -91,8 +94,11 @@ return array(
'congratulations' => 'Congratulations!', 'congratulations' => 'Congratulations!',
'default_user' => 'Username of the default user <small>(maximum 16 alphanumeric characters)</small>', 'default_user' => 'Username of the default user <small>(maximum 16 alphanumeric characters)</small>',
'delete_articles_after' => 'Remove articles after', 'delete_articles_after' => 'Remove articles after',
'fix_errors_before' => 'Fix errors before skip to the next step.', 'fix_errors_before' => 'Please fix errors before skipping to the next step.',
'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled',
'js' => array(
'confirm_reinstall' => 'You will lose your previous configuration by reinstalling FreshRSS. Are you sure you want to continue?',
),
'language' => array( 'language' => array(
'_' => 'Language', '_' => 'Language',
'choose' => 'Choose a language for FreshRSS', 'choose' => 'Choose a language for FreshRSS',

View file

@ -18,7 +18,7 @@ return array(
'password' => 'HTTP password', 'password' => 'HTTP password',
'username' => 'HTTP username', 'username' => 'HTTP username',
), ),
'css_help' => 'Retrieves truncated RSS feeds (attention, requires more time!)', 'css_help' => 'Retrieves truncated RSS feeds (caution, requires more time!)',
'css_path' => 'Articles CSS path on original website', 'css_path' => 'Articles CSS path on original website',
'description' => 'Description', 'description' => 'Description',
'empty' => 'This feed is empty. Please verify that it is still maintained.', 'empty' => 'This feed is empty. Please verify that it is still maintained.',
@ -26,7 +26,7 @@ return array(
'in_main_stream' => 'Show in main stream', 'in_main_stream' => 'Show in main stream',
'informations' => 'Information', 'informations' => 'Information',
'keep_history' => 'Minimum number of articles to keep', 'keep_history' => 'Minimum number of articles to keep',
'moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under <em>%s</em>.', 'moved_category_deleted' => 'When you delete a category, its feeds are automatically classified under <em>%s</em>.',
'no_selected' => 'No feed selected.', 'no_selected' => 'No feed selected.',
'number_entries' => '%d articles', 'number_entries' => '%d articles',
'stats' => 'Statistics', 'stats' => 'Statistics',
@ -37,6 +37,7 @@ return array(
'url' => 'Feed URL', 'url' => 'Feed URL',
'validator' => 'Check the validity of the feed', 'validator' => 'Check the validity of the feed',
'website' => 'Website URL', 'website' => 'Website URL',
'pubsubhubbub' => 'Instant notification with PubSubHubbub',
), ),
'import_export' => array( 'import_export' => array(
'export' => 'Export', 'export' => 'Export',

View file

@ -146,6 +146,17 @@ return array(
'title' => 'Statistiques', 'title' => 'Statistiques',
'top_feed' => 'Les dix plus gros flux', 'top_feed' => 'Les dix plus gros flux',
), ),
'system' => array(
'_' => 'Configuration du système',
'auto-update-url' => 'URL du service de mise à jour',
'instance-name' => 'Nom de linstance',
'max-categories' => 'Limite de catégories par utilisateur',
'max-feeds' => 'Limite de flux par utilisateur',
'registration' => array(
'help' => 'Un chiffre de 0 signifie que lon peut créer un nombre infini de comptes',
'number' => 'Nombre max de comptes',
),
),
'update' => array( 'update' => array(
'_' => 'Système de mise à jour', '_' => 'Système de mise à jour',
'apply' => 'Appliquer la mise à jour', 'apply' => 'Appliquer la mise à jour',
@ -160,6 +171,8 @@ return array(
'create' => 'Créer un nouvel utilisateur', 'create' => 'Créer un nouvel utilisateur',
'email_persona' => 'Adresse courriel de connexion<br /><small>(pour <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Adresse courriel de connexion<br /><small>(pour <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'language' => 'Langue', 'language' => 'Langue',
'number' => '%d compte a déjà été créé',
'numbers' => '%d comptes ont déjà été créés',
'password_form' => 'Mot de passe<br /><small>(pour connexion par formulaire)</small>', 'password_form' => 'Mot de passe<br /><small>(pour connexion par formulaire)</small>',
'password_format' => '7 caractères minimum', 'password_format' => '7 caractères minimum',
'title' => 'Gestion des utilisateurs', 'title' => 'Gestion des utilisateurs',

View file

@ -72,6 +72,10 @@ return array(
), ),
'profile' => array( 'profile' => array(
'_' => 'Gestion du profil', '_' => 'Gestion du profil',
'delete' => array(
'_' => 'Suppression du compte',
'warn' => 'Le compte et toutes les données associées vont être supprimées.',
),
'email_persona' => 'Adresse courriel de connexion<br /><small>(pour <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Adresse courriel de connexion<br /><small>(pour <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'password_api' => 'Mot de passe API<br /><small>(ex. : pour applis mobiles)</small>', 'password_api' => 'Mot de passe API<br /><small>(ex. : pour applis mobiles)</small>',
'password_form' => 'Mot de passe<br /><small>(pour connexion par formulaire)</small>', 'password_form' => 'Mot de passe<br /><small>(pour connexion par formulaire)</small>',
@ -84,6 +88,7 @@ return array(
'articles_per_page' => 'Nombre darticles par page', 'articles_per_page' => 'Nombre darticles par page',
'auto_load_more' => 'Charger les articles suivants en bas de page', 'auto_load_more' => 'Charger les articles suivants en bas de page',
'auto_remove_article' => 'Cacher les articles après lecture', 'auto_remove_article' => 'Cacher les articles après lecture',
'mark_updated_article_unread' => 'Marquer les articles mis à jour comme non-lus',
'confirm_enabled' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', 'confirm_enabled' => 'Afficher une confirmation lors des actions “marquer tout comme lu”',
'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut',
'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut',

View file

@ -21,15 +21,27 @@ return array(
'truncate' => 'Supprimer tous les articles', 'truncate' => 'Supprimer tous les articles',
), ),
'auth' => array( 'auth' => array(
'email' => 'Adresse courriel',
'keep_logged_in' => 'Rester connecté <small>(1 mois)</small>', 'keep_logged_in' => 'Rester connecté <small>(1 mois)</small>',
'login' => 'Connexion', 'login' => 'Connexion',
'login_persona' => 'Connexion avec Persona', 'login_persona' => 'Connexion avec Persona',
'login_persona_problem' => 'Problème de connexion à Persona ?', 'login_persona_problem' => 'Problème de connexion à Persona ?',
'logout' => 'Déconnexion', 'logout' => 'Déconnexion',
'password' => 'Mot de passe', 'password' => array(
'_' => 'Mot de passe',
'format' => '<small>7 caractères minimum</small>',
),
'registration' => array(
'_' => 'Nouveau compte',
'ask' => 'Créer un compte ?',
'title' => 'Création de compte',
),
'reset' => 'Réinitialisation de lauthentification', 'reset' => 'Réinitialisation de lauthentification',
'username' => 'Nom dutilisateur', 'username' => array(
'username_admin' => 'Nom dutilisateur administrateur', '_' => 'Nom dutilisateur',
'admin' => 'Nom dutilisateur administrateur',
'format' => '<small>16 caractères alphanumériques maximum</small>',
),
'will_reset' => 'Le système dauthentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', 'will_reset' => 'Le système dauthentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.',
), ),
'date' => array( 'date' => array(
@ -104,9 +116,12 @@ return array(
'should_be_activated' => 'Le JavaScript doit être activé.', 'should_be_activated' => 'Le JavaScript doit être activé.',
), ),
'lang' => array( 'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch', 'de' => 'Deutsch',
'en' => 'English', 'en' => 'English',
'fr' => 'Français', 'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
), ),
'menu' => array( 'menu' => array(
'about' => 'À propos', 'about' => 'À propos',
@ -124,6 +139,7 @@ return array(
'sharing' => 'Partage', 'sharing' => 'Partage',
'shortcuts' => 'Raccourcis', 'shortcuts' => 'Raccourcis',
'stats' => 'Statistiques', 'stats' => 'Statistiques',
'system' => 'Configuration du système',
'update' => 'Mise à jour', 'update' => 'Mise à jour',
'user_management' => 'Gestion des utilisateurs', 'user_management' => 'Gestion des utilisateurs',
'user_profile' => 'Profil', 'user_profile' => 'Profil',
@ -143,6 +159,7 @@ return array(
'email' => 'Courriel', 'email' => 'Courriel',
'facebook' => 'Facebook', 'facebook' => 'Facebook',
'g+' => 'Google+', 'g+' => 'Google+',
'movim' => 'Movim',
'print' => 'Imprimer', 'print' => 'Imprimer',
'shaarli' => 'Shaarli', 'shaarli' => 'Shaarli',
'twitter' => 'Twitter', 'twitter' => 'Twitter',
@ -156,6 +173,7 @@ return array(
'damn' => 'Arf !', 'damn' => 'Arf !',
'default_category' => 'Sans catégorie', 'default_category' => 'Sans catégorie',
'no' => 'Non', 'no' => 'Non',
'not_applicable' => 'Non disponible',
'ok' => 'Ok !', 'ok' => 'Ok !',
'or' => 'ou', 'or' => 'ou',
'yes' => 'Oui', 'yes' => 'Oui',

View file

@ -4,7 +4,9 @@ return array(
'action' => array( 'action' => array(
'finish' => 'Terminer linstallation', 'finish' => 'Terminer linstallation',
'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à létape suivante.', 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à létape suivante.',
'keep_install' => 'Garder lancienne configuration',
'next_step' => 'Passer à létape suivante', 'next_step' => 'Passer à létape suivante',
'reinstall' => 'Réinstaller FreshRSS',
), ),
'auth' => array( 'auth' => array(
'email_persona' => 'Adresse courriel de connexion<br /><small>(pour <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>', 'email_persona' => 'Adresse courriel de connexion<br /><small>(pour <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
@ -31,6 +33,7 @@ return array(
), ),
'check' => array( 'check' => array(
'_' => 'Vérifications', '_' => 'Vérifications',
'already_installed' => 'FreshRSS semble avoir déjà été installé !',
'cache' => array( 'cache' => array(
'nok' => 'Veuillez vérifier les droits sur le répertoire <em>./data/cache</em>. Le serveur HTTP doit être capable décrire dedans', 'nok' => 'Veuillez vérifier les droits sur le répertoire <em>./data/cache</em>. Le serveur HTTP doit être capable décrire dedans',
'ok' => 'Les droits sur le répertoire de cache sont bons.', 'ok' => 'Les droits sur le répertoire de cache sont bons.',
@ -93,6 +96,9 @@ return array(
'delete_articles_after' => 'Supprimer les articles après', 'delete_articles_after' => 'Supprimer les articles après',
'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à létape suivante.', 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à létape suivante.',
'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé',
'js' => array(
'confirm_reinstall' => 'Réinstaller FreshRSS vous fera perdre la configuration précédente. Êtes-vous sûr de vouloir continuer ?',
),
'language' => array( 'language' => array(
'_' => 'Langue', '_' => 'Langue',
'choose' => 'Choisissez la langue pour FreshRSS', 'choose' => 'Choisissez la langue pour FreshRSS',

View file

@ -35,8 +35,9 @@ return array(
'title_add' => 'Ajouter un flux RSS', 'title_add' => 'Ajouter un flux RSS',
'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que',
'url' => 'URL du flux', 'url' => 'URL du flux',
'validator' => 'Vérifier la valididé du flux', 'validator' => 'Vérifier la validité du flux',
'website' => 'URL du site', 'website' => 'URL du site',
'pubsubhubbub' => 'Notification instantanée par PubSubHubbub',
), ),
'import_export' => array( 'import_export' => array(
'export' => 'Exporter', 'export' => 'Exporter',

183
sources/app/i18n/it/admin.php Executable file
View file

@ -0,0 +1,183 @@
<?php
return array(
'auth' => array(
'allow_anonymous' => 'Consenti la lettura agli utenti anonimi degli articoli dell utente predefinito (%s)',
'allow_anonymous_refresh' => 'Consenti agli utenti anonimi di aggiornare gli articoli',
'api_enabled' => 'Consenti le <abbr>API</abbr> di accesso <small>(richiesto per le app mobili)</small>',
'form' => 'Web form (tradizionale, richiede JavaScript)',
'http' => 'HTTP (per gli utenti avanzati con HTTPS)',
'none' => 'Nessuno (pericoloso)',
'persona' => 'Mozilla Persona (moderno, richiede JavaScript)',
'title' => 'Autenticazione',
'title_reset' => 'Reset autenticazione',
'token' => 'Token di autenticazione',
'token_help' => 'Consenti accesso agli RSS dell utente predefinito senza autenticazione:',
'type' => 'Metodo di autenticazione',
'unsafe_autologin' => 'Consenti accesso automatico non sicuro usando il formato: ',
),
'check_install' => array(
'cache' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/cache</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella della cache sono corretti.',
),
'categories' => array(
'nok' => 'La tabella delle categorie ha una configurazione errata.',
'ok' => 'Tabella delle categorie OK.',
),
'connection' => array(
'nok' => 'La connessione al database non può essere stabilita.',
'ok' => 'Connessione al database OK',
),
'ctype' => array(
'nok' => 'Manca una libreria richiesta per il controllo dei caratteri (php-ctype).',
'ok' => 'Libreria richiesta per il controllo dei caratteri presente (ctype).',
),
'curl' => array(
'nok' => 'Manca il supporto per cURL (pacchetto php5-curl).',
'ok' => 'Estensione cURL presente.',
),
'data' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella data sono corretti.',
),
'database' => 'Installazione database',
'dom' => array(
'nok' => 'Manca una libreria richiesta per leggere DOM (pacchetto php-xml).',
'ok' => 'Libreria richiesta per leggere DOM presente.',
),
'entries' => array(
'nok' => 'La tabella Entry ha una configurazione errata.',
'ok' => 'Tabella Entry OK.',
),
'favicons' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/favicons</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella favicons sono corretti.',
),
'feeds' => array(
'nok' => 'La tabella Feed ha una configurazione errata.',
'ok' => 'Tabella Feed OK.',
),
'files' => 'Installazione files',
'json' => array(
'nok' => 'Manca il supoorto a JSON (pacchetto php5-json).',
'ok' => 'Estensione JSON presente.',
),
'minz' => array(
'nok' => 'Manca il framework Minz.',
'ok' => 'Framework Minz presente.',
),
'pcre' => array(
'nok' => 'Manca una libreria richiesta per le regular expressions (php-pcre).',
'ok' => 'Libreria richiesta per le regular expressions presente (PCRE).',
),
'pdo' => array(
'nok' => 'Manca PDO o uno degli altri driver supportati (pdo_mysql, pdo_sqlite).',
'ok' => 'PDO e altri driver supportati (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/persona</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella Mozilla Persona sono corretti.',
),
'php' => array(
'_' => 'Installazione PHP',
'nok' => 'Versione PHP %s FreshRSS richiede almeno la versione %s.',
'ok' => 'Versione PHP %s, compatibile con FreshRSS.',
),
'tables' => array(
'nok' => 'Rilevate tabelle mancanti nel database.',
'ok' => 'Tutte le tabelle sono presenti nel database.',
),
'title' => 'Verifica installazione',
'tokens' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/tokens</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella tokens sono corretti.',
),
'users' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/users</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella users sono corretti.',
),
'zip' => array(
'nok' => 'Manca estensione ZIP (pacchetto php5-zip).',
'ok' => 'Estensione ZIP presente.',
),
),
'extensions' => array(
'disabled' => 'Disabilitata',
'empty_list' => 'Non ci sono estensioni installate',
'enabled' => 'Abilitata',
'no_configure_view' => 'Questa estensioni non può essere configurata.',
'system' => array(
'_' => 'Estensioni di sistema',
'no_rights' => 'Estensione di sistema (non hai i permessi su questo tipo)',
),
'title' => 'Estensioni',
'user' => 'Estensioni utente',
),
'stats' => array(
'_' => 'Statistiche',
'all_feeds' => 'Tutti i feeds',
'category' => 'Categoria',
'entry_count' => 'Articoli',
'entry_per_category' => 'Articoli per categoria',
'entry_per_day' => 'Articoli per giorno (ultimi 30 giorni)',
'entry_per_day_of_week' => 'Per giorno della settimana (media: %.2f articoli)',
'entry_per_hour' => 'Per ora (media: %.2f articoli)',
'entry_per_month' => 'Per mese (media: %.2f articoli)',
'entry_repartition' => 'Ripartizione contenuti',
'feed' => 'Feed',
'feed_per_category' => 'Feeds per categoria',
'idle' => 'Feeds non aggiornati',
'main' => 'Statistiche principali',
'main_stream' => 'Flusso principale',
'menu' => array(
'idle' => 'Feeds non aggiornati',
'main' => 'Statistiche principali',
'repartition' => 'Ripartizione articoli',
),
'no_idle' => 'Non ci sono feed non aggiornati',
'number_entries' => '%d articoli',
'percent_of_total' => '%% del totale',
'repartition' => 'Ripartizione articoli',
'status_favorites' => 'Preferiti',
'status_read' => 'Letti',
'status_total' => 'Totale',
'status_unread' => 'Non letti',
'title' => 'Statistiche',
'top_feed' => 'I migliori 10 feeds',
),
'system' => array(
'_' => 'Configurazione di sistema',
'auto-update-url' => 'Auto-update server URL', // @todo translate
'instance-name' => 'Nome istanza',
'max-categories' => 'Limite categorie per utente',
'max-feeds' => 'Limite feeds per utente',
'registration' => array(
'help' => '0 significa che non esiste limite sui profili',
'number' => 'Numero massimo di profili',
),
),
'update' => array(
'_' => 'Aggiornamento sistema',
'apply' => 'Applica',
'check' => 'Controlla la presenza di nuovi aggiornamenti',
'current_version' => 'FreshRSS versione %s.',
'last' => 'Ultima verifica: %s',
'none' => 'Nessun aggiornamento da applicare',
'title' => 'Aggiorna sistema',
),
'user' => array(
'articles_and_size' => '%s articoli (%s)',
'create' => 'Crea nuovo utente',
'email_persona' => 'Indirizzo mail<br /><small>(Login <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'language' => 'Lingua',
'number' => ' %d profilo utente creato',
'numbers' => 'Sono presenti %d profili utente',
'password_form' => 'Password<br /><small>(per il login classico)</small>',
'password_format' => 'Almeno 7 caratteri',
'title' => 'Gestione utenti',
'user_list' => 'Lista utenti',
'username' => 'Nome utente',
'users' => 'Utenti',
),
);

174
sources/app/i18n/it/conf.php Executable file
View file

@ -0,0 +1,174 @@
<?php
return array(
'archiving' => array(
'_' => 'Archiviazione',
'advanced' => 'Avanzate',
'delete_after' => 'Rimuovi articoli dopo',
'help' => 'Altre opzioni sono disponibili nelle impostazioni dei singoli feed',
'keep_history_by_feed' => 'Numero minimo di articoli da mantenere per feed',
'optimize' => 'Ottimizza database',
'optimize_help' => 'Da fare occasionalmente per ridurre le dimensioni del database',
'purge_now' => 'Cancella ora',
'title' => 'Archiviazione',
'ttl' => 'Non effettuare aggiornamenti per più di',
),
'display' => array(
'_' => 'Visualizzazione',
'icon' => array(
'bottom_line' => 'Barra in fondo',
'entry' => 'Icone degli articoli',
'publication_date' => 'Data di pubblicazione',
'related_tags' => 'Tags correlati',
'sharing' => 'Condivisione',
'top_line' => 'Barra in alto',
),
'language' => 'Lingua',
'notif_html5' => array(
'seconds' => 'secondi (0 significa nessun timeout)',
'timeout' => 'Notifica timeout HTML5',
),
'theme' => 'Tema',
'title' => 'Visualizzazione',
'width' => array(
'content' => 'Larghezza contenuto',
'large' => 'Largo',
'medium' => 'Medio',
'no_limit' => 'Nessun limite',
'thin' => 'Stretto',
),
),
'query' => array(
'_' => 'Ricerche personali',
'deprecated' => 'Questa query non è più valida. La categoria o il feed di riferimento non stati cancellati.',
'filter' => 'Filtro applicato:',
'get_all' => 'Mostra tutti gli articoli',
'get_category' => 'Mostra la categoria "%s" ',
'get_favorite' => 'Mostra articoli preferiti',
'get_feed' => 'Mostra feed "%s" ',
'no_filter' => 'Nessun filtro',
'none' => 'Non hai creato nessuna ricerca personale.',
'number' => 'Ricerca n°%d',
'order_asc' => 'Mostra prima gli articoli più vecchi',
'order_desc' => 'Mostra prima gli articoli più nuovi',
'search' => 'Cerca per "%s"',
'state_0' => 'Mostra tutti gli articoli',
'state_1' => 'Mostra gli articoli letti',
'state_2' => 'Mostra gli articoli non letti',
'state_3' => 'Mostra tutti gli articoli',
'state_4' => 'Mostra gli articoli preferiti',
'state_5' => 'Mostra gli articoli preferiti letti',
'state_6' => 'Mostra gli articoli preferiti non letti',
'state_7' => 'Mostra gli articoli preferiti',
'state_8' => 'Non mostrare gli articoli preferiti',
'state_9' => 'Mostra gli articoli letti non preferiti',
'state_10' => 'Mostra gli articoli non letti e non preferiti',
'state_11' => 'Non mostrare gli articoli preferiti',
'state_12' => 'Mostra tutti gli articoli',
'state_13' => 'Mostra gli articoli letti',
'state_14' => 'Mostra gli articoli non letti',
'state_15' => 'Mostra tutti gli articoli',
'title' => 'Ricerche personali',
),
'profile' => array(
'_' => 'Gestione profili',
'delete' => array(
'_' => 'Cancellazione account',
'warn' => 'Il tuo account e tutti i dati associati saranno cancellati.',
),
'email_persona' => 'Indirizzo email<br /><small>(Login <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'password_api' => 'Password API<br /><small>(e.g., per applicazioni mobili)</small>',
'password_form' => 'Password<br /><small>(per il login classico)</small>',
'password_format' => 'Almeno 7 caratteri',
'title' => 'Profilo',
),
'reading' => array(
'_' => 'Lettura',
'after_onread' => 'Dopo “segna tutto come letto”,',
'articles_per_page' => 'Numero di articoli per pagina',
'auto_load_more' => 'Carica articoli successivi a fondo pagina',
'auto_remove_article' => 'Nascondi articoli dopo la lettura',
'mark_updated_article_unread' => 'Segna articoli aggiornati come non letti',
'confirm_enabled' => 'Mostra una conferma per “segna tutto come letto”',
'display_articles_unfolded' => 'Mostra articoli aperti di predefinito',
'display_categories_unfolded' => 'Mostra categorie aperte di predefinito',
'hide_read_feeds' => 'Nascondi categorie e feeds con articoli già letti (non funziona se “Mostra tutti gli articoli” è selezionato)',
'img_with_lazyload' => 'Usa la modalità "caricamento ritardato" per le immagini',
'jump_next' => 'Salta al successivo feed o categoria non letto',
'number_divided_when_reader' => 'Diviso 2 nella modalità di lettura.',
'read' => array(
'article_open_on_website' => 'Quando un articolo è aperto nel suo sito di origine',
'article_viewed' => 'Quando un articolo viene letto',
'scroll' => 'Scorrendo la pagina',
'upon_reception' => 'Alla ricezione del contenuto',
'when' => 'Segna articoli come letti…',
),
'show' => array(
'_' => 'Articoli da visualizzare',
'adaptive' => 'Adatta visualizzazione',
'all_articles' => 'Mostra tutti gli articoli',
'unread' => 'Mostra solo non letti',
),
'sort' => array(
'_' => 'Ordinamento',
'newer_first' => 'Prima i più recenti',
'older_first' => 'Prima i più vecchi',
),
'sticky_post' => 'Blocca il contenuto a inizio pagina quando aperto',
'title' => 'Lettura',
'view' => array(
'default' => 'Visualizzazione predefinita',
'global' => 'Vista globale per categorie',
'normal' => 'Vista elenco',
'reader' => 'Modalità di lettura',
),
),
'sharing' => array(
'_' => 'Condivisione',
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'more_information' => 'Ulteriori informazioni',
'print' => 'Stampa',
'shaarli' => 'Shaarli',
'share_name' => 'Nome condivisione',
'share_url' => 'URL condivisione',
'title' => 'Condividi',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'shortcut' => array(
'_' => 'Comandi tastiera',
'article_action' => 'Azioni sugli articoli',
'auto_share' => 'Condividi',
'auto_share_help' => 'Se è presente un solo servizio di condivisione verrà usato quello, altrimenti usare anche il numero associato.',
'close_dropdown' => 'Chiudi menù',
'collapse_article' => 'Collassa articoli',
'first_article' => 'Salta al primo articolo',
'focus_search' => 'Modulo di ricerca',
'help' => 'Mostra documentazione',
'javascript' => 'JavaScript deve essere abilitato per poter usare i comandi da tastiera',
'last_article' => 'Salta all ultimo articolo',
'load_more' => 'Carica altri articoli',
'mark_read' => 'Segna come letto',
'mark_favorite' => 'Segna come preferito',
'navigation' => 'Navigazione',
'navigation_help' => 'Con il tasto "Shift" i comandi di navigazione verranno applicati ai feeds.<br/>Con il tasto "Alt" i comandi di navigazione verranno applicati alle categorie.',
'next_article' => 'Salta al contenuto successivo',
'other_action' => 'Altre azioni',
'previous_article' => 'Salta al contenuto precedente',
'see_on_website' => 'Vai al sito fonte',
'shift_for_all_read' => '+ <code>shift</code> per segnare tutti gli articoli come letti',
'title' => 'Comandi da tastiera',
'user_filter' => 'Accedi alle ricerche personali',
'user_filter_help' => 'Se è presente una sola ricerca personale verrà usata quella, altrimenti usare anche il numero associato.',
),
'user' => array(
'articles_and_size' => '%s articoli (%s)',
'current' => 'Utente connesso',
'is_admin' => 'è amministratore',
'users' => 'Utenti',
),
);

110
sources/app/i18n/it/feedback.php Executable file
View file

@ -0,0 +1,110 @@
<?php
return array(
'admin' => array(
'optimization_complete' => 'Ottimizzazione completata',
),
'access' => array(
'denied' => 'Non hai i permessi per accedere a questa pagina',
'not_found' => 'Pagina non disponibile',
),
'auth' => array(
'form' => array(
'not_set' => 'Si è verificato un problema alla configurazione del sistema di autenticazione. Per favore riprova più tardi.',
'set' => 'Sistema di autenticazione tramite Form impostato come predefinito.',
),
'login' => array(
'invalid' => 'Autenticazione non valida',
'success' => 'Autenticazione effettuata',
),
'logout' => array(
'success' => 'Disconnessione effettuata',
),
'no_password_set' => 'Password di amministrazione non impostata. Opzione non disponibile.',
'not_persona' => 'Solo il sistema Mozilla Persona può essere resettato.',
),
'conf' => array(
'error' => 'Si è verificato un errore durante il salvataggio della configurazione',
'query_created' => 'Ricerca "%s" creata.',
'shortcuts_updated' => 'Collegamenti tastiera aggiornati',
'updated' => 'Configurazione aggiornata',
),
'extensions' => array(
'already_enabled' => '%s è già abilitata',
'disable' => array(
'ko' => '%s non può essere disabilitata. <a href="%s">Verifica i logs</a> per dettagli.',
'ok' => '%s è disabilitata',
),
'enable' => array(
'ko' => '%s non può essere abilitata. <a href="%s">Verifica i logs</a> per dettagli.',
'ok' => '%s è ora abilitata',
),
'no_access' => 'Accesso negato a %s',
'not_enabled' => '%s non abilitato',
'not_found' => '%s non disponibile',
),
'import_export' => array(
'export_no_zip_extension' => 'Estensione Zip non presente sul server. Per favore esporta i files singolarmente.',
'feeds_imported' => 'I tuoi feed sono stati importati e saranno aggiornati',
'feeds_imported_with_errors' => 'I tuoi feeds sono stati importati ma si sono verificati alcuni errori',
'file_cannot_be_uploaded' => 'Il file non può essere caricato!',
'no_zip_extension' => 'Estensione Zip non presente sul server.',
'zip_error' => 'Si è verificato un errore importando il file Zip',
),
'sub' => array(
'actualize' => 'Aggiorna',
'category' => array(
'created' => 'Categoria %s creata.',
'deleted' => 'Categoria cancellata',
'emptied' => 'Categoria svuotata',
'error' => 'Categoria non aggiornata',
'name_exists' => 'Categoria già esistente.',
'no_id' => 'Categoria senza ID.',
'no_name' => 'Il nome della categoria non può essere lasciato vuoto.',
'not_delete_default' => 'Non puoi cancellare la categoria predefinita!',
'not_exist' => 'La categoria non esite!',
'over_max' => 'Hai raggiunto il numero limite di categorie (%d)',
'updated' => 'Categoria aggiornata.',
),
'feed' => array(
'actualized' => '<em>%s</em> aggiornato',
'actualizeds' => 'RSS feeds aggiornati',
'added' => 'RSS feed <em>%s</em> aggiunti',
'already_subscribed' => 'Hai già sottoscritto <em>%s</em>',
'deleted' => 'Feed cancellato',
'error' => 'Feed non aggiornato',
'internal_problem' => 'RSS feed non aggiunto. <a href="%s">Verifica i logs</a> per dettagli.',
'invalid_url' => 'URL <em>%s</em> non valido',
'marked_read' => 'Feeds segnati come letti',
'n_actualized' => '%d feeds aggiornati',
'n_entries_deleted' => '%d articoli cancellati',
'no_refresh' => 'Nessun aggiornamento disponibile…',
'not_added' => '<em>%s</em> non può essere aggiunto',
'over_max' => 'Hai raggiunto il numero limite di feed (%d)',
'updated' => 'Feed aggiornato',
),
'purge_completed' => 'Svecchiamento completato (%d articoli cancellati)',
),
'update' => array(
'can_apply' => 'FreshRSS verrà aggiornato alla <strong>versione %s</strong>.',
'error' => 'Il processo di aggiornamento ha riscontrato il seguente errore: %s',
'file_is_nok' => 'Verifica i permessi della cartella <em>%s</em>. Il server HTTP deve avere i permessi per la scrittura ',
'finished' => 'Aggiornamento completato con successo!',
'none' => 'Nessun aggiornamento disponibile',
'server_not_found' => 'Server per aggiornamento non disponibile. [%s]',
),
'user' => array(
'created' => array(
'_' => 'Utente %s creato',
'error' => 'Errore nella creazione utente %s ',
),
'deleted' => array(
'_' => 'Utente %s cancellato',
'error' => 'Utente %s non cancellato',
),
),
'profile' => array(
'error' => 'Il tuo profilo non può essere modificato',
'updated' => 'Il tuo profilo è stato modificato',
),
);

180
sources/app/i18n/it/gen.php Executable file
View file

@ -0,0 +1,180 @@
<?php
return array(
'action' => array(
'actualize' => 'Aggiorna',
'back_to_rss_feeds' => '← Indietro',
'cancel' => 'Annulla',
'create' => 'Crea',
'disable' => 'Disabilita',
'empty' => 'Vuoto',
'enable' => 'Abilita',
'export' => 'Esporta',
'filter' => 'Filtra',
'import' => 'Importa',
'manage' => 'Gestisci',
'mark_read' => 'Segna come letto',
'mark_favorite' => 'Segna come preferito',
'remove' => 'Rimuovi',
'see_website' => 'Vai al sito',
'submit' => 'Conferma',
'truncate' => 'Cancella tutti gli articoli',
),
'auth' => array(
'email' => 'Indirizzo email',
'keep_logged_in' => 'Ricorda i dati <small>(1 mese)</small>',
'login' => 'Accedi',
'login_persona' => 'Accedi con Mozilla Persona',
'login_persona_problem' => 'Problemi di connessione con Mozilla Persona?',
'logout' => 'Esci',
'password' => array(
'_' => 'Password',
'format' => '<small>almeno 7 caratteri</small>',
),
'registration' => array(
'_' => 'Nuovo profilo',
'ask' => 'Vuoi creare un nuovo profilo?',
'title' => 'Creazione profilo',
),
'reset' => 'Reset autenticazione',
'username' => array(
'_' => 'Username',
'admin' => 'Username amministratore',
'format' => '<small>massimo 16 caratteri alfanumerici</small>',
),
'will_reset' => 'Il sistema di autenticazione verrà resettato: un form verrà usato per Mozilla Persona.',
),
'date' => array(
'Apr' => '\\A\\p\\r\\i\\l\\e',
'Aug' => '\\A\\g\\o\\s\\t\\o',
'Dec' => '\\D\\i\\c\\e\\m\\b\\r\\e',
'Feb' => '\\F\\e\\b\\b\\r\\a\\i\\o',
'Jan' => '\\G\\e\\n\\u\\a\\i\\o',
'Jul' => '\\L\\u\\g\\l\\i\\o',
'Jun' => '\\G\\i\\u\\g\\n\\o',
'Mar' => '\\M\\a\\r\\z\\o',
'May' => '\\M\\a\\g\\g\\i\\o',
'Nov' => '\\N\\o\\v\\e\\m\\b\\r\\e',
'Oct' => '\\O\\t\\t\\o\\b\\r\\e',
'Sep' => '\\S\\e\\t\\t\\e\\m\\b\\r\\e',
'apr' => 'apr',
'april' => 'Apr',
'aug' => 'aug',
'august' => 'Aug',
'before_yesterday' => 'Meno recenti',
'dec' => 'dec',
'december' => 'Dec',
'feb' => 'feb',
'february' => 'Feb',
'format_date' => 'j\\ %s Y',
'format_date_hour' => 'j\\ %s Y \\o\\r\\e H\\:i',
'fri' => 'Fri',
'jan' => 'jan',
'january' => 'Jan',
'jul' => 'jul',
'july' => 'Jul',
'jun' => 'jun',
'june' => 'Jun',
'last_3_month' => 'Ultimi 3 mesi',
'last_6_month' => 'Ultimi 6 mesi',
'last_month' => 'Ultimo mese',
'last_week' => 'Ultima settimana',
'last_year' => 'Ultimo anno',
'mar' => 'mar',
'march' => 'Mar',
'may' => 'May',
'mon' => 'Mon',
'month' => 'mesi',
'nov' => 'nov',
'november' => 'Nov',
'oct' => 'oct',
'october' => 'Oct',
'sat' => 'Sat',
'sep' => 'sep',
'september' => 'Sep',
'sun' => 'Sun',
'thu' => 'Thu',
'today' => 'Oggi',
'tue' => 'Tue',
'wed' => 'Wed',
'yesterday' => 'Ieri',
),
'freshrss' => array(
'_' => 'Feed RSS Reader',
'about' => 'Informazioni',
),
'js' => array(
'category_empty' => 'Categoria vuota',
'confirm_action' => 'Sei sicuro di voler continuare?',
'confirm_action_feed_cat' => 'Sei sicuro di voler continuare? Verranno persi i preferiti e le ricerche utente correlate!',
'feedback' => array(
'body_new_articles' => 'Ci sono \\d nuovi articoli da leggere.',
'request_failed' => 'Richiesta fallita, probabilmente a causa di problemi di connessione',
'title_new_articles' => 'Feed RSS Reader: nuovi articoli!',
),
'new_article' => 'Sono disponibili nuovi articoli, clicca qui per caricarli.',
'should_be_activated' => 'JavaScript deve essere abilitato',
),
'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch',
'en' => 'English',
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
),
'menu' => array(
'about' => 'Informazioni',
'admin' => 'Amministrazione',
'archiving' => 'Archiviazione',
'authentication' => 'Autenticazione',
'check_install' => 'Installazione',
'configuration' => 'Configurazione',
'display' => 'Visualizzazione',
'extensions' => 'Estensioni',
'logs' => 'Logs',
'queries' => 'Ricerche personali',
'reading' => 'Lettura',
'search' => 'Ricerca parole o #tags',
'sharing' => 'Condivisione',
'shortcuts' => 'Comandi tastiera',
'stats' => 'Statistiche',
'system' => 'Configurazione sistema',
'update' => 'Aggiornamento',
'user_management' => 'Gestione utenti',
'user_profile' => 'Profilo',
),
'pagination' => array(
'first' => 'Prima',
'last' => 'Ultima',
'load_more' => 'Carica altri articoli',
'mark_all_read' => 'Segna tutto come letto',
'next' => 'Successiva',
'nothing_to_load' => 'Non ci sono altri articoli',
'previous' => 'Precedente',
),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'print' => 'Stampa',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'short' => array(
'attention' => 'Attenzione!',
'blank_to_disable' => 'Lascia vuoto per disabilitare',
'by_author' => 'di <em>%s</em>',
'by_default' => 'predefinito',
'damn' => 'Ops!',
'default_category' => 'Senza categoria',
'no' => 'No',
'not_applicable' => 'Non disponibile',
'ok' => 'OK!',
'or' => 'o',
'yes' => 'Si',
),
);

61
sources/app/i18n/it/index.php Executable file
View file

@ -0,0 +1,61 @@
<?php
return array(
'about' => array(
'_' => 'Informazioni',
'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
'bugs_reports' => 'Bugs',
'credits' => 'Crediti',
'credits_content' => 'Alcuni elementi di design provengono da <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> sebbene FreshRSS non usi questo framework. Le <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">icone</a> provengono dal progetto <a href="https://www.gnome.org/">GNOME</a>. Il carattere <em>Open Sans</em> è stato creato da <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a>. Le Favicons vengono estratte con le API <a href="https://getfavicon.appspot.com/">getFavicon</a>. FreshRSS è basato su <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, un framework PHP.',
'freshrss_description' => 'FreshRSS è un aggregatore di feeds RSS da installare sul proprio host come <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> o <a href="http://projet.idleman.fr/leed/">Leed</a>. Leggero e facile da mantenere pur essendo molto configurabile e potente.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">su Github</a>',
'license' => 'Licenza',
'project_website' => 'Sito del progetto',
'title' => 'Informazioni',
'version' => 'Versione',
'website' => 'Sito',
),
'feed' => array(
'add' => 'Aggiungi un Feed RSS',
'empty' => 'Non ci sono articoli da mostrare.',
'rss_of' => 'RSS feed di %s',
'title' => 'RSS feeds',
'title_global' => 'Vista globale per categorie',
'title_fav' => 'Preferiti',
),
'log' => array(
'_' => 'Logs',
'clear' => 'Svuota logs',
'empty' => 'File di log vuoto',
'title' => 'Logs',
),
'menu' => array(
'about' => 'Informazioni',
'add_query' => 'Aggiungi ricerca',
'before_one_day' => 'Giorno precedente',
'before_one_week' => 'Settimana precedente',
'favorites' => 'Preferiti (%s)',
'global_view' => 'Vista globale per categorie',
'main_stream' => 'Flusso principale',
'mark_all_read' => 'Segna tutto come letto',
'mark_cat_read' => 'Segna la categoria come letta',
'mark_feed_read' => 'Segna il feed come letto',
'newer_first' => 'Mostra prima i recenti',
'non-starred' => 'Escludi preferiti',
'normal_view' => 'Vista elenco',
'older_first' => 'Ordina per meno recenti',
'queries' => 'Chiavi di ricerca',
'read' => 'Mostra solo letti',
'reader_view' => 'Modalità di lettura',
'rss_view' => 'RSS feed',
'search_short' => 'Cerca',
'starred' => 'Mostra solo preferiti',
'stats' => 'Statistiche',
'subscription' => 'Gestione sottoscrizioni',
'unread' => 'Mostra solo non letti',
),
'share' => 'Condividi',
'tag' => array(
'related' => 'Tags correlati',
),
);

114
sources/app/i18n/it/install.php Executable file
View file

@ -0,0 +1,114 @@
<?php
return array(
'action' => array(
'finish' => 'Installazione completata',
'fix_errors_before' => 'Per favore correggi gli errori prima di passare al passaggio successivo.',
'keep_install' => 'Mantieni installazione precedente',
'next_step' => 'Vai al prossimo passaggio',
'reinstall' => 'Reinstalla FreshRSS',
),
'auth' => array(
'email_persona' => 'Indirizzo mail<br /><small>(per <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'form' => 'Web form (tradizionale, richiede JavaScript)',
'http' => 'HTTP (per gli utenti avanzati con HTTPS)',
'none' => 'Nessuno (pericoloso)',
'password_form' => 'Password<br /><small>(per il login tramite Web-form tradizionale)</small>',
'password_format' => 'Almeno 7 caratteri',
'persona' => 'Mozilla Persona (moderno, richiede JavaScript)',
'type' => 'Metodo di autenticazione',
),
'bdd' => array(
'_' => 'Database',
'conf' => array(
'_' => 'Configurazione database',
'ko' => 'Verifica le informazioni del database.',
'ok' => 'Le configurazioni del database sono state salvate.',
),
'host' => 'Host',
'prefix' => 'Prefisso tabella',
'password' => 'HTTP password',
'type' => 'Tipo di database',
'username' => 'HTTP username',
),
'check' => array(
'_' => 'Controlli',
'already_installed' => 'FreshRSS risulta già installato!',
'cache' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/cache</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella della cache sono corretti.',
),
'ctype' => array(
'nok' => 'Manca una libreria richiesta per il controllo dei caratteri (php-ctype).',
'ok' => 'Libreria richiesta per il controllo dei caratteri presente (ctype).',
),
'curl' => array(
'nok' => 'Manca il supporto per cURL (pacchetto php5-curl).',
'ok' => 'Estensione cURL presente.',
),
'data' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella data sono corretti.',
),
'dom' => array(
'nok' => 'Manca una libreria richiesta per leggere DOM (pacchetto php-xml).',
'ok' => 'Libreria richiesta per leggere DOM presente.',
),
'favicons' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/favicons</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella favicons sono corretti.',
),
'http_referer' => array(
'nok' => 'Per favore verifica che non stai alterando il tuo HTTP REFERER.',
'ok' => 'Il tuo HTTP REFERER riconosciuto corrisponde al tuo server.',
),
'minz' => array(
'nok' => 'Manca il framework Minz.',
'ok' => 'Framework Minz presente.',
),
'pcre' => array(
'nok' => 'Manca una libreria richiesta per le regular expressions (php-pcre).',
'ok' => 'Libreria richiesta per le regular expressions presente (PCRE).',
),
'pdo' => array(
'nok' => 'Manca PDO o uno degli altri driver supportati (pdo_mysql, pdo_sqlite).',
'ok' => 'PDO e altri driver supportati (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/persona</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella Mozilla Persona sono corretti.',
),
'php' => array(
'_' => 'Installazione PHP',
'nok' => 'Versione di PHP %s FreshRSS richiede almeno la versione %s.',
'ok' => 'Versione di PHP %s, compatibile con FreshRSS.',
),
'users' => array(
'nok' => 'Verifica i permessi sulla cartella <em>./data/users</em>. Il server HTTP deve avere i permessi per scriverci dentro',
'ok' => 'I permessi sulla cartella users sono corretti.',
),
),
'conf' => array(
'_' => 'Configurazioni generali',
'ok' => 'Configurazioni generali salvate.',
),
'congratulations' => 'Congratulazione!',
'default_user' => 'Username utente predefinito <small>(massimo 16 caratteri alfanumerici)</small>',
'delete_articles_after' => 'Rimuovi articoli dopo',
'fix_errors_before' => 'Per favore correggi gli errori prima di passare al passaggio successivo.',
'javascript_is_better' => 'FreshRSS funziona meglio con JavaScript abilitato',
'js' => array(
'confirm_reinstall' => 'Reinstallando FreshRSS perderai la configurazione precedente. Sei sicuro di voler procedere?',
),
'language' => array(
'_' => 'Lingua',
'choose' => 'Seleziona la lingua per FreshRSS',
'defined' => 'Lingua impostata.',
),
'not_deleted' => 'Qualcosa non ha funzionato; devi cancellare il file <em>%s</em> manualmente.',
'ok' => 'Processo di installazione terminato con successo.',
'step' => 'Passaggio %d',
'steps' => 'Passaggi',
'title' => 'Installazione · FreshRSS',
'this_is_the_end' => 'Fine',
);

62
sources/app/i18n/it/sub.php Executable file
View file

@ -0,0 +1,62 @@
<?php
return array(
'category' => array(
'_' => 'Categoria',
'add' => 'Aggiungi una categoria',
'empty' => 'Categoria vuota',
'new' => 'Nuova categoria',
),
'feed' => array(
'add' => 'Aggiungi un Feed RSS',
'advanced' => 'Avanzate',
'archiving' => 'Archiviazione',
'auth' => array(
'configuration' => 'Autenticazione',
'help' => 'Accesso per feeds protetti',
'http' => 'Autenticazione HTTP',
'password' => 'HTTP password',
'username' => 'HTTP username',
),
'css_help' => 'In caso di RSS feeds troncati (attenzione, richiede molto tempo!)',
'css_path' => 'Percorso del foglio di stile CSS del sito di origine',
'description' => 'Descrizione',
'empty' => 'Questo feed non contiene articoli. Per favore verifica il sito direttamente.',
'error' => 'Questo feed ha generato un errore. Per favore verifica se ancora disponibile.',
'in_main_stream' => 'Mostra in homepage',
'informations' => 'Informazioni',
'keep_history' => 'Numero minimo di articoli da mantenere',
'moved_category_deleted' => 'Cancellando una categoria i feed al suo interno verranno classificati automaticamente come <em>%s</em>.',
'no_selected' => 'Nessun feed selezionato.',
'number_entries' => '%d articoli',
'stats' => 'Statistiche',
'think_to_add' => 'Aggiungi feed.',
'title' => 'Titolo',
'title_add' => 'Aggiungi RSS feed',
'ttl' => 'Non aggiornare automaticamente piu di',
'url' => 'Feed URL',
'validator' => 'Controlla la validita del feed ',
'website' => 'URL del sito',
'pubsubhubbub' => 'Notifica istantanea con PubSubHubbub',
),
'import_export' => array(
'export' => 'Esporta',
'export_opml' => 'Esporta tutta la lista dei feed (OPML)',
'export_starred' => 'Esporta i tuoi preferiti',
'feed_list' => 'Elenco di %s articoli',
'file_to_import' => 'File da importare<br />(OPML, Json o Zip)',
'file_to_import_no_zip' => 'File da importare<br />(OPML o Json)',
'import' => 'Importa',
'starred_list' => 'Elenco articoli preferiti',
'title' => 'Importa / esporta',
),
'menu' => array(
'bookmark' => 'Bookmark (trascina nei preferiti)',
'import_export' => 'Importa / esporta',
'subscription_management' => 'Gestione sottoscrizioni',
),
'title' => array(
'_' => 'Gestione sottoscrizioni',
'feed_management' => 'Gestione RSS feeds',
),
);

188
sources/app/i18n/nl/admin.php Executable file
View file

@ -0,0 +1,188 @@
<?php
/* Dutch translation by Wanabo. http://www.nieuwskop.be */
return array(
'auth' => array(
'allow_anonymous' => 'Sta bezoekers toe om artikelen te lezen van de standaard gebruiker (%s)',
'allow_anonymous_refresh' => 'Sta bezoekers toe om de artikelen te vernieuwen',
'api_enabled' => 'Sta <abbr>API</abbr> toegang toe <small>(nodig voor mobiele apps)</small>',
'form' => 'Web formulier (traditioneel, benodigd JavaScript)',
'http' => 'HTTP (voor geavanceerde gebruikers met HTTPS)',
'none' => 'Geen (gevaarlijk)',
'persona' => 'Mozilla Persona (modern, benodigd JavaScript)',
'title' => 'Authenticatie',
'title_reset' => 'Authenticatie terugzetten',
'token' => 'Authenticatie teken',
'token_help' => 'Sta toegang toe tot de RSS uitvoer van de standaard gebruiker zonder authenticatie:',
'type' => 'Authenticatie methode',
'unsafe_autologin' => 'Sta onveilige automatische log in toe met het volgende formaat: ',
),
'check_install' => array(
'cache' => array(
'nok' => 'Controleer de permissies van de <em>./data/cache</em> map. HTTP server moet rechten hebben om hierin te schrijven',
'ok' => 'Permissies van de cache map zijn goed.',
),
'categories' => array(
'nok' => 'Categorie tabel is slecht geconfigureerd.',
'ok' => 'Categorie tabel is ok.',
),
'connection' => array(
'nok' => 'Verbinding met de database kan niet worden gemaakt.',
'ok' => 'Verbinding met de database is ok.',
),
'ctype' => array(
'nok' => 'U mist de benodigde bibliotheek voor character type checking (php-ctype).',
'ok' => 'U hebt de benodigde bibliotheek voor character type checking (ctype).',
),
'curl' => array(
'nok' => 'U mist de cURL (php5-curl package).',
'ok' => 'U hebt de cURL uitbreiding.',
),
'data' => array(
'nok' => 'Controleer de permissies op de <em>./data</em> map. HTTP server moet rechten hebben om hierin te schrijven',
'ok' => 'Permissies op de data map zijn goed.',
),
'database' => 'Database installatie',
'dom' => array(
'nok' => 'U mist de benodigde bibliotheek voor het bladeren van DOM (php-xml package).',
'ok' => 'U hebt de benodigde bibliotheek voor het bladeren van DOM.',
),
'entries' => array(
'nok' => 'Invoer tabel is slecht geconfigureerd.',
'ok' => 'Invoer tabel is ok.',
),
'favicons' => array(
'nok' => 'Controleer de permissies op de <em>./data/favicons</em> map. HTTP server moet rechten hebben om hierin te schrijven',
'ok' => 'Permissies op de favicons map zijn goed.',
),
'feeds' => array(
'nok' => 'Feed tabel is slecht geconfigureerd.',
'ok' => 'Feed tabel is ok.',
),
'files' => 'Bestanden installatie',
'json' => array(
'nok' => 'U mist JSON (php5-json package).',
'ok' => 'U hebt JSON uitbreiding.',
),
'minz' => array(
'nok' => 'U mist Minz framework.',
'ok' => 'U hebt Minz framework.',
),
'pcre' => array(
'nok' => 'U mist de benodigde bibliotheek voor regular expressions (php-pcre).',
'ok' => 'U hebt de benodigde bibliotheek voor regular expressions (PCRE).',
),
'pdo' => array(
'nok' => 'U mist PDO of een van de ondersteunde drivers (pdo_mysql, pdo_sqlite).',
'ok' => 'U hebt PDO en ten minste één van de ondersteunde drivers (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Controleer de permissies op de <em>./data/persona</em> map. HTTP server moet rechten hebben om hierin te schrijven',
'ok' => 'Permissies op de Mozilla Persona map zijn goed.',
),
'php' => array(
'_' => 'PHP installatie',
'nok' => 'Uw PHP versie is %s maar FreshRSS benodigd tenminste versie %s.',
'ok' => 'Uw PHP versie is %s, welke compatibel is met FreshRSS.',
),
'tables' => array(
'nok' => 'Er zijn één of meer ontbrekende tabellen in de database.',
'ok' => 'Alle tabellen zijn aanwezig in de database.',
),
'title' => 'Installatie controle',
'tokens' => array(
'nok' => 'Controleer de permissies op de <em>./data/tokens</em> map. HTTP server moet rechten hebben om hierin te schrijven',
'ok' => 'Permissies op de tokens map zijn goed.',
),
'users' => array(
'nok' => 'Controleer de permissies op de <em>./data/users</em> map. HTTP server moet rechten hebben om hierin te schrijven',
'ok' => 'Permissies op de users map zijn goed.',
),
'zip' => array(
'nok' => 'U mist ZIP uitbreiding (php5-zip package).',
'ok' => 'U hebt ZIP uitbreiding.',
),
),
'extensions' => array(
'disabled' => 'Uitgeschakeld',
'empty_list' => 'Er zijn geïnstalleerde uitbreidingen',
'enabled' => 'Ingeschakeld',
'no_configure_view' => 'Deze uitbreiding kan niet worden geconfigureerd.',
'system' => array(
'_' => 'Systeem uitbreidingen',
'no_rights' => 'Systeem uitbreidingen (U hebt hier geen rechten op)',
),
'title' => 'Uitbreidingen',
'user' => 'Gebruikers uitbreidingen',
),
'stats' => array(
'_' => 'Statistieken',
'all_feeds' => 'Alle feeds',
'category' => 'Categorie',
'entry_count' => 'Invoer aantallen',
'entry_per_category' => 'Aantallen per categorie',
'entry_per_day' => 'Aantallen per day (laatste 30 dagen)',
'entry_per_day_of_week' => 'Per dag of week (gemiddeld: %.2f berichten)',
'entry_per_hour' => 'Per uur (gemiddeld: %.2f berichten)',
'entry_per_month' => 'Per maand (gemiddeld: %.2f berichten)',
'entry_repartition' => 'Invoer verdeling',
'feed' => 'Feed',
'feed_per_category' => 'Feeds per categorie',
'idle' => 'Gepauzeerde feeds',
'main' => 'Hoofd statistieken',
'main_stream' => 'Overzicht',
'menu' => array(
'idle' => 'Gepauzeerde feeds',
'main' => 'Hoofd statistieken',
'repartition' => 'Artikelen verdeling',
),
'no_idle' => 'Er is geen gepauzeerde feed!',
'number_entries' => '%d artikelen',
'percent_of_total' => '%% van totaal',
'repartition' => 'Artikelen verdeling',
'status_favorites' => 'Favorieten',
'status_read' => 'Gelezen',
'status_total' => 'Totaal',
'status_unread' => 'Ongelezen',
'title' => 'Statistieken',
'top_feed' => 'Top tien feeds',
),
'system' => array(
'_' => 'System configuration', // @todo translate
'auto-update-url' => 'Auto-update server URL', // @todo translate
'instance-name' => 'Instance name', // @todo translate
'max-categories' => 'Categories per user limit', // @todo translate
'max-feeds' => 'Feeds per user limit', // @todo translate
'registration' => array(
'help' => '0 means that there is no account limit', // @todo translate
'number' => 'Max number of accounts', // @todo translate
),
),
'update' => array(
'_' => 'Versie controle',
'apply' => 'Toepassen',
'check' => 'Controleer op nieuwe versies',
'current_version' => 'Uw huidige versie van FreshRSS is %s.',
'last' => 'Laatste controle: %s',
'none' => 'Geen nieuwe versie om toe te passen',
'title' => 'Vernieuw systeem',
),
'user' => array(
'articles_and_size' => '%s artikelen (%s)',
'create' => 'Creëer nieuwe gebruiker',
'email_persona' => 'Log in mail adres<br /><small>(voor <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'language' => 'Taal',
'number' => 'Er is %d accounts gemaakt',
'numbers' => 'Er zijn %d accounts gemaakt',
'password_form' => 'Wachtwoord<br /><small>(voor de Web-formulier log in methode)</small>',
'password_format' => 'Ten minste 7 tekens',
'registration' => array(
'allow' => 'Sta het maken van nieuwe accounts toe',
'help' => '0 betekent dat er geen account limiet is',
'number' => 'Max aantal van accounts',
),
'title' => 'Beheer gebruikers',
'user_list' => 'Lijst van gebruikers ',
'username' => 'Gebruikers naam',
'users' => 'Gebruikers',
),
);

174
sources/app/i18n/nl/conf.php Executable file
View file

@ -0,0 +1,174 @@
<?php
/* Dutch translation by Wanabo. http://www.nieuwskop.be */
return array(
'archiving' => array(
'_' => 'Archivering',
'advanced' => 'Geavanceerd',
'delete_after' => 'Verwijder artikelen na',
'help' => 'Meer opties zijn beschikbaar in de persoonlijke stroom instellingen',
'keep_history_by_feed' => 'Minimum aantal te behouden artikelen in de feed',
'optimize' => 'Optimaliseer database',
'optimize_help' => 'Doe dit zo af en toe om de omvang van de database te verkleinen',
'purge_now' => 'Schoon nu op',
'title' => 'Archivering',
'ttl' => 'Vernieuw niet automatisch meer dan',
),
'display' => array(
'_' => 'Opmaak',
'icon' => array(
'bottom_line' => 'Onderaan',
'entry' => 'Artikel pictogrammen',
'publication_date' => 'Publicatie datum',
'related_tags' => 'Gerelateerde labels',
'sharing' => 'Delen',
'top_line' => 'Bovenaan',
),
'language' => 'Taal',
'notif_html5' => array(
'seconds' => 'seconden (0 betekent geen stop)',
'timeout' => 'HTML5 notificatie stop',
),
'theme' => 'Thema',
'title' => 'Opmaak',
'width' => array(
'content' => 'Inhoud breedte',
'large' => 'Breed',
'medium' => 'Normaal',
'no_limit' => 'Geen limiet',
'thin' => 'Smal',
),
),
'query' => array(
'_' => 'Gebruikers queries (informatie aanvragen)',
'deprecated' => 'Deze query (informatie aanvraag) is niet langer geldig. De bedoelde categorie of feed is al verwijderd.',
'filter' => 'Filter toegepast:',
'get_all' => 'Toon alle artikelen',
'get_category' => 'Toon "%s" categorie',
'get_favorite' => 'Toon favoriete artikelen',
'get_feed' => 'Toon "%s" feed',
'no_filter' => 'Geen filter',
'none' => 'U hebt nog geen gebruikers query aangemaakt..',
'number' => 'Query n°%d',
'order_asc' => 'Toon oudste artikelen eerst',
'order_desc' => 'Toon nieuwste artikelen eerst',
'search' => 'Zoek naar "%s"',
'state_0' => 'Toon alle artikelen',
'state_1' => 'Toon gelezen artikelen',
'state_2' => 'Toon ongelezen artikelen',
'state_3' => 'Toon alle artikelen',
'state_4' => 'Toon favoriete artikelen',
'state_5' => 'Toon gelezen favoriete artikelen',
'state_6' => 'Toon ongelezen favoriete artikelen',
'state_7' => 'Toon favoriete artikelen',
'state_8' => 'Toon niet favoriete artikelen',
'state_9' => 'Toon gelezen niet favoriete artikelen',
'state_10' => 'Toon ongelezen niet favoriete artikelen',
'state_11' => 'Toon niet favoriete artikelen',
'state_12' => 'Toon alle artikelen',
'state_13' => 'Toon gelezen artikelen',
'state_14' => 'Toon ongelezen artikelen',
'state_15' => 'Toon alle artikelen',
'title' => 'Gebruikers queries',
),
'profile' => array(
'_' => 'Profiel beheer',
'delete' => array(
'_' => 'Account verwijderen',
'warn' => 'Uw account en alle gerelateerde gegvens worden verwijderd.',
),
'email_persona' => 'Log in mail adres<br /><small>(voor <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'password_api' => 'Wachtwoord API<br /><small>(e.g., voor mobiele apps)</small>',
'password_form' => 'Wachtwoord<br /><small>(voor de Web-formulier log in methode)</small>',
'password_format' => 'Ten minste 7 tekens',
'title' => 'Profiel',
),
'reading' => array(
'_' => 'Lezen',
'after_onread' => 'Na “markeer alles als gelezen”,',
'articles_per_page' => 'Aantal artikelen per pagina',
'auto_load_more' => 'Laad volgende artikel onderaan de pagina',
'auto_remove_article' => 'Verberg artikel na lezen',
'confirm_enabled' => 'Toon een bevestigings dialoog op “markeer alles als gelezen” acties',
'display_articles_unfolded' => 'Toon artikelen uitgeklapt als standaard',
'display_categories_unfolded' => 'Toon categoriën ingeklapt als standaard',
'hide_read_feeds' => 'Verberg categoriën en feeds zonder ongelezen artikelen (werkt niet met “Toon alle artikelen” configuratie)',
'img_with_lazyload' => 'Gebruik "lazy load" methode om afbeeldingen te laden',
'jump_next' => 'Ga naar volgende ongelezen (feed of categorie)',
'mark_updated_article_unread' => 'Markeer vernieuwd artikel als ongelezen',
'number_divided_when_reader' => 'Gedeeld door 2 in de lees modus.',
'read' => array(
'article_open_on_website' => 'Als het artikel is geopend op de originele website',
'article_viewed' => 'Als het artikel is bekeken',
'scroll' => 'Tijdens scrollen',
'upon_reception' => 'Tijdens ontvangst van het artikel',
'when' => 'Markeer artikel als gelezen…',
),
'show' => array(
'_' => 'Artikelen om te tonen',
'adaptive' => 'Pas weergave aan',
'all_articles' => 'Bekijk alle artikelen',
'unread' => 'Bekijk alleen ongelezen',
),
'sort' => array(
'_' => 'Sorteer volgorde',
'newer_first' => 'Nieuwste eerst',
'older_first' => 'Oudste eerst',
),
'sticky_post' => 'Koppel artikel aan de bovenkant als het geopend wordt',
'title' => 'Lees modus',
'view' => array(
'default' => 'Standaard weergave',
'global' => 'Globale weergave',
'normal' => 'Normale weergave',
'reader' => 'Lees weergave',
),
),
'sharing' => array(
'_' => 'Delen',
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'more_information' => 'Meer informatie',
'print' => 'Afdrukken',
'shaarli' => 'Shaarli',
'share_name' => 'Gedeelde naam om weer te geven',
'share_url' => 'Deel URL voor gebruik',
'title' => 'Delen',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'shortcut' => array(
'_' => 'Shortcuts',
'article_action' => 'Artikel acties',
'auto_share' => 'Delen',
'auto_share_help' => 'Als er slechts één deel methode i, dan wordt deze gebruikt. Anders zijn ze toegankelijk met hun nummer.',
'close_dropdown' => 'Sluit menu',
'collapse_article' => 'Inklappen',
'first_article' => 'Spring naar eerste artikel',
'focus_search' => 'Toegang zoek venster',
'help' => 'Toon documentatie',
'javascript' => 'JavaScript moet geactiveerd zijn om verwijzingen te gebruiken',
'last_article' => 'Spring naar laatste artikel',
'load_more' => 'Laad meer artikelen',
'mark_read' => 'Markeer als gelezen',
'mark_favorite' => 'Markeer als favoriet',
'navigation' => 'Navigatie',
'navigation_help' => 'Met de "Shift" toets, kunt u navigatie verwijzingen voor feeds gebruiken.<br/>Met de "Alt" toets, kunt u navigatie verwijzingen voor categoriën gebruiken.',
'next_article' => 'Spring naar volgende artikel',
'other_action' => 'Andere acties',
'previous_article' => 'Spring naar vorige artikel',
'see_on_website' => 'Bekijk op originale website',
'shift_for_all_read' => '+ <code>shift</code> om alle artikelen als gelezen te markeren',
'title' => 'Verwijzingen',
'user_filter' => 'Toegang gebruikers filters',
'user_filter_help' => 'Als er slechts één gebruikers filter s, dan wordt deze gebruikt. Anders zijn ze toegankelijk met hun nummer.',
),
'user' => array(
'articles_and_size' => '%s artikelen (%s)',
'current' => 'Huidige gebruiker',
'is_admin' => 'is administrateur',
'users' => 'Gebruikers',
),
);

111
sources/app/i18n/nl/feedback.php Executable file
View file

@ -0,0 +1,111 @@
<?php
/* Dutch translation by Wanabo. http://www.nieuwskop.be */
return array(
'admin' => array(
'optimization_complete' => 'Optimalisatie compleet',
),
'access' => array(
'denied' => 'U hebt geen rechten om deze pagina te bekijken.',
'not_found' => 'Deze pagina bestaat niet',
),
'auth' => array(
'form' => array(
'not_set' => 'Een probleem is opgetreden tijdens de controle van de systeem configuratie. Probeer het later nog eens.',
'set' => 'Formulier is nu uw standaard authenticatie systeem.',
),
'login' => array(
'invalid' => 'Log in is ongeldig',
'success' => 'U bent ingelogd',
),
'logout' => array(
'success' => 'U bent uitgelogd',
),
'no_password_set' => 'Administrateur wachtwoord is niet ingesteld. Deze mogelijkheid is niet beschikbaar.',
'not_persona' => 'Alleen Persona systeem kan worden gereset.',
),
'conf' => array(
'error' => 'Er is een fout opgetreden tijdens het opslaan van de configuratie',
'query_created' => 'Query "%s" is gemaakt.',
'shortcuts_updated' => 'Verwijzingen zijn vernieuwd',
'updated' => 'Configuratie is vernieuwd',
),
'extensions' => array(
'already_enabled' => '%s is al ingeschakeld',
'disable' => array(
'ko' => '%s kan niet worden uitgeschakeld. <a href="%s">Controleer FressRSS log bestanden</a> voor details.',
'ok' => '%s is nu uitgeschakeld',
),
'enable' => array(
'ko' => '%s kan niet worden ingeschakeld. <a href="%s">Controleer FressRSS log bestanden</a> voor details.',
'ok' => '%s is nn ingeschakeld',
),
'no_access' => 'U hebt geen toegang voor %s',
'not_enabled' => '%s is nog niet ingeschakeld',
'not_found' => '%s bestaat niet',
),
'import_export' => array(
'export_no_zip_extension' => 'Zip uitbreiding is niet aanwezig op uw server. Exporteer a.u.b. uw bestanden één voor één.',
'feeds_imported' => 'Uw feeds zijn geimporteerd en worden nu vernieuwd',
'feeds_imported_with_errors' => 'Uw feeds zijn geimporteerd maar er zijn enige fouten opgetreden',
'file_cannot_be_uploaded' => 'Bestand kan niet worden verzonden!',
'no_zip_extension' => 'Zip uitbreiding is niet aanwezig op uw server.',
'zip_error' => 'Er is een fout opgetreden tijdens het imporeren van het Zip bestand.',
),
'sub' => array(
'actualize' => 'Actualiseren',
'category' => array(
'created' => 'Categorie %s is gemaakt.',
'deleted' => 'Categorie is verwijderd.',
'emptied' => 'Categorie is leeg gemaakt',
'error' => 'Categorie kan niet worden vernieuwd',
'name_exists' => 'Categorie naam bestaat al.',
'no_id' => 'U moet de id specificeren of de categorie.',
'no_name' => 'Categorie naam mag niet leeg zijn.',
'not_delete_default' => 'U kunt de standaard categorie niet verwijderen!',
'not_exist' => 'De categorie bestaat niet!',
'over_max' => 'U hebt het maximale aantal categoriën bereikt (%d)',
'updated' => 'Categorie is vernieuwd.',
),
'feed' => array(
'actualized' => '<em>%s</em> is vernieuwd',
'actualizeds' => 'RSS feeds zijn vernieuwd',
'added' => 'RSS feed <em>%s</em> is toegevoegd',
'already_subscribed' => 'U bent al geabonneerd op <em>%s</em>',
'deleted' => 'Feed is verwijderd',
'error' => 'Feed kan niet worden vernieuwd',
'internal_problem' => 'De RSS feed kon niet worden toegevoegd. <a href="%s">Controleer FressRSS log bestanden</a> voor details.',
'invalid_url' => 'URL <em>%s</em> is ongeldig',
'marked_read' => 'Feeds zijn gemarkeerd als gelezen',
'n_actualized' => '%d feeds zijn vernieuwd',
'n_entries_deleted' => '%d artikelen zijn verwijderd',
'no_refresh' => 'Er is geen feed om te vernieuwen…',
'not_added' => '<em>%s</em> kon niet worden toegevoegd',
'over_max' => 'U hebt het maximale aantal feeds bereikt(%d)',
'updated' => 'Feed is vernieuwd',
),
'purge_completed' => 'Opschonen klaar (%d artikelen verwijderd)',
),
'update' => array(
'can_apply' => 'FreshRSS word nu vernieud naar <strong>versie %s</strong>.',
'error' => 'Het vernieuwingsproces kwam een fout tegen: %s',
'file_is_nok' => 'Controleer permissies op <em>%s</em> map. HTTP server moet rechten hebben om er in te schrijven',
'finished' => 'Vernieuwing compleet!',
'none' => 'Geen vernieuwing om toe te passen',
'server_not_found' => 'Vernieuwings server kan niet worden gevonden. [%s]',
),
'user' => array(
'created' => array(
'_' => 'Gebruiker %s is aangemaakt',
'error' => 'Gebruiker %s kan niet worden aangemaakt',
),
'deleted' => array(
'_' => 'Gebruiker %s is verwijderd',
'error' => 'Gebruiker %s kan niet worden verwijderd',
),
'set_registration' => 'Het maximale aantal accounts is vernieuwd.',
),
'profile' => array(
'error' => 'Uw profiel kan niet worden aangepast',
'updated' => 'Uw profiel is aangepast',
),
);

181
sources/app/i18n/nl/gen.php Executable file
View file

@ -0,0 +1,181 @@
<?php
/* Dutch translation by Wanabo. http://www.nieuwskop.be */
return array(
'action' => array(
'actualize' => 'Actualiseren',
'back_to_rss_feeds' => '← Ga terug naar je RSS feeds',
'cancel' => 'Annuleren',
'create' => 'Opslaan',
'disable' => 'Uitzetten',
'empty' => 'Leeg',
'enable' => 'Aanzetten',
'export' => 'Exporteren',
'filter' => 'Filteren',
'import' => 'Importeren',
'manage' => 'Beheren',
'mark_read' => 'Markeer als gelezen',
'mark_favorite' => 'Markeer als favoriet',
'remove' => 'Verwijder',
'see_website' => 'Bekijk website',
'submit' => 'Opslaan',
'truncate' => 'Verwijder alle artikelen',
),
'auth' => array(
'email' => 'Email adres',
'keep_logged_in' => 'Ingelogd blijven voor <small>(1 maand)</small>',
'login' => 'Log in',
'login_persona' => 'Login met Persona',
'login_persona_problem' => 'Connectiviteits problemen met Persona',
'logout' => 'Log uit',
'password' => array(
'_' => 'Wachtwoord',
'format' => '<small>Ten minste 7 tekens</small>',
),
'registration' => array(
'_' => 'Nieuw account',
'ask' => 'Maak een account?',
'title' => 'Account maken',
),
'reset' => 'Authenticatie reset',
'username' => array(
'_' => 'Gebruikersnaam',
'admin' => 'Administrator gebruikersnaam',
'format' => '<small>maximaal 16 alphanumerieke tekens</small>',
),
'will_reset' => 'Het authenticatie system zal worden gereset: een formulier zal worden gebruikt in plaats van Persona.',
),
'date' => array(
'Apr' => '\\A\\p\\r\\i\\l',
'Aug' => '\\A\\u\\g\\u\\s\\t\\u\\s',
'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r',
'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\i',
'Jan' => '\\J\\a\\n\\u\\a\\r\\i',
'Jul' => '\\J\\u\\l\\i',
'Jun' => '\\J\\u\\n\\i',
'Mar' => '\\M\\a\\a\\r\\t',
'May' => '\\M\\e\\i',
'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r',
'Oct' => '\\O\\k\\t\\o\\b\\e\\r',
'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r',
'apr' => 'apr',
'april' => 'Apr',
'aug' => 'aug',
'august' => 'Aug',
'before_yesterday' => 'Ouder',
'dec' => 'dec',
'december' => 'Dec',
'feb' => 'feb',
'february' => 'Feb',
'format_date' => 'j %s Y', //<-- European date format // 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y',
'format_date_hour' => 'j %s Y \\o\\m H\\:i', //<-- European date format // 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i',
'fri' => 'Vr',
'jan' => 'jan',
'january' => 'Jan',
'jul' => 'jul',
'july' => 'Jul',
'jun' => 'jun',
'june' => 'Jun',
'last_3_month' => 'Laatste drie maanden',
'last_6_month' => 'Laatste zes maanden',
'last_month' => 'Vorige maand',
'last_week' => 'Vorige week',
'last_year' => 'Vorig jaar',
'mar' => 'mar',
'march' => 'Mar',
'may' => 'Mei',
'mon' => 'Ma',
'month' => 'maanden',
'nov' => 'nov',
'november' => 'Nov',
'oct' => 'okt',
'october' => 'Okt',
'sat' => 'Za',
'sep' => 'sep',
'september' => 'Sep',
'sun' => 'Zo',
'thu' => 'Do',
'today' => 'Vandaag',
'tue' => 'Di',
'wed' => 'Wo',
'yesterday' => 'Gisteren',
),
'freshrss' => array(
'_' => 'FreshRSS',
'about' => 'Over FreshRSS',
),
'js' => array(
'category_empty' => 'Lege categorie',
'confirm_action' => 'Weet u zeker dat u dit wilt doen? Het kan niet ongedaan worden gemaakt!',
'confirm_action_feed_cat' => 'Weet u zeker dat u dit wilt doen? U verliest alle gereleteerde favorieten en gebruikers informatie. Het kan niet ongedaan worden gemaakt!',
'feedback' => array(
'body_new_articles' => 'Er zijn \\d nieuwe artikelen om te lezen op FreshRSS.',
'request_failed' => 'Een opdracht is mislukt, mogelijk door Internet verbindings problemen.',
'title_new_articles' => 'FreshRSS: nieuwe artikelen!',
),
'new_article' => 'Er zijn nieuwe artikelen beschikbaar, klik om de pagina te vernieuwen.',
'should_be_activated' => 'JavaScript moet aan staan',
),
'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch',
'en' => 'English',
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
),
'menu' => array(
'about' => 'Over',
'admin' => 'Administratie',
'archiving' => 'Archiveren',
'authentication' => 'Authenticatie',
'check_install' => 'Installatie controle',
'configuration' => 'Configuratie',
'display' => 'Opmaak',
'extensions' => 'Uitbreidingen',
'logs' => 'Log boeken',
'queries' => 'Gebruikers informatie',
'reading' => 'Lezen',
'search' => 'Zoek woorden of #labels',
'sharing' => 'Delen',
'shortcuts' => 'Snelle toegang',
'stats' => 'Statistieken',
'system' => 'System configuration', // @todo translate
'update' => 'Versie controle',
'user_management' => 'Beheer gebruikers',
'user_profile' => 'Profiel',
),
'pagination' => array(
'first' => 'Eerste',
'last' => 'Laatste',
'load_more' => 'Laad meer artikelen',
'mark_all_read' => 'Markeer alle als gelezen',
'next' => 'Volgende',
'nothing_to_load' => 'Er zijn geen artikelen meer',
'previous' => 'Vorige',
),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'movim' => 'Movim',
'print' => 'Print',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'short' => array(
'attention' => 'Attentie!',
'blank_to_disable' => 'Laat leeg om uit te zetten',
'by_author' => 'Door <em>%s</em>',
'by_default' => 'Door standaard',
'damn' => 'Potverdorie!',
'default_category' => 'Niet ingedeeld',
'no' => 'Nee',
'not_applicable' => 'Niet aanwezig',
'ok' => 'Ok!',
'or' => 'of',
'yes' => 'Ja',
),
);

61
sources/app/i18n/nl/index.php Executable file
View file

@ -0,0 +1,61 @@
<?php
/* Dutch translation by Wanabo. http://www.nieuwskop.be */
return array(
'about' => array(
'_' => 'Over',
'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
'bugs_reports' => 'Rapporteer fouten',
'credits' => 'Waarderingen',
'credits_content' => 'Sommige ontwerp elementen komen van <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> alhoewel FreshRSS dit raamwerk niet gebruikt. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Pictogrammen</a> komen van het <a href="https://www.gnome.org/">GNOME project</a>. <em>De Open Sans</em> font police is gemaakt door <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a>. Favicons zijn verzameld met de <a href="https://getfavicon.appspot.com/">getFavicon API</a>. FreshRSS is gebaseerd op <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, een PHP raamwerk. Nederlandse vertaling door Wanabo, <a href="http://www.nieuwskop.be" title="NieuwsKop">NieuwsKop.be</a>. Link naar de Nederlandse vertaling, <a href="https://github.com/Wanabo/FreshRSS-Dutch-translation/tree/master">FreshRSS-Dutch-translation</a>.',
'freshrss_description' => 'FreshRSS is een RSS feed aggregator om zelf te hosten zoals <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> of <a href="http://projet.idleman.fr/leed/">Leed</a>. Het gebruikt weinig systeembronnen en is makkelijk te administreren terwijl het een krachtig en makkelijk te configureren programma is.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">op Github</a>',
'license' => 'License',
'project_website' => 'Project website',
'title' => 'Over',
'version' => 'Versie',
'website' => 'Website',
),
'feed' => array(
'add' => 'U kunt wat feeds toevoegen.',
'empty' => 'Er is geen artikel om te laten zien.',
'rss_of' => 'RSS feed van %s',
'title' => 'Overzicht RSS feeds',
'title_global' => 'Globale weergave',
'title_fav' => 'Uw favorieten',
),
'log' => array(
'_' => 'Log bestanden',
'clear' => 'Leeg de log bestanden',
'empty' => 'Log bestand is leeg',
'title' => 'Log bestanden',
),
'menu' => array(
'about' => 'Over FreshRSS',
'add_query' => 'Voeg een query toe',
'before_one_day' => 'Ouder als een dag',
'before_one_week' => 'Ouder als een week',
'favorites' => 'Favorieten (%s)',
'global_view' => 'Globale weergave',
'main_stream' => 'Overzicht',
'mark_all_read' => 'Markeer alles als gelezen',
'mark_cat_read' => 'Markeer categorie als gelezen',
'mark_feed_read' => 'Markeer feed als gelezen',
'newer_first' => 'Nieuwste eerst',
'non-starred' => 'Laat alles zien behalve favorieten',
'normal_view' => 'Normale weergave',
'older_first' => 'Oudste eerst',
'queries' => 'Gebruikers queries',
'read' => 'Laat alleen gelezen zien',
'reader_view' => 'Lees modus',
'rss_view' => 'RSS feed',
'search_short' => 'Zoeken',
'starred' => 'Laat alleen favorieten zien',
'stats' => 'Statistieken',
'subscription' => 'Abonnementen beheer',
'unread' => 'Laat alleen ongelezen zien',
),
'share' => 'Delen',
'tag' => array(
'related' => 'Verwante labels',
),
);

113
sources/app/i18n/nl/install.php Executable file
View file

@ -0,0 +1,113 @@
<?php
/* Dutch translation by Wanabo. http://www.nieuwskop.be */
return array(
'action' => array(
'finish' => 'Completeer installatie',
'fix_errors_before' => 'Repareer de fouten alvorens naar de volgende stap te gaan.',
'keep_install' => 'Behoud de vorige installatie',
'next_step' => 'Ga naar de volgende stap',
'reinstall' => 'Installeer FreshRSS opnieuw',
),
'auth' => array(
'email_persona' => 'Log in mail adres<br /><small>(voor <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'form' => 'Web formulier (traditioneel, benodigd JavaScript)',
'http' => 'HTTP (voor geavanceerde gebruikers met HTTPS)',
'none' => 'Geen (gevaarlijk)',
'password_form' => 'Wachtwoord<br /><small>(voor de Web-formulier log in methode)</small>',
'password_format' => 'Tenminste 7 tekens',
'persona' => 'Mozilla Persona (modern, benodigd JavaScript)',
'type' => 'Authenticatie methode',
),
'bdd' => array(
'_' => 'Database',
'conf' => array(
'_' => 'Database configuratie',
'ko' => 'Controleer uw database informatie.',
'ok' => 'Database configuratie is opgeslagen.',
),
'host' => 'Host',
'prefix' => 'Tabel voorvoegsel',
'password' => 'HTTP wachtwoord',
'type' => 'Type database',
'username' => 'HTTP gebruikersnaam',
),
'check' => array(
'_' => 'Controles',
'already_installed' => 'We hebben geconstateerd dat FreshRSS al is geïnstallerd!',
'cache' => array(
'nok' => 'Controleer permissies van de <em>./data/cache</em> map. HTTP server moet rechten hebben om er in te kunnen schrijven',
'ok' => 'Permissies van de cache map zijn goed.',
),
'ctype' => array(
'nok' => 'U mist een benodigde bibliotheek voor character type checking (php-ctype).',
'ok' => 'U hebt de benodigde bibliotheek voor character type checking (ctype).',
),
'curl' => array(
'nok' => 'U mist cURL (php5-curl package).',
'ok' => 'U hebt de cURL uitbreiding.',
),
'data' => array(
'nok' => 'Controleer permissies van de <em>./data</em> map. HTTP server moet rechten hebben om er in te kunnen schrijven',
'ok' => 'Permissies van de data map zijn goed.',
),
'dom' => array(
'nok' => 'U mist een benodigde bibliotheek om te bladeren in de DOM (php-xml package).',
'ok' => 'U hebt de benodigde bibliotheek om te bladeren in de DOM.',
),
'favicons' => array(
'nok' => 'Controleer permissies van de <em>./data/favicons</em> map. HTTP server moet rechten hebben om er in te kunnen schrijven',
'ok' => 'Permissies van de favicons map zijn goed.',
),
'http_referer' => array(
'nok' => 'Controleer a.u.b. dat u niet uw HTTP REFERER wijzigd.',
'ok' => 'Uw HTTP REFERER is bekend en komt overeen met uw server.',
),
'minz' => array(
'nok' => 'U mist het Minz framework.',
'ok' => 'U hebt het Minz framework.',
),
'pcre' => array(
'nok' => 'U mist een benodigde bibliotheek voor regular expressions (php-pcre).',
'ok' => 'U hebt de benodigde bibliotheek voor regular expressions (PCRE).',
),
'pdo' => array(
'nok' => 'U mist PDO of één van de ondersteunde (pdo_mysql, pdo_sqlite).',
'ok' => 'U hebt PDO en ten minste één van de ondersteunde drivers (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Controleer permissies van de <em>./data/persona</em> map. HTTP server moet rechten hebben om er in te kunnen schrijven',
'ok' => 'Permissies van de Mozilla Persona map zijn goed.',
),
'php' => array(
'nok' => 'Uw PHP versie is %s maar FreshRSS benodigd tenminste versie %s.',
'ok' => 'Uw PHP versie is %s, welke compatibel is met FreshRSS.',
),
'users' => array(
'nok' => 'Controleer permissies van de <em>./data/users</em> map. HTTP server moet rechten hebben om er in te kunnen schrijven',
'ok' => 'Permissies van de users map zijn goed.',
),
),
'conf' => array(
'_' => 'Algemene configuratie',
'ok' => 'Algemene configuratie is opgeslagen.',
),
'congratulations' => 'Gefeliciteerd!',
'default_user' => 'Gebruikersnaam van de standaard gebruiker <small>(maximaal 16 alphanumerieke tekens)</small>',
'delete_articles_after' => 'Verwijder artikelen na',
'fix_errors_before' => 'Repareer fouten alvorens U naar de volgende stap gaat.',
'javascript_is_better' => 'FreshRSS werkt beter JavaScript ingeschakeld',
'js' => array(
'confirm_reinstall' => 'U verliest uw vorige configuratie door FreshRSS opnieuw te installeren. Weet u zeker dat u verder wilt gaan?',
),
'language' => array(
'_' => 'Taal',
'choose' => 'Kies een taal voor FreshRSS',
'defined' => 'Taal is bepaald.',
),
'not_deleted' => 'Er ging iets fout! U moet het bestand <em>%s</em> handmatig verwijderen.',
'ok' => 'De installatie procedure is geslaagd.',
'step' => 'stap %d',
'steps' => 'Stappen',
'title' => 'Installatie · FreshRSS',
'this_is_the_end' => 'Dit is het einde',
);

62
sources/app/i18n/nl/sub.php Executable file
View file

@ -0,0 +1,62 @@
<?php
/* Dutch translation by Wanabo. http://www.nieuwskop.be */
return array(
'category' => array(
'_' => 'Categorie',
'add' => 'Voeg categorie toe',
'empty' => 'Lege categorie',
'new' => 'Nieuwe categorie',
),
'feed' => array(
'add' => 'Voeg een RSS feed toe',
'advanced' => 'Geavanceerd',
'archiving' => 'Archiveren',
'auth' => array(
'configuration' => 'Log in',
'help' => 'Verbinding toestaan toegang te krijgen tot HTTP beveiligde RSS feeds',
'http' => 'HTTP Authenticatie',
'password' => 'HTTP wachtwoord',
'username' => 'HTTP gebruikers naam',
),
'css_help' => 'Haalt verstoorde RSS feeds op (attentie, heeft meer tijd nodig!)',
'css_path' => 'Artikelen CSS pad op originele website',
'description' => 'Omschrijving',
'empty' => 'Deze feed is leeg. Controleer of deze nog actueel is.',
'error' => 'Deze feed heeft problemen. Verifieer a.u.b het doeladres en actualiseer het.',
'in_main_stream' => 'Zichtbaar in het overzicht',
'informations' => 'Informatie',
'keep_history' => 'Minimum aantal artikelen om te houden',
'moved_category_deleted' => 'Als u een categorie verwijderd, worden de feeds automatisch geclassificeerd onder <em>%s</em>.',
'no_selected' => 'Geen feed geselecteerd.',
'number_entries' => '%d artikelen',
'pubsubhubbub' => 'Directe notificaties met PubSubHubbub',
'stats' => 'Statistieken',
'think_to_add' => 'Voeg wat feeds toe.',
'title' => 'Titel',
'title_add' => 'Voeg een RSS feed toe',
'ttl' => 'Vernieuw automatisch niet vaker dan',
'url' => 'Feed URL',
'validator' => 'Controleer de geldigheid van de feed',
'website' => 'Website URL',
),
'import_export' => array(
'export' => 'Exporteer',
'export_opml' => 'Exporteer lijst van feeds (OPML)',
'export_starred' => 'Exporteer je fovorieten',
'feed_list' => 'Lijst van %s artikelen',
'file_to_import' => 'Bestand om te importeren<br />(OPML, Json of Zip)',
'file_to_import_no_zip' => 'Bestand om te importeren<br />(OPML of Json)',
'import' => 'Importeer',
'starred_list' => 'Lijst van favoriete artikelen',
'title' => 'Importeren / exporteren',
),
'menu' => array(
'bookmark' => 'Abonneer (FreshRSS bladwijzer)',
'import_export' => 'Importeer / exporteer',
'subscription_management' => 'Abonnementen beheer',
),
'title' => array(
'_' => 'Abonnementen beheer',
'feed_management' => 'RSS feed beheer',
),
);

View file

@ -9,6 +9,9 @@ session_name('FreshRSS');
session_set_cookie_params(0, dirname(empty($_SERVER['REQUEST_URI']) ? '/' : dirname($_SERVER['REQUEST_URI'])), null, false, true); session_set_cookie_params(0, dirname(empty($_SERVER['REQUEST_URI']) ? '/' : dirname($_SERVER['REQUEST_URI'])), null, false, true);
session_start(); session_start();
Minz_Configuration::register('default_system', join_path(DATA_PATH, 'config.default.php'));
Minz_Configuration::register('default_user', join_path(USERS_PATH, '_', 'config.default.php'));
if (isset($_GET['step'])) { if (isset($_GET['step'])) {
define('STEP',(int)$_GET['step']); define('STEP',(int)$_GET['step']);
} else { } else {
@ -76,10 +79,52 @@ function saveLanguage() {
} }
} }
function saveStep1() {
if (isset($_POST['freshrss-keep-install']) &&
$_POST['freshrss-keep-install'] === '1') {
// We want to keep our previous installation of FreshRSS
// so we need to make next steps valid by setting $_SESSION vars
// with values from the previous installation
// First, we try to get previous configurations
Minz_Configuration::register('system',
join_path(DATA_PATH, 'config.php'),
join_path(DATA_PATH, 'config.default.php'));
$system_conf = Minz_Configuration::get('system');
$current_user = $system_conf->default_user;
Minz_Configuration::register('user',
join_path(USERS_PATH, $current_user, 'config.php'),
join_path(USERS_PATH, '_', 'config.default.php'));
$user_conf = Minz_Configuration::get('user');
// Then, we set $_SESSION vars
$_SESSION['title'] = $system_conf->title;
$_SESSION['auth_type'] = $system_conf->auth_type;
$_SESSION['old_entries'] = $user_conf->old_entries;
$_SESSION['mail_login'] = $user_conf->mail_login;
$_SESSION['default_user'] = $current_user;
$_SESSION['passwordHash'] = $user_conf->passwordHash;
$db = $system_conf->db;
$_SESSION['bd_type'] = $db['type'];
$_SESSION['bd_host'] = $db['host'];
$_SESSION['bd_user'] = $db['user'];
$_SESSION['bd_password'] = $db['password'];
$_SESSION['bd_base'] = $db['base'];
$_SESSION['bd_prefix'] = $db['prefix'];
$_SESSION['bd_error'] = '';
header('Location: index.php?step=4');
}
}
function saveStep2() { function saveStep2() {
$user_default_config = Minz_Configuration::get('default_user');
if (!empty($_POST)) { if (!empty($_POST)) {
$_SESSION['title'] = substr(trim(param('title', _t('gen.freshrss'))), 0, 25); $system_default_config = Minz_Configuration::get('default_system');
$_SESSION['old_entries'] = param('old_entries', 3); $_SESSION['title'] = $system_default_config->title;
$_SESSION['old_entries'] = param('old_entries', $user_default_config->old_entries);
$_SESSION['auth_type'] = param('auth_type', 'form'); $_SESSION['auth_type'] = param('auth_type', 'form');
$_SESSION['default_user'] = substr(preg_replace('/[^a-zA-Z0-9]/', '', param('default_user', '')), 0, 16); $_SESSION['default_user'] = substr(preg_replace('/[^a-zA-Z0-9]/', '', param('default_user', '')), 0, 16);
$_SESSION['mail_login'] = filter_var(param('mail_login', ''), FILTER_VALIDATE_EMAIL); $_SESSION['mail_login'] = filter_var(param('mail_login', ''), FILTER_VALIDATE_EMAIL);
@ -94,8 +139,7 @@ function saveStep2() {
$_SESSION['passwordHash'] = $passwordHash; $_SESSION['passwordHash'] = $passwordHash;
} }
if (empty($_SESSION['title']) || if (empty($_SESSION['old_entries']) ||
empty($_SESSION['old_entries']) ||
empty($_SESSION['auth_type']) || empty($_SESSION['auth_type']) ||
empty($_SESSION['default_user'])) { empty($_SESSION['default_user'])) {
return false; return false;
@ -108,7 +152,7 @@ function saveStep2() {
$_SESSION['salt'] = sha1(uniqid(mt_rand(), true).implode('', stat(__FILE__))); $_SESSION['salt'] = sha1(uniqid(mt_rand(), true).implode('', stat(__FILE__)));
if ((!ctype_digit($_SESSION['old_entries'])) ||($_SESSION['old_entries'] < 1)) { if ((!ctype_digit($_SESSION['old_entries'])) ||($_SESSION['old_entries'] < 1)) {
$_SESSION['old_entries'] = 3; $_SESSION['old_entries'] = $user_default_config->old_entries;
} }
$token = ''; $token = '';
@ -118,7 +162,7 @@ function saveStep2() {
$config_array = array( $config_array = array(
'language' => $_SESSION['language'], 'language' => $_SESSION['language'],
'theme' => 'Origine', 'theme' => $user_default_config->theme,
'old_entries' => $_SESSION['old_entries'], 'old_entries' => $_SESSION['old_entries'],
'mail_login' => $_SESSION['mail_login'], 'mail_login' => $_SESSION['mail_login'],
'passwordHash' => $_SESSION['passwordHash'], 'passwordHash' => $_SESSION['passwordHash'],
@ -165,12 +209,14 @@ function saveStep3() {
$_SESSION['bd_user'] = $_POST['user']; $_SESSION['bd_user'] = $_POST['user'];
$_SESSION['bd_password'] = $_POST['pass']; $_SESSION['bd_password'] = $_POST['pass'];
$_SESSION['bd_prefix'] = substr($_POST['prefix'], 0, 16); $_SESSION['bd_prefix'] = substr($_POST['prefix'], 0, 16);
$_SESSION['bd_prefix_user'] = $_SESSION['bd_prefix'] .(empty($_SESSION['default_user']) ? '' :($_SESSION['default_user'] . '_')); $_SESSION['bd_prefix_user'] = $_SESSION['bd_prefix'] . (empty($_SESSION['default_user']) ? '' : ($_SESSION['default_user'] . '_'));
} }
// We use dirname to remove the /i part
$base_url = dirname(Minz_Request::guessBaseUrl());
$config_array = array( $config_array = array(
'environment' => 'production',
'salt' => $_SESSION['salt'], 'salt' => $_SESSION['salt'],
'base_url' => $base_url,
'title' => $_SESSION['title'], 'title' => $_SESSION['title'],
'default_user' => $_SESSION['default_user'], 'default_user' => $_SESSION['default_user'],
'auth_type' => $_SESSION['auth_type'], 'auth_type' => $_SESSION['auth_type'],
@ -181,7 +227,9 @@ function saveStep3() {
'password' => $_SESSION['bd_password'], 'password' => $_SESSION['bd_password'],
'base' => $_SESSION['bd_base'], 'base' => $_SESSION['bd_base'],
'prefix' => $_SESSION['bd_prefix'], 'prefix' => $_SESSION['bd_prefix'],
'pdo_options' => array(),
), ),
'pubsubhubbub_enabled' => server_is_public($base_url),
); );
@unlink(join_path(DATA_PATH, 'config.php')); //To avoid access-rights problems @unlink(join_path(DATA_PATH, 'config.php')); //To avoid access-rights problems
@ -298,9 +346,35 @@ function checkStep1() {
); );
} }
function freshrss_already_installed() {
$conf_path = join_path(DATA_PATH, 'config.php');
if (!file_exists($conf_path)) {
return false;
}
// A configuration file already exists, we try to load it.
$system_conf = null;
try {
Minz_Configuration::register('system', $conf_path);
$system_conf = Minz_Configuration::get('system');
} catch (Minz_FileNotExistException $e) {
return false;
}
// ok, the global conf exists... but what about default user conf?
$current_user = $system_conf->default_user;
try {
Minz_Configuration::register('user', join_path(USERS_PATH, $current_user, 'config.php'));
} catch (Minz_FileNotExistException $e) {
return false;
}
// ok, ok, default user exists too!
return true;
}
function checkStep2() { function checkStep2() {
$conf = !empty($_SESSION['title']) && $conf = !empty($_SESSION['old_entries']) &&
!empty($_SESSION['old_entries']) &&
isset($_SESSION['mail_login']) && isset($_SESSION['mail_login']) &&
!empty($_SESSION['default_user']); !empty($_SESSION['default_user']);
@ -425,7 +499,7 @@ function printStep0() {
<div class="form-group"> <div class="form-group">
<label class="group-name" for="language"><?php echo _t('install.language'); ?></label> <label class="group-name" for="language"><?php echo _t('install.language'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select name="language" id="language"> <select name="language" id="language" tabindex="1" >
<?php foreach ($languages as $lang) { ?> <?php foreach ($languages as $lang) { ?>
<option value="<?php echo $lang; ?>"<?php echo $actual == $lang ? ' selected="selected"' : ''; ?>> <option value="<?php echo $lang; ?>"<?php echo $actual == $lang ? ' selected="selected"' : ''; ?>>
<?php echo _t('gen.lang.' . $lang); ?> <?php echo _t('gen.lang.' . $lang); ?>
@ -437,10 +511,10 @@ function printStep0() {
<div class="form-group form-actions"> <div class="form-group form-actions">
<div class="group-controls"> <div class="group-controls">
<button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button> <button type="submit" class="btn btn-important" tabindex="2" ><?php echo _t('gen.action.submit'); ?></button>
<button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button> <button type="reset" class="btn" tabindex="3" ><?php echo _t('gen.action.cancel'); ?></button>
<?php if ($s0['all'] == 'ok') { ?> <?php if ($s0['all'] == 'ok') { ?>
<a class="btn btn-important next-step" href="?step=1"><?php echo _t('install.action.next_step'); ?></a> <a class="btn btn-important next-step" href="?step=1" tabindex="4" ><?php echo _t('install.action.next_step'); ?></a>
<?php } ?> <?php } ?>
</div> </div>
</div> </div>
@ -533,8 +607,38 @@ function printStep1() {
<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.http_referer.nok'); ?></p> <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.http_referer.nok'); ?></p>
<?php } ?> <?php } ?>
<?php if ($res['all'] == 'ok') { ?> <?php if (freshrss_already_installed() && $res['all'] == 'ok') { ?>
<a class="btn btn-important next-step" href="?step=2"><?php echo _t('install.action.next_step'); ?></a> <p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.attention'); ?></span> <?php echo _t('install.check.already_installed'); ?></p>
<form action="index.php?step=1" method="post">
<input type="hidden" name="freshrss-keep-install" value="1" />
<button type="submit" class="btn btn-important next-step" tabindex="1" ><?php echo _t('install.action.keep_install'); ?></button>
<a class="btn btn-attention next-step confirm" data-str-confirm="<?php echo _t('install.js.confirm_reinstall'); ?>" href="?step=2" tabindex="2" ><?php echo _t('install.action.reinstall'); ?></a>
</form>
<script>
function ask_confirmation(e) {
var str_confirmation = this.getAttribute('data-str-confirm');
if (!str_confirmation) {
str_confirmation = "<?php echo _t('gen.js.confirm_action'); ?>";
}
if (!confirm(str_confirmation)) {
e.preventDefault();
}
}
function init_confirm() {
confirms = document.getElementsByClassName('confirm');
for (var i = 0 ; i < confirms.length ; i++) {
confirms[i].addEventListener('click', ask_confirmation);
}
}
init_confirm();
</script>
<?php } elseif ($res['all'] == 'ok') { ?>
<a class="btn btn-important next-step" href="?step=2" tabindex="1" ><?php echo _t('install.action.next_step'); ?></a>
<?php } else { ?> <?php } else { ?>
<p class="alert alert-error"><?php echo _t('install.action.fix_errors_before'); ?></p> <p class="alert alert-error"><?php echo _t('install.action.fix_errors_before'); ?></p>
<?php } ?> <?php } ?>
@ -542,6 +646,7 @@ function printStep1() {
} }
function printStep2() { function printStep2() {
$user_default_config = Minz_Configuration::get('default_user');
?> ?>
<?php $s2 = checkStep2(); if ($s2['all'] == 'ok') { ?> <?php $s2 = checkStep2(); if ($s2['all'] == 'ok') { ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.conf.ok'); ?></p> <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.conf.ok'); ?></p>
@ -552,31 +657,24 @@ function printStep2() {
<form action="index.php?step=2" method="post"> <form action="index.php?step=2" method="post">
<legend><?php echo _t('install.conf'); ?></legend> <legend><?php echo _t('install.conf'); ?></legend>
<div class="form-group">
<label class="group-name" for="title"><?php echo _t('install.title'); ?></label>
<div class="group-controls">
<input type="text" id="title" name="title" value="<?php echo isset($_SESSION['title']) ? $_SESSION['title'] : _t('gen.freshrss'); ?>" />
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="old_entries"><?php echo _t('install.delete_articles_after'); ?></label> <label class="group-name" for="old_entries"><?php echo _t('install.delete_articles_after'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="number" id="old_entries" name="old_entries" required="required" min="1" max="1200" value="<?php echo isset($_SESSION['old_entries']) ? $_SESSION['old_entries'] : '3'; ?>" /> <?php echo _t('gen.date.month'); ?> <input type="number" id="old_entries" name="old_entries" required="required" min="1" max="1200" value="<?php echo isset($_SESSION['old_entries']) ? $_SESSION['old_entries'] : $user_default_config->old_entries; ?>" tabindex="2" /> <?php echo _t('gen.date.month'); ?>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="default_user"><?php echo _t('install.default_user'); ?></label> <label class="group-name" for="default_user"><?php echo _t('install.default_user'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="default_user" name="default_user" required="required" size="16" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" value="<?php echo isset($_SESSION['default_user']) ? $_SESSION['default_user'] : ''; ?>" placeholder="<?php echo httpAuthUser() == '' ? 'alice' : httpAuthUser(); ?>" /> <input type="text" id="default_user" name="default_user" required="required" size="16" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" value="<?php echo isset($_SESSION['default_user']) ? $_SESSION['default_user'] : ''; ?>" placeholder="<?php echo httpAuthUser() == '' ? 'alice' : httpAuthUser(); ?>" tabindex="3" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="auth_type"><?php echo _t('install.auth.type'); ?></label> <label class="group-name" for="auth_type"><?php echo _t('install.auth.type'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select id="auth_type" name="auth_type" required="required" onchange="auth_type_change(true)"> <select id="auth_type" name="auth_type" required="required" onchange="auth_type_change(true)" tabindex="4">
<?php <?php
function no_auth($auth_type) { function no_auth($auth_type) {
return !in_array($auth_type, array('form', 'persona', 'http_auth', 'none')); return !in_array($auth_type, array('form', 'persona', 'http_auth', 'none'));
@ -595,7 +693,7 @@ function printStep2() {
<label class="group-name" for="passwordPlain"><?php echo _t('install.auth.password_form'); ?></label> <label class="group-name" for="passwordPlain"><?php echo _t('install.auth.password_form'); ?></label>
<div class="group-controls"> <div class="group-controls">
<div class="stick"> <div class="stick">
<input type="password" id="passwordPlain" name="passwordPlain" pattern=".{7,}" autocomplete="off" <?php echo $auth_type === 'form' ? ' required="required"' : ''; ?> /> <input type="password" id="passwordPlain" name="passwordPlain" pattern=".{7,}" autocomplete="off" <?php echo $auth_type === 'form' ? ' required="required"' : ''; ?> tabindex="5" />
<a class="btn toggle-password" data-toggle="passwordPlain"><?php echo FreshRSS_Themes::icon('key'); ?></a> <a class="btn toggle-password" data-toggle="passwordPlain"><?php echo FreshRSS_Themes::icon('key'); ?></a>
</div> </div>
<?php echo _i('help'); ?> <?php echo _t('install.auth.password_format'); ?> <?php echo _i('help'); ?> <?php echo _t('install.auth.password_format'); ?>
@ -606,7 +704,7 @@ function printStep2() {
<div class="form-group"> <div class="form-group">
<label class="group-name" for="mail_login"><?php echo _t('install.auth.email_persona'); ?></label> <label class="group-name" for="mail_login"><?php echo _t('install.auth.email_persona'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="email" id="mail_login" name="mail_login" value="<?php echo isset($_SESSION['mail_login']) ? $_SESSION['mail_login'] : ''; ?>" placeholder="alice@example.net" <?php echo $auth_type === 'persona' ? ' required="required"' : ''; ?> /> <input type="email" id="mail_login" name="mail_login" value="<?php echo isset($_SESSION['mail_login']) ? $_SESSION['mail_login'] : ''; ?>" placeholder="alice@example.net" <?php echo $auth_type === 'persona' ? ' required="required"' : ''; ?> tabindex="6"/>
<noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript> <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
</div> </div>
</div> </div>
@ -634,7 +732,7 @@ function printStep2() {
toggles[i].addEventListener('mouseup', hide_password); toggles[i].addEventListener('mouseup', hide_password);
} }
function auth_type_change(focus) { function auth_type_change() {
var auth_value = document.getElementById('auth_type').value, var auth_value = document.getElementById('auth_type').value,
password_input = document.getElementById('passwordPlain'), password_input = document.getElementById('passwordPlain'),
mail_input = document.getElementById('mail_login'); mail_input = document.getElementById('mail_login');
@ -642,29 +740,23 @@ function printStep2() {
if (auth_value === 'form') { if (auth_value === 'form') {
password_input.required = true; password_input.required = true;
mail_input.required = false; mail_input.required = false;
if (focus) {
password_input.focus();
}
} else if (auth_value === 'persona') { } else if (auth_value === 'persona') {
password_input.required = false; password_input.required = false;
mail_input.required = true; mail_input.required = true;
if (focus) {
mail_input.focus();
}
} else { } else {
password_input.required = false; password_input.required = false;
mail_input.required = false; mail_input.required = false;
} }
} }
auth_type_change(false); auth_type_change();
</script> </script>
<div class="form-group form-actions"> <div class="form-group form-actions">
<div class="group-controls"> <div class="group-controls">
<button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button> <button type="submit" class="btn btn-important" tabindex="7" ><?php echo _t('gen.action.submit'); ?></button>
<button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button> <button type="reset" class="btn" tabindex="8" ><?php echo _t('gen.action.cancel'); ?></button>
<?php if ($s2['all'] == 'ok') { ?> <?php if ($s2['all'] == 'ok') { ?>
<a class="btn btn-important next-step" href="?step=3"><?php echo _t('install.action.next_step'); ?></a> <a class="btn btn-important next-step" href="?step=3" tabindex="9" ><?php echo _t('install.action.next_step'); ?></a>
<?php } ?> <?php } ?>
</div> </div>
</div> </div>
@ -673,6 +765,7 @@ function printStep2() {
} }
function printStep3() { function printStep3() {
$system_default_config = Minz_Configuration::get('default_system');
?> ?>
<?php $s3 = checkStep3(); if ($s3['all'] == 'ok') { ?> <?php $s3 = checkStep3(); if ($s3['all'] == 'ok') { ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.bdd.conf.ok'); ?></p> <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.bdd.conf.ok'); ?></p>
@ -685,7 +778,7 @@ function printStep3() {
<div class="form-group"> <div class="form-group">
<label class="group-name" for="type"><?php echo _t('install.bdd.type'); ?></label> <label class="group-name" for="type"><?php echo _t('install.bdd.type'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select name="type" id="type" onchange="mySqlShowHide()"> <select name="type" id="type" onchange="mySqlShowHide()" tabindex="1" >
<?php if (extension_loaded('pdo_mysql')) {?> <?php if (extension_loaded('pdo_mysql')) {?>
<option value="mysql" <option value="mysql"
<?php echo(isset($_SESSION['bd_type']) && $_SESSION['bd_type'] === 'mysql') ? 'selected="selected"' : ''; ?>> <?php echo(isset($_SESSION['bd_type']) && $_SESSION['bd_type'] === 'mysql') ? 'selected="selected"' : ''; ?>>
@ -706,51 +799,58 @@ function printStep3() {
<div class="form-group"> <div class="form-group">
<label class="group-name" for="host"><?php echo _t('install.bdd.host'); ?></label> <label class="group-name" for="host"><?php echo _t('install.bdd.host'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="host" name="host" pattern="[0-9A-Za-z_.-]{1,64}" value="<?php echo isset($_SESSION['bd_host']) ? $_SESSION['bd_host'] : 'localhost'; ?>" /> <input type="text" id="host" name="host" pattern="[0-9A-Za-z_.-]{1,64}" value="<?php echo isset($_SESSION['bd_host']) ? $_SESSION['bd_host'] : $system_default_config->db['host']; ?>" tabindex="2" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="user"><?php echo _t('install.bdd.username'); ?></label> <label class="group-name" for="user"><?php echo _t('install.bdd.username'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="user" name="user" maxlength="16" pattern="[0-9A-Za-z_.-]{1,16}" value="<?php echo isset($_SESSION['bd_user']) ? $_SESSION['bd_user'] : ''; ?>" /> <input type="text" id="user" name="user" maxlength="16" pattern="[0-9A-Za-z_.-]{1,16}" value="<?php echo isset($_SESSION['bd_user']) ? $_SESSION['bd_user'] : ''; ?>" tabindex="3" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="pass"><?php echo _t('install.bdd.password'); ?></label> <label class="group-name" for="pass"><?php echo _t('install.bdd.password'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="password" id="pass" name="pass" value="<?php echo isset($_SESSION['bd_password']) ? $_SESSION['bd_password'] : ''; ?>" /> <input type="password" id="pass" name="pass" value="<?php echo isset($_SESSION['bd_password']) ? $_SESSION['bd_password'] : ''; ?>" tabindex="4" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="base"><?php echo _t('install.bdd'); ?></label> <label class="group-name" for="base"><?php echo _t('install.bdd'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="base" name="base" maxlength="64" pattern="[0-9A-Za-z_]{1,64}" value="<?php echo isset($_SESSION['bd_base']) ? $_SESSION['bd_base'] : ''; ?>" /> <input type="text" id="base" name="base" maxlength="64" pattern="[0-9A-Za-z_]{1,64}" value="<?php echo isset($_SESSION['bd_base']) ? $_SESSION['bd_base'] : ''; ?>" tabindex="5" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="prefix"><?php echo _t('install.bdd.prefix'); ?></label> <label class="group-name" for="prefix"><?php echo _t('install.bdd.prefix'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="prefix" name="prefix" maxlength="16" pattern="[0-9A-Za-z_]{1,16}" value="<?php echo isset($_SESSION['bd_prefix']) ? $_SESSION['bd_prefix'] : 'freshrss_'; ?>" /> <input type="text" id="prefix" name="prefix" maxlength="16" pattern="[0-9A-Za-z_]{1,16}" value="<?php echo isset($_SESSION['bd_prefix']) ? $_SESSION['bd_prefix'] : $system_default_config->db['prefix']; ?>" tabindex="6" />
</div> </div>
</div> </div>
</div> </div>
<script> <script>
function mySqlShowHide() { function mySqlShowHide() {
document.getElementById('mysql').style.display = document.getElementById('type').value === 'mysql' ? 'block' : 'none'; document.getElementById('mysql').style.display = document.getElementById('type').value === 'mysql' ? 'block' : 'none';
if (document.getElementById('type').value !== 'mysql') {
document.getElementById('host').value = '';
document.getElementById('user').value = '';
document.getElementById('pass').value = '';
document.getElementById('base').value = '';
document.getElementById('prefix').value = '';
}
} }
mySqlShowHide(); mySqlShowHide();
</script> </script>
<div class="form-group form-actions"> <div class="form-group form-actions">
<div class="group-controls"> <div class="group-controls">
<button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button> <button type="submit" class="btn btn-important" tabindex="7" ><?php echo _t('gen.action.submit'); ?></button>
<button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button> <button type="reset" class="btn" tabindex="8" ><?php echo _t('gen.action.cancel'); ?></button>
<?php if ($s3['all'] == 'ok') { ?> <?php if ($s3['all'] == 'ok') { ?>
<a class="btn btn-important next-step" href="?step=4"><?php echo _t('install.action.next_step'); ?></a> <a class="btn btn-important next-step" href="?step=4" tabindex="9" ><?php echo _t('install.action.next_step'); ?></a>
<?php } ?> <?php } ?>
</div> </div>
</div> </div>
@ -761,7 +861,7 @@ function printStep3() {
function printStep4() { function printStep4() {
?> ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('install.congratulations'); ?></span> <?php echo _t('install.ok'); ?></p> <p class="alert alert-success"><span class="alert-head"><?php echo _t('install.congratulations'); ?></span> <?php echo _t('install.ok'); ?></p>
<a class="btn btn-important next-step" href="?step=5"><?php echo _t('install.action.finish'); ?></a> <a class="btn btn-important next-step" href="?step=5" tabindex="1"><?php echo _t('install.action.finish'); ?></a>
<?php <?php
} }
@ -781,6 +881,7 @@ default:
saveLanguage(); saveLanguage();
break; break;
case 1: case 1:
saveStep1();
break; break;
case 2: case 2:
saveStep2(); saveStep2();
@ -820,7 +921,7 @@ case 5:
<li class="item<?php echo STEP == 1 ? ' active' : ''; ?>"><a href="?step=1"><?php echo _t('install.check'); ?></a></li> <li class="item<?php echo STEP == 1 ? ' active' : ''; ?>"><a href="?step=1"><?php echo _t('install.check'); ?></a></li>
<li class="item<?php echo STEP == 2 ? ' active' : ''; ?>"><a href="?step=2"><?php echo _t('install.conf'); ?></a></li> <li class="item<?php echo STEP == 2 ? ' active' : ''; ?>"><a href="?step=2"><?php echo _t('install.conf'); ?></a></li>
<li class="item<?php echo STEP == 3 ? ' active' : ''; ?>"><a href="?step=3"><?php echo _t('install.bdd.conf'); ?></a></li> <li class="item<?php echo STEP == 3 ? ' active' : ''; ?>"><a href="?step=3"><?php echo _t('install.bdd.conf'); ?></a></li>
<li class="item<?php echo STEP == 4 ? ' active' : ''; ?>"><a href="?step=5"><?php echo _t('install.this_is_the_end'); ?></a></li> <li class="item<?php echo STEP == 4 ? ' active' : ''; ?>"><a href="?step=4"><?php echo _t('install.this_is_the_end'); ?></a></li>
</ul> </ul>
<div class="post"> <div class="post">

View file

@ -27,6 +27,9 @@
</li> </li>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?> <?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<li class="nav-header"><?php echo _t('gen.menu.admin'); ?></li> <li class="nav-header"><?php echo _t('gen.menu.admin'); ?></li>
<li class="item<?php echo Minz_Request::actionName() === 'system' ? ' active' : ''; ?>">
<a href="<?php echo _url('configure', 'system')?>"><?php echo _t('gen.menu.system'); ?></a>
</li>
<li class="item<?php echo Minz_Request::controllerName() === 'user' && <li class="item<?php echo Minz_Request::controllerName() === 'user' &&
Minz_Request::actionName() === 'manage' ? ' active' : ''; ?>"> Minz_Request::actionName() === 'manage' ? ' active' : ''; ?>">
<a href="<?php echo _url('user', 'manage'); ?>"><?php echo _t('gen.menu.user_management'); ?></a> <a href="<?php echo _url('user', 'manage'); ?>"><?php echo _t('gen.menu.user_management'); ?></a>

View file

@ -45,7 +45,7 @@
<li class="tree-folder category<?php echo $c_active ? ' active' : ''; ?>" data-unread="<?php echo $cat->nbNotRead(); ?>"> <li class="tree-folder category<?php echo $c_active ? ' active' : ''; ?>" data-unread="<?php echo $cat->nbNotRead(); ?>">
<div class="tree-folder-title"> <div class="tree-folder-title">
<a class="dropdown-toggle" href="#"><?php echo _i($c_show ? 'up' : 'down'); ?></a> <a class="dropdown-toggle" href="#"><?php echo _i($c_show ? 'up' : 'down'); ?></a>
<a class="title" data-unread="<?php echo format_number($cat->nbNotRead()); ?>" href="<?php echo _url('index', 'index', 'get', 'c_' . $cat->id()); ?>"><?php echo $cat->name(); ?></a> <a class="title<?php echo $cat->hasFeedsWithError() ? ' error' : ''; ?>" data-unread="<?php echo format_number($cat->nbNotRead()); ?>" href="<?php echo _url('index', 'index', 'get', 'c_' . $cat->id()); ?>"><?php echo $cat->name(); ?></a>
</div> </div>
<ul class="tree-folder-items<?php echo $c_show ? ' active' : ''; ?>"> <ul class="tree-folder-items<?php echo $c_show ? ' active' : ''; ?>">

View file

@ -67,6 +67,7 @@ if (FreshRSS_Auth::accessNeedsAction()) {
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?> <?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<li class="separator"></li> <li class="separator"></li>
<li class="dropdown-header"><?php echo _t('gen.menu.admin'); ?></li> <li class="dropdown-header"><?php echo _t('gen.menu.admin'); ?></li>
<li class="item"><a href="<?php echo _url('configure', 'system'); ?>"><?php echo _t('gen.menu.system'); ?></a></li>
<li class="item"><a href="<?php echo _url('user', 'manage'); ?>"><?php echo _t('gen.menu.user_management'); ?></a></li> <li class="item"><a href="<?php echo _url('user', 'manage'); ?>"><?php echo _t('gen.menu.user_management'); ?></a></li>
<li class="item"><a href="<?php echo _url('auth', 'index'); ?>"><?php echo _t('gen.menu.authentication'); ?></a></li> <li class="item"><a href="<?php echo _url('auth', 'index'); ?>"><?php echo _t('gen.menu.authentication'); ?></a></li>
<li class="item"><a href="<?php echo _url('update', 'checkInstall'); ?>"><?php echo _t('gen.menu.check_install'); ?></a></li> <li class="item"><a href="<?php echo _url('update', 'checkInstall'); ?>"><?php echo _t('gen.menu.check_install'); ?></a></li>

View file

@ -36,7 +36,11 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="<?php echo FreshRSS_Context::$system_conf->title; ?>"> <meta name="apple-mobile-web-app-title" content="<?php echo FreshRSS_Context::$system_conf->title; ?>">
<meta name="msapplication-TileColor" content="#FFF" /> <meta name="msapplication-TileColor" content="#FFF" />
<?php if (FreshRSS_Context::$system_conf->allow_robots) { ?>
<meta name="description" content="<?php echo htmlspecialchars(FreshRSS_Context::$name . ' | ' . FreshRSS_Context::$description, ENT_COMPAT, 'UTF-8'); ?>" />
<?php } else { ?>
<meta name="robots" content="noindex,nofollow" /> <meta name="robots" content="noindex,nofollow" />
<?php } ?>
</head> </head>
<body class="<?php echo Minz_Request::param('output', 'normal'); ?>"> <body class="<?php echo Minz_Request::param('output', 'normal'); ?>">
<?php $this->partial('header'); ?> <?php $this->partial('header'); ?>

View file

@ -1,6 +1,10 @@
<div class="prompt"> <div class="prompt">
<h1><?php echo _t('gen.auth.login'); ?></h1> <h1><?php echo _t('gen.auth.login'); ?></h1>
<?php if (!max_registrations_reached()) { ?>
<a href="<?php echo _url('auth', 'register'); ?>"><?php echo _t('gen.auth.registration.ask'); ?></a>
<?php } ?>
<form id="crypto-form" method="post" action="<?php echo _url('auth', 'login'); ?>"> <form id="crypto-form" method="post" action="<?php echo _url('auth', 'login'); ?>">
<div> <div>
<label for="username"><?php echo _t('gen.auth.username'); ?></label> <label for="username"><?php echo _t('gen.auth.username'); ?></label>

View file

@ -9,7 +9,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="auth_type"><?php echo _t('admin.auth.type'); ?></label> <label class="group-name" for="auth_type"><?php echo _t('admin.auth.type'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select id="auth_type" name="auth_type" required="required"> <select id="auth_type" name="auth_type" required="required" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->auth_type; ?>">
<?php if (!in_array(FreshRSS_Context::$system_conf->auth_type, array('form', 'persona', 'http_auth', 'none'))) { ?> <?php if (!in_array(FreshRSS_Context::$system_conf->auth_type, array('form', 'persona', 'http_auth', 'none'))) { ?>
<option selected="selected"></option> <option selected="selected"></option>
<?php } ?> <?php } ?>
@ -25,7 +25,7 @@
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="anon_access"> <label class="checkbox" for="anon_access">
<input type="checkbox" name="anon_access" id="anon_access" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous ? ' checked="checked"' : '', <input type="checkbox" name="anon_access" id="anon_access" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous ? ' checked="checked"' : '',
FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->allow_anonymous; ?>"/>
<?php echo _t('admin.auth.allow_anonymous', FreshRSS_Context::$system_conf->default_user); ?> <?php echo _t('admin.auth.allow_anonymous', FreshRSS_Context::$system_conf->default_user); ?>
</label> </label>
</div> </div>
@ -35,7 +35,7 @@
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="anon_refresh"> <label class="checkbox" for="anon_refresh">
<input type="checkbox" name="anon_refresh" id="anon_refresh" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous_refresh ? ' checked="checked"' : '', <input type="checkbox" name="anon_refresh" id="anon_refresh" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous_refresh ? ' checked="checked"' : '',
FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->allow_anonymous_refresh; ?>"/>
<?php echo _t('admin.auth.allow_anonymous_refresh'); ?> <?php echo _t('admin.auth.allow_anonymous_refresh'); ?>
</label> </label>
</div> </div>
@ -45,7 +45,7 @@
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="unsafe_autologin"> <label class="checkbox" for="unsafe_autologin">
<input type="checkbox" name="unsafe_autologin" id="unsafe_autologin" value="1"<?php echo FreshRSS_Context::$system_conf->unsafe_autologin_enabled ? ' checked="checked"' : '', <input type="checkbox" name="unsafe_autologin" id="unsafe_autologin" value="1"<?php echo FreshRSS_Context::$system_conf->unsafe_autologin_enabled ? ' checked="checked"' : '',
FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->unsafe_autologin_enabled; ?>"/>
<?php echo _t('admin.auth.unsafe_autologin'); ?> <?php echo _t('admin.auth.unsafe_autologin'); ?>
<kbd><?php echo Minz_Url::display(array('c' => 'auth', 'a' => 'login', 'params' => array('u' => 'alice', 'p' => '1234')), 'html', true); ?></kbd> <kbd><?php echo Minz_Url::display(array('c' => 'auth', 'a' => 'login', 'params' => array('u' => 'alice', 'p' => '1234')), 'html', true); ?></kbd>
</label> </label>
@ -58,7 +58,7 @@
<?php $token = FreshRSS_Context::$user_conf->token; ?> <?php $token = FreshRSS_Context::$user_conf->token; ?>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="token" name="token" value="<?php echo $token; ?>" placeholder="<?php echo _t('gen.short.blank_to_disable'); ?>"<?php <input type="text" id="token" name="token" value="<?php echo $token; ?>" placeholder="<?php echo _t('gen.short.blank_to_disable'); ?>"<?php
echo FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> echo FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo $token; ?>"/>
<?php echo _i('help'); ?> <?php echo _t('admin.auth.token_help'); ?> <?php echo _i('help'); ?> <?php echo _t('admin.auth.token_help'); ?>
<kbd><?php echo Minz_Url::display(array('params' => array('output' => 'rss', 'token' => $token)), 'html', true); ?></kbd> <kbd><?php echo Minz_Url::display(array('params' => array('output' => 'rss', 'token' => $token)), 'html', true); ?></kbd>
</div> </div>
@ -69,7 +69,7 @@
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="api_enabled"> <label class="checkbox" for="api_enabled">
<input type="checkbox" name="api_enabled" id="api_enabled" value="1"<?php echo FreshRSS_Context::$system_conf->api_enabled ? ' checked="checked"' : '', <input type="checkbox" name="api_enabled" id="api_enabled" value="1"<?php echo FreshRSS_Context::$system_conf->api_enabled ? ' checked="checked"' : '',
FreshRSS_Auth::accessNeedsLogin() ? '' : ' disabled="disabled"'; ?> /> FreshRSS_Auth::accessNeedsLogin() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->api_enabled; ?>"/>
<?php echo _t('admin.auth.api_enabled'); ?> <?php echo _t('admin.auth.api_enabled'); ?>
</label> </label>
</div> </div>

View file

@ -2,6 +2,10 @@
<div class="prompt"> <div class="prompt">
<h1><?php echo _t('gen.auth.login'); ?></h1> <h1><?php echo _t('gen.auth.login'); ?></h1>
<?php if (!max_registrations_reached()) { ?>
<a href="<?php echo _url('auth', 'register'); ?>"><?php echo _t('gen.auth.registration.ask'); ?></a>
<?php } ?>
<p> <p>
<a class="signin btn btn-important" href="<?php echo _url('auth', 'login'); ?>"> <a class="signin btn btn-important" href="<?php echo _url('auth', 'login'); ?>">
<?php echo _i('login'); ?> <?php echo _t('gen.auth.login_persona'); ?> <?php echo _i('login'); ?> <?php echo _t('gen.auth.login_persona'); ?>

View file

@ -0,0 +1,38 @@
<div class="prompt">
<h1><?php echo _t('gen.auth.registration'); ?></h1>
<form method="post" action="<?php echo _url('user', 'create'); ?>">
<div>
<label class="group-name" for="new_user_name"><?php echo _t('gen.auth.username'), '<br />', _i('help'), ' ', _t('gen.auth.username.format'); ?></label>
<input id="new_user_name" name="new_user_name" type="text" size="16" required="required" maxlength="16" autocomplete="off" pattern="[0-9a-zA-Z]{1,16}" />
</div>
<div>
<label class="group-name" for="new_user_passwordPlain"><?php echo _t('gen.auth.password'), '<br />', _i('help'), ' ', _t('gen.auth.password.format'); ?></label>
<div class="stick">
<input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" required="required" autocomplete="off" pattern=".{7,}" />
<a class="btn toggle-password" data-toggle="new_user_passwordPlain"><?php echo _i('key'); ?></a>
</div>
<noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
</div>
<div>
<label class="group-name" for="new_user_email"><?php echo _t('gen.auth.email'); ?></label>
<input type="email" id="new_user_email" name="new_user_email" class="extend" required="required" autocomplete="off" />
</div>
<div>
<?php
$redirect_url = urlencode(Minz_Url::display(
array('c' => 'index', 'a' => 'index'),
'php', true
));
?>
<input type="hidden" name="r" value="<?php echo $redirect_url; ?>" />
<button type="submit" class="btn btn-important"><?php echo _t('gen.action.create'); ?></button>
<a class="btn" href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.cancel'); ?></a>
</div>
</form>
<p><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('gen.freshrss.about'); ?></a></p>
</div>

View file

@ -16,7 +16,7 @@
</p> </p>
<div> <div>
<label for="username"><?php echo _t('gen.auth.username_admin'); ?></label> <label for="username"><?php echo _t('gen.auth.username.admin'); ?></label>
<input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" /> <input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" />
</div> </div>
<div> <div>

View file

@ -10,14 +10,14 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="old_entries"><?php echo _t('conf.archiving.delete_after'); ?></label> <label class="group-name" for="old_entries"><?php echo _t('conf.archiving.delete_after'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="number" id="old_entries" name="old_entries" min="1" max="1200" value="<?php echo FreshRSS_Context::$user_conf->old_entries; ?>" /> <?php echo _t('gen.date.month'); ?> <input type="number" id="old_entries" name="old_entries" min="1" max="1200" value="<?php echo FreshRSS_Context::$user_conf->old_entries; ?>" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->old_entries; ?>"/> <?php echo _t('gen.date.month'); ?>
  <a class="btn confirm" href="<?php echo _url('entry', 'purge'); ?>"><?php echo _t('conf.archiving.purge_now'); ?></a>   <a class="btn confirm" href="<?php echo _url('entry', 'purge'); ?>"><?php echo _t('conf.archiving.purge_now'); ?></a>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="keep_history_default"><?php echo _t('conf.archiving.keep_history_by_feed'); ?></label> <label class="group-name" for="keep_history_default"><?php echo _t('conf.archiving.keep_history_by_feed'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select class="number" name="keep_history_default" id="keep_history_default" required="required"><?php <select class="number" name="keep_history_default" id="keep_history_default" required="required" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->keep_history_default; ?>"><?php
foreach (array('' => '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { foreach (array('' => '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) {
echo '<option value="' . $v . (FreshRSS_Context::$user_conf->keep_history_default == $v ? '" selected="selected' : '') . '">' . $t . ' </option>'; echo '<option value="' . $v . (FreshRSS_Context::$user_conf->keep_history_default == $v ? '" selected="selected' : '') . '">' . $t . ' </option>';
} }
@ -27,7 +27,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="ttl_default"><?php echo _t('conf.archiving.ttl'); ?></label> <label class="group-name" for="ttl_default"><?php echo _t('conf.archiving.ttl'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select class="number" name="ttl_default" id="ttl_default" required="required"><?php <select class="number" name="ttl_default" id="ttl_default" required="required" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->ttl_default; ?>"><?php
$found = false; $found = false;
foreach (array(1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min', foreach (array(1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min',
3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h', 3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h',

View file

@ -9,7 +9,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="language"><?php echo _t('conf.display.language'); ?></label> <label class="group-name" for="language"><?php echo _t('conf.display.language'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select name="language" id="language"> <select name="language" id="language" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->language; ?>">
<?php $languages = Minz_Translate::availableLanguages(); ?> <?php $languages = Minz_Translate::availableLanguages(); ?>
<?php foreach ($languages as $lang) { ?> <?php foreach ($languages as $lang) { ?>
<option value="<?php echo $lang; ?>"<?php echo FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : ''; ?>><?php echo _t('gen.lang.' . $lang); ?></option> <option value="<?php echo $lang; ?>"<?php echo FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : ''; ?>><?php echo _t('gen.lang.' . $lang); ?></option>
@ -24,7 +24,7 @@
<ul class="slides"> <ul class="slides">
<?php $slides = count($this->themes); $i = 1; ?> <?php $slides = count($this->themes); $i = 1; ?>
<?php foreach($this->themes as $theme) { ?> <?php foreach($this->themes as $theme) { ?>
<input type="radio" name="theme" id="img-<?php echo $i ?>" <?php if (FreshRSS_Context::$user_conf->theme === $theme['id']) {echo "checked";}?> value="<?php echo $theme['id'] ?>"/> <input type="radio" name="theme" id="img-<?php echo $i ?>" <?php if (FreshRSS_Context::$user_conf->theme === $theme['id']) {echo "checked";}?> value="<?php echo $theme['id'] ?>" data-leave-validation="<?php echo (FreshRSS_Context::$user_conf->theme === $theme['id']) ? 1 : 0; ?>"/>
<li class="slide-container"> <li class="slide-container">
<div class="slide"> <div class="slide">
<img src="<?php echo Minz_Url::display('/themes/' . $theme['id'] . '/thumbs/original.png')?>"/> <img src="<?php echo Minz_Url::display('/themes/' . $theme['id'] . '/thumbs/original.png')?>"/>
@ -53,7 +53,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="content_width"><?php echo _t('conf.display.width.content'); ?></label> <label class="group-name" for="content_width"><?php echo _t('conf.display.width.content'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select name="content_width" id="content_width" required=""> <select name="content_width" id="content_width" required="" data-leave-validation="<?php echo $width; ?>">
<option value="thin" <?php echo $width === 'thin'? 'selected="selected"' : ''; ?>> <option value="thin" <?php echo $width === 'thin'? 'selected="selected"' : ''; ?>>
<?php echo _t('conf.display.width.thin'); ?> <?php echo _t('conf.display.width.thin'); ?>
</option> </option>
@ -87,29 +87,29 @@
<tbody> <tbody>
<tr> <tr>
<th><?php echo _t('conf.display.icon.top_line'); ?></th> <th><?php echo _t('conf.display.icon.top_line'); ?></th>
<td><input type="checkbox" name="topline_read" value="1"<?php echo FreshRSS_Context::$user_conf->topline_read ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="topline_read" value="1"<?php echo FreshRSS_Context::$user_conf->topline_read ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_read; ?>"/></td>
<td><input type="checkbox" name="topline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->topline_favorite ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="topline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->topline_favorite ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_favorite; ?>"/></td>
<td><input type="checkbox" disabled="disabled" /></td> <td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" disabled="disabled" /></td> <td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" name="topline_date" value="1"<?php echo FreshRSS_Context::$user_conf->topline_date ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="topline_date" value="1"<?php echo FreshRSS_Context::$user_conf->topline_date ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_date; ?>"/></td>
<td><input type="checkbox" name="topline_link" value="1"<?php echo FreshRSS_Context::$user_conf->topline_link ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="topline_link" value="1"<?php echo FreshRSS_Context::$user_conf->topline_link ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_link; ?>"/></td>
</tr><tr> </tr><tr>
<th><?php echo _t('conf.display.icon.bottom_line'); ?></th> <th><?php echo _t('conf.display.icon.bottom_line'); ?></th>
<td><input type="checkbox" name="bottomline_read" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_read ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="bottomline_read" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_read ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_read; ?>"/></td>
<td><input type="checkbox" name="bottomline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_favorite ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="bottomline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_favorite ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_favorite; ?>"/></td>
<td><input type="checkbox" name="bottomline_sharing" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_sharing ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="bottomline_sharing" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_sharing ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_sharing; ?>"/></td>
<td><input type="checkbox" name="bottomline_tags" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_tags ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="bottomline_tags" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_tags ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_tags; ?>"/></td>
<td><input type="checkbox" name="bottomline_date" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_date ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="bottomline_date" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_date ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_date; ?>"/></td>
<td><input type="checkbox" name="bottomline_link" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_link ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" name="bottomline_link" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_link ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_link; ?>"/></td>
</tr> </tr>
</tbody> </tbody>
</table><br /> </table><br />
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="posts_per_page"><?php echo _t('conf.display.notif_html5.timeout'); ?></label> <label class="group-name" for="html5_notif_timeout"><?php echo _t('conf.display.notif_html5.timeout'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?php echo FreshRSS_Context::$user_conf->html5_notif_timeout; ?>" /> <?php echo _t('conf.display.notif_html5.seconds'); ?> <input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?php echo FreshRSS_Context::$user_conf->html5_notif_timeout; ?>" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->html5_notif_timeout; ?>"/> <?php echo _t('conf.display.notif_html5.seconds'); ?>
</div> </div>
</div> </div>

View file

@ -6,27 +6,29 @@
<form method="post" action="<?php echo _url('configure', 'queries'); ?>"> <form method="post" action="<?php echo _url('configure', 'queries'); ?>">
<legend><?php echo _t('conf.query'); ?></legend> <legend><?php echo _t('conf.query'); ?></legend>
<?php foreach (FreshRSS_Context::$user_conf->queries as $key => $query) { ?> <?php foreach ($this->queries as $key => $query) { ?>
<div class="form-group" id="query-group-<?php echo $key; ?>"> <div class="form-group" id="query-group-<?php echo $key; ?>">
<label class="group-name" for="queries_<?php echo $key; ?>_name"> <label class="group-name" for="queries_<?php echo $key; ?>_name">
<?php echo _t('conf.query.number', $key + 1); ?> <?php echo _t('conf.query.number', $key + 1); ?>
</label> </label>
<div class="group-controls"> <div class="group-controls">
<input type="hidden" id="queries_<?php echo $key; ?>_search" name="queries[<?php echo $key; ?>][search]" value="<?php echo isset($query['search']) ? $query['search'] : ""; ?>"/> <input type="hidden" id="queries_<?php echo $key; ?>_search" name="queries[<?php echo $key; ?>][url]" value="<?php echo $query->getUrl(); ?>"/>
<input type="hidden" id="queries_<?php echo $key; ?>_state" name="queries[<?php echo $key; ?>][state]" value="<?php echo isset($query['state']) ? $query['state'] : ""; ?>"/> <input type="hidden" id="queries_<?php echo $key; ?>_search" name="queries[<?php echo $key; ?>][search]" value="<?php echo $query->getSearch(); ?>"/>
<input type="hidden" id="queries_<?php echo $key; ?>_order" name="queries[<?php echo $key; ?>][order]" value="<?php echo isset($query['order']) ? $query['order'] : ""; ?>"/> <input type="hidden" id="queries_<?php echo $key; ?>_state" name="queries[<?php echo $key; ?>][state]" value="<?php echo $query->getState(); ?>"/>
<input type="hidden" id="queries_<?php echo $key; ?>_get" name="queries[<?php echo $key; ?>][get]" value="<?php echo isset($query['get']) ? $query['get'] : ""; ?>"/> <input type="hidden" id="queries_<?php echo $key; ?>_order" name="queries[<?php echo $key; ?>][order]" value="<?php echo $query->getOrder(); ?>"/>
<input type="hidden" id="queries_<?php echo $key; ?>_get" name="queries[<?php echo $key; ?>][get]" value="<?php echo $query->getGet(); ?>"/>
<div class="stick"> <div class="stick">
<input class="extend" <input class="extend"
type="text" type="text"
id="queries_<?php echo $key; ?>_name" id="queries_<?php echo $key; ?>_name"
name="queries[<?php echo $key; ?>][name]" name="queries[<?php echo $key; ?>][name]"
value="<?php echo $query['name']; ?>" value="<?php echo $query->getName(); ?>"
data-leave-validation="<?php echo $query->getName(); ?>"
/> />
<a class="btn" href="<?php echo $query['url']; ?>"> <a class="btn" href="<?php echo $query->getUrl(); ?>">
<?php echo _i('link'); ?> <?php echo _i('link'); ?>
</a> </a>
@ -35,23 +37,11 @@
</a> </a>
</div> </div>
<?php <?php if (!$query->hasParameters()) { ?>
$exist = (isset($query['search']) ? 1 : 0)
+ (isset($query['state']) ? 1 : 0)
+ (isset($query['order']) ? 1 : 0)
+ (isset($query['get']) ? 1 : 0);
// If the only filter is "all" articles, we consider there is no filter
$exist = ($exist === 1 && isset($query['get']) && $query['get'] === 'a') ? 0 : $exist;
$deprecated = (isset($this->query_get[$key]) &&
$this->query_get[$key]['deprecated']);
?>
<?php if ($exist === 0) { ?>
<div class="alert alert-warn"> <div class="alert alert-warn">
<div class="alert-head"><?php echo _t('conf.query.no_filter'); ?></div> <div class="alert-head"><?php echo _t('conf.query.no_filter'); ?></div>
</div> </div>
<?php } elseif ($deprecated) { ?> <?php } elseif ($query->isDeprecated()) { ?>
<div class="alert alert-error"> <div class="alert alert-error">
<div class="alert-head"><?php echo _t('conf.query.deprecated'); ?></div> <div class="alert-head"><?php echo _t('conf.query.deprecated'); ?></div>
</div> </div>
@ -60,20 +50,20 @@
<div class="alert-head"><?php echo _t('conf.query.filter'); ?></div> <div class="alert-head"><?php echo _t('conf.query.filter'); ?></div>
<ul> <ul>
<?php if (isset($query['search'])) { ?> <?php if ($query->hasSearch()) { ?>
<li class="item"><?php echo _t('conf.query.search', $query['search']); ?></li> <li class="item"><?php echo _t('conf.query.search', $query->getSearch()->getRawInput()); ?></li>
<?php } ?> <?php } ?>
<?php if (isset($query['state'])) { ?> <?php if ($query->getState()) { ?>
<li class="item"><?php echo _t('conf.query.state_' . $query['state']); ?></li> <li class="item"><?php echo _t('conf.query.state_' . $query->getState()); ?></li>
<?php } ?> <?php } ?>
<?php if (isset($query['order'])) { ?> <?php if ($query->getOrder()) { ?>
<li class="item"><?php echo _t('conf.query.order_' . strtolower($query['order'])); ?></li> <li class="item"><?php echo _t('conf.query.order_' . strtolower($query->getOrder())); ?></li>
<?php } ?> <?php } ?>
<?php if (isset($query['get'])) { ?> <?php if ($query->getGet()) { ?>
<li class="item"><?php echo _t('conf.query.get_' . $this->query_get[$key]['type'], $this->query_get[$key]['name']); ?></li> <li class="item"><?php echo _t('conf.query.get_' . $query->getGetType(), $query->getGetName()); ?></li>
<?php } ?> <?php } ?>
</ul> </ul>
</div> </div>

View file

@ -9,7 +9,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="posts_per_page"><?php echo _t('conf.reading.articles_per_page'); ?></label> <label class="group-name" for="posts_per_page"><?php echo _t('conf.reading.articles_per_page'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo FreshRSS_Context::$user_conf->posts_per_page; ?>" min="5" max="50" /> <input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo FreshRSS_Context::$user_conf->posts_per_page; ?>" min="5" max="500" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->posts_per_page; ?>"/>
<?php echo _i('help'); ?> <?php echo _t('conf.reading.number_divided_when_reader'); ?> <?php echo _i('help'); ?> <?php echo _t('conf.reading.number_divided_when_reader'); ?>
</div> </div>
</div> </div>
@ -17,7 +17,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="sort_order"><?php echo _t('conf.reading.sort'); ?></label> <label class="group-name" for="sort_order"><?php echo _t('conf.reading.sort'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select name="sort_order" id="sort_order"> <select name="sort_order" id="sort_order" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->sort_order; ?>">
<option value="DESC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'DESC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.newer_first'); ?></option> <option value="DESC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'DESC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.newer_first'); ?></option>
<option value="ASC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'ASC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.older_first'); ?></option> <option value="ASC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'ASC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.older_first'); ?></option>
</select> </select>
@ -27,7 +27,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="view_mode"><?php echo _t('conf.reading.view.default'); ?></label> <label class="group-name" for="view_mode"><?php echo _t('conf.reading.view.default'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select name="view_mode" id="view_mode"> <select name="view_mode" id="view_mode" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->view_mode; ?>">
<option value="normal"<?php echo FreshRSS_Context::$user_conf->view_mode === 'normal' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.normal'); ?></option> <option value="normal"<?php echo FreshRSS_Context::$user_conf->view_mode === 'normal' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.normal'); ?></option>
<option value="reader"<?php echo FreshRSS_Context::$user_conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.reader'); ?></option> <option value="reader"<?php echo FreshRSS_Context::$user_conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.reader'); ?></option>
<option value="global"<?php echo FreshRSS_Context::$user_conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.global'); ?></option> <option value="global"<?php echo FreshRSS_Context::$user_conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.global'); ?></option>
@ -38,7 +38,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="view_mode"><?php echo _t('conf.reading.show'); ?></label> <label class="group-name" for="view_mode"><?php echo _t('conf.reading.show'); ?></label>
<div class="group-controls"> <div class="group-controls">
<select name="default_view" id="default_view"> <select name="default_view" id="default_view" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->default_view; ?>">
<option value="adaptive"<?php echo FreshRSS_Context::$user_conf->default_view === 'adaptive' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.adaptive'); ?></option> <option value="adaptive"<?php echo FreshRSS_Context::$user_conf->default_view === 'adaptive' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.adaptive'); ?></option>
<option value="all"<?php echo FreshRSS_Context::$user_conf->default_view === 'all' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.all_articles'); ?></option> <option value="all"<?php echo FreshRSS_Context::$user_conf->default_view === 'all' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.all_articles'); ?></option>
<option value="unread"<?php echo FreshRSS_Context::$user_conf->default_view === 'unread' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.unread'); ?></option> <option value="unread"<?php echo FreshRSS_Context::$user_conf->default_view === 'unread' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.unread'); ?></option>
@ -49,7 +49,7 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="hide_read_feeds"> <label class="checkbox" for="hide_read_feeds">
<input type="checkbox" name="hide_read_feeds" id="hide_read_feeds" value="1"<?php echo FreshRSS_Context::$user_conf->hide_read_feeds ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="hide_read_feeds" id="hide_read_feeds" value="1"<?php echo FreshRSS_Context::$user_conf->hide_read_feeds ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->hide_read_feeds; ?>"/>
<?php echo _t('conf.reading.hide_read_feeds'); ?> <?php echo _t('conf.reading.hide_read_feeds'); ?>
</label> </label>
</div> </div>
@ -58,7 +58,7 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="display_posts"> <label class="checkbox" for="display_posts">
<input type="checkbox" name="display_posts" id="display_posts" value="1"<?php echo FreshRSS_Context::$user_conf->display_posts ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="display_posts" id="display_posts" value="1"<?php echo FreshRSS_Context::$user_conf->display_posts ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->display_posts; ?>"/>
<?php echo _t('conf.reading.display_articles_unfolded'); ?> <?php echo _t('conf.reading.display_articles_unfolded'); ?>
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</label> </label>
@ -68,7 +68,7 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="display_categories"> <label class="checkbox" for="display_categories">
<input type="checkbox" name="display_categories" id="display_categories" value="1"<?php echo FreshRSS_Context::$user_conf->display_categories ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="display_categories" id="display_categories" value="1"<?php echo FreshRSS_Context::$user_conf->display_categories ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->display_categories; ?>"/>
<?php echo _t('conf.reading.display_categories_unfolded'); ?> <?php echo _t('conf.reading.display_categories_unfolded'); ?>
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</label> </label>
@ -78,7 +78,7 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="sticky_post"> <label class="checkbox" for="sticky_post">
<input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?php echo FreshRSS_Context::$user_conf->sticky_post ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?php echo FreshRSS_Context::$user_conf->sticky_post ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->sticky_post; ?>"/>
<?php echo _t('conf.reading.sticky_post'); ?> <?php echo _t('conf.reading.sticky_post'); ?>
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</label> </label>
@ -88,7 +88,7 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="auto_load_more"> <label class="checkbox" for="auto_load_more">
<input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?php echo FreshRSS_Context::$user_conf->auto_load_more ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?php echo FreshRSS_Context::$user_conf->auto_load_more ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->auto_load_more; ?>"/>
<?php echo _t('conf.reading.auto_load_more'); ?> <?php echo _t('conf.reading.auto_load_more'); ?>
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</label> </label>
@ -98,7 +98,7 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="lazyload"> <label class="checkbox" for="lazyload">
<input type="checkbox" name="lazyload" id="lazyload" value="1"<?php echo FreshRSS_Context::$user_conf->lazyload ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="lazyload" id="lazyload" value="1"<?php echo FreshRSS_Context::$user_conf->lazyload ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->lazyload; ?>"/>
<?php echo _t('conf.reading.img_with_lazyload'); ?> <?php echo _t('conf.reading.img_with_lazyload'); ?>
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</label> </label>
@ -108,7 +108,7 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="reading_confirm"> <label class="checkbox" for="reading_confirm">
<input type="checkbox" name="reading_confirm" id="reading_confirm" value="1"<?php echo FreshRSS_Context::$user_conf->reading_confirm ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="reading_confirm" id="reading_confirm" value="1"<?php echo FreshRSS_Context::$user_conf->reading_confirm ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->reading_confirm; ?>"/>
<?php echo _t('conf.reading.confirm_enabled'); ?> <?php echo _t('conf.reading.confirm_enabled'); ?>
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</label> </label>
@ -118,30 +118,39 @@
<div class="form-group"> <div class="form-group">
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="auto_remove_article"> <label class="checkbox" for="auto_remove_article">
<input type="checkbox" name="auto_remove_article" id="auto_remove_article" value="1"<?php echo FreshRSS_Context::$user_conf->auto_remove_article ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="auto_remove_article" id="auto_remove_article" value="1"<?php echo FreshRSS_Context::$user_conf->auto_remove_article ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->auto_remove_article; ?>"/>
<?php echo _t('conf.reading.auto_remove_article'); ?> <?php echo _t('conf.reading.auto_remove_article'); ?>
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</label> </label>
</div> </div>
</div> </div>
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="mark_updated_article_unread">
<input type="checkbox" name="mark_updated_article_unread" id="mark_updated_article_unread" value="1"<?php echo FreshRSS_Context::$user_conf->mark_updated_article_unread ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_updated_article_unread; ?>"/>
<?php echo _t('conf.reading.mark_updated_article_unread'); ?>
</label>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="group-name"><?php echo _t('conf.reading.read.when'); ?></label> <label class="group-name"><?php echo _t('conf.reading.read.when'); ?></label>
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="check_open_article"> <label class="checkbox" for="check_open_article">
<input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['article'] ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['article'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['article']; ?>"/>
<?php echo _t('conf.reading.read.article_viewed'); ?> <?php echo _t('conf.reading.read.article_viewed'); ?>
</label> </label>
<label class="checkbox" for="check_open_site"> <label class="checkbox" for="check_open_site">
<input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['site'] ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['site'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['site']; ?>"/>
<?php echo _t('conf.reading.read.article_open_on_website'); ?> <?php echo _t('conf.reading.read.article_open_on_website'); ?>
</label> </label>
<label class="checkbox" for="check_scroll"> <label class="checkbox" for="check_scroll">
<input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['scroll'] ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['scroll'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['scroll']; ?>"/>
<?php echo _t('conf.reading.read.scroll'); ?> <?php echo _t('conf.reading.read.scroll'); ?>
</label> </label>
<label class="checkbox" for="check_reception"> <label class="checkbox" for="check_reception">
<input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['reception'] ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['reception'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['reception']; ?>"/>
<?php echo _t('conf.reading.read.upon_reception'); ?> <?php echo _t('conf.reading.read.upon_reception'); ?>
</label> </label>
</div> </div>
@ -151,7 +160,7 @@
<label class="group-name"><?php echo _t('conf.reading.after_onread'); ?></label> <label class="group-name"><?php echo _t('conf.reading.after_onread'); ?></label>
<div class="group-controls"> <div class="group-controls">
<label class="checkbox" for="onread_jump_next"> <label class="checkbox" for="onread_jump_next">
<input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?php echo FreshRSS_Context::$user_conf->onread_jump_next ? ' checked="checked"' : ''; ?> /> <input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?php echo FreshRSS_Context::$user_conf->onread_jump_next ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->onread_jump_next; ?>"/>
<?php echo _t('conf.reading.jump_next'); ?> <?php echo _t('conf.reading.jump_next'); ?>
</label> </label>
</div> </div>

View file

@ -4,7 +4,8 @@
<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a> <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
<form method="post" action="<?php echo _url('configure', 'sharing'); ?>" <form method="post" action="<?php echo _url('configure', 'sharing'); ?>"
data-simple='<div class="form-group" id="group-share-##key##"><label class="group-name">##label##</label><div class="group-controls"><a href="#" class="remove btn btn-attention" data-remove="group-share-##key##"><?php echo _i('close'); ?></a> data-simple='<div class="form-group" id="group-share-##key##"><label class="group-name">##label##</label><div class="group-controls"><div class="stick"><input type="text" id="share_##key##_name" name="share[##key##][name]" class="extend" value="##label##" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" />
<input type="url" id="share_##key##_url" name="share[##key##][url]" class="extend" value="" placeholder="<?php echo _t('gen.short.not_applicable'); ?>" size="64" disabled /><a href="#" class="remove btn btn-attention" data-remove="group-share-##key##"><?php echo _i('close'); ?></a></div>
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" /></div></div>' <input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" /></div></div>'
data-advanced='<div class="form-group" id="group-share-##key##"><label class="group-name">##label##</label><div class="group-controls"> data-advanced='<div class="form-group" id="group-share-##key##"><label class="group-name">##label##</label><div class="group-controls">
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" /> <input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" />
@ -26,16 +27,17 @@
</label> </label>
<div class="group-controls"> <div class="group-controls">
<input type='hidden' id='share_<?php echo $key; ?>_type' name="share[<?php echo $key; ?>][type]" value='<?php echo $share->type(); ?>' /> <input type='hidden' id='share_<?php echo $key; ?>_type' name="share[<?php echo $key; ?>][type]" value='<?php echo $share->type(); ?>' />
<div class="stick">
<input type="text" id="share_<?php echo $key; ?>_name" name="share[<?php echo $key; ?>][name]" class="extend" value="<?php echo $share->name(); ?>" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" data-leave-validation="<?php echo $share->name(); ?>"/>
<?php if ($share->formType() === 'advanced') { ?> <?php if ($share->formType() === 'advanced') { ?>
<div class="stick"> <input type="url" id="share_<?php echo $key; ?>_url" name="share[<?php echo $key; ?>][url]" class="extend" value="<?php echo $share->baseUrl(); ?>" placeholder="<?php echo _t('conf.sharing.share_url'); ?>" size="64" data-leave-validation="<?php echo $share->baseUrl(); ?>"/>
<input type="text" id="share_<?php echo $key; ?>_name" name="share[<?php echo $key; ?>][name]" class="extend" value="<?php echo $share->name(); ?>" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" />
<input type="url" id="share_<?php echo $key; ?>_url" name="share[<?php echo $key; ?>][url]" class="extend" value="<?php echo $share->baseUrl(); ?>" placeholder="<?php echo _t('conf.sharing.share_url'); ?>" size="64" />
<a href='#' class='remove btn btn-attention' data-remove="group-share-<?php echo $key; ?>"><?php echo _i('close'); ?></a>
</div>
<a target="_blank" class="btn" title="<?php echo _t('conf.sharing.more_information'); ?>" href="<?php echo $share->help(); ?>"><?php echo _i('help'); ?></a>
<?php } else { ?> <?php } else { ?>
<a href='#' class='remove btn btn-attention' data-remove="group-share-<?php echo $key; ?>"><?php echo _i('close'); ?></a> <input type="url" id="share_<?php echo $key; ?>_url" name="share[<?php echo $key; ?>][url]" class="extend" value="<?php echo $share->baseUrl(); ?>" placeholder="<?php echo _t('gen.short.not_applicable'); ?>" size="64" disabled/>
<?php } ?>
<a href='#' class='remove btn btn-attention' data-remove="group-share-<?php echo $key; ?>"><?php echo _i('close'); ?></a>
</div>
<?php if ($share->formType() === 'advanced') { ?>
<a target="_blank" class="btn" title="<?php echo _t('conf.sharing.more_information'); ?>" href="<?php echo $share->help(); ?>"><?php echo _i('help'); ?></a>
<?php } ?> <?php } ?>
</div> </div>
</div> </div>

View file

@ -23,28 +23,28 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="next_entry"><?php echo _t('conf.shortcut.next_article'); ?></label> <label class="group-name" for="next_entry"><?php echo _t('conf.shortcut.next_article'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="next_entry" name="shortcuts[next_entry]" list="keys" value="<?php echo $s['next_entry']; ?>" /> <input type="text" id="next_entry" name="shortcuts[next_entry]" list="keys" value="<?php echo $s['next_entry']; ?>" data-leave-validation="<?php echo $s['next_entry']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="prev_entry"><?php echo _t('conf.shortcut.previous_article'); ?></label> <label class="group-name" for="prev_entry"><?php echo _t('conf.shortcut.previous_article'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="prev_entry" name="shortcuts[prev_entry]" list="keys" value="<?php echo $s['prev_entry']; ?>" /> <input type="text" id="prev_entry" name="shortcuts[prev_entry]" list="keys" value="<?php echo $s['prev_entry']; ?>" data-leave-validation="<?php echo $s['prev_entry']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="first_entry"><?php echo _t('conf.shortcut.first_article'); ?></label> <label class="group-name" for="first_entry"><?php echo _t('conf.shortcut.first_article'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="first_entry" name="shortcuts[first_entry]" list="keys" value="<?php echo $s['first_entry']; ?>" /> <input type="text" id="first_entry" name="shortcuts[first_entry]" list="keys" value="<?php echo $s['first_entry']; ?>" data-leave-validation="<?php echo $s['first_entry']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="last_entry"><?php echo _t('conf.shortcut.last_article'); ?></label> <label class="group-name" for="last_entry"><?php echo _t('conf.shortcut.last_article'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="last_entry" name="shortcuts[last_entry]" list="keys" value="<?php echo $s['last_entry']; ?>" /> <input type="text" id="last_entry" name="shortcuts[last_entry]" list="keys" value="<?php echo $s['last_entry']; ?>" data-leave-validation="<?php echo $s['last_entry']; ?>"/>
</div> </div>
</div> </div>
@ -53,7 +53,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="mark_read"><?php echo _t('conf.shortcut.mark_read'); ?></label> <label class="group-name" for="mark_read"><?php echo _t('conf.shortcut.mark_read'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="mark_read" name="shortcuts[mark_read]" list="keys" value="<?php echo $s['mark_read']; ?>" /> <input type="text" id="mark_read" name="shortcuts[mark_read]" list="keys" value="<?php echo $s['mark_read']; ?>" data-leave-validation="<?php echo $s['mark_read']; ?>"/>
<?php echo _t('conf.shortcut.shift_for_all_read'); ?> <?php echo _t('conf.shortcut.shift_for_all_read'); ?>
</div> </div>
</div> </div>
@ -61,21 +61,21 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="mark_favorite"><?php echo _t('conf.shortcut.mark_favorite'); ?></label> <label class="group-name" for="mark_favorite"><?php echo _t('conf.shortcut.mark_favorite'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="mark_favorite" name="shortcuts[mark_favorite]" list="keys" value="<?php echo $s['mark_favorite']; ?>" /> <input type="text" id="mark_favorite" name="shortcuts[mark_favorite]" list="keys" value="<?php echo $s['mark_favorite']; ?>" data-leave-validation="<?php echo $s['mark_favorite']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="go_website"><?php echo _t('conf.shortcut.see_on_website'); ?></label> <label class="group-name" for="go_website"><?php echo _t('conf.shortcut.see_on_website'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="go_website" name="shortcuts[go_website]" list="keys" value="<?php echo $s['go_website']; ?>" /> <input type="text" id="go_website" name="shortcuts[go_website]" list="keys" value="<?php echo $s['go_website']; ?>" data-leave-validation="<?php echo $s['go_website']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="auto_share_shortcut"><?php echo _t('conf.shortcut.auto_share'); ?></label> <label class="group-name" for="auto_share_shortcut"><?php echo _t('conf.shortcut.auto_share'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="auto_share_shortcut" name="shortcuts[auto_share]" list="keys" value="<?php echo $s['auto_share']; ?>" /> <input type="text" id="auto_share_shortcut" name="shortcuts[auto_share]" list="keys" value="<?php echo $s['auto_share']; ?>" data-leave-validation="<?php echo $s['auto_share']; ?>"/>
<?php echo _t('conf.shortcut.auto_share_help'); ?> <?php echo _t('conf.shortcut.auto_share_help'); ?>
</div> </div>
</div> </div>
@ -83,7 +83,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="collapse_entry"><?php echo _t('conf.shortcut.collapse_article'); ?></label> <label class="group-name" for="collapse_entry"><?php echo _t('conf.shortcut.collapse_article'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="collapse_entry" name="shortcuts[collapse_entry]" list="keys" value="<?php echo $s['collapse_entry']; ?>" /> <input type="text" id="collapse_entry" name="shortcuts[collapse_entry]" list="keys" value="<?php echo $s['collapse_entry']; ?>" data-leave-validation="<?php echo $s['collapse_entry']; ?>"/>
</div> </div>
</div> </div>
@ -92,21 +92,21 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="load_more_shortcut"><?php echo _t('conf.shortcut.load_more'); ?></label> <label class="group-name" for="load_more_shortcut"><?php echo _t('conf.shortcut.load_more'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="load_more_shortcut" name="shortcuts[load_more]" list="keys" value="<?php echo $s['load_more']; ?>" /> <input type="text" id="load_more_shortcut" name="shortcuts[load_more]" list="keys" value="<?php echo $s['load_more']; ?>" data-leave-validation="<?php echo $s['load_more']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="focus_search_shortcut"><?php echo _t('conf.shortcut.focus_search'); ?></label> <label class="group-name" for="focus_search_shortcut"><?php echo _t('conf.shortcut.focus_search'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="focus_search_shortcut" name="shortcuts[focus_search]" list="keys" value="<?php echo $s['focus_search']; ?>" /> <input type="text" id="focus_search_shortcut" name="shortcuts[focus_search]" list="keys" value="<?php echo $s['focus_search']; ?>" data-leave-validation="<?php echo $s['focus_search']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="user_filter_shortcut"><?php echo _t('conf.shortcut.user_filter'); ?></label> <label class="group-name" for="user_filter_shortcut"><?php echo _t('conf.shortcut.user_filter'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="user_filter_shortcut" name="shortcuts[user_filter]" list="keys" value="<?php echo $s['user_filter']; ?>" /> <input type="text" id="user_filter_shortcut" name="shortcuts[user_filter]" list="keys" value="<?php echo $s['user_filter']; ?>" data-leave-validation="<?php echo $s['user_filter']; ?>"/>
<?php echo _t('conf.shortcut.user_filter_help'); ?> <?php echo _t('conf.shortcut.user_filter_help'); ?>
</div> </div>
</div> </div>
@ -114,14 +114,14 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="close_dropdown_shortcut"><?php echo _t('conf.shortcut.close_dropdown'); ?></label> <label class="group-name" for="close_dropdown_shortcut"><?php echo _t('conf.shortcut.close_dropdown'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="close_dropdown" name="shortcuts[close_dropdown]" list="keys" value="<?php echo $s['close_dropdown']; ?>" /> <input type="text" id="close_dropdown" name="shortcuts[close_dropdown]" list="keys" value="<?php echo $s['close_dropdown']; ?>" data-leave-validation="<?php echo $s['close_dropdown']; ?>"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="help_shortcut"><?php echo _t('conf.shortcut.help'); ?></label> <label class="group-name" for="help_shortcut"><?php echo _t('conf.shortcut.help'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" id="help_shortcut" name="shortcuts[help]" list="keys" value="<?php echo $s['help']; ?>" /> <input type="text" id="help_shortcut" name="shortcuts[help]" list="keys" value="<?php echo $s['help']; ?>" data-leave-validation="<?php echo $s['help']; ?>"/>
</div> </div>
</div> </div>

View file

@ -0,0 +1,61 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
<form method="post" action="<?php echo _url('configure', 'system'); ?>">
<legend><?php echo _t('admin.system'); ?></legend>
<div class="form-group">
<label class="group-name" for="instance-name"><?php echo _t('admin.system.instance-name'); ?></label>
<div class="group-controls">
<input type="text" class="extend" id="instance-name" name="instance-name" value="<?php echo FreshRSS_Context::$system_conf->title; ?>" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->title; ?>"/>
</div>
</div>
<div class="form-group">
<label class="group-name" for="auto-update-url"><?php echo _t('admin.system.auto-update-url'); ?></label>
<div class="group-controls">
<input type="text" class="extend" id="auto-update-url" name="auto-update-url" value="<?php echo FreshRSS_Context::$system_conf->auto_update_url; ?>" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->auto_update_url; ?>"/>
</div>
</div>
<div class="form-group">
<label class="group-name" for="max-registrations"><?php echo _t('admin.system.registration.number'); ?></label>
<div class="group-controls">
<input type="number" id="max-registrations" name="max-registrations" value="<?php echo FreshRSS_Context::$system_conf->limits['max_registrations']; ?>" min="0" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->limits['max_registrations']; ?>"/>
<?php echo _i('help'); ?> <?php echo _t('admin.system.registration.help'); ?>
</div>
</div>
<div class="form-group">
<div class="group-controls">
<?php
$number = count(listUsers());
echo _t($number > 1 ? 'admin.user.numbers' : 'admin.user.number', $number);
?>
</div>
</div>
<div class="form-group">
<label class="group-name" for="max-feeds"><?php echo _t('admin.system.max-feeds'); ?></label>
<div class="group-controls">
<input type="number" id="max-feeds" name="max-feeds" value="<?php echo FreshRSS_Context::$system_conf->limits['max_feeds']; ?>" min="1" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->limits['max_feeds']; ?>"/>
</div>
</div>
<div class="form-group">
<label class="group-name" for="max-categories"><?php echo _t('admin.system.max-categories'); ?></label>
<div class="group-controls">
<input type="number" id="max-categories" name="max-categories" value="<?php echo FreshRSS_Context::$system_conf->limits['max_categories']; ?>" min="1" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->limits['max_categories']; ?>"/>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
<button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
</div>
</div>
</form>
</div>

View file

@ -67,7 +67,7 @@
<div class="form-group"> <div class="form-group">
<label class="group-name" for="http_user"><?php echo _t('sub.feed.auth.username'); ?></label> <label class="group-name" for="http_user"><?php echo _t('sub.feed.auth.username'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" name="http_user" id="http_user" class="extend" value="<?php echo $auth['username']; ?>" autocomplete="off" /> <input type="text" name="http_user" id="http_user" class="extend" value="<?php echo empty($auth['username']) ? ' ' : $auth['username']; ?>" autocomplete="off" />
</div> </div>
<label class="group-name" for="http_pass"><?php echo _t('sub.feed.auth.password'); ?></label> <label class="group-name" for="http_pass"><?php echo _t('sub.feed.auth.password'); ?></label>

View file

@ -126,6 +126,14 @@
?></select> ?></select>
</div> </div>
</div> </div>
<div class="form-group">
<label class="group-name" for="pubsubhubbub"><?php echo _t('sub.feed.pubsubhubbub'); ?></label>
<div class="group-controls">
<label class="checkbox" for="pubsubhubbub">
<input type="checkbox" name="pubsubhubbub" id="pubsubhubbub" disabled="disabled" value="1"<?php echo $this->feed->pubSubHubbubEnabled() ? ' checked="checked"' : ''; ?> />
</label>
</div>
</div>
<div class="form-group form-actions"> <div class="form-group form-actions">
<div class="group-controls"> <div class="group-controls">
<button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button> <button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
@ -136,15 +144,15 @@
<legend><?php echo _t('sub.feed.auth.configuration'); ?></legend> <legend><?php echo _t('sub.feed.auth.configuration'); ?></legend>
<?php $auth = $this->feed->httpAuth(false); ?> <?php $auth = $this->feed->httpAuth(false); ?>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="http_user"><?php echo _t('sub.feed.auth.username'); ?></label> <label class="group-name" for="http_user_feed<?php echo $this->feed->id(); ?>"><?php echo _t('sub.feed.auth.username'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="text" name="http_user" id="http_user" class="extend" value="<?php echo $auth['username']; ?>" autocomplete="off" /> <input type="text" name="http_user_feed<?php echo $this->feed->id(); ?>" id="http_user_feed<?php echo $this->feed->id(); ?>" class="extend" value="<?php echo empty($auth['username']) ? ' ' : $auth['username']; ?>" autocomplete="off" />
<?php echo _i('help'); ?> <?php echo _t('sub.feed.auth.help'); ?> <?php echo _i('help'); ?> <?php echo _t('sub.feed.auth.help'); ?>
</div> </div>
<label class="group-name" for="http_pass"><?php echo _t('sub.feed.auth.password'); ?></label> <label class="group-name" for="http_pass_feed<?php echo $this->feed->id(); ?>"><?php echo _t('sub.feed.auth.password'); ?></label>
<div class="group-controls"> <div class="group-controls">
<input type="password" name="http_pass" id="http_pass" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="off" /> <input type="password" name="http_pass_feed<?php echo $this->feed->id(); ?>" id="http_pass_feed<?php echo $this->feed->id(); ?>" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="off" />
</div> </div>
</div> </div>

View file

@ -71,7 +71,7 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close"></a></li><?php <li class="dropdown-close"><a href="#close"></a></li><?php
foreach($tags as $tag) { foreach($tags as $tag) {
?><li class="item"><a href="<?php echo _url('index', 'index', 'search', urlencode('#' . $tag)); ?>"><?php echo $tag; ?></a></li><?php ?><li class="item"><a href="<?php echo _url('index', 'index', 'search', '#' . htmlspecialchars_decode($tag)); ?>"><?php echo $tag; ?></a></li><?php
} ?> } ?>
</ul> </ul>
</div> </div>

View file

@ -56,7 +56,11 @@ if (!empty($this->entries)) {
?></div><?php ?></div><?php
$display_others = false; $display_others = false;
} }
?><div class="flux<?php echo !$this->entry->isRead() ? ' not_read' : ''; ?><?php echo $this->entry->isFavorite() ? ' favorite' : ''; ?>" id="flux_<?php echo $this->entry->id(); ?>"><?php ?><div class="flux<?php echo !$this->entry->isRead() ? ' not_read' : '';
?><?php echo $this->entry->isFavorite() ? ' favorite' : '';
?>" id="flux_<?php echo $this->entry->id();
?>" data-feed="<?php echo $this->feed->id();
?>"><?php
$this->renderHelper('index/normal/entry_header'); $this->renderHelper('index/normal/entry_header');

View file

@ -36,10 +36,10 @@
<li class="dropdown-header"><?php echo _t('sub.feed.auth.http'); ?></li> <li class="dropdown-header"><?php echo _t('sub.feed.auth.http'); ?></li>
<li class="input"> <li class="input">
<input type="text" name="http_user" id="http_user_add" autocomplete="off" placeholder="<?php echo _t('sub.feed.auth.username'); ?>" /> <input type="text" name="http_user" id="http_user_feed" value=" " autocomplete="off" placeholder="<?php echo _t('sub.feed.auth.username'); ?>" />
</li> </li>
<li class="input"> <li class="input">
<input type="password" name="http_pass" id="http_pass_add" autocomplete="off" placeholder="<?php echo _t('sub.feed.auth.password'); ?>" /> <input type="password" name="http_pass" id="http_pass_feed" autocomplete="off" placeholder="<?php echo _t('sub.feed.auth.password'); ?>" />
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -18,11 +18,11 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="group-name" for="passwordPlain"><?php echo _t('conf.profile.password_form'); ?></label> <label class="group-name" for="newPasswordPlain"><?php echo _t('conf.profile.password_form'); ?></label>
<div class="group-controls"> <div class="group-controls">
<div class="stick"> <div class="stick">
<input type="password" id="passwordPlain" name="passwordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
<a class="btn toggle-password" data-toggle="passwordPlain"><?php echo _i('key'); ?></a> <a class="btn toggle-password" data-toggle="newPasswordPlain"><?php echo _i('key'); ?></a>
</div> </div>
<?php echo _i('help'); ?> <?php echo _t('conf.profile.password_format'); ?> <?php echo _i('help'); ?> <?php echo _t('conf.profile.password_format'); ?>
<noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript> <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
@ -57,4 +57,35 @@
</div> </div>
</div> </div>
</form> </form>
<?php if (!FreshRSS_Auth::hasAccess('admin')) { ?>
<form id="crypto-form" method="post" action="<?php echo _url('user', 'delete'); ?>">
<legend><?php echo _t('conf.profile.delete'); ?></legend>
<p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.attention'); ?></span> <?php echo _t('conf.profile.delete.warn'); ?></p>
<div class="form-group">
<label class="group-name" for="passwordPlain"><?php echo _t('gen.auth.password'); ?></label>
<div class="group-controls">
<input type="password" id="passwordPlain" required="required" />
<input type="hidden" id="challenge" name="challenge" /><br />
<noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
<?php
$redirect_url = urlencode(Minz_Url::display(
array('c' => 'user', 'a' => 'profile'),
'php', true
));
?>
<input type="hidden" name="r" value="<?php echo $redirect_url; ?>" />
<input type="hidden" name="username" id="username" value="<?php echo Minz_Session::param('currentUser', '_'); ?>" />
<button type="submit" class="btn btn-attention confirm"><?php echo _t('gen.action.remove'); ?></button>
</div>
</div>
</form>
<?php } ?>
</div> </div>

Some files were not shown because too many files have changed in this diff Show more