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

Merge pull request #16 from plopoyop/freshrss-1.4.0

Freshrss 1.4.0
This commit is contained in:
Clément 2016-07-24 19:23:15 +02:00 committed by GitHub
commit cdc8c98331
99 changed files with 3394 additions and 623 deletions

View file

@ -1,5 +1,61 @@
# Changelog
## 2016-07-23 FreshRSS 1.4.0
## 2016-06-12 FreshRSS 1.3.2-beta
* Compatibility
* Require at least PHP 5.3+ (drop PHP 5.2) [#1133](https://github.com/FreshRSS/FreshRSS/pull/1133)
* Features
* Support for MySQL 5.7+ (e.g. Ubuntu 16.04 LTS) [#1132](https://github.com/FreshRSS/FreshRSS/pull/1132)
* Speed optimization for HTTP/2 [#1133](https://github.com/FreshRSS/FreshRSS/pull/1133)
* API support for REDIRECT_* HTTP headers (fcgi) [#1128](https://github.com/FreshRSS/FreshRSS/issues/1128)
* SimplePie
* Support for feeds with invalid whitespace [#1142](https://github.com/FreshRSS/FreshRSS/issues/1142)
* Bug fixing
* Fix bug when adding feeds with passwords [#1137](https://github.com/FreshRSS/FreshRSS/pull/1137)
* Fix validator link [#1147](https://github.com/FreshRSS/FreshRSS/pull/1147)
* Fix Favicon small bugs [#1135](https://github.com/FreshRSS/FreshRSS/pull/1135)
* Security
* CSP compatibility for homepage [#1120](https://github.com/FreshRSS/FreshRSS/pull/1120)
* I18n
* Draft of Russian [#1085](https://github.com/FreshRSS/FreshRSS/pull/1085)
* Misc.
* Change default feed timeout to 15 seconds [#1146](https://github.com/FreshRSS/FreshRSS/pull/1146)
* Updated Wallabag v2 [#1150](https://github.com/FreshRSS/FreshRSS/pull/1150)
## 2016-03-11 FreshRSS 1.3.1-beta
* Security
* Added CSP `Content-Security-Policy: default-src 'self'; child-src *; frame-src *; img-src * data:; media-src *` [#1075](https://github.com/FreshRSS/FreshRSS/issues/1075), [#1114](https://github.com/FreshRSS/FreshRSS/issues/1114)
* Added `X-Content-Type-Options: nosniff` [#1116](https://github.com/FreshRSS/FreshRSS/pull/1116)
* Cookie with `Secure` tag when used over HTTPS [#1117](https://github.com/FreshRSS/FreshRSS/pull/1117)
* Limit API post input to 1MB [#1118](https://github.com/FreshRSS/FreshRSS/pull/1118)
* Features
* New list of domains for which to force HTTPS (for images, videos, iframes…) defined in `./data/force-https.default.txt` and `./data/force-https.txt` [#1083](https://github.com/FreshRSS/FreshRSS/issues/1083)
* In particular useful for privacy and to avoid mixed content errors, e.g. to see YouTube videos when FreshRSS is in HTTPS
* Add sharing with “Journal du Hacker” [#1056](https://github.com/FreshRSS/FreshRSS/pull/1056)
* UI
* Updated to jQuery 2.2.1 and changed code for auto-load on scroll [#1050](https://github.com/FreshRSS/FreshRSS/pull/1050), [#1091](https://github.com/FreshRSS/FreshRSS/pull/1091)
* I18n
* Turkish [#1073](https://github.com/FreshRSS/FreshRSS/issues/1073)
* Bug fixing
* Fixed OPML import title bug [#1048](https://github.com/FreshRSS/FreshRSS/issues/1048)
* Fixed upgrade bug with SQLite when articles were marked as unread [#1049](https://github.com/FreshRSS/FreshRSS/issues/1049)
* Fixed error when deleting feeds from statistics page [#1047](https://github.com/FreshRSS/FreshRSS/issues/1047)
* Fixed several small bugs in global and reader view [#1050](https://github.com/FreshRSS/FreshRSS/pull/1050)
* Fixed sharing bug with PHP7 [#1072](https://github.com/FreshRSS/FreshRSS/issues/1072)
* Fixed fall-back when php-json is not installed [#1092](https://github.com/FreshRSS/FreshRSS/issues/1092)
* API
* Possibility to show only read items [#1035](https://github.com/FreshRSS/FreshRSS/pull/1035)
* Misc.
* Filters `<img />` attributes `srcset` and `sizes` [#1077](https://github.com/FreshRSS/FreshRSS/issues/1077), [#1086](https://github.com/FreshRSS/FreshRSS/pull/1086)
* Implement PubSubHubbub unsubscribe responses [#1058](https://github.com/FreshRSS/FreshRSS/issues/1058)
* Restored some compatibility with PHP 5.2 [#1055](https://github.com/FreshRSS/FreshRSS/issues/1055)
* Check for extension php-xml during install [#1094](https://github.com/FreshRSS/FreshRSS/issues/1094)
* Updated the sharing with Movim [#1030](https://github.com/FreshRSS/FreshRSS/pull/1030)
## 2015-11-03 FreshRSS 1.2.0 / 1.3.0-beta
* Features

View file

@ -31,14 +31,16 @@ Nous sommes une communauté amicale.
# Prérequis
* 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 1 avec des temps de réponse < 1s (testé sur 150 flux, 22k articles)
* Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres)
* 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)
* PHP 5.3+ (PHP 5.3.7+ recommandé, et PHP 5.5+ pour les performances, et PHP 7+ pour dencore 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) (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 : [iconv](http://php.net/iconv), [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [Zip](http://php.net/zip), [zlib](http://php.net/zlib)
* Inclus par défaut : [DOM](http://php.net/dom), [XML](http://php.net/xml)…
* MySQL 5.0.3+ (recommandé) ou SQLite 3.7.4+
* 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
* Lentête HTTP `Referer` ne doit pas être désactivé pour pouvoir utiliser le formulaire de connexion
![Capture décran de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_default-design.png)
@ -50,6 +52,9 @@ Nous sommes une communauté amicale.
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).
## Installation automatisée
[![DP deploy](https://raw.githubusercontent.com/DFabric/DPlatform-ShellCore/gh-pages/img/deploy.png)](https://dfabric.github.io/DPlatform-ShellCore)
## Exemple dinstallation complète sur Linux Debian/Ubuntu
```sh
# Si vous utilisez le serveur Web Apache (sinon il faut un autre serveur Web)
@ -58,7 +63,7 @@ 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
sudo apt-get install git php5 php5-curl php5-gmp php5-intl php5-json php5-sqlite
# Redémarrage du serveur Web
sudo service apache2 restart

View file

@ -31,14 +31,16 @@ We are a friendly community.
# Requirements
* 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 1 with response time under a second (tested with 150 feeds, 22k articles)
* A web server: Apache2 (recommended), nginx, lighttpd (not tested on others)
* PHP 5.2.1+ (PHP 5.3.7+ recommended, and PHP 5.5+ for performance) (beta support for PHP 7 with even higher performance)
* PHP 5.3+ (PHP 5.3.7+ recommended, and PHP 5.5+ for performance, and PHP 7 for 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) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names)
* Recommended extensions: [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [zlib](http://php.net/zlib), [Zip](http://php.net/zip)
* Recommended extensions: [iconv](http://php.net/iconv), [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [Zip](http://php.net/zip), [zlib](http://php.net/zlib)
* Enabled by default: [DOM](http://php.net/dom), [XML](http://php.net/xml)…
* MySQL 5.0.3+ (recommended) or SQLite 3.7.4+
* 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
* The browser HTTP `Referer` header must not be disabled when using the form login method
![FreshRSS screenshot](http://marienfressinaud.fr/data/images/freshrss/freshrss_default-design.png)
@ -50,6 +52,9 @@ We are a friendly community.
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).
## Automated install
[![DP deploy](https://raw.githubusercontent.com/DFabric/DPlatform-ShellCore/gh-pages/img/deploy.png)](https://dfabric.github.io/DPlatform-ShellCore)
## Example of full installation on Linux Debian/Ubuntu
```sh
# If you use an Apache Web server (otherwise you need another Web server)
@ -58,7 +63,7 @@ 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
sudo apt-get install git php5 php5-curl php5-gmp php5-intl php5-json php5-sqlite
# Restart Web server
sudo service apache2 restart

View file

@ -46,6 +46,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
if ($id === false) {
// id is false? It MUST be a POST request!
if (!Minz_Request::isPost()) {
Minz_Request::bad(_t('feedback.access.not_found'), array('c' => 'index', 'a' => 'index'));
return;
}

View file

@ -114,6 +114,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
Minz_Request::bad(_t('feedback.sub.feed.invalid_url', $url), $url_redirect);
}
$feed->_httpAuth($http_auth);
try {
$feed->load(true);
} catch (FreshRSS_Feed_Exception $e) {
@ -140,7 +142,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
}
$feed->_category($cat);
$feed->_httpAuth($http_auth);
// Call the extension hook
$name = $feed->name();
@ -355,12 +356,12 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$entry_date = $entry->date(true);
if (isset($existingHashForGuids[$entry->guid()])) {
$existingHash = $existingHashForGuids[$entry->guid()];
if (strcasecmp($existingHash, $entry->hash()) === 0 || $existingHash === '00000000000000000000000000000000') {
if (strcasecmp($existingHash, $entry->hash()) === 0 || trim($existingHash, '0') == '') {
//This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3
$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());
//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()) {

View file

@ -32,6 +32,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
Minz_Error::error(404);
}
$this->view->callbackBeforeContent = function() {
try {
$entries = $this->listEntriesByContext();
@ -68,6 +69,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
$title = '(' . FreshRSS_Context::$get_unread . ') ' . $title;
}
Minz_View::prependTitle($title . ' · ');
};
}
/**

View file

@ -6,7 +6,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController {
}
public function actualizeAction() {
header('Content-Type: text/javascript; charset=UTF-8');
header('Content-Type: application/json; charset=UTF-8');
$feedDAO = FreshRSS_Factory::createFeedDao();
$this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default);
}

View file

@ -34,7 +34,7 @@ class FreshRSS extends Minz_FrontController {
// Auth has to be initialized before using currentUser session parameter
// because it's this part which create this parameter.
$this->initAuth();
self::initAuth();
// Then, register the user configuration and use the configuration setter
// created above.
@ -46,10 +46,8 @@ class FreshRSS extends Minz_FrontController {
// Finish to initialize the other FreshRSS / Minz components.
FreshRSS_Context::init();
$this->initI18n();
FreshRSS_Share::load(join_path(DATA_PATH, 'shares.php'));
$this->loadStylesAndScripts();
$this->loadNotifications();
self::initI18n();
self::loadNotifications();
// Enable extensions for the current (logged) user.
if (FreshRSS_Auth::hasAccess()) {
$ext_list = FreshRSS_Context::$user_conf->extensions_enabled;
@ -57,7 +55,7 @@ class FreshRSS extends Minz_FrontController {
}
}
private function initAuth() {
private static function initAuth() {
FreshRSS_Auth::init();
if (Minz_Request::isPost() && !is_referer_from_same_domain()) {
// Basic protection against XSRF attacks
@ -74,12 +72,12 @@ class FreshRSS extends Minz_FrontController {
}
}
private function initI18n() {
private static function initI18n() {
Minz_Session::_param('language', FreshRSS_Context::$user_conf->language);
Minz_Translate::init(FreshRSS_Context::$user_conf->language);
}
private function loadStylesAndScripts() {
public static function loadStylesAndScripts() {
$theme = FreshRSS_Themes::load(FreshRSS_Context::$user_conf->theme);
if ($theme) {
foreach($theme['files'] as $file) {
@ -91,9 +89,9 @@ class FreshRSS extends Minz_FrontController {
$filename = $file;
}
$filetime = @filemtime(PUBLIC_PATH . '/themes/' . $theme_id . '/' . $filename);
Minz_View::appendStyle(Minz_Url::display(
'/themes/' . $theme_id . '/' . $filename . '?' . $filetime
));
$url = '/themes/' . $theme_id . '/' . $filename . '?' . $filetime;
header('Link: <' . Minz_Url::display($url, '', 'root') . '>;rel=preload', false); //HTTP2
Minz_View::appendStyle(Minz_Url::display($url));
}
}
@ -110,11 +108,29 @@ class FreshRSS extends Minz_FrontController {
}
}
private function loadNotifications() {
private static function loadNotifications() {
$notif = Minz_Session::param('notification');
if ($notif) {
Minz_View::_param('notification', $notif);
Minz_Session::_param('notification');
}
}
public static function preLayout() {
switch (Minz_Request::controllerName()) {
case 'index':
header("Content-Security-Policy: default-src 'self'; child-src *; frame-src *; img-src * data:; media-src *");
break;
case 'stats':
header("Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'");
break;
default:
header("Content-Security-Policy: default-src 'self'");
break;
}
header("X-Content-Type-Options: nosniff");
FreshRSS_Share::load(join_path(DATA_PATH, 'shares.php'));
self::loadStylesAndScripts();
}
}

View file

@ -103,7 +103,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
. ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.cache_nbEntries, f.cache_nbUnreads ')
. 'FROM `' . $this->prefix . 'category` c '
. 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category=c.id '
. 'GROUP BY f.id '
. 'GROUP BY f.id, c_id '
. 'ORDER BY c.name, f.name';
$stm = $this->bd->prepare($sql);
$stm->execute();

View file

@ -451,6 +451,10 @@ class FreshRSS_Feed extends Minz_Model {
Minz_Log::warning('Invalid callback for PubSubHubbub: ' . $this->url);
return false;
}
if (!$state) { //unsubscribe
$hubJson['lease_end'] = time() - 60;
file_put_contents($hubFilename, json_encode($hubJson));
}
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $this->hubUrl,
@ -470,11 +474,6 @@ class FreshRSS_Feed extends Minz_Model {
'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 {

View file

@ -119,11 +119,9 @@ class FreshRSS_Share {
);
foreach ($options as $key => $value) {
if (!isset($available_options[$key])) {
continue;
if (isset($available_options[$key])) {
$this->{$available_options[$key]} = $value;
}
$this->$available_options[$key] = $value;
}
}

View file

@ -55,9 +55,9 @@ SQL;
/**
* Calculates entry count per day on a 30 days period.
* Returns the result as a JSON string.
* Returns the result as a JSON object.
*
* @return string
* @return JSON object
*/
public function calculateEntryCount() {
$count = $this->initEntryCountArray();
@ -257,9 +257,9 @@ SQL;
/**
* Calculates feed count per category.
* Returns the result as a JSON string.
* Returns the result as a JSON object.
*
* @return string
* @return JSON object
*/
public function calculateFeedByCategory() {
$sql = <<<SQL
@ -282,7 +282,7 @@ SQL;
* Calculates entry count per category.
* Returns the result as a JSON string.
*
* @return string
* @return JSON object
*/
public function calculateEntryByCategory() {
$sql = <<<SQL
@ -357,7 +357,7 @@ SQL;
$serie[] = array($key, $value);
}
return json_encode($serie);
return $serie;
}
protected function convertToPieSerie($data) {
@ -368,7 +368,7 @@ SQL;
$serie[] = $value;
}
return json_encode($serie);
return $serie;
}
/**
@ -411,17 +411,17 @@ SQL;
}
/**
* Translates array content and encode it as JSON
* Translates array content
*
* @param array $data
* @return string
* @return JSON object
*/
private function convertToTranslatedJson($data = array()) {
$translated = array_map(function($a) {
return _t('gen.date.' . $a);
}, $data);
return json_encode($translated);
return $translated;
}
}

View file

@ -4,9 +4,9 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO {
/**
* Calculates entry count per day on a 30 days period.
* Returns the result as a JSON string.
* Returns the result as a JSON object.
*
* @return string
* @return JSON object
*/
public function calculateEntryCount() {
$count = $this->initEntryCountArray();

View file

@ -116,7 +116,3 @@ class FreshRSS_Themes extends Minz_Model {
'<img class="icon" src="' . Minz_Url::display($url) . '" alt="' . $alts[$name] . '" />';
}
}
function _i($icon, $url_only = false) {
return FreshRSS_Themes::icon($icon, $url_only);
}

View file

@ -13,7 +13,7 @@ CREATE TABLE IF NOT EXISTS `YnoUser_feed` (
`name` varchar(255) NOT NULL,
`website` varchar(255) CHARACTER SET latin1,
`description` text,
`lastUpdate` int(11) DEFAULT 0,
`lastUpdate` int(11) DEFAULT 0, -- Until year 2038
`priority` tinyint(2) NOT NULL DEFAULT 10,
`pathEntries` varchar(511) DEFAULT NULL,
`httpAuth` varchar(511) DEFAULT NULL,
@ -38,7 +38,9 @@ CREATE TABLE IF NOT EXISTS `YnoUser_entry` (
`author` varchar(255),
`content_bin` blob, -- v0.7
`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_favorite` boolean NOT NULL DEFAULT 0,
`id_feed` SMALLINT, -- v0.7
@ -47,7 +49,8 @@ CREATE TABLE IF NOT EXISTS `YnoUser_entry` (
FOREIGN KEY (`id_feed`) REFERENCES `YnoUser_feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE KEY (`id_feed`,`guid`), -- 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
ENGINE = INNODB;

View file

@ -108,7 +108,7 @@ return array(
'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.',
'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!',
),
@ -122,6 +122,8 @@ return array(
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'O aplikaci',
@ -163,7 +165,9 @@ return array(
'print' => 'Tisk',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
'jdh' => 'Journal du hacker',
),
'short' => array(
'attention' => 'Upozornění!',

View file

@ -51,7 +51,7 @@ return array(
'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).',
'nok' => 'Nemáte požadovanou knihovnu pro procházení DOM.',
'ok' => 'Máte požadovanou knihovnu pro procházení DOM.',
),
'favicons' => array(
@ -62,6 +62,10 @@ return array(
'nok' => 'Zkontrolujte prosím že neměníte HTTP REFERER.',
'ok' => 'Váš HTTP REFERER je znám a odpovídá Vašemu serveru.',
),
'json' => array(
'nok' => 'Pro parsování JSON chybí doporučená knihovna.',
'ok' => 'Máte doporučenou knihovnu pro parsování JSON.',
),
'minz' => array(
'nok' => 'Nemáte framework Minz.',
'ok' => 'Máte framework Minz.',
@ -86,6 +90,10 @@ return 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.',
),
'xml' => array(
'nok' => 'Pro parsování XML chybí požadovaná knihovna.',
'ok' => 'Máte požadovanou knihovnu pro parsování XML.',
),
),
'conf' => array(
'_' => 'Obecná nastavení',

View file

@ -108,7 +108,7 @@ return array(
'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!',
'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.',
'request_failed' => 'Eine Anfrage ist fehlgeschlagen, dies könnte durch Probleme mit der Internetverbindung verursacht worden sein.',
'title_new_articles' => 'FreshRSS: neue Artikel!',
),
@ -122,6 +122,8 @@ return array(
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'Über',
@ -163,7 +165,9 @@ return array(
'print' => 'Drucken',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
'jdh' => 'Journal du hacker',
),
'short' => array(
'attention' => 'Achtung!',

View file

@ -51,7 +51,7 @@ return array(
'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data</em> sind in Ordnung.',
),
'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.',
'ok' => 'Sie haben die benötigte Bibliothek um DOM zu durchstöbern.',
),
'favicons' => array(
@ -62,6 +62,10 @@ return array(
'nok' => 'Bitte stellen Sie sicher, dass Sie Ihren HTTP REFERER nicht abändern.',
'ok' => 'Ihr HTTP REFERER ist bekannt und entspricht Ihrem Server.',
),
'json' => array(
'nok' => 'Ihnen fehlt eine empfohlene Bibliothek um JSON zu parsen.',
'ok' => 'Sie haben eine empfohlene Bibliothek um JSON zu parsen.',
),
'minz' => array(
'nok' => 'Ihnen fehlt das Minz-Framework.',
'ok' => 'Sie haben das Minz-Framework.',
@ -86,6 +90,10 @@ return array(
'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses <em>./data/users</em>. Der HTTP-Server muss Schreibrechte besitzen.',
'ok' => 'Die Berechtigungen des Verzeichnisses <em>./data/users</em> sind in Ordnung.',
),
'xml' => array(
'nok' => 'Ihnen fehlt die benötigte Bibliothek um XML zu parsen.',
'ok' => 'Sie haben die benötigte Bibliothek um XML zu parsen.',
),
),
'conf' => array(
'_' => 'Allgemeine Konfiguration',

View file

@ -77,7 +77,7 @@ return array(
'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' => 'API password<br /><small>(e.g., for mobile apps)</small>',
'password_form' => 'Password<br /><small>(for the Web-form login method)</small>',
'password_format' => 'At least 7 characters',
'title' => 'Profile',

View file

@ -108,7 +108,7 @@ return array(
'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!',
'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!',
'feedback' => array(
'body_new_articles' => 'There are \\d new articles to read on FreshRSS.',
'body_new_articles' => 'There are %%d new articles to read on FreshRSS.',
'request_failed' => 'A request has failed, it may have been caused by Internet connection problems.',
'title_new_articles' => 'FreshRSS: new articles!',
),
@ -122,6 +122,8 @@ return array(
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'About',
@ -163,7 +165,9 @@ return array(
'print' => 'Print',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
'jdh' => 'Journal du hacker',
),
'short' => array(
'attention' => 'Warning!',

View file

@ -51,7 +51,7 @@ return array(
'ok' => 'Permissions on data directory are good.',
),
'dom' => array(
'nok' => 'You lack a required library to browse the DOM (php-xml package).',
'nok' => 'You lack a required library to browse the DOM.',
'ok' => 'You have the required library to browse the DOM.',
),
'favicons' => array(
@ -62,6 +62,10 @@ return array(
'nok' => 'Please check that you are not altering your HTTP REFERER.',
'ok' => 'Your HTTP REFERER is known and corresponds to your server.',
),
'json' => array(
'nok' => 'You lack a recommended library to parse JSON.',
'ok' => 'You have a recommended library to parse JSON.',
),
'minz' => array(
'nok' => 'You lack the Minz framework.',
'ok' => 'You have the Minz framework.',
@ -86,6 +90,10 @@ return array(
'nok' => 'Check permissions on <em>./data/users</em> directory. HTTP server must have rights to write into',
'ok' => 'Permissions on users directory are good.',
),
'xml' => array(
'nok' => 'You lack the required library to parse XML.',
'ok' => 'You have the required library to parse XML.',
),
),
'conf' => array(
'_' => 'General configuration',

View file

@ -108,7 +108,7 @@ return array(
'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !',
'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !',
'feedback' => array(
'body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.',
'body_new_articles' => 'Il y a %%d nouveaux articles à lire sur FreshRSS.',
'request_failed' => 'Une requête a échoué, cela peut être dû à des problèmes de connexion à Internet.',
'title_new_articles' => 'FreshRSS : nouveaux articles !',
),
@ -122,6 +122,8 @@ return array(
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'À propos',
@ -163,7 +165,9 @@ return array(
'print' => 'Imprimer',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
'jdh' => 'Journal du hacker',
),
'short' => array(
'attention' => 'Attention !',

View file

@ -51,7 +51,7 @@ return array(
'ok' => 'Les droits sur le répertoire de data sont bons.',
),
'dom' => array(
'nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml).',
'nok' => 'Il manque une librairie pour parcourir le DOM.',
'ok' => 'Vous disposez du nécessaire pour parcourir le DOM.',
),
'favicons' => array(
@ -62,6 +62,10 @@ return array(
'nok' => 'Veuillez vérifier que vous ne modifiez pas votre HTTP REFERER.',
'ok' => 'Le HTTP REFERER est connu et semble correspondre à votre serveur.',
),
'json' => array(
'nok' => 'Il manque une librairie recommandée pour JSON.',
'ok' => 'Vouz disposez de la librairie recommandée pour JSON.',
),
'minz' => array(
'nok' => 'Vous ne disposez pas de la librairie Minz.',
'ok' => 'Vous disposez du framework Minz',
@ -86,6 +90,10 @@ return array(
'nok' => 'Veuillez vérifier les droits sur le répertoire <em>./data/users</em>. Le serveur HTTP doit être capable décrire dedans',
'ok' => 'Les droits sur le répertoire des utilisateurs sont bons.',
),
'xml' => array(
'nok' => 'Il manque une librairie requise pour XML.',
'ok' => 'Vouz disposez de la librairie requise pour XML.',
),
),
'conf' => array(
'_' => 'Configuration générale',

View file

@ -108,7 +108,7 @@ return array(
'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.',
'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!',
),
@ -122,6 +122,8 @@ return array(
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'Informazioni',
@ -159,10 +161,13 @@ return array(
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'movim' => 'Movim',
'print' => 'Stampa',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
'jdh' => 'Journal du hacker',
),
'short' => array(
'attention' => 'Attenzione!',

View file

@ -51,7 +51,7 @@ return array(
'ok' => 'I permessi sulla cartella data sono corretti.',
),
'dom' => array(
'nok' => 'Manca una libreria richiesta per leggere DOM (pacchetto php-xml).',
'nok' => 'Manca una libreria richiesta per leggere DOM.',
'ok' => 'Libreria richiesta per leggere DOM presente.',
),
'favicons' => array(
@ -62,6 +62,10 @@ return array(
'nok' => 'Per favore verifica che non stai alterando il tuo HTTP REFERER.',
'ok' => 'Il tuo HTTP REFERER riconosciuto corrisponde al tuo server.',
),
'json' => array(
'nok' => 'You lack a recommended library to parse JSON.',
'ok' => 'You have a recommended library to parse JSON.',
),
'minz' => array(
'nok' => 'Manca il framework Minz.',
'ok' => 'Framework Minz presente.',
@ -87,6 +91,10 @@ return 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.',
),
'xml' => array(
'nok' => 'You lack the required library to parse XML.',
'ok' => 'You have the required library to parse XML.',
),
),
'conf' => array(
'_' => 'Configurazioni generali',

View file

@ -120,7 +120,7 @@ return array(
'category' => 'Categorie',
'entry_count' => 'Invoer aantallen',
'entry_per_category' => 'Aantallen per categorie',
'entry_per_day' => 'Aantallen per day (laatste 30 dagen)',
'entry_per_day' => 'Aantallen per dag (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)',
@ -147,14 +147,14 @@ return array(
'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
'_' => 'Systeem configuratie',
'auto-update-url' => 'Automatische update server URL',
'instance-name' => 'Voorbeeld naam',
'max-categories' => 'Categoriën limiet per gebruiker',
'max-feeds' => 'Feed limiet per gebruiker',
'registration' => array(
'help' => '0 means that there is no account limit', // @todo translate
'number' => 'Max number of accounts', // @todo translate
'help' => '0 betekent geen account limiet',
'number' => 'Maximum aantal accounts',
),
),
'update' => array(
@ -178,7 +178,7 @@ return array(
'registration' => array(
'allow' => 'Sta het maken van nieuwe accounts toe',
'help' => '0 betekent dat er geen account limiet is',
'number' => 'Max aantal van accounts',
'number' => 'Max aantal accounts',
),
'title' => 'Beheer gebruikers',
'user_list' => 'Lijst van gebruikers ',

View file

@ -108,7 +108,7 @@ return array(
'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.',
'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!',
),
@ -122,6 +122,8 @@ return array(
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'Over',
@ -139,7 +141,7 @@ return array(
'sharing' => 'Delen',
'shortcuts' => 'Snelle toegang',
'stats' => 'Statistieken',
'system' => 'System configuration', // @todo translate
'system' => 'Systeem configuratie',
'update' => 'Versie controle',
'user_management' => 'Beheer gebruikers',
'user_profile' => 'Profiel',
@ -163,7 +165,9 @@ return array(
'print' => 'Print',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
'jdh' => 'Journal du hacker',
),
'short' => array(
'attention' => 'Attentie!',

View file

@ -51,7 +51,7 @@ return array(
'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).',
'nok' => 'U mist een benodigde bibliotheek om te bladeren in de DOM.',
'ok' => 'U hebt de benodigde bibliotheek om te bladeren in de DOM.',
),
'favicons' => array(
@ -62,6 +62,10 @@ return 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.',
),
'json' => array(
'nok' => 'U mist een benodigede bibliotheek om JSON te gebruiken.',
'ok' => 'U hebt de benodigde bibliotheek om JSON te gebruiken.',
),
'minz' => array(
'nok' => 'U mist het Minz framework.',
'ok' => 'U hebt het Minz framework.',
@ -86,6 +90,10 @@ return 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.',
),
'xml' => array(
'nok' => 'U mist de benodigde bibliotheek om XML te gebruiken.',
'ok' => 'U hebt de benodigde bibliotheek om XML te gebruiken.',
),
),
'conf' => array(
'_' => 'Algemene configuratie',

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

@ -0,0 +1,183 @@
<?php
return array(
'auth' => array(
'allow_anonymous' => 'Разрешить анонимное чтение статей для пользователя по умолчанию (%s)',
'allow_anonymous_refresh' => 'Разрешить анонимное обновление статей',
'api_enabled' => 'Включить доступ к <abbr>API</abbr> <small>(необходимо для мобильных приложений)</small>',
'form' => 'На основе веб-формы (традиционный, необходим JavaScript)',
'http' => 'HTTP (для продвинутых пользователей - по HTTPS)',
'none' => 'Без аутентификации (небезопасный)',
'persona' => 'Mozilla Persona (новый, необходим JavaScript)',
'title' => 'Аутентификации',
'title_reset' => 'Сброс аутентицикации',
'token' => 'Токен аутентификации',
'token_help' => 'Разрешает доступ к RSS ленте пользователя по умолчанию без аутентификации:',
'type' => 'Метод аутентификации',
'unsafe_autologin' => 'Разрешить небезопасный автоматический вход с использованием следующего формата: ',
),
'check_install' => array(
'cache' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/cache</em>. Сервер HTTP должен иметь права на запись в эту папку',
'ok' => 'Права на <em>./data/cache</em> в порядке.',
),
'categories' => array(
'nok' => 'Таблица категорий настроена неправильно.',
'ok' => 'Таблица категорий настроена правильно.',
),
'connection' => array(
'nok' => 'Подключение к базе данных не может быть установлено.',
'ok' => 'Подключение к базе данных в порядке.',
),
'ctype' => array(
'nok' => 'У вас не установлена библиотека для проверки типов символов (php-ctype).',
'ok' => 'У вас не установлена библиотека для проверки типов символов (ctype).',
),
'curl' => array(
'nok' => 'У вас не установлено расширение cURL (пакет php5-curl).',
'ok' => 'У вас установлено расширение cURL.',
),
'data' => array(
'nok' => 'Проверьте права доступа к папке <em>./data</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на <em>./data/</em> в порядке.',
),
'database' => 'Установка базы данных',
'dom' => array(
'nok' => 'У вас не установлена библиотека для просмотра DOM (пакет php-xml).',
'ok' => 'У вас установлена библиотека для просмотра DOM.',
),
'entries' => array(
'nok' => 'Таблица статей (entry) неправильно настроена.',
'ok' => 'Таблица статей (entry) настроена правильно.',
),
'favicons' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/favicons</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку значков в порядке.',
),
'feeds' => array(
'nok' => 'Таблица подписок (feed) неправильно настроена.',
'ok' => 'Таблица подписок (feed) настроена правильно.',
),
'files' => 'Установка файлов',
'json' => array(
'nok' => 'У вас не установлена библиотека для работы с JSON (пакет php5-json).',
'ok' => 'У вас установлена библиотека для работы с JSON.',
),
'minz' => array(
'nok' => 'У вас не установлен фрейворк Minz.',
'ok' => 'У вас установлен фрейворк Minz.',
),
'pcre' => array(
'nok' => 'У вас не установлена необходимая библиотека для работы с регулярными выражениями (php-pcre).',
'ok' => 'У вас установлена необходимая библиотека для работы с регулярными выражениями (PCRE).',
),
'pdo' => array(
'nok' => 'У вас не установлен PDO или один из необходимых драйверов (pdo_mysql, pdo_sqlite).',
'ok' => 'У вас установлен PDO и как минимум один из поддерживаемых драйверов (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/persona</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку Mozilla Persona в порядке.',
),
'php' => array(
'_' => 'PHP installation',
'nok' => 'У вас установлен PHP версии %s, но FreshRSS необходима версия не ниже %s.',
'ok' => 'У вас установлен PHP версии %s, который совместим с FreshRSS.',
),
'tables' => array(
'nok' => 'В базе данных отсуствует одна или больше таблица.',
'ok' => 'Все таблицы есть в базе данных.',
),
'title' => 'Проверка установки и настройки',
'tokens' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/tokens</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку tokens в порядке.',
),
'users' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/users</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку users в порядке.',
),
'zip' => array(
'nok' => 'You lack ZIP extension (php5-zip package).',
'ok' => 'You have ZIP extension.',
),
),
'extensions' => array(
'disabled' => 'Отключены',
'empty_list' => 'Расширения не установлены',
'enabled' => 'Включены',
'no_configure_view' => 'Это расширение нельзя настроить.',
'system' => array(
'_' => 'Системные расширения',
'no_rights' => 'Системные расширения (у вас нет к ним доступа)',
),
'title' => 'Расширения',
'user' => 'Расширения пользователя',
),
'stats' => array(
'_' => 'Статистика',
'all_feeds' => 'Все подписки',
'category' => 'Категория',
'entry_count' => 'Количество статей',
'entry_per_category' => 'Статей в категории',
'entry_per_day' => 'Статей за день (за последние 30 дней)',
'entry_per_day_of_week' => 'За неделю (в среднем - %.2f сообщений)',
'entry_per_hour' => 'За час (в среднем - %.2f сообщений)',
'entry_per_month' => 'За месяц (в среднем - %.2f сообщений)',
'entry_repartition' => 'Перерасределение статей',
'feed' => 'Подписка',
'feed_per_category' => 'Подписок в категории',
'idle' => 'Неактивные подписки',
'main' => 'Основная статистика',
'main_stream' => 'Основной поток',
'menu' => array(
'idle' => 'Неактивные подписки',
'main' => 'Основная статистика',
'repartition' => 'Перерасределение статей',
),
'no_idle' => 'Нет неактивных подписок!',
'number_entries' => 'статей: %d',
'percent_of_total' => '%% от всего',
'repartition' => 'Перераспределение статей',
'status_favorites' => 'Избранное',
'status_read' => 'Читать',
'status_total' => 'Всего',
'status_unread' => 'Не прочитано',
'title' => 'Статистика',
'top_feed' => '10 лучших подписок',
),
'system' => array(
'_' => 'Системные настройки',
'auto-update-url' => 'Адрес сервера для автоматического обновления',
'instance-name' => 'Название этого сервера',
'max-categories' => 'Количество категорий на пользователя',
'max-feeds' => 'Количество статей на пользователя',
'registration' => array(
'help' => '0 означает неограниченное количество пользователей',
'number' => 'Максимальное количество пользователей',
),
),
'update' => array(
'_' => 'Обновление системы',
'apply' => 'Применить',
'check' => 'Проверить обновления',
'current_version' => 'Ваша текущая версия FreshRSS: %s.',
'last' => 'Последняя проверка: %s',
'none' => 'Нечего обновлять',
'title' => 'Обновить систему',
),
'user' => array(
'articles_and_size' => '%s статей (%s)',
'create' => 'Создать нового пользователя',
'email_persona' => 'Адрес электронной почты для входа<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'language' => 'Язык',
'number' => 'На данный момент создан %d аккаунт',
'numbers' => 'На данный момент аккаунтов создано: %d',
'password_form' => 'Пароль<br /><small>(для входа через Веб-форму)</small>',
'password_format' => 'Минимум 7 символов',
'title' => 'Управление пользователями',
'user_list' => 'Список пользователей',
'username' => 'Имя пользователя',
'users' => 'Пользователи',
),
);

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

@ -0,0 +1,174 @@
<?php
return array(
'archiving' => array(
'_' => 'Архивация',
'advanced' => 'Продвинутые настройки',
'delete_after' => 'Удалять статьи после',
'help' => 'Каждую подписку можно настроить более гибко',
'keep_history_by_feed' => 'Minimum number of articles to keep by feed',
'optimize' => 'Оптимизировать базу данных',
'optimize_help' => 'To do occasionally to reduce the size of the database',
'purge_now' => 'Очистить сейчас',
'title' => 'Архивация',
'ttl' => 'Не обновлять чаще чем',
),
'display' => array(
'_' => 'Display',
'icon' => array(
'bottom_line' => 'Bottom line',
'entry' => 'Article icons',
'publication_date' => 'Date of publication',
'related_tags' => 'Related tags',
'sharing' => 'Sharing',
'top_line' => 'Top line',
),
'language' => 'Язык',
'notif_html5' => array(
'seconds' => 'seconds (0 means no timeout)',
'timeout' => 'HTML5 notification timeout',
),
'theme' => 'Тема',
'title' => 'Display',
'width' => array(
'content' => 'Content width',
'large' => 'Large',
'medium' => 'Medium',
'no_limit' => 'No limit',
'thin' => 'Thin',
),
),
'query' => array(
'_' => 'User queries',
'deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.',
'filter' => 'Filter applied:',
'get_all' => 'Display all articles',
'get_category' => 'Display "%s" category',
'get_favorite' => 'Display favorite articles',
'get_feed' => 'Display "%s" feed',
'no_filter' => 'No filter',
'none' => 'You havent created any user query yet.',
'number' => 'Query n°%d',
'order_asc' => 'Display oldest articles first',
'order_desc' => 'Display newest articles first',
'search' => 'Search for "%s"',
'state_0' => 'Display all articles',
'state_1' => 'Display read articles',
'state_2' => 'Display unread articles',
'state_3' => 'Display all articles',
'state_4' => 'Display favorite articles',
'state_5' => 'Display read favorite articles',
'state_6' => 'Display unread favorite articles',
'state_7' => 'Display favorite articles',
'state_8' => 'Display not favorite articles',
'state_9' => 'Display read not favorite articles',
'state_10' => 'Display unread not favorite articles',
'state_11' => 'Display not favorite articles',
'state_12' => 'Display all articles',
'state_13' => 'Display read articles',
'state_14' => 'Display unread articles',
'state_15' => 'Display all articles',
'title' => 'User queries',
),
'profile' => array(
'_' => 'Profile management',
'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_form' => 'Password<br /><small>(for the Web-form login method)</small>',
'password_format' => 'At least 7 characters',
'title' => 'Profile',
),
'reading' => array(
'_' => 'Reading',
'after_onread' => 'After “mark all as read”,',
'articles_per_page' => 'Number of articles per page',
'auto_load_more' => 'Load next articles at the page bottom',
'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',
'display_articles_unfolded' => 'Show articles unfolded by default',
'display_categories_unfolded' => 'Show categories folded by default',
'hide_read_feeds' => 'Hide categories & feeds with no unread article (does not work with “Show all articles” configuration)',
'img_with_lazyload' => 'Use "lazy load" mode to load pictures',
'jump_next' => 'jump to next unread sibling (feed or category)',
'number_divided_when_reader' => 'Divided by 2 in the reading view.',
'read' => array(
'article_open_on_website' => 'when article is opened on its original website',
'article_viewed' => 'when article is viewed',
'scroll' => 'while scrolling',
'upon_reception' => 'upon reception of the article',
'when' => 'Mark article as read…',
),
'show' => array(
'_' => 'Articles to display',
'adaptive' => 'Adjust showing',
'all_articles' => 'Show all articles',
'unread' => 'Show only unread',
),
'sort' => array(
'_' => 'Sort order',
'newer_first' => 'Newer first',
'older_first' => 'Oldest first',
),
'sticky_post' => 'Stick the article to the top when opened',
'title' => 'Reading',
'view' => array(
'default' => 'Default view',
'global' => 'Global view',
'normal' => 'Normal view',
'reader' => 'Reading view',
),
),
'sharing' => array(
'_' => 'Sharing',
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'more_information' => 'More information',
'print' => 'Print',
'shaarli' => 'Shaarli',
'share_name' => 'Share name to display',
'share_url' => 'Share URL to use',
'title' => 'Sharing',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'shortcut' => array(
'_' => 'Shortcuts',
'article_action' => 'Article actions',
'auto_share' => 'Share',
'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.',
'close_dropdown' => 'Close menus',
'collapse_article' => 'Collapse',
'first_article' => 'Skip to the first article',
'focus_search' => 'Access search box',
'help' => 'Display documentation',
'javascript' => 'JavaScript must be enabled in order to use shortcuts',
'last_article' => 'Skip to the last article',
'load_more' => 'Load more articles',
'mark_read' => 'Mark as read',
'mark_favorite' => 'Mark as favourite',
'navigation' => 'Navigation',
'navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.<br/>With the "Alt" modifier, navigation shortcuts apply on categories.',
'next_article' => 'Skip to the next article',
'other_action' => 'Other actions',
'previous_article' => 'Skip to the previous article',
'see_on_website' => 'See on original website',
'shift_for_all_read' => '+ <code>shift</code> to mark all articles as read',
'title' => 'Shortcuts',
'user_filter' => 'Access user filters',
'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.',
),
'user' => array(
'articles_and_size' => '%s articles (%s)',
'current' => 'Current user',
'is_admin' => 'is administrator',
'users' => 'Users',
),
);

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

@ -0,0 +1,110 @@
<?php
return array(
'admin' => array(
'optimization_complete' => 'Optimisation complete',
),
'access' => array(
'denied' => 'You dont have permission to access this page',
'not_found' => 'You are looking for a page which doesnt exist',
),
'auth' => array(
'form' => array(
'not_set' => 'A problem occured during authentication system configuration. Please retry later.',
'set' => 'Form is now your default authentication system.',
),
'login' => array(
'invalid' => 'Login is invalid',
'success' => 'You are connected',
),
'logout' => array(
'success' => 'You are disconnected',
),
'no_password_set' => 'Administrator password hasnt been set. This feature isnt available.',
'not_persona' => 'Only Persona system can be reset.',
),
'conf' => array(
'error' => 'An error occurred during configuration saving',
'query_created' => 'Query "%s" has been created.',
'shortcuts_updated' => 'Shortcuts have been updated',
'updated' => 'Configuration has been updated',
),
'extensions' => array(
'already_enabled' => '%s is already enabled',
'disable' => array(
'ko' => '%s cannot be disabled. <a href="%s">Check FressRSS logs</a> for details.',
'ok' => '%s is now disabled',
),
'enable' => array(
'ko' => '%s cannot be enabled. <a href="%s">Check FressRSS logs</a> for details.',
'ok' => '%s is now enabled',
),
'no_access' => 'You have no access on %s',
'not_enabled' => '%s is not enabled yet',
'not_found' => '%s does not exist',
),
'import_export' => array(
'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.',
'feeds_imported' => 'Your feeds have been imported and will now be updated',
'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred',
'file_cannot_be_uploaded' => 'File cannot be uploaded!',
'no_zip_extension' => 'Zip extension is not present on your server.',
'zip_error' => 'An error occured during Zip import.',
),
'sub' => array(
'actualize' => 'Actualise',
'category' => array(
'created' => 'Category %s has been created.',
'deleted' => 'Category has been deleted.',
'emptied' => 'Category has been emptied',
'error' => 'Category cannot be updated',
'name_exists' => 'Category name already exists.',
'no_id' => 'You must precise the id of the category.',
'no_name' => 'Category name cannot be empty.',
'not_delete_default' => 'You cannot delete the default category!',
'not_exist' => 'The category does not exist!',
'over_max' => 'You have reached your limit of categories (%d)',
'updated' => 'Category has been updated.',
),
'feed' => array(
'actualized' => '<em>%s</em> has been updated',
'actualizeds' => 'RSS feeds have been updated',
'added' => 'RSS feed <em>%s</em> has been added',
'already_subscribed' => 'You have already subscribed to <em>%s</em>',
'deleted' => 'Feed has been deleted',
'error' => 'Feed cannot be updated',
'internal_problem' => 'The RSS feed could not be added. <a href="%s">Check FressRSS logs</a> for details.',
'invalid_url' => 'URL <em>%s</em> is invalid',
'marked_read' => 'Feeds have been marked as read',
'n_actualized' => '%d feeds have been updated',
'n_entries_deleted' => '%d articles have been deleted',
'no_refresh' => 'There is no feed to refresh…',
'not_added' => '<em>%s</em> could not be added',
'over_max' => 'You have reached your limit of feeds (%d)',
'updated' => 'Feed has been updated',
),
'purge_completed' => 'Purge completed (%d articles deleted)',
),
'update' => array(
'can_apply' => 'FreshRSS will now be updated to the <strong>version %s</strong>.',
'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',
'finished' => 'Update completed!',
'none' => 'No update to apply',
'server_not_found' => 'Update server cannot be found. [%s]',
),
'user' => array(
'created' => array(
'_' => 'User %s has been created',
'error' => 'User %s cannot be created',
),
'deleted' => array(
'_' => 'User %s has been deleted',
'error' => 'User %s cannot be deleted',
),
),
'profile' => array(
'error' => 'Your profile cannot be modified',
'updated' => 'Your profile has been modified',
),
);

185
sources/app/i18n/ru/gen.php Executable file
View file

@ -0,0 +1,185 @@
<?php
return array(
'action' => array(
'actualize' => 'Actualize',
'back_to_rss_feeds' => '← Go back to your RSS feeds',
'cancel' => 'Cancel',
'create' => 'Create',
'disable' => 'Disable',
'empty' => 'Empty',
'enable' => 'Enable',
'export' => 'Export',
'filter' => 'Filter',
'import' => 'Import',
'manage' => 'Manage',
'mark_read' => 'Mark as read',
'mark_favorite' => 'Mark as favourite',
'remove' => 'Remove',
'see_website' => 'See website',
'submit' => 'Submit',
'truncate' => 'Delete all articles',
),
'auth' => array(
'email' => 'Email address',
'keep_logged_in' => 'Keep me logged in <small>(1 month)</small>',
'login' => 'Login',
'login_persona' => 'Login with Persona',
'login_persona_problem' => 'Connection problem with Persona?',
'logout' => 'Logout',
'password' => array(
'_' => 'Password',
'format' => '<small>At least 7 characters</small>',
),
'registration' => array(
'_' => 'New account',
'ask' => 'Create an account?',
'title' => 'Account creation',
),
'reset' => 'Authentication reset',
'username' => array(
'_' => '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.',
),
'date' => array(
'Apr' => '\\A\\p\\r\\i\\l',
'Aug' => '\\A\\u\\g\\u\\s\\t',
'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r',
'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y',
'Jan' => '\\J\\a\\n\\u\\a\\r\\y',
'Jul' => '\\J\\u\\l\\y',
'Jun' => '\\J\\u\\n\\e',
'Mar' => '\\M\\a\\r\\c\\h',
'May' => '\\M\\a\\y',
'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r',
'Oct' => '\\O\\c\\t\\o\\b\\e\\r',
'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r',
'apr' => 'apr',
'april' => 'Apr',
'aug' => 'aug',
'august' => 'Aug',
'before_yesterday' => 'Before yesterday',
'dec' => 'dec',
'december' => 'Dec',
'feb' => 'feb',
'february' => 'Feb',
'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y',
'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i',
'fri' => 'Fri',
'jan' => 'jan',
'january' => 'Jan',
'jul' => 'jul',
'july' => 'Jul',
'jun' => 'jun',
'june' => 'Jun',
'last_3_month' => 'Last three months',
'last_6_month' => 'Last six months',
'last_month' => 'Last month',
'last_week' => 'Last week',
'last_year' => 'Last year',
'mar' => 'mar',
'march' => 'Mar',
'may' => 'May',
'mon' => 'Mon',
'month' => 'months',
'nov' => 'nov',
'november' => 'Nov',
'oct' => 'oct',
'october' => 'Oct',
'sat' => 'Sat',
'sep' => 'sep',
'september' => 'Sep',
'sun' => 'Sun',
'thu' => 'Thu',
'today' => 'Today',
'tue' => 'Tue',
'wed' => 'Wed',
'yesterday' => 'Yesterday',
),
'freshrss' => array(
'_' => 'FreshRSS',
'about' => 'About FreshRSS',
),
'js' => array(
'category_empty' => 'Empty category',
'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!',
'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!',
'feedback' => array(
'body_new_articles' => 'There are %%d new articles to read on FreshRSS.',
'request_failed' => 'A request has failed, it may have been caused by Internet connection problems.',
'title_new_articles' => 'FreshRSS: new articles!',
),
'new_article' => 'There are new available articles, click to refresh the page.',
'should_be_activated' => 'JavaScript must be enabled',
),
'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch',
'en' => 'English',
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'About',
'admin' => 'Administration',
'archiving' => 'Archiving',
'authentication' => 'Authentication',
'check_install' => 'Installation checking',
'configuration' => 'Configuration',
'display' => 'Display',
'extensions' => 'Extensions',
'logs' => 'Logs',
'queries' => 'User queries',
'reading' => 'Reading',
'search' => 'Search words or #tags',
'sharing' => 'Sharing',
'shortcuts' => 'Shortcuts',
'stats' => 'Statistics',
'system' => 'System configuration',
'update' => 'Update',
'user_management' => 'Manage users',
'user_profile' => 'Profile',
),
'pagination' => array(
'first' => 'First',
'last' => 'Last',
'load_more' => 'Load more articles',
'mark_all_read' => 'Mark all as read',
'next' => 'Next',
'nothing_to_load' => 'There are no more articles',
'previous' => 'Previous',
),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'jdh' => 'Journal du hacker',
'movim' => 'Movim',
'print' => 'Print',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
),
'short' => array(
'attention' => 'Warning!',
'blank_to_disable' => 'Leave blank to disable',
'by_author' => 'By <em>%s</em>',
'by_default' => 'By default',
'damn' => 'Damn!',
'default_category' => 'Uncategorized',
'no' => 'No',
'not_applicable' => 'Not available',
'ok' => 'Ok!',
'or' => 'or',
'yes' => 'Yes',
),
);

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

@ -0,0 +1,61 @@
<?php
return array(
'about' => array(
'_' => 'About',
'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
'bugs_reports' => 'Bugs reports',
'credits' => 'Credits',
'credits_content' => 'Some design elements come from <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> although FreshRSS doesnt use this framework. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Icons</a> come from <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> font police has been created by <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a>. Favicons are collected with <a href="https://getfavicon.appspot.com/">getFavicon API</a>. FreshRSS is based on <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, a PHP framework.',
'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> or <a href="http://projet.idleman.fr/leed/">Leed</a>. It is light and easy to take in hand while being powerful and configurable tool.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">on Github</a>',
'license' => 'License',
'project_website' => 'Project website',
'title' => 'About',
'version' => 'Version',
'website' => 'Website',
),
'feed' => array(
'add' => 'You may add some feeds.',
'empty' => 'There is no article to show.',
'rss_of' => 'RSS feed of %s',
'title' => 'Your RSS feeds',
'title_global' => 'Global view',
'title_fav' => 'Your favourites',
),
'log' => array(
'_' => 'Logs',
'clear' => 'Clear the logs',
'empty' => 'Log file is empty',
'title' => 'Logs',
),
'menu' => array(
'about' => 'About FreshRSS',
'add_query' => 'Add a query',
'before_one_day' => 'Before one day',
'before_one_week' => 'Before one week',
'favorites' => 'Favourites (%s)',
'global_view' => 'Global view',
'main_stream' => 'Main stream',
'mark_all_read' => 'Mark all as read',
'mark_cat_read' => 'Mark category as read',
'mark_feed_read' => 'Mark feed as read',
'newer_first' => 'Newer first',
'non-starred' => 'Show all but favorites',
'normal_view' => 'Normal view',
'older_first' => 'Oldest first',
'queries' => 'User queries',
'read' => 'Show only read',
'reader_view' => 'Reading view',
'rss_view' => 'RSS feed',
'search_short' => 'Search',
'starred' => 'Show only favorites',
'stats' => 'Statistics',
'subscription' => 'Subscriptions management',
'unread' => 'Show only unread',
),
'share' => 'Share',
'tag' => array(
'related' => 'Related tags',
),
);

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

@ -0,0 +1,113 @@
<?php
return array(
'action' => array(
'finish' => 'Завершить установку',
'fix_errors_before' => 'Пожалуйста, исправьте ошибки прежде чем переходить к следующему этапу.',
'keep_install' => 'Сохранить предыдущую установку',
'next_step' => 'Перейти к следующему этапу',
'reinstall' => 'Переустановить FreshRSS',
),
'auth' => array(
'email_persona' => 'Почта (логин) для <br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
'form' => 'Вэб-форма (традиционный, необходим JavaScript)',
'http' => 'HTTP (для продвинутых пользователей с HTTPS)',
'none' => 'Никакого (опасно)',
'password_form' => 'Пароль<br /><small>(для метода аутентификации на Вэб-формах)</small>',
'password_format' => 'Как минимум 7 букв',
'persona' => 'Mozilla Persona (современный, необходим JavaScript)',
'type' => 'Метод аутентификации',
),
'bdd' => array(
'_' => 'База данных',
'conf' => array(
'_' => 'Конфигурация базы данныхDatabase configuration',
'ko' => 'Проверьте конфигурацию базы данных.',
'ok' => 'Конфигурация базы данных сохранена.',
),
'host' => 'Хост',
'prefix' => 'Префикс таблицы',
'password' => 'Пароль HTTP',
'type' => 'Тип базы данных',
'username' => 'Имя пользователя HTTP',
),
'check' => array(
'_' => 'Проверки',
'already_installed' => 'Обнаружена предыдущая установка FreshRSS!',
'cache' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/cache</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку кэша в порядке.',
),
'ctype' => array(
'nok' => 'У вас не установлена необходимая библиотека для проверки типов символов (php-ctype).',
'ok' => 'У вас установлена необходимая библиотека для проверки типов символов (ctype).',
),
'curl' => array(
'nok' => 'У вас нет расширения cURL (пакет php5-curl).',
'ok' => 'У вас установлено расширение cURL.',
),
'data' => array(
'nok' => 'Проверьте права доступа к папке <em>./data</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на <em>./data/</em> в порядке.',
),
'dom' => array(
'nok' => 'У вас не установлена необходимая библиотека для просмотра DOM (пакет php-xml).',
'ok' => 'У вас установлена необходимая библиотека для просмотра DOM.',
),
'favicons' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/favicons</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку значков в порядке.',
),
'http_referer' => array(
'nok' => 'Убедитесь, что вы не изменяете ваш HTTP REFERER.',
'ok' => 'Ваш HTTP REFERER известен и соотвествует вашему серверу.',
),
'minz' => array(
'nok' => 'У вас не установлен фрейворк Minz.',
'ok' => 'У вас установлен фрейворк Minz.',
),
'pcre' => array(
'nok' => 'У вас не установлена необходимая библиотека для работы с регулярными выражениями (php-pcre).',
'ok' => 'У вас установлена необходимая библиотека для работы с регулярными выражениями (PCRE).',
),
'pdo' => array(
'nok' => 'У вас не установлен PDO или один из необходимых драйверов (pdo_mysql, pdo_sqlite).',
'ok' => 'У вас установлен PDO и как минимум один из поддерживаемых драйверов (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/persona</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку Mozilla Persona в порядке.',
),
'php' => array(
'nok' => 'У вас установлен PHP версии %s, но FreshRSS необходима версия не ниже %s.',
'ok' => 'У вас установлен PHP версии %s, который совместим с FreshRSS.',
),
'users' => array(
'nok' => 'Проверьте права доступа к папке <em>./data/users</em> . Сервер HTTP должен иметь права на запись в эту папку.',
'ok' => 'Права на папку users в порядке.',
),
),
'conf' => array(
'_' => 'Общие настройки',
'ok' => 'Общие настройки были сохранены.',
),
'congratulations' => 'Поздравляем!',
'default_user' => 'Имя пользователя по умолчанию <small>(максимум 16 латинских букв и/или цифр)</small>',
'delete_articles_after' => 'Удалять статьи после',
'fix_errors_before' => 'Пожалуйста, исправьте ошибки прежде чем переходить к следующему этапу..',
'javascript_is_better' => 'FreshRSS принесёт больше удовольствия, если включить JavaScript',
'js' => array(
'confirm_reinstall' => 'Переустанавливая FreshRSS, вы потеряете предыдущую конфигурацию. Вы хотите продолжить?',
),
'language' => array(
'_' => 'Язык',
'choose' => 'Выберите язык для FreshRSS',
'defined' => 'Язык выбран.',
),
'not_deleted' => 'Что-то пошло не так; удалите файл <em>%s</em> вручную.',
'ok' => 'Установка успешна.',
'step' => '%d этап',
'steps' => 'Этапы',
'title' => 'Установка · FreshRSS',
'this_is_the_end' => 'Это конец',
);

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

@ -0,0 +1,62 @@
<?php
return array(
'category' => array(
'_' => 'Category',
'add' => 'Add a category',
'empty' => 'Empty category',
'new' => 'New category',
),
'feed' => array(
'add' => 'Add a RSS feed',
'advanced' => 'Advanced',
'archiving' => 'Archivage',
'auth' => array(
'configuration' => 'Login',
'help' => 'Connection allows to access HTTP protected RSS feeds',
'http' => 'HTTP Authentication',
'password' => 'HTTP password',
'username' => 'HTTP username',
),
'css_help' => 'Retrieves truncated RSS feeds (caution, requires more time!)',
'css_path' => 'Articles CSS path on original website',
'description' => 'Description',
'empty' => 'This feed is empty. Please verify that it is still maintained.',
'error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.',
'in_main_stream' => 'Show in main stream',
'informations' => 'Information',
'keep_history' => 'Minimum number of articles to keep',
'moved_category_deleted' => 'When you delete a category, its feeds are automatically classified under <em>%s</em>.',
'no_selected' => 'No feed selected.',
'number_entries' => '%d articles',
'stats' => 'Statistics',
'think_to_add' => 'You may add some feeds.',
'title' => 'Title',
'title_add' => 'Add a RSS feed',
'ttl' => 'Do not automatically refresh more often than',
'url' => 'Feed URL',
'validator' => 'Check the validity of the feed',
'website' => 'Website URL',
'pubsubhubbub' => 'Instant notification with PubSubHubbub',
),
'import_export' => array(
'export' => 'Export',
'export_opml' => 'Export list of feeds (OPML)',
'export_starred' => 'Export your favourites',
'feed_list' => 'List of %s articles',
'file_to_import' => 'File to import<br />(OPML, Json or Zip)',
'file_to_import_no_zip' => 'File to import<br />(OPML or Json)',
'import' => 'Import',
'starred_list' => 'List of favourite articles',
'title' => 'Import / export',
),
'menu' => array(
'bookmark' => 'Subscribe (FreshRSS bookmark)',
'import_export' => 'Import / export',
'subscription_management' => 'Subscriptions management',
),
'title' => array(
'_' => 'Subscriptions management',
'feed_management' => 'RSS feeds management',
),
);

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

@ -0,0 +1,183 @@
<?php
return array(
'auth' => array(
'allow_anonymous' => 'Öntanımlı kullanıcının makalelerinin anonim okunmasına izin ver (%s)',
'allow_anonymous_refresh' => 'Anonim makale yenilemesine izin ver',
'api_enabled' => '<abbr>API</abbr> erişimine izin ver <small>(mobil uygulamalar için gerekli)</small>',
'form' => 'Web formu (geleneksel, JavaScript gerektirir)',
'http' => 'HTTP (ileri kullanıcılar için, HTTPS)',
'none' => 'Hiçbiri (tehlikeli)',
'persona' => 'Mozilla Persona (modern, JavaScript gerektirir)',
'title' => 'Kimlik doğrulama',
'title_reset' => 'Kimlik doğrulama sıfırla',
'token' => 'Kimlik doğrulama işareti',
'token_help' => 'Kimlik doğrulama olmaksızın öntanımlı kullanıcının RSS çıktısına erişime izin ver:',
'type' => 'Kimlik doğrulama yöntemi',
'unsafe_autologin' => 'Güvensiz otomatik girişe izin ver: ',
),
'check_install' => array(
'cache' => array(
'nok' => '<em>./data/cache</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Önbellek klasörü yetkileri sorunsuz.',
),
'categories' => array(
'nok' => 'Kategori tablosu kötü yapılandırılmış.',
'ok' => 'Kategori tablosu sorunsuz.',
),
'connection' => array(
'nok' => 'Veritabanı ile bağlantı kurulamıyor.',
'ok' => 'Veritabanı ile bağlantı sorunsuz.',
),
'ctype' => array(
'nok' => 'Karakter yazım kontrolü için kütüphane eksik (php-ctype).',
'ok' => 'Karakter yazım kontrolü için kütüphane sorunsuz (ctype).',
),
'curl' => array(
'nok' => 'cURL eksik (php5-curl package).',
'ok' => 'cURL eklentisi sorunsuz.',
),
'data' => array(
'nok' => '<em>./data</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Veri klasörü yetkileri sorunsuz.',
),
'database' => 'Veritabanı kurulumu',
'dom' => array(
'nok' => 'DOM kütüpbanesi eksik (php-xml package).',
'ok' => 'DOM kütüphanesi sorunsuz.',
),
'entries' => array(
'nok' => 'Giriş tablosu kötü yapılandırılmış.',
'ok' => 'Giriş tablosu sorunsuz.',
),
'favicons' => array(
'nok' => '<em>./data/favicons</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Site ikonu klasörü yetkileri sorunsuz.',
),
'feeds' => array(
'nok' => 'Akış tablosu kötü yapılandırılmış.',
'ok' => 'Akış tablosu sorunsuz.',
),
'files' => 'Dosya kurulumu',
'json' => array(
'nok' => 'JSON eklentisi eksik (php5-json package).',
'ok' => 'JSON eklentisi sorunsuz.',
),
'minz' => array(
'nok' => 'Minz framework eksik.',
'ok' => 'Minz framework sorunsuz.',
),
'pcre' => array(
'nok' => 'Düzenli ifadeler kütüphanesi eksik (php-pcre).',
'ok' => 'Düzenli ifadeler kütüphanesi sorunsuz (PCRE).',
),
'pdo' => array(
'nok' => 'PDO veya PDO destekli bir sürücü eksik (pdo_mysql, pdo_sqlite).',
'ok' => 'PDO sorunsuz (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => '<em>./data/persona</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Mozilla Persona klasörü yetkileri sorunsuz.',
),
'php' => array(
'_' => 'PHP kurulumu',
'nok' => 'PHP versiyonunuz %s fakat FreshRSS için gerekli olan en düşük sürüm %s.',
'ok' => 'PHP versiyonunuz %s, FreshRSS ile tam uyumlu.',
),
'tables' => array(
'nok' => 'Veritabanında bir veya daha fazla tablo eksik.',
'ok' => 'Veritabanı tabloları sorunsuz.',
),
'title' => 'Kurulum kontrolü',
'tokens' => array(
'nok' => '<em>./data/tokens</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'İşaretler klasörü yetkileri sorunsuz..',
),
'users' => array(
'nok' => '<em>./data/users</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Kullanıcılar klasörü yetkileri sorunsuz.',
),
'zip' => array(
'nok' => 'ZIP eklentisi eksik (php5-zip package).',
'ok' => 'ZIP eklentisi sorunsuz.',
),
),
'extensions' => array(
'disabled' => 'Pasif',
'empty_list' => 'Yüklenmiş eklenti bulunmamaktadır',
'enabled' => 'Aktif',
'no_configure_view' => 'Bu eklenti yapılandırılamaz.',
'system' => array(
'_' => 'Sistem eklentileri',
'no_rights' => 'Sistem eklentileri (düzenleme hakkınız yok)',
),
'title' => 'Eklentiler',
'user' => 'Kullanıcı eklentileri',
),
'stats' => array(
'_' => 'İstatistikler',
'all_feeds' => 'Tüm akış',
'category' => 'Kategori',
'entry_count' => 'Makale sayısı',
'entry_per_category' => 'Kategori başı makale sayısı',
'entry_per_day' => 'Günlük makale sayısı (last 30 days)',
'entry_per_day_of_week' => 'Haftanın günü (ortalama: %.2f makale)',
'entry_per_hour' => 'Saatlik (ortalama: %.2f makale)',
'entry_per_month' => 'Aylık (average: %.2f makale)',
'entry_repartition' => 'Giriş dağılımı',
'feed' => 'Akış',
'feed_per_category' => 'Kategoriye göre akışlar',
'idle' => 'Boştaki akışlar',
'main' => 'Ana istatistikler',
'main_stream' => 'Ana akış',
'menu' => array(
'idle' => 'Boştaki akışlar',
'main' => 'Ana istatistikler',
'repartition' => 'Makale dağılımı',
),
'no_idle' => 'Boşta akış yok!',
'number_entries' => '%d makale',
'percent_of_total' => '%% toplamın yüzdesi',
'repartition' => 'Makale dağılımı',
'status_favorites' => 'Favoriler',
'status_read' => 'Okunmuş',
'status_total' => 'Toplam',
'status_unread' => 'Okunmamış',
'title' => 'İstatistikler',
'top_feed' => 'İlk 10 akış',
),
'system' => array(
'_' => 'Sistem yapılandırması',
'auto-update-url' => 'Otomatik güncelleme sunucu URL',
'instance-name' => 'Örnek isim',
'max-categories' => 'Kullanıcı başına kategori limiti',
'max-feeds' => 'Kullanıcı başına akış limiti',
'registration' => array(
'help' => '0 sınır yok anlamındadır',
'number' => 'En fazla hesap sayısı',
),
),
'update' => array(
'_' => 'Sistem güncelleme',
'apply' => 'Uygula',
'check' => 'Güncelleme kontrolü',
'current_version' => 'Mevcut FreshRSS sürümünüz %s.',
'last' => 'Son kontrol: %s',
'none' => 'Yeni güncelleme yok',
'title' => 'Sistem güncelleme',
),
'user' => array(
'articles_and_size' => '%s makale (%s)',
'create' => 'Yeni kullanıcı oluştur',
'email_persona' => 'Giriş email adresi<br /><small>(<a href="https://persona.org/" rel="external">Mozilla Persona</a> için)</small>',
'language' => 'Dil',
'number' => 'Oluşturulmuş %d hesap var',
'numbers' => 'Oluşturulmuş %d hesap var',
'password_form' => 'Şifre<br /><small>(Tarayıcı girişi için)</small>',
'password_format' => 'En az 7 karakter',
'title' => 'Kullanıcıları yönet',
'user_list' => 'Kullanıcı listesi',
'username' => 'Kullanıcı adı',
'users' => 'Kullanıcılar',
),
);

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

@ -0,0 +1,174 @@
<?php
return array(
'archiving' => array(
'_' => 'Arşiv',
'advanced' => 'Gelişmiş',
'delete_after' => 'Makelelerin tutulacağı süre',
'help' => 'Akış ayarlarında daha çok ayar bulabilirsiniz',
'keep_history_by_feed' => 'Akışta en az tutulacak makale sayısı',
'optimize' => 'Veritabanı optimize et',
'optimize_help' => 'Bu işlem bazen veritabanı boyutunu düşürmeye yardımcı olur',
'purge_now' => 'Şimdi temizle',
'title' => 'Arşiv',
'ttl' => 'Şu süreden sık otomatik yenileme yapma',
),
'display' => array(
'_' => 'Görünüm',
'icon' => array(
'bottom_line' => 'Alt çizgi',
'entry' => 'Makale ikonları',
'publication_date' => 'Yayınlama Tarihi',
'related_tags' => 'İlgili etiketler',
'sharing' => 'Paylaşım',
'top_line' => 'Üst çizgi',
),
'language' => 'Dil',
'notif_html5' => array(
'seconds' => 'saniye (0 zaman aşımı yok demektir)',
'timeout' => 'HTML5 bildirim zaman aşımı',
),
'theme' => 'Tema',
'title' => 'Görünüm',
'width' => array(
'content' => 'İçerik genişliği',
'large' => 'Geniş',
'medium' => 'Orta',
'no_limit' => 'Sınırsız',
'thin' => 'Zayıf',
),
),
'query' => array(
'_' => 'Kullanıcı sorguları',
'deprecated' => 'Bu sorgu artık geçerli değil. İlgili akış veya kategori silinmiş.',
'filter' => 'Filtre uygulandı:',
'get_all' => 'Tüm makaleleri göster',
'get_category' => '"%s" kategorisini göster',
'get_favorite' => 'Favori makaleleri göster',
'get_feed' => '"%s" akışını göster',
'no_filter' => 'Filtre yok',
'none' => 'Henüz hiç kullanıcı sorgusu oluşturmadınız.',
'number' => 'Sorgu n°%d',
'order_asc' => 'Önce eski makaleleri göster',
'order_desc' => 'Önce yeni makaleleri göster',
'search' => '"%s" için arama',
'state_0' => 'Tüm makaleleri göster',
'state_1' => 'Okunmuş makaleleri göster',
'state_2' => 'Okunmamış makaleleri göster',
'state_3' => 'Tüm makaleleri göster',
'state_4' => 'Favori makaleleri göster',
'state_5' => 'Okunmuş favori makaleleri göster',
'state_6' => 'Okunmamış favori makaleleri göster',
'state_7' => 'Favori makaleleri göster',
'state_8' => 'Favori olmayan makaleleri göster',
'state_9' => 'Favori olmayan okunmuş makaleleri göster',
'state_10' => 'Favori olmayan okunmamış makaleleri göster',
'state_11' => 'Favori olmayan makaleleri göster',
'state_12' => 'Tüm makaleleri göster',
'state_13' => 'Okunmuş makaleleri göster',
'state_14' => 'Okunmamış makaleleri göster',
'state_15' => 'Tüm makaleleri göster',
'title' => 'Kullanıcı sorguları',
),
'profile' => array(
'_' => 'Profil yönetimi',
'delete' => array(
'_' => 'Hesap silme',
'warn' => 'Hesabınız ve tüm verileriniz silinecek.',
),
'email_persona' => 'Giriş email adresi<br /><small>(<a href="https://persona.org/" rel="external">Mozilla Persona</a> için)</small>',
'password_api' => 'API Şifresi<br /><small>(ör. mobil uygulamalar için)</small>',
'password_form' => 'Şifre<br /><small>(Tarayıcı girişi için)</small>',
'password_format' => 'En az 7 karakter',
'title' => 'Profil',
),
'reading' => array(
'_' => 'Okuma',
'after_onread' => '"Hepsini okundu say" dedinten sonra,',
'articles_per_page' => 'Sayfa başına makale sayısı',
'auto_load_more' => 'Sayfa sonunda yeni makaleleri yükle',
'auto_remove_article' => 'Okuduktan sonra makaleleri gizle',
'mark_updated_article_unread' => 'Güncellenen makaleleri okundu olarak işaretle',
'confirm_enabled' => '"Hepsini okundu say" eylemi için onay iste',
'display_articles_unfolded' => 'Show articles unfolded by default',
'display_categories_unfolded' => 'Show categories folded by default',
'hide_read_feeds' => 'Okunmamış makalesi olmayan kategori veya akışı gizle ("Tüm makaleleri göster" komutunda çalışmaz)',
'img_with_lazyload' => 'Resimleri yüklemek için "tembel modu" kullan',
'jump_next' => 'Bir sonraki benzer okunmamışa geç (akış veya kategori)',
'number_divided_when_reader' => 'Okuma modunda ikiye bölünecek.',
'read' => array(
'article_open_on_website' => 'orijinal makale sitesi açıldığında',
'article_viewed' => 'makale görüntülendiğinde',
'scroll' => 'kaydırma yapılırken',
'upon_reception' => 'makale üzerinde gelince',
'when' => 'Makaleyi okundu olarak işaretle…',
),
'show' => array(
'_' => 'Gösterilecek makaleler',
'adaptive' => 'Ayarlanmış gösterim',
'all_articles' => 'Tüm makaleleri göster',
'unread' => 'Sadece okunmamış makaleleri göster',
),
'sort' => array(
'_' => 'Sıralama',
'newer_first' => 'Önce yeniler',
'older_first' => 'Önce eskiler',
),
'sticky_post' => 'Makale açıldığında yukarı getir',
'title' => 'Okuma',
'view' => array(
'default' => 'Öntanımlı görünüm',
'global' => 'Global görünüm',
'normal' => 'Normal görünüm',
'reader' => 'Okuma görünümü',
),
),
'sharing' => array(
'_' => 'Paylaşım',
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'more_information' => 'Daha fazla bilgi',
'print' => 'Yazdır',
'shaarli' => 'Shaarli',
'share_name' => 'Paylaşım ismi',
'share_url' => 'Paylaşım URL si',
'title' => 'Paylaşım',
'twitter' => 'Twitter',
'wallabag' => 'wallabag',
),
'shortcut' => array(
'_' => 'Kısayollar',
'article_action' => 'Makale eylemleri',
'auto_share' => 'Paylaş',
'auto_share_help' => 'Sadece 1 paylaşım modu varsa bu kullanılır. Yoksa kendi paylaşım numaraları ile kullanılır.',
'close_dropdown' => 'Menüleri kapat',
'collapse_article' => 'Kapat',
'first_article' => 'İlk makaleyi atla',
'focus_search' => 'Arama kutusuna eriş',
'help' => 'Dokümantasyonu göster',
'javascript' => 'Kısayolları kullanabilmek için JavaScript aktif olmalıdır',
'last_article' => 'Son makaleyi atla',
'load_more' => 'Daha fazla makale yükle',
'mark_read' => 'Okundu olarak işaretle',
'mark_favorite' => 'Favori olarak işaretle',
'navigation' => 'Genel eylemler',
'navigation_help' => '"Shift" tuşu ile kısayollar akışlar için geçerli olur.<br/>"Alt" tuşu ile kısayollar kategoriler için geçerli olur.',
'next_article' => 'Sonraki makaleye geç',
'other_action' => 'Diğer eylemler',
'previous_article' => 'Önceki makaleye geç',
'see_on_website' => 'Orijinal sitede göster',
'shift_for_all_read' => '+ <code>shift</code> tuşu ile tüm makaleler okundu olarak işaretlenir',
'title' => 'Kısayollar',
'user_filter' => 'Kullanıcı filtrelerine eriş',
'user_filter_help' => 'Eğer tek filtre varsa o kullanılır. Yoksa filtrelerin kendi numaralarıyla kullanılır.',
),
'user' => array(
'articles_and_size' => '%s makale (%s)',
'current' => 'Mevcut kullanıcı',
'is_admin' => 'yöneticidir',
'users' => 'Kullanıcılar',
),
);

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

@ -0,0 +1,110 @@
<?php
return array(
'admin' => array(
'optimization_complete' => 'Optimizasyon tamamlandı',
),
'access' => array(
'denied' => 'Bu sayfaya erişim yetkiniz yok',
'not_found' => 'Varolmayan bir sayfa arıyorsunuz',
),
'auth' => array(
'form' => array(
'not_set' => 'Sistem yapılandırma kimlik doğrulaması sırasında hata oldu. Lütfen daha sonra tekrar deneyin.',
'set' => 'Kimlik doğrulama sistemi tamamnaldı.',
),
'login' => array(
'invalid' => 'Giriş geçersiz',
'success' => 'Bağlantı kuruldu',
),
'logout' => array(
'success' => 'Bağlantı koptu',
),
'no_password_set' => 'Yönetici şifresi ayarlanmadı. Bu özellik kullanıma uygun değil.',
'not_persona' => 'Sadece Persona sistem sıfırlanabilir.',
),
'conf' => array(
'error' => 'Yapılandırma ayarları kaydedilirken hata oluştu',
'query_created' => 'Sorgu "%s" oluşturuldu.',
'shortcuts_updated' => 'Kısayollar yenilendi',
'updated' => 'Yapılandırm ayarları yenilendi',
),
'extensions' => array(
'already_enabled' => '%s zaten aktif',
'disable' => array(
'ko' => '%s gösterilemiyor. Detaylar için <a href="%s">FressRSS log kayıtlarını</a> kontrol edin.',
'ok' => '%s pasif',
),
'enable' => array(
'ko' => '%s aktifleştirilemiyor. Detaylar için <a href="%s">FressRSS log kayıtlarını</a> kontrol edin.',
'ok' => '%s aktif',
),
'no_access' => '%s de yetkiniz yok',
'not_enabled' => '%s henüz aktif değil',
'not_found' => '%s bulunmamaktadır',
),
'import_export' => array(
'export_no_zip_extension' => 'Zip eklentisi mevcut sunucunuzda yer almıyor. Lütfen başka dosya formatında dışarı aktarmayı deneyin.',
'feeds_imported' => 'Akışlarınız içe aktarıldı ve şimdi güncellenecek',
'feeds_imported_with_errors' => 'Akışlarınız içeri aktarıldı ama bazı hatalar meydana geldi',
'file_cannot_be_uploaded' => 'Dosya yüklenemedi!',
'no_zip_extension' => 'Zip eklentisi mevcut sunucunuzda yer almıyor.',
'zip_error' => 'Zip içe aktarımı sırasında hata meydana geldi.',
),
'sub' => array(
'actualize' => 'Güncelleme',
'category' => array(
'created' => 'Kategori %s oluşturuldu.',
'deleted' => 'Kategori silindi.',
'emptied' => 'Kategori boşaltıldı',
'error' => 'Kategori güncellenemedi',
'name_exists' => 'Kategori ismi zaten bulunmakta.',
'no_id' => 'Kategori id sinden emin olmalısınız.',
'no_name' => 'Kategori ismi boş olamaz.',
'not_delete_default' => 'Öntanımlı kategoriyi silemezsiniz!',
'not_exist' => 'Kategori bulunmamakta!',
'over_max' => 'Kategori limitini aştınız (%d)',
'updated' => 'Karegori güncellendi.',
),
'feed' => array(
'actualized' => '<em>%s</em> güncellendi',
'actualizeds' => 'RSS akışları güncellendi',
'added' => '<em>%s</em> RSS akışı eklendi',
'already_subscribed' => '<em>%s</em> için zaten aboneliğiniz bulunmakta',
'deleted' => 'Akış silindi',
'error' => 'Akış güncellenemiyor',
'internal_problem' => 'RSS akışı eklenemiyor. Detaylar için <a href="%s">FressRSS log kayıtlarını</a> kontrol edin.',
'invalid_url' => 'URL <em>%s</em> geçersiz',
'marked_read' => 'Akışlar okundu olarak işaretlendi',
'n_actualized' => '%d akışları güncellendi',
'n_entries_deleted' => '%d makaleleri silindi',
'no_refresh' => 'Yenilenecek akış yok…',
'not_added' => '<em>%s</em> eklenemedi',
'over_max' => 'Akış limitini aştınız (%d)',
'updated' => 'Akış güncellendi',
),
'purge_completed' => 'Temizleme tamamlandı (%d makale silindi)',
),
'update' => array(
'can_apply' => 'FreshRSS <strong>%s versiyonuna</strong> güncellenecek.',
'error' => 'Güncelleme işlemi sırasında hata: %s',
'file_is_nok' => '<em>%s</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'finished' => 'Güncelleme tamamlandı!',
'none' => 'Güncelleme yok',
'server_not_found' => 'Güncelleme sunucusu bulunamadı. [%s]',
),
'user' => array(
'created' => array(
'_' => '%s kullanıcısı oluşturuldu',
'error' => '%s kullanıcısı oluşturulamadı',
),
'deleted' => array(
'_' => '%s kullanıcısı silindi',
'error' => '%s kullanıcısı silinemedi',
),
),
'profile' => array(
'error' => 'Profiliniz düzenlenemedi',
'updated' => 'Profiliniz düzenlendi',
),
);

185
sources/app/i18n/tr/gen.php Executable file
View file

@ -0,0 +1,185 @@
<?php
return array(
'action' => array(
'actualize' => 'Yenile',
'back_to_rss_feeds' => '← RSS akışlarınız için geri gidin',
'cancel' => 'İptal',
'create' => 'Oluştur',
'disable' => 'Pasif',
'empty' => 'Boş',
'enable' => 'Aktif',
'export' => 'Dışa Aktar',
'filter' => 'Filtrele',
'import' => 'İçe Aktar',
'manage' => 'Yönet',
'mark_read' => 'Okundu olarak işaretle',
'mark_favorite' => 'Favoriye ekle',
'remove' => 'Sil',
'see_website' => 'Siteyi gör',
'submit' => 'Onayla',
'truncate' => 'Tüm makaleleri sil',
),
'auth' => array(
'email' => 'Email adresleri',
'keep_logged_in' => '<small>(1 ay)</small> oturumu açık tut',
'login' => 'Giriş',
'login_persona' => 'Persona ile giriş yap',
'login_persona_problem' => 'Persona ile bağlantı sorununuz mu var ?',
'logout' => ıkış',
'password' => array(
'_' => 'Şifre',
'format' => '<small>En az 7 karakter</small>',
),
'registration' => array(
'_' => 'Yeni hesap',
'ask' => 'Yeni bir hesap oluştur',
'title' => 'Hesap oluşturma',
),
'reset' => 'Kimlik doğrulama sıfırla',
'username' => array(
'_' => 'Kullancı adı',
'admin' => 'Yönetici kullanıcı adı',
'format' => '<small>en fazla 16 alfanümerik karakter</small>',
),
'will_reset' => 'Kimlik doğrulama sistemi sıfırlanacak: Persone yerine bir form kullanılacak.',
),
'date' => array(
'Apr' => '\\N\\i\\s\\a\\n',
'Aug' => '\\A\\ğ\\u\\s\\t\\o\\s',
'Dec' => '\\A\\r\\a\\l\\ı\\k',
'Feb' => '\\Ş\\u\\b\\a\\t',
'Jan' => '\\O\\c\\a\\k',
'Jul' => '\\T\\e\\m\\m\\u\\z',
'Jun' => '\\H\\a\\z\\i\\r\\a\\n',
'Mar' => '\\M\\a\\r\\t',
'May' => '\\M\\a\\y\\ı\\s',
'Nov' => '\\K\\a\\s\\ı\\m',
'Oct' => '\\E\\k\\i\\m',
'Sep' => '\\E\\y\\l\\ü\\l',
'apr' => 'nis',
'april' => 'Nis',
'aug' => 'ağu',
'august' => 'Ağu',
'before_yesterday' => 'Dünden önceki gün',
'dec' => 'ara',
'december' => 'Ara',
'feb' => 'şub',
'february' => 'Şub',
'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y',
'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i',
'fri' => 'Cum',
'jan' => 'oca',
'january' => 'Oca',
'jul' => 'tem',
'july' => 'Tem',
'jun' => 'haz',
'june' => 'Haz',
'last_3_month' => 'Son 3 ay',
'last_6_month' => 'Son 6 ay',
'last_month' => 'Geçen ay',
'last_week' => 'Geçen hafta',
'last_year' => 'Geçen yıl',
'mar' => 'mar',
'march' => 'Mar',
'may' => 'May',
'mon' => 'Pzt',
'month' => 'ay',
'nov' => 'kas',
'november' => 'Kas',
'oct' => 'ekm',
'october' => 'Ekm',
'sat' => 'Cts',
'sep' => 'eyl',
'september' => 'Eyl',
'sun' => 'Pzr',
'thu' => 'Per',
'today' => 'Bugün',
'tue' => 'Sal',
'wed' => 'Çar',
'yesterday' => 'Dün',
),
'freshrss' => array(
'_' => 'FreshRSS',
'about' => 'FreshRSS hakkında',
),
'js' => array(
'category_empty' => 'Boş kategori',
'confirm_action' => 'Bunu yapmak istediğinize emin misiniz ? Daha sonra iptal edilemez!',
'confirm_action_feed_cat' => 'Bunu yapmak istediğinize emin misiniz ? Favorileriniz ve sorgularınız silinecek. Daha sonra iptal edilemez!',
'feedback' => array(
'body_new_articles' => 'FreshRSS de okunmaz üzere %%d yeni makale var.',
'request_failed' => 'Hata. İnternet bağlantınızı kontrol edin.',
'title_new_articles' => 'FreshRSS: yeni makaleler!',
),
'new_article' => 'Yeni makaleler mevcut. Sayfayı yenilemek için tıklayın.',
'should_be_activated' => 'JavaScript aktif olmalıdır.',
),
'lang' => array(
'cz' => 'Čeština',
'de' => 'Deutsch',
'en' => 'English',
'fr' => 'Français',
'it' => 'Italiano',
'nl' => 'Nederlands',
'ru' => 'Русский',
'tr' => 'Türkçe',
),
'menu' => array(
'about' => 'Hakkında',
'admin' => 'Yönetim',
'archiving' => 'Arşiv',
'authentication' => 'Kimlik doğrulama',
'check_install' => 'Kurulum kontrolü',
'configuration' => 'Yapılandırma',
'display' => 'Görünüm',
'extensions' => 'Eklentiler',
'logs' => 'Log kayıtları',
'queries' => 'Kullanıcı sorguları',
'reading' => 'Okuma',
'search' => 'Kelime veya #etiket ara',
'sharing' => 'Paylaşım',
'shortcuts' => 'Kısayollar',
'stats' => 'İstatistikler',
'system' => 'Sistem yapılandırması',
'update' => 'Güncelleme',
'user_management' => 'Kullanıcıları yönet',
'user_profile' => 'Profil',
),
'pagination' => array(
'first' => 'İlk',
'last' => 'Son',
'load_more' => 'Daha fazla makale yükle',
'mark_all_read' => 'Tümünü okundu say',
'next' => 'Sonraki',
'nothing_to_load' => 'Başka makale yok',
'previous' => 'Önceki',
),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
'g+' => 'Google+',
'movim' => 'Movim',
'print' => 'Print',
'shaarli' => 'Shaarli',
'twitter' => 'Twitter',
'wallabag' => 'wallabag v1',
'wallabagv2' => 'wallabag v2',
'jdh' => 'Journal du hacker',
),
'short' => array(
'attention' => 'Tehlike!',
'blank_to_disable' => 'Devredışı bırakmak için boş bırakın',
'by_author' => '<em>%s</em> tarafından',
'by_default' => 'Öntanımlı',
'damn' => 'Hay aksi!',
'default_category' => 'Kategorisiz',
'no' => 'Hayır',
'not_applicable' => 'Uygun değil',
'ok' => 'Tamam!',
'or' => 'ya da',
'yes' => 'Evet',
),
);

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

@ -0,0 +1,61 @@
<?php
return array(
'about' => array(
'_' => 'Hakkında',
'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
'bugs_reports' => 'Hata raporu',
'credits' => 'Tanıtım',
'credits_content' => 'Bu frameworkü kullanmamasına rağmen FreshRSS bazı tasarım ögelerini <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> dan almıştır. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">İkonlar</a> <a href="https://www.gnome.org/">GNOME projesinden</a> alınmıştır. <em>Open Sans</em> yazı tipi <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a> tarafından oluşturulmuştur. Site ikonları <a href="https://getfavicon.appspot.com/">getFavicon API</a> ile oluşturuldu. FreshRSS bir PHP framework olan <a href="https://github.com/marienfressinaud/MINZ">Minz</a> i temel alır.',
'freshrss_description' => 'FreshRSS <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> veya <a href="http://projet.idleman.fr/leed/">Leed</a> gibi kendi hostunuzda çalışan bir RSS akış toplayıcısıdır. Güçlü ve yapılandırılabilir araçlarıyla basit ve kullanımı kolay bir uygulamadır.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">Github sayfası</a>',
'license' => 'Lisans',
'project_website' => 'Proje sayfası',
'title' => 'Hakkında',
'version' => 'Versiyon',
'website' => 'Website',
),
'feed' => array(
'add' => 'Akış ekleyebilirsin.',
'empty' => 'Gösterilecek makale yok.',
'rss_of' => 'RSS feed of %s',
'title' => 'RSS akışlarınız',
'title_global' => 'Global görünüm',
'title_fav' => 'Favorilerin',
),
'log' => array(
'_' => 'Log Kayıtları',
'clear' => 'Log kayıt dosyasını temizle',
'empty' => 'Log kayır dosyası boş',
'title' => 'Log Kayıtları',
),
'menu' => array(
'about' => 'FreshRSS hakkında',
'add_query' => 'Sorgu ekle',
'before_one_day' => 'Bir gün önce',
'before_one_week' => 'Bir hafta önce',
'favorites' => 'Favoriler (%s)',
'global_view' => 'Global görünüm',
'main_stream' => 'Ana akış',
'mark_all_read' => 'Hepsini okundu olarak işaretle',
'mark_cat_read' => 'Kategoriyi okundu olarak işaretle',
'mark_feed_read' => 'Akışı okundu olarak işaretle',
'newer_first' => 'Önce yeniler',
'non-starred' => 'Favori dışındakileri göster',
'normal_view' => 'Normal görünüm',
'older_first' => 'Önce eskiler',
'queries' => 'Kullanıcı sorguları',
'read' => 'Okunmuşları göster',
'reader_view' => 'Okuma görünümü',
'rss_view' => 'RSS akışı',
'search_short' => 'Ara',
'starred' => 'Favorileri göster',
'stats' => 'İstatistikler',
'subscription' => 'Abonelik yönetimi',
'unread' => 'Okunmamışları göster',
),
'share' => 'Share',
'tag' => array(
'related' => 'İlgili etiketler',
),
);

121
sources/app/i18n/tr/install.php Executable file
View file

@ -0,0 +1,121 @@
<?php
return array(
'action' => array(
'finish' => 'Kurulumu tamamla',
'fix_errors_before' => 'Lütfen sonraki adıma geçmek için hataları düzeltin.',
'keep_install' => 'Önceki kuruluma devam et',
'next_step' => 'Sonraki adım',
'reinstall' => 'FreshRSS i yeniden yükle',
),
'auth' => array(
'email_persona' => 'Giriş email adresi<br /><small>(<a href="https://persona.org/" rel="external">Mozilla Persona</a> için)</small>',
'form' => 'Web formu (geleneksel, JavaScript gerektirir)',
'http' => 'HTTP (ileri kullanıcılar için, HTTPS)',
'none' => 'Hiçbiri (tehlikeli)',
'password_form' => 'Şifre<br /><small>(Tarayıcı girişi için)</small>',
'password_format' => 'En az 7 karakter',
'persona' => 'Mozilla Persona (modern, JavaScript gerektirir)',
'type' => 'Kimlik doğrulama yöntemi',
),
'bdd' => array(
'_' => 'Veritabanı',
'conf' => array(
'_' => 'Veritabanı yapılandırılması',
'ko' => 'Veritabanı bilginizi doğrulayın.',
'ok' => 'Veritabanı yapılandırılması kayıt edildi.',
),
'host' => 'Sunucu',
'prefix' => 'Tablo ön eki',
'password' => 'HTTP şifre',
'type' => 'Veritabanı türü',
'username' => 'HTTP kullanıcı adı',
),
'check' => array(
'_' => 'Kontroller',
'already_installed' => 'FreshRSS zaten yüklü!',
'cache' => array(
'nok' => '<em>./data/cache</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Önbellek klasörü yetkileri sorunsuz.',
),
'ctype' => array(
'nok' => 'Karakter yazım kontrolü için kütüphane eksik (php-ctype).',
'ok' => 'Karakter yazım kontrolü için kütüphane sorunsuz (ctype).',
),
'curl' => array(
'nok' => 'cURL eksik (php5-curl package).',
'ok' => 'cURL eklentisi sorunsuz.',
),
'data' => array(
'nok' => '<em>./data</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Veri klasörü yetkileri sorunsuz.',
),
'dom' => array(
'nok' => 'DOM kütüpbanesi eksik.',
'ok' => 'DOM kütüphanesi sorunsuz.',
),
'favicons' => array(
'nok' => '<em>./data/favicons</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Site ikonu klasörü yetkileri sorunsuz.',
),
'http_referer' => array(
'nok' => 'Lütfen HTTP REFERER değiştirmediğinize emin olun.',
'ok' => 'HTTP REFERER ve sunucunuz arası iletişim sorunsuz.',
),
'json' => array(
'nok' => 'Tavsiye edilen JSON çözümleme kütüphanesi eksik.',
'ok' => 'Tavsiye edilen JSON çözümleme kütüphanesi sorunsuz.',
),
'minz' => array(
'nok' => 'Minz framework eksik.',
'ok' => 'Minz framework sorunsuz.',
),
'pcre' => array(
'nok' => 'Düzenli ifadeler kütüphanesi eksik (php-pcre).',
'ok' => 'Düzenli ifadeler kütüphanesi sorunsuz (PCRE).',
),
'pdo' => array(
'nok' => 'PDO veya PDO destekli bir sürücü eksik (pdo_mysql, pdo_sqlite).',
'ok' => 'PDO sorunsuz (pdo_mysql, pdo_sqlite).',
),
'persona' => array(
'nok' => '<em>./data/persona</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Mozilla Persona klasörü yetkileri sorunsuz.',
),
'php' => array(
'nok' => 'PHP versiyonunuz %s fakat FreshRSS için gerekli olan en düşük sürüm %s.',
'ok' => 'PHP versiyonunuz %s, FreshRSS ile tam uyumlu.',
),
'users' => array(
'nok' => '<em>./data/users</em> klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı',
'ok' => 'Kullanıcılar klasörü yetkileri sorunsuz.',
),
'xml' => array(
'nok' => 'You lack the required library to parse XML.',
'ok' => 'You have the required library to parse XML.',
),
),
'conf' => array(
'_' => 'Genel yapılandırma',
'ok' => 'Genel yapılandırma ayarları kayıt edildi.',
),
'congratulations' => 'Tebrikler!',
'default_user' => 'Öntanımlı kullanıcı adı <small>(en fazla 16 alfanümerik karakter)</small>',
'delete_articles_after' => 'Makaleleri şu süre sonunda sil',
'fix_errors_before' => 'Lütfen sonraki adıma geçmek için hataları düzeltin.',
'javascript_is_better' => 'FreshRSS JavaScript ile daha işlevseldir',
'js' => array(
'confirm_reinstall' => 'FressRSS i yeniden kurarak önceki yapılandırma ayarlarınızı kaybedeceksiniz. Devam etmek istiyor musunuz ?',
),
'language' => array(
'_' => 'Dil',
'choose' => 'FreshRSS için bir dil seçin',
'defined' => 'Dil belirlendi.',
),
'not_deleted' => 'Hata meydana geldi; <em>%s</em> dosyasını elle silmelisiniz.',
'ok' => 'Kurulum başarıyla tamamlandı.',
'step' => 'adım %d',
'steps' => 'Adımlar',
'title' => 'Kurulum · FreshRSS',
'this_is_the_end' => 'Son Adım',
);

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

@ -0,0 +1,62 @@
<?php
return array(
'category' => array(
'_' => 'Kategori',
'add' => 'Kategori ekle',
'empty' => 'Boş kategori',
'new' => 'Yeni kategori',
),
'feed' => array(
'add' => 'RSS akışı ekle',
'advanced' => 'Gelişmiş',
'archiving' => 'Arşiv',
'auth' => array(
'configuration' => 'Giriş',
'help' => 'HTTP korumalı RSS akışlarına bağlantı izni sağlar',
'http' => 'HTTP Kimlik Doğrulama',
'password' => 'HTTP şifre',
'username' => 'HTTP kullanıcı adı',
),
'css_help' => 'Dikkat, daha çok zaman gerekir!',
'css_path' => 'Makaleleri kendi CSS görünümü ile göster',
'description' => 'Tanım',
'empty' => 'Bu akış boş. Lütfen akışın aktif olduğuna emin olun.',
'error' => 'Bu akışda bir hatayla karşılaşıldı. Lütfen akışın sürekli ulaşılabilir olduğuna emin olun.',
'in_main_stream' => 'Ana akışda göster',
'informations' => 'Bilgi',
'keep_history' => 'En az tutulacak makale sayısı',
'moved_category_deleted' => 'Bir kategoriyi silerseniz, içerisindeki akışlar <em>%s</em> içerisine yerleşir.',
'no_selected' => 'Hiçbir akış seçilmedi.',
'number_entries' => '%d makale',
'stats' => 'İstatistikler',
'think_to_add' => 'Akış ekleyebilirsiniz.',
'title' => 'Başlık',
'title_add' => 'RSS akışı ekle',
'ttl' => 'Şu kadar süreden fazla otomatik yenileme yapma',
'url' => 'Akış URL',
'validator' => 'Akış geçerliliğini kontrol edin',
'website' => 'Site URL',
'pubsubhubbub' => 'PubSubHubbub ile anlık bildirim',
),
'import_export' => array(
'export' => 'Dışa aktar',
'export_opml' => 'Akış listesini dışarı aktar (OPML)',
'export_starred' => 'Favorileri dışarı aktar',
'feed_list' => '%s makalenin listesi',
'file_to_import' => 'Dosyadan içe aktar<br />(OPML, Json or Zip)',
'file_to_import_no_zip' => 'Dosyadan içe aktar<br />(OPML or Json)',
'import' => 'İçe aktar',
'starred_list' => 'Favori makaleleirn listesi',
'title' => 'İçe / dışa aktar',
),
'menu' => array(
'bookmark' => 'Abonelik (FreshRSS yer imleri)',
'import_export' => 'İçe / dışa aktar',
'subscription_management' => 'Abonelik yönetimi',
),
'title' => array(
'_' => 'Abonelik yönetimi',
'feed_management' => 'RSS akış yönetimi',
),
);

View file

@ -2,6 +2,7 @@
if (function_exists('opcache_reset')) {
opcache_reset();
}
header("Content-Security-Policy: default-src 'self'");
define('BCRYPT_COST', 9);
@ -130,7 +131,7 @@ function saveStep2() {
$_SESSION['mail_login'] = filter_var(param('mail_login', ''), FILTER_VALIDATE_EMAIL);
$password_plain = param('passwordPlain', false);
if ($password_plain !== false) {
if ($password_plain !== false && cryptAvailable()) {
if (!function_exists('password_hash')) {
include_once(LIB_PATH . '/password_compat.php');
}
@ -308,7 +309,7 @@ function checkStep0() {
}
function checkStep1() {
$php = version_compare(PHP_VERSION, '5.2.1') >= 0;
$php = version_compare(PHP_VERSION, '5.3.0') >= 0;
$minz = file_exists(join_path(LIB_PATH, 'Minz'));
$curl = extension_loaded('curl');
$pdo_mysql = extension_loaded('pdo_mysql');
@ -317,6 +318,8 @@ function checkStep1() {
$pcre = extension_loaded('pcre');
$ctype = extension_loaded('ctype');
$dom = class_exists('DOMDocument');
$xml = function_exists('xml_parser_create');
$json = function_exists('json_encode');
$data = DATA_PATH && is_writable(DATA_PATH);
$cache = CACHE_PATH && is_writable(CACHE_PATH);
$users = USERS_PATH && is_writable(USERS_PATH);
@ -334,13 +337,15 @@ function checkStep1() {
'pcre' => $pcre ? 'ok' : 'ko',
'ctype' => $ctype ? 'ok' : 'ko',
'dom' => $dom ? 'ok' : 'ko',
'xml' => $xml ? 'ok' : 'ko',
'json' => $json ? 'ok' : 'ko',
'data' => $data ? 'ok' : 'ko',
'cache' => $cache ? 'ok' : 'ko',
'users' => $users ? 'ok' : 'ko',
'favicons' => $favicons ? 'ok' : 'ko',
'persona' => $persona ? 'ok' : 'ko',
'http_referer' => $http_referer ? 'ok' : 'ko',
'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom &&
'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom && $xml &&
$data && $cache && $users && $favicons && $persona && $http_referer ?
'ok' : 'ko'
);
@ -531,7 +536,7 @@ function printStep1() {
<?php if ($res['php'] == 'ok') { ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.php.ok', PHP_VERSION); ?></p>
<?php } else { ?>
<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.php.nok', PHP_VERSION, '5.2.1'); ?></p>
<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.php.nok', PHP_VERSION, '5.3.0'); ?></p>
<?php } ?>
<?php if ($res['minz'] == 'ok') { ?>
@ -553,6 +558,12 @@ function printStep1() {
<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.curl.nok'); ?></p>
<?php } ?>
<?php if ($res['json'] == 'ok') { ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.json.ok'); ?></p>
<?php } else { ?>
<p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.json.nok'); ?></p>
<?php } ?>
<?php if ($res['pcre'] == 'ok') { ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.pcre.ok'); ?></p>
<?php } else { ?>
@ -571,6 +582,12 @@ function printStep1() {
<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.dom.nok'); ?></p>
<?php } ?>
<?php if ($res['xml'] == 'ok') { ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.xml.ok'); ?></p>
<?php } else { ?>
<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.xml.nok'); ?></p>
<?php } ?>
<?php if ($res['data'] == 'ok') { ?>
<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.data.ok'); ?></p>
<?php } else { ?>
@ -616,27 +633,6 @@ function printStep1() {
<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 { ?>
@ -674,17 +670,17 @@ function printStep2() {
<div class="form-group">
<label class="group-name" for="auth_type"><?php echo _t('install.auth.type'); ?></label>
<div class="group-controls">
<select id="auth_type" name="auth_type" required="required" onchange="auth_type_change(true)" tabindex="4">
<select id="auth_type" name="auth_type" required="required" tabindex="4">
<?php
function no_auth($auth_type) {
return !in_array($auth_type, array('form', 'persona', 'http_auth', 'none'));
}
$auth_type = isset($_SESSION['auth_type']) ? $_SESSION['auth_type'] : '';
?>
<option value="form"<?php echo $auth_type === 'form' || no_auth($auth_type) ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"'; ?>><?php echo _t('install.auth.form'); ?></option>
<option value="form"<?php echo $auth_type === 'form' || (no_auth($auth_type) && cryptAvailable()) ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"'; ?>><?php echo _t('install.auth.form'); ?></option>
<option value="persona"<?php echo $auth_type === 'persona' ? ' selected="selected"' : ''; ?>><?php echo _t('install.auth.persona'); ?></option>
<option value="http_auth"<?php echo $auth_type === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : ''; ?>><?php echo _t('install.auth.http'); ?>(REMOTE_USER = '<?php echo httpAuthUser(); ?>')</option>
<option value="none"<?php echo $auth_type === 'none' ? ' selected="selected"' : ''; ?>><?php echo _t('install.auth.none'); ?></option>
<option value="none"<?php echo $auth_type === 'none' || (no_auth($auth_type) && !cryptAvailable()) ? ' selected="selected"' : ''; ?>><?php echo _t('install.auth.none'); ?></option>
</select>
</div>
</div>
@ -709,48 +705,6 @@ function printStep2() {
</div>
</div>
<script>
function show_password() {
var button = this;
var passwordField = document.getElementById(button.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'text');
button.className += ' active';
return false;
}
function hide_password() {
var button = this;
var passwordField = document.getElementById(button.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'password');
button.className = button.className.replace(/(?:^|\s)active(?!\S)/g , '');
return false;
}
toggles = document.getElementsByClassName('toggle-password');
for (var i = 0 ; i < toggles.length ; i++) {
toggles[i].addEventListener('mousedown', show_password);
toggles[i].addEventListener('mouseup', hide_password);
}
function auth_type_change() {
var auth_value = document.getElementById('auth_type').value,
password_input = document.getElementById('passwordPlain'),
mail_input = document.getElementById('mail_login');
if (auth_value === 'form') {
password_input.required = true;
mail_input.required = false;
} else if (auth_value === 'persona') {
password_input.required = false;
mail_input.required = true;
} else {
password_input.required = false;
mail_input.required = false;
}
}
auth_type_change();
</script>
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-important" tabindex="7" ><?php echo _t('gen.action.submit'); ?></button>
@ -778,7 +732,7 @@ function printStep3() {
<div class="form-group">
<label class="group-name" for="type"><?php echo _t('install.bdd.type'); ?></label>
<div class="group-controls">
<select name="type" id="type" onchange="mySqlShowHide()" tabindex="1" >
<select name="type" id="type" tabindex="1">
<?php if (extension_loaded('pdo_mysql')) {?>
<option value="mysql"
<?php echo(isset($_SESSION['bd_type']) && $_SESSION['bd_type'] === 'mysql') ? 'selected="selected"' : ''; ?>>
@ -831,19 +785,6 @@ function printStep3() {
</div>
</div>
</div>
<script>
function mySqlShowHide() {
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();
</script>
<div class="form-group form-actions">
<div class="group-controls">
@ -897,13 +838,14 @@ case 5:
}
?>
<!DOCTYPE html>
<html lang="fr">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1.0" />
<title><?php echo _t('install.title'); ?></title>
<link rel="stylesheet" type="text/css" media="all" href="../themes/base-theme/template.css" />
<link rel="stylesheet" type="text/css" media="all" href="../themes/Origine/origine.css" />
<link rel="stylesheet" href="../themes/base-theme/template.css?<?php echo @filemtime(PUBLIC_PATH . '/themes/base-theme/template.css'); ?>" />
<link rel="stylesheet" href="../themes/Origine/origine.css?<?php echo @filemtime(PUBLIC_PATH . '/themes/Origine/origine.css'); ?>" />
<meta name="robots" content="noindex,nofollow" />
</head>
<body>
@ -950,5 +892,6 @@ case 5:
?>
</div>
</div>
<script src="../scripts/install.js?<?php echo @filemtime(PUBLIC_PATH . '/scripts/install.js'); ?>"></script>
</body>
</html>

View file

@ -19,7 +19,7 @@
<a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('index.menu.about'); ?></a>
<?php } ?>
<form id="mark-read-aside" method="post" style="display: none"></form>
<form id="mark-read-aside" method="post" aria-hidden="true"></form>
<ul class="tree">
<li class="tree-folder category all<?php echo FreshRSS_Context::isCurrentGet('a') ? ' active' : ''; ?>">

View file

@ -10,7 +10,7 @@
</li>
<li class="item">
<a onclick="return false;" href="javascript:(function(){var%20url%20=%20location.href;window.open('<?php echo Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true); ?>&amp;url_rss='+encodeURIComponent(url), '_blank');})();">
<a class="bookmarkClick" href="javascript:(function(){var%20url%20=%20location.href;window.open('<?php echo Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true); ?>&amp;url_rss='+encodeURIComponent(url), '_blank');})();">
<?php echo _t('sub.menu.bookmark'); ?>
</a>
</li>

View file

@ -1,32 +1,16 @@
<?php FreshRSS::preLayout(); ?>
<!DOCTYPE html>
<html lang="<?php echo FreshRSS_Context::$user_conf->language; ?>" xml:lang="<?php echo FreshRSS_Context::$user_conf->language; ?>">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1.0" />
<?php echo self::headTitle(); ?>
<?php echo self::headStyle(); ?>
<?php echo self::headScript(); ?>
<script>//<![CDATA[
<script id="jsonVars" type="application/json">
<?php $this->renderHelper('javascript_vars'); ?>
//]]></script>
<?php
$url_base = Minz_Request::currentRequest();
if (FreshRSS_Context::$next_id !== '') {
$url_next = $url_base;
$url_next['params']['next'] = FreshRSS_Context::$next_id;
$url_next['params']['ajax'] = 1;
?>
<link id="prefetch" rel="next prefetch" href="<?php echo Minz_Url::display($url_next); ?>" />
<?php } ?>
</script>
<?php echo self::headScript(); ?>
<link rel="shortcut icon" id="favicon" type="image/x-icon" sizes="16x16 64x64" href="<?php echo Minz_Url::display('/favicon.ico'); ?>" />
<link rel="icon msapplication-TileImage apple-touch-icon" type="image/png" sizes="256x256" href="<?php echo Minz_Url::display('/themes/icons/favicon-256.png'); ?>" />
<?php
if (isset($this->rss_title)) {
$url_rss = $url_base;
$url_rss['a'] = 'rss';
?>
<link rel="alternate" type="application/rss+xml" title="<?php echo $this->rss_title; ?>" href="<?php echo Minz_Url::display($url_rss); ?>" />
<?php } ?>
<link rel="prefetch" href="<?php echo FreshRSS_Themes::icon('starred', true); ?>">
<link rel="prefetch" href="<?php echo FreshRSS_Themes::icon('non-starred', true); ?>">
<link rel="prefetch" href="<?php echo FreshRSS_Themes::icon('read', true); ?>">
@ -36,13 +20,34 @@
<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="msapplication-TileColor" content="#FFF" />
<?php if (FreshRSS_Context::$system_conf->allow_robots) { ?>
<?php
flush();
if (isset($this->callbackBeforeContent)) {
call_user_func($this->callbackBeforeContent);
}
?>
<?php echo self::headTitle(); ?>
<?php
$url_base = Minz_Request::currentRequest();
if (FreshRSS_Context::$next_id !== '') {
$url_next = $url_base;
$url_next['params']['next'] = FreshRSS_Context::$next_id;
$url_next['params']['ajax'] = 1;
?>
<link id="prefetch" rel="next prefetch" href="<?php echo Minz_Url::display($url_next); ?>" />
<?php
} if (isset($this->rss_title)) {
$url_rss = $url_base;
$url_rss['a'] = 'rss';
?>
<link rel="alternate" type="application/rss+xml" title="<?php echo $this->rss_title; ?>" href="<?php echo Minz_Url::display($url_rss); ?>" />
<?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" />
<?php } ?>
</head>
<body class="<?php echo Minz_Request::param('output', 'normal'); ?>">
<body class="<?php echo Minz_Request::actionName(); ?>">
<?php $this->partial('header'); ?>
<div id="global">

View file

@ -79,7 +79,7 @@
);
?>
<form id="mark-read-menu" method="post" style="display: none"></form>
<form id="mark-read-menu" method="post" aria-hidden="true"></form>
<div class="stick" id="nav_menu_read_all">
<?php $confirm = FreshRSS_Context::$user_conf->reading_confirm ? 'confirm' : ''; ?>

View file

@ -13,4 +13,5 @@ $url = Minz_Url::display(array(
'params' => Minz_Request::params(),
));
FreshRSS::loadStylesAndScripts();
echo json_encode(array('url' => str_ireplace('&amp;', '&', $url), 'icon' => _i(Minz_Request::param('is_favorite') ? 'non-starred' : 'starred')));

View file

@ -13,4 +13,5 @@ $url = Minz_Url::display(array(
'params' => Minz_Request::params(),
));
FreshRSS::loadStylesAndScripts();
echo json_encode(array('url' => str_ireplace('&amp;', '&', $url), 'icon' => _i(Minz_Request::param('is_read') ? 'unread' : 'read')));

View file

@ -5,7 +5,7 @@
<h1><?php echo _t('admin.extensions.title'); ?></h1>
<form id="form-extension" method="post" style="display: none"></form>
<form id="form-extension" method="post" aria-hidden="true"></form>
<?php if (!empty($this->extension_list['system'])) { ?>
<h2><?php echo _t('admin.extensions.system'); ?></h2>
<?php

View file

@ -56,7 +56,7 @@
<option value="nc"><?php echo _t('sub.category.new'); ?></option>
</select>
<span style="display: none;">
<span aria-hidden="true">
<input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?php echo _t('sub.category.new'); ?>" />
</span>
</div>

View file

@ -48,7 +48,7 @@
<a class="btn" target="_blank" href="<?php echo $this->feed->url(); ?>"><?php echo _i('link'); ?></a>
</div>
<a class="btn" target="_blank" href="http://validator.w3.org/feed/check.cgi?url=<?php echo $this->feed->url(); ?>"><?php echo _t('sub.feed.validator'); ?></a>
<a class="btn" target="_blank" href="http://validator.w3.org/feed/check.cgi?url=<?php echo rawurlencode(htmlspecialchars_decode($this->feed->url(), ENT_QUOTES)); ?>"><?php echo _t('sub.feed.validator'); ?></a>
</div>
</div>
<div class="form-group">

View file

@ -1,71 +1,54 @@
"use strict";
<?php
$mark = FreshRSS_Context::$user_conf->mark_when;
$mail = Minz_Session::param('mail', false);
$auto_actualize = Minz_Session::param('actualize_feeds', false);
$hide_posts = (FreshRSS_Context::$user_conf->display_posts ||
Minz_Request::param('output') === 'reader');
$s = FreshRSS_Context::$user_conf->shortcuts;
$url_login = Minz_Url::display(array(
'c' => 'auth',
'a' => 'login'
), 'php');
$url_logout = Minz_Url::display(array(
'c' => 'auth',
'a' => 'logout'
), 'php');
echo 'var context={',
'auto_remove_article:', FreshRSS_Context::isAutoRemoveAvailable() ? 'true' : 'false', ',',
'hide_posts:', $hide_posts ? 'false' : 'true', ',',
'display_order:"', Minz_Request::param('order', FreshRSS_Context::$user_conf->sort_order), '",',
'auto_mark_article:', $mark['article'] ? 'true' : 'false', ',',
'auto_mark_site:', $mark['site'] ? 'true' : 'false', ',',
'auto_mark_scroll:', $mark['scroll'] ? 'true' : 'false', ',',
'auto_load_more:', FreshRSS_Context::$user_conf->auto_load_more ? 'true' : 'false', ',',
'auto_actualize_feeds:', $auto_actualize ? 'true' : 'false', ',',
'does_lazyload:', FreshRSS_Context::$user_conf->lazyload ? 'true' : 'false', ',',
'sticky_post:', FreshRSS_Context::isStickyPostEnabled() ? 'true' : 'false', ',',
'html5_notif_timeout:', FreshRSS_Context::$user_conf->html5_notif_timeout, ',',
'auth_type:"', FreshRSS_Context::$system_conf->auth_type, '",',
'current_user_mail:', $mail ? ('"' . $mail . '"') : 'null', ',',
'current_view:"', Minz_Request::param('output', 'normal'), '"',
"},\n";
echo 'shortcuts={',
'mark_read:"', @$s['mark_read'], '",',
'mark_favorite:"', @$s['mark_favorite'], '",',
'go_website:"', @$s['go_website'], '",',
'prev_entry:"', @$s['prev_entry'], '",',
'next_entry:"', @$s['next_entry'], '",',
'first_entry:"', @$s['first_entry'], '",',
'last_entry:"', @$s['last_entry'], '",',
'collapse_entry:"', @$s['collapse_entry'], '",',
'load_more:"', @$s['load_more'], '",',
'auto_share:"', @$s['auto_share'], '",',
'focus_search:"', @$s['focus_search'], '",',
'user_filter:"', @$s['user_filter'], '",',
'help:"', @$s['help'], '",',
'close_dropdown:"', @$s['close_dropdown'], '"',
"},\n";
echo 'url={',
'index:"', _url('index', 'index'), '",',
'login:"', $url_login, '",',
'logout:"', $url_logout, '",',
'help:"', FRESHRSS_WIKI, '"',
"},\n";
echo 'i18n={',
'confirmation_default:"', _t('gen.js.confirm_action'), '",',
'notif_title_articles:"', _t('gen.js.feedback.title_new_articles'), '",',
'notif_body_articles:"', _t('gen.js.feedback.body_new_articles'), '",',
'notif_request_failed:"', _t('gen.js.feedback.request_failed'), '",',
'category_empty:"', _t('gen.js.category_empty'), '"',
"},\n";
echo 'icons={',
'close:\'', _i('close'), '\'',
"}\n";
echo htmlspecialchars(json_encode(array(
'context' => array(
'auto_remove_article' => !!FreshRSS_Context::isAutoRemoveAvailable(),
'hide_posts' => !(FreshRSS_Context::$user_conf->display_posts || Minz_Request::actionName() === 'reader'),
'display_order' => Minz_Request::param('order', FreshRSS_Context::$user_conf->sort_order),
'auto_mark_article' => !!$mark['article'],
'auto_mark_site' => !!$mark['site'],
'auto_mark_scroll' => !!$mark['scroll'],
'auto_load_more' => !!FreshRSS_Context::$user_conf->auto_load_more,
'auto_actualize_feeds' => !!Minz_Session::param('actualize_feeds', false),
'does_lazyload' => !!FreshRSS_Context::$user_conf->lazyload ,
'sticky_post' => !!FreshRSS_Context::isStickyPostEnabled(),
'html5_notif_timeout' => FreshRSS_Context::$user_conf->html5_notif_timeout,
'auth_type' => FreshRSS_Context::$system_conf->auth_type,
'current_user_mail' => $mail ? ('"' . $mail . '"') : null,
'current_view' => Minz_Request::actionName(),
),
'shortcuts' => array(
'mark_read' => @$s['mark_read'],
'mark_favorite' => @$s['mark_favorite'],
'go_website' => @$s['go_website'],
'prev_entry' => @$s['prev_entry'],
'next_entry' => @$s['next_entry'],
'first_entry' => @$s['first_entry'],
'last_entry' => @$s['last_entry'],
'collapse_entry' => @$s['collapse_entry'],
'load_more' => @$s['load_more'],
'auto_share' => @$s['auto_share'],
'focus_search' => @$s['focus_search'],
'user_filter' => @$s['user_filter'],
'help' => @$s['help'],
'close_dropdown' => @$s['close_dropdown'],
),
'url' => array(
'index' => _url('index', 'index'),
'login' => Minz_Url::display(array('c' => 'auth', 'a' => 'login'), 'php'),
'logout' => Minz_Url::display(array('c' => 'auth', 'a' => 'logout'), 'php'),
'help' => FRESHRSS_WIKI,
),
'i18n' => array(
'confirmation_default' => _t('gen.js.confirm_action'),
'notif_title_articles' => _t('gen.js.feedback.title_new_articles'),
'notif_body_articles' => _t('gen.js.feedback.body_new_articles'),
'notif_request_failed' => _t('gen.js.feedback.request_failed'),
'category_empty' => _t('gen.js.category_empty'),
),
'icons' => array(
'close' => _i('close'),
),
), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES);

View file

@ -14,7 +14,7 @@
);
?>
<form id="mark-read-pagination" method="post" style="display: none"></form>
<form id="mark-read-pagination" method="post" aria-hidden="true"></form>
<ul class="pagination">
<li class="item pager-next">

View file

@ -1,56 +1,13 @@
"use strict";
var feeds = [<?php foreach ($this->feeds as $feed) { ?>{<?php
?>url: "<?php echo Minz_Url::display(array('c' => 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'); ?>",<?php
?>title: "<?php echo $feed->name(); ?>"<?php
?>},<?php } ?>],
feed_processed = 0,
feed_count = feeds.length;
function initProgressBar(init) {
if (init) {
$("body").after("\<div id=\"actualizeProgress\" class=\"notification good\">\
<?php echo _t('feedback.sub.actualize'); ?><br /><span class=\"title\">/</span><br />\
<span class=\"progress\">0 / " + feed_count + "</span>\
</div>");
} else {
window.location.reload();
}
}
function updateProgressBar(i, title_feed) {
$("#actualizeProgress .progress").html(i + " / " + feed_count);
$("#actualizeProgress .title").html(title_feed);
}
function updateFeeds() {
if (feed_count === 0) {
openNotification("<?php echo _t('feedback.sub.feed.no_refresh'); ?>", "good");
ajax_loading = false;
return;
}
initProgressBar(true);
for (var i = 0; i < 10; i++) {
updateFeed();
}
}
function updateFeed() {
var feed = feeds.pop();
if (feed == undefined) {
return;
}
$.ajax({
type: 'POST',
url: feed['url'],
}).complete(function (data) {
feed_processed++;
updateProgressBar(feed_processed, feed['title']);
if (feed_processed === feed_count) {
initProgressBar(false);
} else {
updateFeed();
}
});
<?php
$feeds = array();
foreach ($this->feeds as $feed) {
$feeds[] = array(
'url' => Minz_Url::display(array('c' => 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'),
'title' => $feed->name(),
);
}
echo json_encode(array(
'feeds' => $feeds,
'feedback_no_refresh' => _t('feedback.sub.feed.no_refresh'),
'feedback_actualize' => _t('feedback.sub.actualize'),
));

View file

@ -6,10 +6,10 @@
<h1><?php echo _t('admin.stats.idle'); ?></h1>
<?php
$current_url = urlencode(Minz_Url::display(
$current_url = Minz_Url::display(
array('c' => 'stats', 'a' => 'idle'),
'php', true
));
);
$nothing = true;
foreach ($this->idleFeeds as $period => $feeds) {
if (!empty($feeds)) {
@ -18,7 +18,7 @@
<div class="stat">
<h2><?php echo _t('gen.date.' . $period); ?></h2>
<form id="form-delete" method="post" style="display: none"></form>
<form id="form-delete" method="post" aria-hidden="true"></form>
<?php foreach ($feeds as $feed) { ?>
<ul class="horizontal-list">

View file

@ -66,74 +66,28 @@
<div class="stat">
<h2><?php echo _t('admin.stats.entry_per_day'); ?></h2>
<div id="statsEntryPerDay" style="height: 300px"></div>
<div id="statsEntryPerDay" class="statGraph"></div>
</div>
<div class="stat half">
<h2><?php echo _t('admin.stats.feed_per_category'); ?></h2>
<div id="statsFeedPerCategory" style="height: 300px"></div>
<div id="statsFeedPerCategory" class="statGraph"></div>
<div id="statsFeedPerCategoryLegend"></div>
</div><!--
</div>
--><div class="stat half">
<div class="stat half">
<h2><?php echo _t('admin.stats.entry_per_category'); ?></h2>
<div id="statsEntryPerCategory" style="height: 300px"></div>
<div id="statsEntryPerCategory" class="statGraph"></div>
<div id="statsEntryPerCategoryLegend"></div>
</div>
</div>
<script>
"use strict";
function initStats() {
if (!window.Flotr) {
if (window.console) {
console.log('FreshRSS waiting for Flotr…');
}
window.setTimeout(initStats, 50);
return;
}
// Entry per day
var avg = [];
for (var i = -31; i <= 0; i++) {
avg.push([i, <?php echo $this->average?>]);
}
Flotr.draw(document.getElementById('statsEntryPerDay'),
[{
data: <?php echo $this->count ?>,
bars: {horizontal: false, show: true}
},{
data: avg,
lines: {show: true},
label: "<?php echo $this->average?>"
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0, min: -30.75, max: -0.25},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
// Feed per category
Flotr.draw(document.getElementById('statsFeedPerCategory'),
<?php echo $this->feedByCategory ?>,
{
grid: {verticalLines: false, horizontalLines: false},
pie: {explode: 10, show: true, labelFormatter: function(){return '';}},
xaxis: {showLabels: false},
yaxis: {showLabels: false},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}},
legend: {container: document.getElementById('statsFeedPerCategoryLegend'), noColumns: 3}
});
// Entry per category
Flotr.draw(document.getElementById('statsEntryPerCategory'),
<?php echo $this->entryByCategory ?>,
{
grid: {verticalLines: false, horizontalLines: false},
pie: {explode: 10, show: true, labelFormatter: function(){return '';}},
xaxis: {showLabels: false},
yaxis: {showLabels: false},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}},
legend: {container: document.getElementById('statsEntryPerCategoryLegend'), noColumns: 3}
});
}
initStats();
</script>
<script id="jsonStats" type="application/json"><?php
echo htmlspecialchars(json_encode(array(
'average' => $this->average,
'dataCount' => $this->count,
'feedByCategory' => $this->feedByCategory,
'entryByCategory' => $this->entryByCategory,
), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES);
?></script>
<script src="../scripts/stats.js?<?php echo @filemtime(PUBLIC_PATH . '/scripts/stats.js'); ?>"></script>

View file

@ -48,90 +48,27 @@
<div class="stat">
<h2><?php echo _t('admin.stats.entry_per_hour', $this->averageHour); ?></h2>
<div id="statsEntryPerHour" style="height: 300px"></div>
<div id="statsEntryPerHour" class="statGraph"></div>
</div>
<div class="stat half">
<h2><?php echo _t('admin.stats.entry_per_day_of_week', $this->averageDayOfWeek); ?></h2>
<div id="statsEntryPerDayOfWeek" style="height: 300px"></div>
</div><!--
<div id="statsEntryPerDayOfWeek" class="statGraph"></div>
</div>
--><div class="stat half">
<div class="stat half">
<h2><?php echo _t('admin.stats.entry_per_month', $this->averageMonth); ?></h2>
<div id="statsEntryPerMonth" style="height: 300px"></div>
<div id="statsEntryPerMonth" class="statGraph"></div>
</div>
</div>
<script>
"use strict";
function initStats() {
if (!window.Flotr) {
if (window.console) {
console.log('FreshRSS waiting for Flotr…');
}
window.setTimeout(initStats, 50);
return;
}
// Entry per hour
Flotr.draw(document.getElementById('statsEntryPerHour'),
[{
data: <?php echo $this->repartitionHour ?>,
bars: {horizontal: false, show: true}
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 23,
tickFormatter: function(x) {
var x = parseInt(x);
return x + 1;
},
min: -0.9,
max: 23.9,
tickDecimals: 0},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
// Entry per day of week
Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'),
[{
data: <?php echo $this->repartitionDayOfWeek ?>,
bars: {horizontal: false, show: true}
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 6,
tickFormatter: function(x) {
var x = parseInt(x),
days = <?php echo $this->days?>;
return days[x];
},
min: -0.9,
max: 6.9,
tickDecimals: 0},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
// Entry per month
Flotr.draw(document.getElementById('statsEntryPerMonth'),
[{
data: <?php echo $this->repartitionMonth ?>,
bars: {horizontal: false, show: true}
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 12,
tickFormatter: function(x) {
var x = parseInt(x),
months = <?php echo $this->months?>;
return months[(x - 1)];
},
min: 0.1,
max: 12.9,
tickDecimals: 0},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
}
initStats();
</script>
<script id="jsonRepartition" type="application/json"><?php
echo htmlspecialchars(json_encode(array(
'repartitionHour' => $this->repartitionHour,
'repartitionDayOfWeek' => $this->repartitionDayOfWeek,
'days' => $this->days,
'repartitionMonth' => $this->repartitionMonth,
'months' => $this->months,
), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES);
?></script>
<script src="../scripts/repartition.js?<?php echo @filemtime(PUBLIC_PATH . '/scripts/repartition.js'); ?>"></script>

View file

@ -28,7 +28,7 @@
</select>
</li>
<li class="input" style="display:none">
<li class="input" aria-hidden="true">
<input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?php echo _t('sub.category.new'); ?>" />
</li>
@ -62,7 +62,7 @@
</ul>
</div>
<form id="controller-category" method="post" style="display: none;"></form>
<form id="controller-category" method="post" aria-hidden="true"></form>
<?php
foreach ($this->categories as $cat) {

View file

@ -9,7 +9,7 @@
<p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
<?php
if ($key === 'php') {
echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'), PHP_VERSION, '5.2.1');
echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'), PHP_VERSION, '5.3.0');
} else {
echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'));
}

View file

@ -1,5 +1,5 @@
<?php
define('FRESHRSS_VERSION', '1.2.0');
define('FRESHRSS_VERSION', '1.4.0');
define('FRESHRSS_WEBSITE', 'http://freshrss.org');
define('FRESHRSS_WIKI', 'http://doc.freshrss.org');

View file

@ -7,3 +7,4 @@ no-cache.txt
*.lock.txt
last_update.txt
update.php
force-https.txt

View file

@ -75,7 +75,7 @@ return array(
'cache_duration' => 800,
# SimplePie HTTP request timeout in seconds.
'timeout' => 10,
'timeout' => 15,
# If a user has not used FreshRSS for more than x seconds,
# then its feeds are not refreshed anymore.

View file

@ -0,0 +1,7 @@
dailymotion.com
feedburner.com
gravatar.com
gstatic.com
tumblr.com
wordpress.com
youtube.com

View file

@ -38,6 +38,15 @@ return array(
'help' => 'http://www.wallabag.org/',
'form' => 'advanced',
),
'wallabagv2' => array(
'url' => '~URL~/bookmarklet?url=~LINK~',
'transform' => array(
'link' => array('rawurlencode'),
'title' => array(),
),
'help' => 'http://www.wallabag.org/',
'form' => 'advanced',
),
'diaspora' => array(
'url' => '~URL~/bookmarklet?url=~LINK~&amp;title=~TITLE~',
'transform' => array('rawurlencode'),
@ -45,7 +54,7 @@ return array(
'form' => 'advanced',
),
'movim' => array(
'url' => '~URL~/index.php/share/~LINK~',
'url' => '~URL~/?share/~LINK~',
'transform' => array('rawurlencode', 'urlencode'),
'help' => 'https://github.com/edhelas/movim',
'form' => 'advanced',
@ -75,4 +84,9 @@ return array(
'transform' => array(),
'form' => 'simple',
),
'jdh' => array(
'url' => 'https://www.journalduhacker.net/stories/new?url=~LINK~&title=~TITLE~',
'transform' => array('rawurlencode'),
'form' => 'simple',
),
);

View file

@ -15,7 +15,8 @@ class DataAccess {
public function retrieveHeader($url) {
$this->set_context();
return @get_headers($url, TRUE);
$headers = @get_headers($url, 1);
return array_change_key_case($headers);
}
public function saveCache($file, $data) {

View file

@ -99,7 +99,7 @@ class Favicon
switch ($status) {
case '301':
case '302':
$url = $headers['Location'];
$url = isset($headers['location']) ? $headers['location'] : '';
break;
default:
$loop = FALSE;

View file

@ -84,6 +84,17 @@ class Minz_Request {
self::magicQuotesOff();
}
/**
* Return true if the request is over HTTPS, false otherwise (HTTP)
*/
public static function isHttps() {
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
return strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https';
} else {
return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on';
}
}
/**
* Try to guess the base URL from $_SERVER information
*
@ -92,11 +103,7 @@ class Minz_Request {
public static function guessBaseUrl() {
$url = 'http';
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
$https = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https';
} else {
$https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on';
}
$https = self::isHttps();
if (!empty($_SERVER['HTTP_HOST'])) {
$host = $_SERVER['HTTP_HOST'];
@ -130,12 +137,11 @@ class Minz_Request {
/**
* Return the base_url from configuration and add a suffix if given.
*
* @param $base_url_suffix a string to add at base_url (default: empty string)
* @return the base_url with a suffix.
*/
public static function getBaseUrl($base_url_suffix = '') {
public static function getBaseUrl() {
$conf = Minz_Configuration::get('system');
$url = rtrim($conf->base_url, '/\\') . $base_url_suffix;
$url = rtrim($conf->base_url, '/\\');
return filter_var($url, FILTER_SANITIZE_URL);
}

View file

@ -59,18 +59,21 @@ class Minz_Session {
}
}
public static function getCookieDir() {
// Get the script_name (e.g. /p/i/index.php) and keep only the path.
$cookie_dir = empty($_SERVER['REQUEST_URI']) ? '/' : $_SERVER['REQUEST_URI'];
if (substr($cookie_dir, -1) !== '/') {
$cookie_dir = dirname($cookie_dir) . '/';
}
return $cookie_dir;
}
/**
* Spécifie la durée de vie des cookies
* @param $l la durée de vie
*/
public static function keepCookie($l) {
// Get the script_name (e.g. /p/i/index.php) and keep only the path.
$cookie_dir = empty($_SERVER['REQUEST_URI']) ? '/' : $_SERVER['REQUEST_URI'];
if (substr($cookie_dir, -1) !== '/') {
$cookie_dir = dirname($cookie_dir) . '/';
}
session_set_cookie_params($l, $cookie_dir, '', false, true);
session_set_cookie_params($l, self::getCookieDir(), '', Minz_Request::isHttps(), true);
}
@ -83,11 +86,11 @@ class Minz_Session {
}
public static function deleteLongTermCookie($name) {
setcookie($name, '', 1, '', '', false, true);
setcookie($name, '', 1, '', '', Minz_Request::isHttps(), true);
}
public static function setLongTermCookie($name, $value, $expire) {
setcookie($name, $value, $expire, '', '', false, true);
setcookie($name, $value, $expire, '', '', Minz_Request::isHttps(), true);
}
public static function getLongTermCookie($name) {

View file

@ -24,10 +24,16 @@ class Minz_Url {
$url_string = '';
if ($absolute) {
$url_string = Minz_Request::getBaseUrl(PUBLIC_TO_INDEX_PATH);
if ($url_string === PUBLIC_TO_INDEX_PATH) {
$url_string = Minz_Request::getBaseUrl();
if ($url_string == '') {
$url_string = Minz_Request::guessBaseUrl();
}
if ($isArray) {
$url_string .= PUBLIC_TO_INDEX_PATH;
}
if ($absolute === 'root') {
$url_string = parse_url($url_string, PHP_URL_PATH);
}
} else {
$url_string = $isArray ? '.' : PUBLIC_RELATIVE;
}

View file

@ -1123,6 +1123,7 @@ class SimplePie
$this->strip_attributes(false);
$this->add_attributes(false);
$this->set_image_handler(false);
$this->set_https_domains(array());
}
}
@ -1233,6 +1234,19 @@ class SimplePie
$this->sanitize->set_url_replacements($element_attribute);
}
/**
* Set the list of domains for which force HTTPS.
* @see SimplePie_Sanitize::set_https_domains()
* FreshRSS
*/
public function set_https_domains($domains = array())
{
if (is_array($domains))
{
$this->sanitize->set_https_domains($domains);
}
}
/**
* Set the handler to enable the display of cached images.
*
@ -1654,6 +1668,7 @@ class SimplePie
$locate = null;
}
$file->body = trim($file->body);
$this->raw_data = $file->body;
$this->permanent_url = $file->permanent_url;
$headers = $file->headers;

View file

@ -2877,6 +2877,7 @@ class SimplePie_Item
$width = null;
$url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
$url = $this->feed->sanitize->https_url($url); //FreshRSS
if (isset($enclosure[0]['attribs']['']['type']))
{
$type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);

View file

@ -80,8 +80,8 @@ class SimplePie_Misc
public static function absolutize_url($relative, $base)
{
if (substr($relative, 0, 2) === '//')
{//Allow protocol-relative URLs "//www.example.net" which will pick HTTP or HTTPS automatically
return $relative;
{//Protocol-relative URLs "//www.example.net"
return 'https:' . $relative;
}
$iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
if ($iri === false)

View file

@ -73,6 +73,15 @@ class SimplePie_Sanitize
var $force_fsockopen = false;
var $replace_url_attributes = null;
/**
* List of domains for which force HTTPS.
* @see SimplePie_Sanitize::set_https_domains()
* Array is tree split at DNS levels. Example:
* array('biz' => true, 'com' => array('example' => true), 'net' => array('example') => array('www' => true))
* FreshRSS
*/
var $https_domains = array('com' => array('dailymotion' => true, 'youtube' => true));
public function __construct()
{
// Set defaults
@ -242,6 +251,71 @@ class SimplePie_Sanitize
$this->replace_url_attributes = (array) $element_attribute;
}
/**
* Set the list of domains for which force HTTPS.
* @see SimplePie_Misc::https_url()
* Example array('biz', 'example.com', 'example.org', 'www.example.net');
* FreshRSS
*/
public function set_https_domains($domains)
{
$this->https_domains = array();
foreach ($domains as $domain)
{
$domain = trim($domain, ". \t\n\r\0\x0B");
$segments = array_reverse(explode('.', $domain));
$node =& $this->https_domains;
foreach ($segments as $segment)
{//Build a tree
if ($node === true)
{
break;
}
if (!isset($node[$segment]))
{
$node[$segment] = array();
}
$node =& $node[$segment];
}
$node = true;
}
}
/**
* Check if the domain is in the list of forced HTTPS
* FreshRSS
*/
protected function is_https_domain($domain)
{
$domain = trim($domain, '. ');
$segments = array_reverse(explode('.', $domain));
$node =& $this->https_domains;
foreach ($segments as $segment)
{//Explore the tree
if (isset($node[$segment]))
{
$node =& $node[$segment];
}
else
{
break;
}
}
return $node === true;
}
/**
* Force HTTPS for selected Web sites
* FreshRSS
*/
public function https_url($url)
{
return (strtolower(substr($url, 0, 7)) === 'http://') &&
$this->is_https_domain(parse_url($url, PHP_URL_HOST)) ?
substr_replace($url, 's', 4, 0) : //Add the 's' to HTTPS
$url;
}
public function sanitize($data, $type, $base = '')
{
$data = trim($data);
@ -451,7 +525,8 @@ class SimplePie_Sanitize
if ($element->hasAttribute($attribute))
{
$value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
if ($value !== false)
$value = $this->https_url($value); //FreshRSS
if ($value)
{
$element->setAttribute($attribute, $value);
}

View file

@ -105,6 +105,10 @@ function libopml_parse_outline($outline_xml, $strict = true) {
);
}
if (empty($outline['text']) && isset($outline['title'])) {
$outline['text'] = $outline['title'];
}
foreach ($outline_xml->children() as $key => $value) {
// An outline may contain any number of outline children
if ($key === 'outline') {

View file

@ -1,20 +1,49 @@
<?php
if (!function_exists('json_decode')) {
require_once('JSON.php');
function json_decode($var) {
$JSON = new Services_JSON;
return (array)($JSON->decode($var));
function json_decode($var, $assoc = false) {
$JSON = new Services_JSON($assoc ? SERVICES_JSON_LOOSE_TYPE : 0);
return $JSON->decode($var);
}
}
if (!function_exists('json_encode')) {
require_once('JSON.php');
function json_encode($var) {
$JSON = new Services_JSON;
$JSON = new Services_JSON();
return $JSON->encodeUnsafe($var);
}
}
if (!function_exists('array_replace_recursive')) { //PHP 5.2
function arr_recurse($array, $array1) {
foreach ($array1 as $key => $value) {
if (!isset($array[$key]) || (isset($array[$key]) && !is_array($array[$key]))) {
$array[$key] = array(); //create new key in $array, if it is empty or not an array
}
if (is_array($value)) {
$value = arr_recurse($array[$key], $value); // overwrite the value in the base array
}
$array[$key] = $value;
}
return $array;
}
function array_replace_recursive($array, $array1) { //http://php.net/manual/function.array-replace-recursive.php#92574
// handle the arguments, merge one by one
$args = func_get_args();
$array = $args[0];
if (!is_array($array)) {
return $array;
}
for ($i = 1; $i < count($args); $i++) {
if (is_array($args[$i])) {
$array = arr_recurse($array, $args[$i]);
}
}
return $array;
}
}
/**
* Build a directory path by concatenating a list of directory names.
*
@ -180,7 +209,7 @@ function customSimplePie() {
$simplePie->strip_attributes(array_merge($simplePie->strip_attributes, array(
'autoplay', 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup',
'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur',
'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless')));
'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless', 'sizes', 'srcset')));
$simplePie->add_attributes(array(
'img' => array('lazyload' => '', 'postpone' => ''), //http://www.w3.org/TR/resource-priorities/
'audio' => array('lazyload' => '', 'postpone' => '', 'preload' => 'none'),
@ -209,6 +238,16 @@ function customSimplePie() {
'src',
),
));
$https_domains = array();
$force = @file(DATA_PATH . '/force-https.default.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (is_array($force)) {
$https_domains = array_merge($https_domains, $force);
}
$force = @file(DATA_PATH . '/force-https.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (is_array($force)) {
$https_domains = array_merge($https_domains, $force);
}
$simplePie->set_https_domains($https_domains);
return $simplePie;
}
@ -509,3 +548,7 @@ function base64url_encode($data) {
function base64url_decode($data) {
return base64_decode(strtr($data, '-_', '+/'));
}
function _i($icon, $url_only = false) {
return FreshRSS_Themes::icon($icon, $url_only);
}

View file

@ -6,13 +6,8 @@ FileETag None
AddDefaultCharset UTF-8
<IfModule mod_mime.c>
AddType application/json .map
AddType application/font-woff .woff
AddCharset UTF-8 .css
AddCharset UTF-8 .html
AddCharset UTF-8 .js
AddCharset UTF-8 .svg
</IfModule>
<IfModule mod_deflate.c>
@ -21,15 +16,9 @@ AddDefaultCharset UTF-8
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType application/font-woff "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/json "access plus 1 month"
ExpiresByType application/xhtml+xml "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/html "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
<FilesMatch "\.php$">
@ -38,7 +27,7 @@ AddDefaultCharset UTF-8
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(css|html|js|ico|gif|png|woff)$">
<FilesMatch "\.(css|gif|html|ico|js|png|svg|woff)$">
Header merge Cache-Control "public"
</FilesMatch>
</IfModule>

View file

@ -23,7 +23,7 @@ Server-side API compatible with Google Reader API layer 2
require('../../constants.php');
require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader
$ORIGINAL_INPUT = file_get_contents('php://input');
$ORIGINAL_INPUT = file_get_contents('php://input', false, null, -1, 1048576);
if (PHP_INT_SIZE < 8) { //32-bit
function dec2hex($dec) {
@ -46,6 +46,8 @@ function headerVariable($headerName, $varName) {
$upName = 'HTTP_' . strtoupper($headerName);
if (isset($_SERVER[$upName])) {
$header = $_SERVER[$upName];
} elseif (isset($_SERVER['REDIRECT_' . $upName])) {
$header = $_SERVER['REDIRECT_' . $upName];
} elseif (function_exists('getallheaders')) {
$ALL_HEADERS = getallheaders();
if (isset($ALL_HEADERS[$headerName])) {
@ -134,6 +136,7 @@ function checkCompatibility() {
die('FAIL 64-bit or GMP extension!');
}
if ((!array_key_exists('HTTP_AUTHORIZATION', $_SERVER)) && //Apache mod_rewrite trick should be fine
(!array_key_exists('REDIRECT_HTTP_AUTHORIZATION', $_SERVER)) && //Apache mod_rewrite with FCGI
(empty($_SERVER['SERVER_SOFTWARE']) || (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') === false)) && //nginx should be fine
(empty($_SERVER['SERVER_SOFTWARE']) || (stripos($_SERVER['SERVER_SOFTWARE'], 'lighttpd') === false)) && //lighttpd should be fine
((!function_exists('getallheaders')) || (stripos(php_sapi_name(), 'cgi') !== false))) { //Main problem is Apache/CGI mode
@ -361,6 +364,9 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex
case 'user/-/state/com.google/read':
$state = FreshRSS_Entry::STATE_NOT_READ;
break;
case 'user/-/state/com.google/unread':
$state = FreshRSS_Entry::STATE_READ;
break;
default:
$state = FreshRSS_Entry::STATE_ALL;
break;

View file

@ -68,6 +68,15 @@ if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'subscribe') {
exit(isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : '');
}
if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'unsubscribe') {
if (empty($hubJson['lease_end']) || $hubJson['lease_end'] < time()) {
exit(isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : '');
} else {
header('HTTP/1.1 422 Unprocessable Entity');
die('We did not ask to unsubscribe!');
}
}
if ($ORIGINAL_INPUT == '') {
header('HTTP/1.1 422 Unprocessable Entity');
die('Missing XML payload!');

View file

@ -44,14 +44,13 @@ function download_favicon($website, $dest) {
}
function show_default_favicon() {
function show_default_favicon($cacheSeconds = 3600) {
global $default_favicon;
header('Content-Type: image/x-icon');
header('Content-Disposition: inline; filename="default_favicon.ico"');
$default_mtime = @filemtime($default_favicon);
if (!httpConditional($default_mtime, 2592000, 2)) {
if (!httpConditional($default_mtime, $cacheSeconds, 2)) {
readfile($default_favicon);
}
}
@ -68,10 +67,11 @@ $ico = $favicons_dir . $id . '.ico';
$ico_mtime = @filemtime($ico);
$txt_mtime = @filemtime($txt);
header('Content-Type: image/x-icon');
if ($ico_mtime == false || $txt_mtime > $ico_mtime) {
if ($txt_mtime == false) {
show_default_favicon();
show_default_favicon(1800);
return;
}
@ -79,12 +79,11 @@ if ($ico_mtime == false || $txt_mtime > $ico_mtime) {
$url = file_get_contents($txt);
if (!download_favicon($url, $ico)) {
// Download failed, show the default favicon
show_default_favicon();
show_default_favicon(86400);
return;
}
}
header('Content-Type: image/x-icon');
header('Content-Disposition: inline; filename="' . $id . '.ico"');
if (!httpConditional($ico_mtime, 2592000, 2)) {

View file

@ -5,27 +5,11 @@
<meta name="viewport" content="initial-scale=1.0" />
<meta http-equiv="Refresh" content="0; url=i/" />
<title>FreshRSS</title>
<link rel="stylesheet" href="themes/p.css" />
<link rel="shortcut icon" type="image/x-icon" sizes="16x16 64x64" href="favicon.ico" />
<link rel="icon msapplication-TileImage apple-touch-icon" type="image/png" sizes="256x256" href="themes/icons/favicon-256.png" />
<meta name="msapplication-TileColor" content="#FFF" />
<meta name="robots" content="noindex" />
<style>
body {
font-family: sans-serif;
text-align: center;
}
h1 {
font-size: xx-large;
text-shadow: 1px -1px 0 #CCCCCC;
}
h1 a {
color: #0062BE;
text-decoration: none;
}
img {
border: 0;
}
</style>
</head>
<body>

76
sources/p/scripts/install.js Executable file
View file

@ -0,0 +1,76 @@
"use strict";
function show_password() {
var button = this;
var passwordField = document.getElementById(button.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'text');
button.className += ' active';
return false;
}
function hide_password() {
var button = this;
var passwordField = document.getElementById(button.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'password');
button.className = button.className.replace(/(?:^|\s)active(?!\S)/g , '');
return false;
}
var toggles = document.getElementsByClassName('toggle-password');
for (var i = 0 ; i < toggles.length ; i++) {
toggles[i].addEventListener('mousedown', show_password);
toggles[i].addEventListener('mouseup', hide_password);
}
function auth_type_change() {
var auth_type = document.getElementById('auth_type');
if (auth_type) {
var auth_value = auth_type.value,
password_input = document.getElementById('passwordPlain'),
mail_input = document.getElementById('mail_login');
if (auth_value === 'form') {
password_input.required = true;
mail_input.required = false;
} else if (auth_value === 'persona') {
password_input.required = false;
mail_input.required = true;
} else {
password_input.required = false;
mail_input.required = false;
}
}
}
var auth_type = document.getElementById('auth_type');
if (auth_type) {
auth_type_change();
auth_type.addEventListener('change', auth_type_change);
}
function mySqlShowHide() {
var mysql = document.getElementById('mysql');
if (mysql) {
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 = '';
}
}
}
var bd_type = document.getElementById('type');
if (bd_type) {
mySqlShowHide();
bd_type.addEventListener('change', mySqlShowHide);
}
function ask_confirmation(e) {
var str_confirmation = this.getAttribute('data-str-confirm');
if (!confirm(str_confirmation)) {
e.preventDefault();
}
}
var confirms = document.getElementsByClassName('confirm');
for (var i = 0 ; i < confirms.length ; i++) {
confirms[i].addEventListener('click', ask_confirmation);
}

File diff suppressed because one or more lines are too long

View file

@ -244,20 +244,19 @@ function toggleContent(new_active, old_active) {
new_active.toggleClass('active');
}
var box_to_move = "html,body",
relative_move = false;
if (context['current_view'] == 'global') {
box_to_move = "#panel";
relative_move = true;
}
var relative_move = context['current_view'] === 'global',
box_to_move = $(relative_move ? "#panel" : "html,body");
if (context['sticky_post']) {
var prev_article = new_active.prevAll('.flux'),
new_pos = new_active.position().top,
old_scroll = $(box_to_move).scrollTop();
new_pos = new_active.offset().top,
old_scroll = box_to_move.scrollTop();
if (prev_article.length > 0 && new_pos - prev_article.position().top <= 150) {
new_pos = prev_article.position().top;
if (prev_article.length > 0 && new_pos - prev_article.offset().top <= 150) {
new_pos = prev_article.offset().top;
if (relative_move) {
new_pos -= box_to_move.offset().top;
}
}
if (context['hide_posts']) {
@ -267,7 +266,7 @@ function toggleContent(new_active, old_active) {
if (old_active[0] !== new_active[0]) {
new_active.children(".flux_content").first().each(function () {
$(box_to_move).scrollTop(new_pos).scrollTop();
box_to_move.scrollTop(new_pos).scrollTop();
});
}
} else {
@ -275,7 +274,7 @@ function toggleContent(new_active, old_active) {
new_pos += old_scroll;
}
$(box_to_move).scrollTop(new_pos).scrollTop();
box_to_move.scrollTop(new_pos).scrollTop();
}
}
@ -451,11 +450,8 @@ function auto_share(key) {
}
}
function inMarkViewport(flux, box_to_follow, relative_follow) {
var top = flux.position().top;
if (relative_follow) {
top += box_to_follow.scrollTop();
}
function inMarkViewport(flux, box_to_follow) {
var top = flux.offset().top;
var height = flux.height(),
begin = top + 3 * height / 4,
bot = Math.min(begin + 75, top + height),
@ -466,17 +462,15 @@ function inMarkViewport(flux, box_to_follow, relative_follow) {
}
function init_posts() {
var box_to_follow = $(window),
relative_follow = false;
if (context['current_view'] == 'global') {
var box_to_follow = $(window);
if (context['current_view'] === 'global') {
box_to_follow = $("#panel");
relative_follow = true;
}
if (context['auto_mark_scroll']) {
box_to_follow.scroll(function () {
$('.not_read:visible').each(function () {
if ($(this).children(".flux_content").is(':visible') && inMarkViewport($(this), box_to_follow, relative_follow)) {
if ($(this).children(".flux_content").is(':visible') && inMarkViewport($(this), box_to_follow)) {
mark_read($(this), true);
}
});
@ -490,10 +484,7 @@ function init_posts() {
return;
}
var boxBot = box_to_follow.scrollTop() + box_to_follow.height(),
load_more_top = load_more.position().top;
if (relative_follow) {
load_more_top += box_to_follow.scrollTop();
}
load_more_top = load_more.offset().top;
if (boxBot >= load_more_top) {
load_more_posts();
}
@ -765,7 +756,7 @@ function init_nav_entries() {
$nav_entries.find('.up').click(function () {
var active_item = $(".flux.current"),
windowTop = $(window).scrollTop(),
item_top = active_item.position().top;
item_top = active_item.offset().top;
if (windowTop > item_top) {
$("html,body").scrollTop(item_top);
@ -776,6 +767,31 @@ function init_nav_entries() {
});
}
// <actualize>
var feed_processed = 0;
function updateFeed(feeds, feeds_count) {
var feed = feeds.pop();
if (feed == undefined) {
return;
}
$.ajax({
type: 'POST',
url: feed['url'],
}).complete(function (data) {
feed_processed++;
$("#actualizeProgress .progress").html(feed_processed + " / " + feeds_count);
$("#actualizeProgress .title").html(feed['title']);
if (feed_processed === feeds_count) {
window.location.reload();
} else {
updateFeed(feeds, feeds_count);
}
});
}
function init_actualize() {
var auto = false;
@ -786,14 +802,25 @@ function init_actualize() {
ajax_loading = true;
$.getScript('./?c=javascript&a=actualize').done(function () {
if (auto && feed_count < 1) {
$.getJSON('./?c=javascript&a=actualize').done(function (data) {
if (auto && data.feeds.length < 1) {
auto = false;
ajax_loading = false;
return false;
}
updateFeeds();
if (data.feeds.length === 0) {
openNotification(data.feedback_no_refresh, "good");
ajax_loading = false;
return;
}
//Progress bar
var feeds_count = data.feeds.length;
$('body').after('<div id="actualizeProgress" class="notification good">' + data.feedback_actualize +
'<br /><span class="title">/</span><br /><span class="progress">0 / ' + feeds_count +
'</span></div>');
for (var i = 10; i > 0; i--) {
updateFeed(data.feeds, feeds_count);
}
});
return false;
@ -804,7 +831,7 @@ function init_actualize() {
$("#actualize").click();
}
}
// </actualize>
// <notification>
var notification = null,
@ -872,7 +899,7 @@ function notifs_html5_show(nb) {
var notification = new window.Notification(i18n['notif_title_articles'], {
icon: "../themes/icons/favicon-256.png",
body: i18n['notif_body_articles'].replace("\d", nb),
body: i18n['notif_body_articles'].replace('%d', nb),
tag: "freshRssNewArticles"
});
@ -908,7 +935,7 @@ function refreshUnreads() {
if ((incUnreadsFeed(null, feed_id, nbUnreads - feed_unreads) || isAll) && //Update of current view?
(nbUnreads - feed_unreads > 0)) {
$('#new-article').show();
$('#new-article').attr('aria-hidden', 'false').show();
new_articles = true;
};
});
@ -1131,10 +1158,10 @@ function init_feed_observers() {
$('select[id="category"]').on('change', function() {
var detail = $('#new_category_name').parent();
if ($(this).val() === 'nc') {
detail.show();
detail.attr('aria-hidden', 'false').show();
detail.find('input').focus();
} else {
detail.hide();
detail.attr('aria-hidden', 'true').hide();
}
});
}
@ -1254,14 +1281,32 @@ function init_configuration_alert() {
});
}
function init_subscription() {
$('body').on('click', '.bookmarkClick', function (e) {
return false;
});
}
function parseJsonVars() {
var jsonVars = document.getElementById('jsonVars'),
json = JSON.parse(jsonVars.innerHTML);
jsonVars.outerHTML = '';
window.context = json.context;
window.shortcuts = json.shortcuts;
window.url = json.url;
window.i18n = json.i18n;
window.icons = json.icons;
}
function init_all() {
if (!(window.$ && window.context)) {
if (!window.$) {
if (window.console) {
console.log('FreshRSS waiting for JS…');
}
window.setTimeout(init_all, 50);
return;
}
parseJsonVars();
init_notifications();
init_confirm_action();
$stream = $('#stream');
@ -1278,6 +1323,7 @@ function init_all() {
init_notifs_html5();
window.setInterval(refreshUnreads, 120000);
} else {
init_subscription();
init_crypto_form();
init_share_observers();
init_remove_observers();

View file

@ -1,7 +1,7 @@
"use strict";
function init_persona() {
if (!(navigator.id && window.$)) {
if (!(navigator.id && window.$ && window.url)) {
if (window.console) {
console.log('FreshRSS (Persona) waiting for JS…');
}

View file

@ -0,0 +1,72 @@
"use strict";
function initStats() {
if (!window.Flotr) {
if (window.console) {
console.log('FreshRSS waiting for Flotr…');
}
window.setTimeout(initStats, 50);
return;
}
var jsonRepartition = document.getElementById('jsonRepartition'),
stats = JSON.parse(jsonRepartition.innerHTML);
jsonRepartition.outerHTML = '';
// Entry per hour
Flotr.draw(document.getElementById('statsEntryPerHour'),
[{
data: stats.repartitionHour,
bars: {horizontal: false, show: true}
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 23,
tickFormatter: function(x) {
var x = parseInt(x);
return x + 1;
},
min: -0.9,
max: 23.9,
tickDecimals: 0},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
// Entry per day of week
Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'),
[{
data: stats.repartitionDayOfWeek,
bars: {horizontal: false, show: true}
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 6,
tickFormatter: function(x) {
var x = parseInt(x);
return stats.days[x];
},
min: -0.9,
max: 6.9,
tickDecimals: 0},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
// Entry per month
Flotr.draw(document.getElementById('statsEntryPerMonth'),
[{
data: stats.repartitionMonth,
bars: {horizontal: false, show: true}
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 12,
tickFormatter: function(x) {
var x = parseInt(x);
return stats.months[(x - 1)];
},
min: 0.1,
max: 12.9,
tickDecimals: 0},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
}
initStats();

56
sources/p/scripts/stats.js Executable file
View file

@ -0,0 +1,56 @@
"use strict";
function initStats() {
if (!window.Flotr) {
if (window.console) {
console.log('FreshRSS waiting for Flotr…');
}
window.setTimeout(initStats, 50);
return;
}
var jsonStats = document.getElementById('jsonStats'),
stats = JSON.parse(jsonStats.innerHTML);
jsonStats.outerHTML = '';
// Entry per day
var avg = [];
for (var i = -31; i <= 0; i++) {
avg.push([i, stats.average]);
}
Flotr.draw(document.getElementById('statsEntryPerDay'),
[{
data: stats.dataCount,
bars: {horizontal: false, show: true}
},{
data: avg,
lines: {show: true},
label: stats.average,
}],
{
grid: {verticalLines: false},
xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0, min: -30.75, max: -0.25},
yaxis: {min: 0},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
});
// Feed per category
Flotr.draw(document.getElementById('statsFeedPerCategory'),
stats.feedByCategory,
{
grid: {verticalLines: false, horizontalLines: false},
pie: {explode: 10, show: true, labelFormatter: function(){return '';}},
xaxis: {showLabels: false},
yaxis: {showLabels: false},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}},
legend: {container: document.getElementById('statsFeedPerCategoryLegend'), noColumns: 3}
});
// Entry per category
Flotr.draw(document.getElementById('statsEntryPerCategory'),
stats.entryByCategory,
{
grid: {verticalLines: false, horizontalLines: false},
pie: {explode: 10, show: true, labelFormatter: function(){return '';}},
xaxis: {showLabels: false},
yaxis: {showLabels: false},
mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}},
legend: {container: document.getElementById('statsEntryPerCategoryLegend'), noColumns: 3}
});
}
initStats();

21
sources/p/themes/.htaccess Executable file
View file

@ -0,0 +1,21 @@
<IfModule mod_mime.c>
AddType application/font-woff .woff
AddCharset UTF-8 .css
AddCharset UTF-8 .svg
</IfModule>
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType application/font-woff "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.svg$">
Header set Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'"
</FilesMatch>
</IfModule>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -110,6 +110,11 @@ td.numeric {
/*=== COMPONENTS */
/*===============*/
[aria-hidden="true"] {
display: none;
}
/*=== Forms */
.form-group::after {
content: "";
@ -620,6 +625,9 @@ br + br + br {
.stat > table {
width: 100%;
}
.statGraph {
height: 300px;
}
/*=== GLOBAL VIEW */
/*================*/

13
sources/p/themes/index.html Executable file
View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-GB" lang="en-GB">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Refresh" content="0; url=/" />
<title>Redirection</title>
<meta name="robots" content="noindex" />
</head>
<body>
<p><a href="/">Redirection</a></p>
</body>
</html>

17
sources/p/themes/p.css Executable file
View file

@ -0,0 +1,17 @@
@charset "UTF-8";
body {
font-family: sans-serif;
text-align: center;
}
h1 {
font-size: xx-large;
text-shadow: 1px -1px 0 #CCCCCC;
}
h1 a {
color: #0062BE;
text-decoration: none;
}
img {
border: 0;
}

View file

@ -0,0 +1,32 @@
<?php
class FreshRSS_CategoryTest extends \PHPUnit_Framework_TestCase {
public function test__construct_whenNoParameters_createsObjectWithDefaultValues() {
$category = new FreshRSS_Category();
$this->assertEquals(0, $category->id());
$this->assertEquals('', $category->name());
}
/**
* @param string $input
* @param string $expected
* @dataProvider provideValidNames
*/
public function test_name_whenValidValue_storesModifiedValue($input, $expected) {
$category = new FreshRSS_Category($input);
$this->assertEquals($expected, $category->name());
}
public function provideValidNames() {
return array(
array('', ''),
array('this string does not need trimming', 'this string does not need trimming'),
array(' this string needs trimming on left', 'this string needs trimming on left'),
array('this string needs trimming on right ', 'this string needs trimming on right'),
array(' this string needs trimming on both ends ', 'this string needs trimming on both ends'),
array(str_repeat('This string needs to be shortened because its length is way too long. ', 4), str_repeat('This string needs to be shortened because its length is way too long. ', 3) . 'This string needs to be shortened because its'),
);
}
}

View file

@ -0,0 +1,5 @@
<?php
class ContextTest extends \PHPUnit_Framework_TestCase {
}

View file

@ -0,0 +1,293 @@
<?php
require_once(LIB_PATH . '/lib_date.php');
class SearchTest extends \PHPUnit_Framework_TestCase {
/**
* @dataProvider provideEmptyInput
* @param string|null $input
*/
public function test__construct_whenInputIsEmpty_getsOnlyNullValues($input) {
$search = new FreshRSS_Search($input);
$this->assertEquals('', $search->getRawInput());
$this->assertNull($search->getIntitle());
$this->assertNull($search->getMinDate());
$this->assertNull($search->getMaxDate());
$this->assertNull($search->getMinPubdate());
$this->assertNull($search->getMaxPubdate());
$this->assertNull($search->getAuthor());
$this->assertNull($search->getTags());
$this->assertNull($search->getSearch());
}
/**
* Return an array of values for the search object.
* Here is the description of the values
* @return array
*/
public function provideEmptyInput() {
return array(
array(''),
array(null),
);
}
/**
* @dataProvider provideIntitleSearch
* @param string $input
* @param string $intitle_value
* @param string|null $search_value
*/
public function test__construct_whenInputContainsIntitle_setsIntitlePropery($input, $intitle_value, $search_value) {
$search = new FreshRSS_Search($input);
$this->assertEquals($intitle_value, $search->getIntitle());
$this->assertEquals($search_value, $search->getSearch());
}
/**
* @return array
*/
public function provideIntitleSearch() {
return array(
array('intitle:word1', 'word1', null),
array('intitle:word1 word2', 'word1', array('word2')),
array('intitle:"word1 word2"', 'word1 word2', null),
array("intitle:'word1 word2'", 'word1 word2', null),
array('word1 intitle:word2', 'word2', array('word1')),
array('word1 intitle:word2 word3', 'word2', array('word1', 'word3')),
array('word1 intitle:"word2 word3"', 'word2 word3', array('word1')),
array("word1 intitle:'word2 word3'", 'word2 word3', array('word1')),
array('intitle:word1 intitle:word2', 'word1', array('intitle:word2')),
array('intitle: word1 word2', null, array('word1', 'word2')),
array('intitle:123', '123', null),
array('intitle:"word1 word2" word3"', 'word1 word2', array('word3"')),
array("intitle:'word1 word2' word3'", 'word1 word2', array("word3'")),
array('intitle:"word1 word2\' word3"', "word1 word2' word3", null),
array("intitle:'word1 word2\" word3'", 'word1 word2" word3', null),
array("intitle:word1 'word2 word3' word4", 'word1', array('word2 word3', 'word4')),
);
}
/**
* @dataProvider provideAuthorSearch
* @param string $input
* @param string $author_value
* @param string|null $search_value
*/
public function test__construct_whenInputContainsAuthor_setsAuthorValue($input, $author_value, $search_value) {
$search = new FreshRSS_Search($input);
$this->assertEquals($author_value, $search->getAuthor());
$this->assertEquals($search_value, $search->getSearch());
}
/**
* @return array
*/
public function provideAuthorSearch() {
return array(
array('author:word1', 'word1', null),
array('author:word1 word2', 'word1', array('word2')),
array('author:"word1 word2"', 'word1 word2', null),
array("author:'word1 word2'", 'word1 word2', null),
array('word1 author:word2', 'word2', array('word1')),
array('word1 author:word2 word3', 'word2', array('word1', 'word3')),
array('word1 author:"word2 word3"', 'word2 word3', array('word1')),
array("word1 author:'word2 word3'", 'word2 word3', array('word1')),
array('author:word1 author:word2', 'word1', array('author:word2')),
array('author: word1 word2', null, array('word1', 'word2')),
array('author:123', '123', null),
array('author:"word1 word2" word3"', 'word1 word2', array('word3"')),
array("author:'word1 word2' word3'", 'word1 word2', array("word3'")),
array('author:"word1 word2\' word3"', "word1 word2' word3", null),
array("author:'word1 word2\" word3'", 'word1 word2" word3', null),
array("author:word1 'word2 word3' word4", 'word1', array('word2 word3', 'word4')),
);
}
/**
* @dataProvider provideInurlSearch
* @param string $input
* @param string $inurl_value
* @param string|null $search_value
*/
public function test__construct_whenInputContainsInurl_setsInurlValue($input, $inurl_value, $search_value) {
$search = new FreshRSS_Search($input);
$this->assertEquals($inurl_value, $search->getInurl());
$this->assertEquals($search_value, $search->getSearch());
}
/**
* @return array
*/
public function provideInurlSearch() {
return array(
array('inurl:word1', 'word1', null),
array('inurl: word1', null, array('word1')),
array('inurl:123', '123', null),
array('inurl:word1 word2', 'word1', array('word2')),
array('inurl:"word1 word2"', '"word1', array('word2"')),
array("inurl:word1 'word2 word3' word4", 'word1', array('word2 word3', 'word4')),
);
}
/**
* @dataProvider provideDateSearch
* @param string $input
* @param string $min_date_value
* @param string $max_date_value
*/
public function test__construct_whenInputContainsDate_setsDateValues($input, $min_date_value, $max_date_value) {
$search = new FreshRSS_Search($input);
$this->assertEquals($min_date_value, $search->getMinDate());
$this->assertEquals($max_date_value, $search->getMaxDate());
}
/**
* @return array
*/
public function provideDateSearch() {
return array(
array('date:2007-03-01T13:00:00Z/2008-05-11T15:30:00Z', '1172754000', '1210519800'),
array('date:2007-03-01T13:00:00Z/P1Y2M10DT2H30M', '1172754000', '1210516199'),
array('date:P1Y2M10DT2H30M/2008-05-11T15:30:00Z', '1172757601', '1210519800'),
array('date:2007-03-01/2008-05-11', '1172725200', '1210564799'),
array('date:2007-03-01/', '1172725200', ''),
array('date:/2008-05-11', '', '1210564799'),
);
}
/**
* @dataProvider providePubdateSearch
* @param string $input
* @param string $min_pubdate_value
* @param string $max_pubdate_value
*/
public function test__construct_whenInputContainsPubdate_setsPubdateValues($input, $min_pubdate_value, $max_pubdate_value) {
$search = new FreshRSS_Search($input);
$this->assertEquals($min_pubdate_value, $search->getMinPubdate());
$this->assertEquals($max_pubdate_value, $search->getMaxPubdate());
}
/**
* @return array
*/
public function providePubdateSearch() {
return array(
array('pubdate:2007-03-01T13:00:00Z/2008-05-11T15:30:00Z', '1172754000', '1210519800'),
array('pubdate:2007-03-01T13:00:00Z/P1Y2M10DT2H30M', '1172754000', '1210516199'),
array('pubdate:P1Y2M10DT2H30M/2008-05-11T15:30:00Z', '1172757601', '1210519800'),
array('pubdate:2007-03-01/2008-05-11', '1172725200', '1210564799'),
array('pubdate:2007-03-01/', '1172725200', ''),
array('pubdate:/2008-05-11', '', '1210564799'),
);
}
/**
* @dataProvider provideTagsSearch
* @param string $input
* @param string $tags_value
* @param string|null $search_value
*/
public function test__construct_whenInputContainsTags_setsTagsValue($input, $tags_value, $search_value) {
$search = new FreshRSS_Search($input);
$this->assertEquals($tags_value, $search->getTags());
$this->assertEquals($search_value, $search->getSearch());
}
/**
* @return array
*/
public function provideTagsSearch() {
return array(
array('#word1', array('word1'), null),
array('# word1', null, array('#', 'word1')),
array('#123', array('123'), null),
array('#word1 word2', array('word1'), array('word2')),
array('#"word1 word2"', array('"word1'), array('word2"')),
array('#word1 #word2', array('word1', 'word2'), null),
array("#word1 'word2 word3' word4", array('word1'), array('word2 word3', 'word4')),
);
}
/**
* @dataProvider provideMultipleSearch
* @param string $input
* @param string $author_value
* @param string $min_date_value
* @param string $max_date_value
* @param string $intitle_value
* @param string $inurl_value
* @param string $min_pubdate_value
* @param string $max_pubdate_value
* @param array $tags_value
* @param string|null $search_value
*/
public function test__construct_whenInputContainsMultipleKeywords_setsValues($input, $author_value, $min_date_value, $max_date_value, $intitle_value, $inurl_value, $min_pubdate_value, $max_pubdate_value, $tags_value, $search_value) {
$search = new FreshRSS_Search($input);
$this->assertEquals($author_value, $search->getAuthor());
$this->assertEquals($min_date_value, $search->getMinDate());
$this->assertEquals($max_date_value, $search->getMaxDate());
$this->assertEquals($intitle_value, $search->getIntitle());
$this->assertEquals($inurl_value, $search->getInurl());
$this->assertEquals($min_pubdate_value, $search->getMinPubdate());
$this->assertEquals($max_pubdate_value, $search->getMaxPubdate());
$this->assertEquals($tags_value, $search->getTags());
$this->assertEquals($search_value, $search->getSearch());
$this->assertEquals($input, $search->getRawInput());
}
public function provideMultipleSearch() {
return array(
array(
'author:word1 date:2007-03-01/2008-05-11 intitle:word2 inurl:word3 pubdate:2007-03-01/2008-05-11 #word4 #word5',
'word1',
'1172725200',
'1210564799',
'word2',
'word3',
'1172725200',
'1210564799',
array('word4', 'word5'),
null,
),
array(
'word6 intitle:word2 inurl:word3 pubdate:2007-03-01/2008-05-11 #word4 author:word1 #word5 date:2007-03-01/2008-05-11',
'word1',
'1172725200',
'1210564799',
'word2',
'word3',
'1172725200',
'1210564799',
array('word4', 'word5'),
array('word6'),
),
array(
'word6 intitle:word2 inurl:word3 pubdate:2007-03-01/2008-05-11 #word4 author:word1 #word5 word7 date:2007-03-01/2008-05-11',
'word1',
'1172725200',
'1210564799',
'word2',
'word3',
'1172725200',
'1210564799',
array('word4', 'word5'),
array('word6', 'word7'),
),
array(
'word6 intitle:word2 inurl:word3 pubdate:2007-03-01/2008-05-11 #word4 author:word1 #word5 "word7 word8" date:2007-03-01/2008-05-11',
'word1',
'1172725200',
'1210564799',
'word2',
'word3',
'1172725200',
'1210564799',
array('word4', 'word5'),
array('word7 word8', 'word6'),
),
);
}
}

View file

@ -0,0 +1,229 @@
<?php
/**
* Description of UserQueryTest
*/
class UserQueryTest extends \PHPUnit_Framework_TestCase {
public function test__construct_whenAllQuery_storesAllParameters() {
$query = array('get' => 'a');
$user_query = new FreshRSS_UserQuery($query);
$this->assertEquals('all', $user_query->getGetName());
$this->assertEquals('all', $user_query->getGetType());
}
public function test__construct_whenFavoriteQuery_storesFavoriteParameters() {
$query = array('get' => 's');
$user_query = new FreshRSS_UserQuery($query);
$this->assertEquals('favorite', $user_query->getGetName());
$this->assertEquals('favorite', $user_query->getGetType());
}
/**
* @expectedException Exceptions/FreshRSS_DAO_Exception
* @expectedExceptionMessage Category DAO is not loaded in UserQuery
*/
public function test__construct_whenCategoryQueryAndNoDao_throwsException() {
$this->markTestIncomplete('There is a problem with the exception autoloading. We need to make a better autoloading process');
$query = array('get' => 'c_1');
new FreshRSS_UserQuery($query);
}
public function test__construct_whenCategoryQuery_storesCategoryParameters() {
$category_name = 'some category name';
$cat = $this->getMock('FreshRSS_Category');
$cat->expects($this->atLeastOnce())
->method('name')
->withAnyParameters()
->willReturn($category_name);
$cat_dao = $this->getMock('FreshRSS_Searchable');
$cat_dao->expects($this->atLeastOnce())
->method('searchById')
->withAnyParameters()
->willReturn($cat);
$query = array('get' => 'c_1');
$user_query = new FreshRSS_UserQuery($query, null, $cat_dao);
$this->assertEquals($category_name, $user_query->getGetName());
$this->assertEquals('category', $user_query->getGetType());
}
/**
* @expectedException Exceptions/FreshRSS_DAO_Exception
* @expectedExceptionMessage Feed DAO is not loaded in UserQuery
*/
public function test__construct_whenFeedQueryAndNoDao_throwsException() {
$this->markTestIncomplete('There is a problem with the exception autoloading. We need to make a better autoloading process');
$query = array('get' => 'c_1');
new FreshRSS_UserQuery($query);
}
public function test__construct_whenFeedQuery_storesFeedParameters() {
$feed_name = 'some feed name';
$feed = $this->getMock('FreshRSS_Feed', array(), array('', false));
$feed->expects($this->atLeastOnce())
->method('name')
->withAnyParameters()
->willReturn($feed_name);
$feed_dao = $this->getMock('FreshRSS_Searchable');
$feed_dao->expects($this->atLeastOnce())
->method('searchById')
->withAnyParameters()
->willReturn($feed);
$query = array('get' => 'f_1');
$user_query = new FreshRSS_UserQuery($query, $feed_dao, null);
$this->assertEquals($feed_name, $user_query->getGetName());
$this->assertEquals('feed', $user_query->getGetType());
}
public function test__construct_whenUnknownQuery_doesStoreParameters() {
$query = array('get' => 'q');
$user_query = new FreshRSS_UserQuery($query);
$this->assertNull($user_query->getGetName());
$this->assertNull($user_query->getGetType());
}
public function test__construct_whenName_storesName() {
$name = 'some name';
$query = array('name' => $name);
$user_query = new FreshRSS_UserQuery($query);
$this->assertEquals($name, $user_query->getName());
}
public function test__construct_whenOrder_storesOrder() {
$order = 'some order';
$query = array('order' => $order);
$user_query = new FreshRSS_UserQuery($query);
$this->assertEquals($order, $user_query->getOrder());
}
public function test__construct_whenState_storesState() {
$state = 'some state';
$query = array('state' => $state);
$user_query = new FreshRSS_UserQuery($query);
$this->assertEquals($state, $user_query->getState());
}
public function test__construct_whenUrl_storesUrl() {
$url = 'some url';
$query = array('url' => $url);
$user_query = new FreshRSS_UserQuery($query);
$this->assertEquals($url, $user_query->getUrl());
}
public function testToArray_whenNoData_returnsEmptyArray() {
$user_query = new FreshRSS_UserQuery(array());
$this->assertInternalType('array', $user_query->toArray());
$this->assertCount(0, $user_query->toArray());
}
public function testToArray_whenData_returnsArray() {
$query = array(
'get' => 's',
'name' => 'some name',
'order' => 'some order',
'search' => 'some search',
'state' => 'some state',
'url' => 'some url',
);
$user_query = new FreshRSS_UserQuery($query);
$this->assertInternalType('array', $user_query->toArray());
$this->assertCount(6, $user_query->toArray());
$this->assertEquals($query, $user_query->toArray());
}
public function testHasSearch_whenSearch_returnsTrue() {
$query = array(
'search' => 'some search',
);
$user_query = new FreshRSS_UserQuery($query);
$this->assertTrue($user_query->hasSearch());
}
public function testHasSearch_whenNoSearch_returnsFalse() {
$user_query = new FreshRSS_UserQuery(array());
$this->assertFalse($user_query->hasSearch());
}
public function testHasParameters_whenAllQuery_returnsFalse() {
$query = array('get' => 'a');
$user_query = new FreshRSS_UserQuery($query);
$this->assertFalse($user_query->hasParameters());
}
public function testHasParameters_whenNoParameter_returnsFalse() {
$query = array();
$user_query = new FreshRSS_UserQuery($query);
$this->assertFalse($user_query->hasParameters());
}
public function testHasParameters_whenParameter_returnTrue() {
$query = array('get' => 's');
$user_query = new FreshRSS_UserQuery($query);
$this->assertTrue($user_query->hasParameters());
}
public function testIsDeprecated_whenCategoryExists_returnFalse() {
$cat = $this->getMock('FreshRSS_Category');
$cat_dao = $this->getMock('FreshRSS_Searchable');
$cat_dao->expects($this->atLeastOnce())
->method('searchById')
->withAnyParameters()
->willReturn($cat);
$query = array('get' => 'c_1');
$user_query = new FreshRSS_UserQuery($query, null, $cat_dao);
$this->assertFalse($user_query->isDeprecated());
}
public function testIsDeprecated_whenCategoryDoesNotExist_returnTrue() {
$cat_dao = $this->getMock('FreshRSS_Searchable');
$cat_dao->expects($this->atLeastOnce())
->method('searchById')
->withAnyParameters()
->willReturn(null);
$query = array('get' => 'c_1');
$user_query = new FreshRSS_UserQuery($query, null, $cat_dao);
$this->assertTrue($user_query->isDeprecated());
}
public function testIsDeprecated_whenFeedExists_returnFalse() {
$feed = $this->getMock('FreshRSS_Feed', array(), array('', false));
$feed_dao = $this->getMock('FreshRSS_Searchable');
$feed_dao->expects($this->atLeastOnce())
->method('searchById')
->withAnyParameters()
->willReturn($feed);
$query = array('get' => 'f_1');
$user_query = new FreshRSS_UserQuery($query, $feed_dao, null);
$this->assertFalse($user_query->isDeprecated());
}
public function testIsDeprecated_whenFeedDoesNotExist_returnTrue() {
$feed_dao = $this->getMock('FreshRSS_Searchable');
$feed_dao->expects($this->atLeastOnce())
->method('searchById')
->withAnyParameters()
->willReturn(null);
$query = array('get' => 'f_1');
$user_query = new FreshRSS_UserQuery($query, $feed_dao, null);
$this->assertTrue($user_query->isDeprecated());
}
public function testIsDeprecated_whenAllQuery_returnFalse() {
$query = array('get' => 'a');
$user_query = new FreshRSS_UserQuery($query);
$this->assertFalse($user_query->isDeprecated());
}
public function testIsDeprecated_whenFavoriteQuery_returnFalse() {
$query = array('get' => 's');
$user_query = new FreshRSS_UserQuery($query);
$this->assertFalse($user_query->isDeprecated());
}
public function testIsDeprecated_whenUnknownQuery_returnFalse() {
$query = array('get' => 'q');
$user_query = new FreshRSS_UserQuery($query);
$this->assertFalse($user_query->isDeprecated());
}
}

7
sources/tests/bootstrap.php Executable file
View file

@ -0,0 +1,7 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
require('../constants.php');
require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader

13
sources/tests/phpunit.xml Executable file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="bootstrap.php">
<filter>
<whitelist>
<directory suffix=".php">../app</directory>
</whitelist>
</filter>
<testsuites>
<testsuite name="FreshRSS">
<directory>app</directory>
</testsuite>
</testsuites>
</phpunit>