From e3de9d7dd1331f9718e04cc98e9ca7cfa27cf4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20L=C3=A9cureuil?= Date: Sun, 17 May 2020 14:46:00 +0200 Subject: Sync with master of moonmoon ( version 9.0.0-rc) Source from https://github.com/Emmafrs/moonmoon/ --- common/app/app.php | 37 ++--- common/app/classes/CSRF.php | 55 ++++++++ common/app/classes/Cache.php | 254 ++++++++++++++++++++++++++++++++++ common/app/classes/Opml.php | 70 ++++++++++ common/app/classes/OpmlManager.php | 50 +++++++ common/app/classes/Planet.php | 266 ++++++++++++++++++++++++++++++++++++ common/app/classes/PlanetConfig.php | 166 ++++++++++++++++++---- common/app/classes/PlanetError.php | 23 +++- common/app/classes/PlanetFeed.php | 20 ++- common/app/classes/PlanetItem.php | 11 +- common/app/classes/Simplel10n.php | 52 +++++++ common/app/helpers.php | 130 ++++++++++++++++++ common/app/l10n/de.lang | 219 +++++++++++++++++++++++++++++ common/app/l10n/en.lang | 4 + common/app/l10n/es.lang | 244 +++++++++++++++++++++++++++++++++ common/app/l10n/extract.php | 13 +- common/app/l10n/fr.lang | 4 + 17 files changed, 1543 insertions(+), 75 deletions(-) create mode 100644 common/app/classes/CSRF.php create mode 100644 common/app/classes/Cache.php create mode 100644 common/app/classes/Opml.php create mode 100644 common/app/classes/OpmlManager.php create mode 100644 common/app/classes/Planet.php create mode 100755 common/app/classes/Simplel10n.php create mode 100644 common/app/helpers.php create mode 100644 common/app/l10n/de.lang create mode 100644 common/app/l10n/es.lang (limited to 'common/app') diff --git a/common/app/app.php b/common/app/app.php index 0703ac5..0797cc7 100755 --- a/common/app/app.php +++ b/common/app/app.php @@ -1,29 +1,15 @@ time()) { + return true; + } + + @unlink($filename); + + return false; + } + + /** + * Builds a filename/path from group, id and + * store. + * + * @param string $group Group to store data under + * @param string $id Unique ID of this data + */ + protected static function getFilename($group, $id) + { + $id = md5($id); + + return self::$store . self::$prefix . "{$group}_{$id}"; + } + + /** + * Sets the filename prefix to use + * + * @param string $prefix Filename Prefix to use + */ + public static function setPrefix($prefix) + { + self::$prefix = $prefix; + } + + /** + * Sets the store for cache files. Defaults to + * /dev/shm. Must have trailing slash. + * + * @param string $store The dir to store the cache data in + */ + public static function setStore($store) + { + self::$store = $store; + } + } + + /** + * Output Cache extension of base caching class + */ + class OutputCache extends Cache + { + /** + * Group of currently being recorded data + * @var string + */ + private static $group; + + /** + * ID of currently being recorded data + * @var string + */ + private static $id; + + /** + * Ttl of currently being recorded data + * @var int + */ + private static $ttl; + + /** + * Starts caching off. Returns true if cached, and dumps + * the output. False if not cached and start output buffering. + * + * @param string $group Group to store data under + * @param string $id Unique ID of this data + * @param int $ttl How long to cache for (in seconds) + * @return bool True if cached, false if not + */ + public static function Start($group, $id, $ttl) + { + if (self::isCached($group, $id)) { + echo self::read($group, $id); + return true; + + } else { + + ob_start(); + + self::$group = $group; + self::$id = $id; + self::$ttl = $ttl; + + return false; + } + } + + /** + * Ends caching. Writes data to disk. + */ + public static function End() + { + $data = ob_get_contents(); + ob_end_flush(); + + self::write(self::$group, self::$id, self::$ttl, $data); + } + } + + /** + * Data cache extension of base caching class + */ + class DataCache extends Cache + { + + /** + * Retrieves data from the cache + * + * @param string $group Group this data belongs to + * @param string $id Unique ID of the data + * @return mixed Either the resulting data, or null + */ + public static function Get($group, $id) + { + if (self::isCached($group, $id)) { + return unserialize(self::read($group, $id)); + } + + return null; + } + + /** + * Stores data in the cache + * + * @param string $group Group this data belongs to + * @param string $id Unique ID of the data + * @param int $ttl How long to cache for (in seconds) + * @param mixed $data The data to store + */ + public static function Put($group, $id, $ttl, $data) + { + self::write($group, $id, $ttl, serialize($data)); + } + } +?> \ No newline at end of file diff --git a/common/app/classes/Opml.php b/common/app/classes/Opml.php new file mode 100644 index 0000000..ae9e8b1 --- /dev/null +++ b/common/app/classes/Opml.php @@ -0,0 +1,70 @@ + 'website', + 'HTMLURL' => 'website', + 'TEXT' => 'name', + 'TITLE' => 'name', + 'XMLURL' => 'feed', + 'DESCRIPTION' => 'description', + 'ISDOWN' => 'isDown' + ); + + + function parse($data) + { + $this->_xml = xml_parser_create('UTF-8'); + //xml_parser_set_option($this->_xml, XML_OPTION_CASE_FOLDING, false); + //xml_parser_set_option($this->_xml, XML_OPTION_SKIP_WHITE, true); + xml_set_object($this->_xml, $this); + xml_set_element_handler($this->_xml,'_openTag','_closeTag'); + xml_set_character_data_handler ($this->_xml, '_cData'); + + xml_parse($this->_xml,$data); + xml_parser_free($this->_xml); + return $this->entries; + } + + + function _openTag($p,$tag,$attrs) + { + $this->_currentTag = $tag; + + if ($tag == 'OUTLINE') + { + $i = count($this->entries); + foreach (array_keys($this->map) as $key) + { + if (isset($attrs[$key])) { + $this->entries[$i][$this->map[$key]] = $attrs[$key]; + } + } + } + } + + function _closeTag($p, $tag){ + $this->_currentTag = ''; + } + + function _cData($p, $cdata){ + if ($this->_currentTag == 'TITLE'){ + $this->title = $cdata; + } + } + + function getTitle(){ + return $this->title; + } + + function getPeople(){ + return $this->entries; + } +} \ No newline at end of file diff --git a/common/app/classes/OpmlManager.php b/common/app/classes/OpmlManager.php new file mode 100644 index 0000000..d3940b2 --- /dev/null +++ b/common/app/classes/OpmlManager.php @@ -0,0 +1,50 @@ +parse($fileContent); + + return $opml; + } + + /** + * @param Opml $opml + * @param string $file + */ + public static function save($opml, $file){ + $out = ''."\n"; + $out.= ''."\n"; + $out.= ''."\n"; + $out.= ''.htmlspecialchars($opml->getTitle()).''."\n"; + $out.= ''.date('c').''."\n"; + $out.= ''.date('c').''."\n"; + $out.= ''."\n"; + $out.= ''."\n"; + foreach ($opml->entries as $person) { + $out.= ''."\n"; + } + $out.= ''."\n"; + $out.= ''; + + file_put_contents($file, $out); + } + + public static function backup($file){ + copy($file, $file.'.bak'); + } +} diff --git a/common/app/classes/Planet.php b/common/app/classes/Planet.php new file mode 100644 index 0000000..b146eaf --- /dev/null +++ b/common/app/classes/Planet.php @@ -0,0 +1,266 @@ +config = $config === null ? new PlanetConfig() : $config; + + $this->items = []; + $this->people = []; + $this->errors = []; + } + + /** + * Compare the supplied password with the known one. + * + * This functions uses a type-safe and timing-safe comparison, in order to + * improve the security of the authentication. + * + * Read more about this sort of attacks (used for the < PHP 5.6.0 implementation): + * - https://security.stackexchange.com/questions/83660/simple-string-comparisons-not-secure-against-timing-attacks + * - https://github.com/laravel/framework/blob/a1dc78820d2dbf207dbdf0f7075f17f7021c4ee8/src/Illuminate/Support/Str.php#L289 + * - https://github.com/symfony/security-core/blob/master/Util/StringUtils.php#L39 + * + * @param string $known + * @param string $supplied + * @return bool + */ + public static function authenticateUser($known = '', $supplied = '') + { + // The hash_equals function was introduced in PHP 5.6.0. If it's not + // existing in the current context (PHP version too old), and to ensure + // compatibility with those old interpreters, we'll have to provide + // an PHP implementation of this function. + if (function_exists('hash_equals')) { + return hash_equals($known, $supplied); + } + + // Some implementation references can be found on the function comment. + $knownLen = mb_strlen($known); + if ($knownLen !== mb_strlen($supplied)) { + return false; + } + + // Ensure that all the characters are the same, and continue until the + // end of the string even if an difference was found. + for ($i = 0, $comparison = 0; $i < $knownLen; $i++) { + $comparison |= ord($known[$i]) ^ ord($supplied[$i]); + } + + return ($comparison === 0); + } + + /** + * Getters + */ + public function getItems() + { + $this->items = $this->_filterItemsByCategory( + $this->items, + $this->config->getCategories()); + + return $this->items; + } + + public function getPeople() + { + return $this->people; + } + + /** + * Adds a feed to the planet. + * + * @param PlanetFeed $feed + */ + public function addPerson(&$feed) + { + $this->people[] = $feed; + } + + /** + * Load people from an OPML. + * + * @param string $file File to load the OPML from. + * @return integer Number of people loaded. + */ + public function loadOpml($file) + { + if (!is_file($file)) { + $this->errors[] = new PlanetError(3, $file.' is missing.'); + return 0; + } + + $opml = OpmlManager::load($file); + $opml_people = $opml->getPeople(); + foreach ($opml_people as $opml_person){ + $person = new PlanetFeed( + $opml_person['name'], + $opml_person['feed'], + $opml_person['website'], + $opml_person['isDown'] + ); + $this->addPerson($person); + } + return count($opml_people); + } + + /** + * Load feeds + */ + public function loadFeeds() + { + foreach ($this->people as $feed) { + //Is down it's filled by cron.php, $Planet->download(1.0) proccess + if (!$feed->isDown) { + $feed->set_timeout(-1); + $feed->init(); + $this->items = array_merge($this->items, $feed->get_items()); + } + + } + $this->sort(); + } + + /** + * Fetch feeds and see if new data is present. + * + * @param float $max_load Percentage of feeds to load + */ + public function download($max_load=0.1) + { + $max_load_feeds = ceil(count($this->people) * $max_load); + $opml = OpmlManager::load(__DIR__.'/../../custom/people.opml'); + + foreach ($this->people as $feed) { + //Avoid mass loading with variable cache duration + $feed->set_cache_duration($this->config->getCacheTimeout()); + + //Load only a few feeds, force other to fetch from the cache + if (0 > $max_load_feeds--) { + $feed->set_timeout(-1); + $this->errors[] = new PlanetError(1, 'Forced from cache : '.$feed->getFeed()); + } + + // Bypass remote's SSL/TLS certificate if the user explicitly + // asked for it in the configuration. + if ($this->config->checkcerts === false) { + $feed->set_curl_options([ + CURLOPT_SSL_VERIFYHOST => false, + CURLOPT_SSL_VERIFYPEER => false + ]); + } + + $feed->init(); + $isDown = ''; + + // http://simplepie.org/wiki/reference/simplepie/merge_items ? + if (($feed->data) && ($feed->get_item_quantity() > 0)){ + $items = $feed->get_items(); + $this->items = array_merge($this->items, $items); + } else { + $this->errors[] = new PlanetError(1, 'No items or down : ' . $feed->getFeed()); + $isDown = '1'; + } + + foreach ($opml->entries as $key => $entrie) { + if ($feed->getFeed() === $entrie['feed']) { + $opml->entries[$key]['isDown'] = $isDown; + } + } + } + + OpmlManager::save($opml, __DIR__.'/../../custom/people.opml'); + } + + public function sort() + { + usort($this->items, array('PlanetItem','compare')); + } + + /** + * Filter out items that do not match at least one + * of the defined categories. + * + * If there's no category, return all items. + * + * @param array $items to filter + * @param string $categories to filter against; may be a single word + * or a comma-separated list of words. + * + * @return array resulting list of items + */ + public function _filterItemsByCategory($items, $categories = null) + { + $categories = trim($categories); + + if (empty($categories)) + return $items; + + $categories = array_map('trim', explode(',', strtolower($categories))); + $cb_category_filter = + function ($item) use ($categories) + { + if (!is_array($item_categories = $item->get_categories())) + return false; + + $item_categories = array_map( + function ($i) { return strtolower($i->get_label()); }, + $item_categories + ); + + return array_intersect($categories, $item_categories); + }; + + return array_values(array_filter($items, $cb_category_filter)); + } +} diff --git a/common/app/classes/PlanetConfig.php b/common/app/classes/PlanetConfig.php index a31938e..f3928bc 100644 --- a/common/app/classes/PlanetConfig.php +++ b/common/app/classes/PlanetConfig.php @@ -6,32 +6,45 @@ class PlanetConfig { - public $conf; - - public function __construct($array) - { - $defaultConfig = array( - 'url' => 'http://www.example.com/', - 'name' => '', - 'locale' => 'en', - 'items' => 10, - 'shuffle' => 0, - 'refresh' => 240, - 'cache' => 10, - 'nohtml' => 0, - 'postmaxlength' => 0, - 'cachedir' => './cache', - ); - - // User config - $this->conf = $array; - - // Complete config with default config - foreach ($defaultConfig as $key => $value) { - if (!isset($this->conf[$key])) { - $this->conf[$key] = $value; - } - } + protected $conf = []; + + public static $defaultConfig = [ + 'url' => 'http://www.example.com/', + 'name' => '', + 'locale' => 'en', + 'items' => 10, + 'shuffle' => 0, + 'refresh' => 240, + 'cache' => 10, + 'nohtml' => 0, + 'postmaxlength' => 0, + 'categories' => '', + 'cachedir' => './cache', + 'debug' => false, + 'checkcerts' => true, + ]; + + /** + * PlanetConfig constructor. + * @param array $userConfig + * @param bool $useDefaultConfig + */ + public function __construct($userConfig = [], $useDefaultConfig = true) + { + $default = $useDefaultConfig ? self::$defaultConfig : array(); + $this->conf = $this->merge($default, $userConfig); + } + + /** + * Merge the configuration of the user in the default one. + * + * @param array $default + * @param array $user + * @return array + */ + protected function merge($default = [], $user = []) + { + return array_merge($default, $this->normalizeArrayKeys($user)); } public function getUrl() @@ -58,7 +71,10 @@ class PlanetConfig return $this->conf['cache']; } - //@TODO: drop this pref + /** + * @deprecated + * @return mixed + */ public function getShuffle() { return $this->conf['shuffle']; @@ -69,20 +85,110 @@ class PlanetConfig return $this->conf['items']; } - //@TODO: drop this pref + /** + * @deprecated + * @return mixed + */ public function getNoHTML() { return $this->conf['nohtml']; } - //@TODO: drop this pref + /** + * @deprecated + * @return mixed + */ public function getPostMaxLength() { return $this->conf['postmaxlength']; } + public function getCategories() + { + return $this->conf['categories']; + } + public function toYaml() { - return Spyc::YAMLDump($this->conf,4); + return Spyc::YAMLDump($this->conf, 4); + } + + /** + * @return array + */ + public function toArray() + { + return $this->conf; + } + + public function getDebug() + { + return $this->conf['debug']; + } + + /** + * @return array + */ + public function getDefaultConfig() + { + return self::$defaultConfig; + } + + /** + * Normalize the name of a configuration key. + * + * @param string $key + * @return string + */ + protected function normalizeKeyName($key = null) + { + return strtolower($key); + } + + /** + * Normalize all the keys of the array. + * + * @param array $array + * @return array + */ + protected function normalizeArrayKeys($array = []) + { + foreach ($array as $key => $value) { + $normalized = $this->normalizeKeyName($key); + if ($normalized !== $key) { + $array[$this->normalizeKeyName($key)] = $value; + unset($array[$key]); + } + } + + return $array; } + + /** + * Generic configuration getter. + * + * @return mixed|null + */ + public function __get($key) + { + $key = $this->normalizeKeyName($key); + + return array_key_exists($key, $this->conf) ? + $this->conf[$key] : + null; + } + + /** + * Generic configuration setter. + * + * @param $key + * @param $value + */ + public function __set($key, $value) + { + $key = $this->normalizeKeyName($key); + + $this->conf[$key] = $value; + } + } diff --git a/common/app/classes/PlanetError.php b/common/app/classes/PlanetError.php index 31923a3..e47ab1d 100644 --- a/common/app/classes/PlanetError.php +++ b/common/app/classes/PlanetError.php @@ -3,21 +3,30 @@ class PlanetError { public $level; + public $levels = array( + 1 => 'notice', + 2 => 'warning', + 3 => 'error', + ); public $message; + /** + * PlanetError constructor. + * @param $level + * @param $message + */ public function __construct($level, $message) { $this->level = (int) $level; $this->message = $message; } - public function toString($format = '%1$s : %2$s') + /** + * @param string $format + * @return string + */ + public function toString($format = '%1$s: %2$s') { - $levels = array( - 1 => 'notice', - 2 => 'warning', - 3 => 'error', - ); - return sprintf($format, $levels[$this->level], $this->message); + return sprintf($format, $this->levels[$this->level], $this->message); } } diff --git a/common/app/classes/PlanetFeed.php b/common/app/classes/PlanetFeed.php index a6c7aab..3d2ea2f 100644 --- a/common/app/classes/PlanetFeed.php +++ b/common/app/classes/PlanetFeed.php @@ -9,15 +9,17 @@ class PlanetFeed extends SimplePie public $name; public $feed; public $website; + public $isDown; - public function __construct($name, $feed, $website) + public function __construct($name, $feed, $website, $isDown) { $this->name = $name; $this->feed = $feed; $this->website = $website; + $this->isDown = $isDown; parent::__construct(); $this->set_item_class('PlanetItem'); - $this->set_cache_location(dirname(__FILE__).'/../../cache'); + $this->set_cache_location(__DIR__.'/../../cache'); $this->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE); $this->set_feed_url($this->getFeed()); $this->set_timeout(5); @@ -39,7 +41,19 @@ class PlanetFeed extends SimplePie return $this->website; } - public function compare($person1, $person2) + public function getIsDown() + { + return $this->isDown; + } + + /** + * Compare two Person by their name. + * + * @param $person1 + * @param $person2 + * @return int + */ + public static function compare($person1, $person2) { return strcasecmp($person1->name, $person2->name); } diff --git a/common/app/classes/PlanetItem.php b/common/app/classes/PlanetItem.php index 039d0ca..7d55781 100644 --- a/common/app/classes/PlanetItem.php +++ b/common/app/classes/PlanetItem.php @@ -4,14 +4,19 @@ * Planet item */ -class PlanetItem +class PlanetItem extends SimplePie_Item { public function __construct($feed, $data) { - parent::SimplePie_Item($feed, $data); + parent::__construct($feed, $data); } - public function compare($item1, $item2) + /** + * @param PlanetItem $item1 + * @param PlanetItem $item2 + * @return int + */ + public static function compare($item1, $item2) { $item1_date = $item1->get_date('U'); $item2_date = $item2->get_date('U'); diff --git a/common/app/classes/Simplel10n.php b/common/app/classes/Simplel10n.php new file mode 100755 index 0000000..79313b3 --- /dev/null +++ b/common/app/classes/Simplel10n.php @@ -0,0 +1,52 @@ +locale = $locale; + $this->l10nFolder = __DIR__ . '/../l10n/'; + $this->load($this->l10nFolder . $this->locale); + } + + public function setL1OnFolder($path) { + $this->l10nFolder = $path; + } + + static function getString($str, $comment='') { + if(array_key_exists($str, $GLOBALS['locale'])) { + return trim(str_replace('{ok}', '', $GLOBALS['locale'][$str])); + } else { + return $str; + } + } + + /* + * This is the same as getString except that we don't remove the {ok} string + * This is needed only for the extraction script + */ + static function extractString($str, $comment='') { + if(array_key_exists($str, $GLOBALS['locale'])) { + return $GLOBALS['locale'][$str]; + } else { + return $str; + } + } + + static function load($pathToFile) { + + if (!file_exists($pathToFile . '.lang')) return false; + + $file = file($pathToFile . '.lang'); + + foreach ($file as $k => $v) { + if (substr($v,0,1) == ';' && !empty($file[$k+1])) { + $GLOBALS['locale'][trim(substr($v,1))] = trim($file[$k+1]); + } + } + } +} diff --git a/common/app/helpers.php b/common/app/helpers.php new file mode 100644 index 0000000..e943252 --- /dev/null +++ b/common/app/helpers.php @@ -0,0 +1,130 @@ +moonmoon +Powered by moonmoon + + +;No article +Kein Artikel + + +;No news, good news. +Keine Neuigkeiten, gute Neuigkeiten. + + +;Today +Heute + + +;Go to original place +Gehe zur Originalseite + + +;This week +Diese Woche + + +;This month +Diesen Monat + + +;Older items +Ältere Einträge + + +;People +Personen + + +;Feed +Feed + + +;Website +Webseite + + +;All feeds in OPML format +Alle Feeds im OPML-Format + + +;Syndicate +Zusammenfassung + + +;Feed (ATOM) +Feed (ATOM) + + +;Archives +Archive + + +;See all headlines +Alle Schlagzeilen ansehen + + +;Source: +Quelle: + + +;You might want to install moonmoon. +Sie könnten moonmoon installieren wollen. + + +;moonmoon installation +moonmoon Installation + + +;Congratulations! Your moonmoon is ready. +Gratulation! Ihr moonmoon ist bereit. + + +;What's next? +Was nun? + + +;Delete install.php with your FTP software. +Entfernen Sie install.php mit Ihrer FTP-Software. + + +;Use your password to go to the administration panel +Verwenden Sie Ihr Passwort, um zum Administrationsbereich zu gehen. + + diff --git a/common/app/l10n/en.lang b/common/app/l10n/en.lang index 64d5a82..ff49307 100644 --- a/common/app/l10n/en.lang +++ b/common/app/l10n/en.lang @@ -113,6 +113,10 @@ Website link Feed link +# Translation note: ** String needs translation ** +;Unavailable +Unavailable + # Translation note: ** String needs translation ** ;Not in cache Not in cache diff --git a/common/app/l10n/es.lang b/common/app/l10n/es.lang new file mode 100644 index 0000000..11b80df --- /dev/null +++ b/common/app/l10n/es.lang @@ -0,0 +1,244 @@ +# Translation note: ¿Está seguro que desea vaciar la caché? +;Are you sure you want to purge the cache? +¿Está seguro de que desea vaciar la caché? + + +# Translation note: Vaciar la caché +;Clear cache +Vaciar la caché + + +# Translation note: Vaciar la caché: +;Clear cache: +Vaciar la caché: + + +;Clear +Vaciar + + +# Translation note: Vaciar la caché hará que moonmoon recargue todas las fuentes web. +;Clearing the cache will make moonmoon reload all feeds. +Vaciar la caché hará que moonmoon recargue todas las fuentes web. + + +# Translation note: Cambiar la contraseña de administración +;Change administrator password +Cambiar la contraseña de administración + + +# Translation note: Nueva contraseña: +;New password: +Nueva contraseña: + + +# Translation note: Cambiar la contraseña +;Change password +Cambiar la contraseña + + +# Translation note: Añadir una nueva fuente web - 'feed' = 'fuente web', 'fuente' or 'canal' in spanish, but you can use 'feed' anyway. +;Add a new feed +Añadir una nueva fuente web + + +# Translation note: Añadir fuente +;Add Feed +Añadir fuente + + +;Link: +Enlace: + + +# Translation note: Los formatos aceptados son RSS y ATOM. Si el enlace no es una fuente web, moonmoon tratará de encontrar la fuente de forma automática. +;Accepted formats are RSS and ATOM. If the link is not a feed, moonmoon will try to autodiscover the feed. +Los formatos aceptados son RSS y ATOM. Si el enlace no es una fuente web, moonmoon tratará de encontrar la fuente de forma automática. + + +;Manage existing feeds +Administrar las fuentes existentes + + +# Translation note: Número de fuentes +;Number of feeds: %s +Número de fuentes: %s + + +;Save changes +Guardar cambios + + +;Delete selected Feeds +Borrar seleccionadas + + +;Select : +Seleccionar: + + +;All +Todas + + +;None +Ninguna + + +# Translation note: Selección +;Selection +Selección + + +;Name +Nombre + +# Translation note: Última entrada +;Last entry +Última entrada + + +;Website link +Enlace a la web + + +;Feed link +Enlace a la fuente + + +# Translation note: 'No está en caché' or 'No en caché' +;Not in cache +No está en caché + + +# Translation note: Contraseña: +;Password: +Contraseña: + + +;OK +Entrar + + +# Translation note: Administración de moonmoon +;moonmoon administration +Administración de moonmoon + + +# Translation note: Volver a la página principal +;Back to main page +Volver a la página principal + + +;Logout +Salir + + +;Feeds +Fuentes + + +# Translation note: Administración +;Administration +Administración + + +;Powered by moonmoon +Desarrollado por moonmoon + + +# Translation note: Sin artículos +;No article +Sin artículos + + +;No news, good news. +No hay noticias, buena noticia. + + +;Today +Hoy + + +# Translation note: Ir a la ubicación original +;Go to original place +Ir a la ubicación original + + +;This week +Esta semana + + +;This month +Este mes + + +;Older items +Titulares anteriores + + +# Translation note: 'People' = 'Personas', but 'fuentes'(sources), which in Spanish means origins, is more generic. +;People +Fuentes + + +;Feed +Fuente + + +;Website +Sitio web + + +;All feeds in OPML format +Todas las fuentes (OPML) + + +# Translation note: Redifusión +;Syndicate +Redifusión + + +;Feed (ATOM) +Fuente (ATOM) + + +;Archives +Archivos + + +;See all headlines +Ver todos los titulares + + +# Translation note: You may use 'Source' = 'Origen' too. +;Source: +Fuente: + + +;You might want to install moonmoon. +Es posible que desee instalar moonmoon. + + +# Translation note: Instalación de moonmoon +;moonmoon installation +Instalación de moonmoon + + +# Translation note: ¡Felicidades! Su moonmoon está preparado. +;Congratulations! Your moonmoon is ready. +¡Felicidades! Su moonmoon está preparado. + + +# Translation note: ¿Y ahora? +;What's next? +¿Y ahora? + + +;Delete install.php with your FTP software. +Borre install.php con su programa de FTP. + + +# Translation note: Utilice su contraseña para acceder al panel de administración. +;Use your password to go to the administration panel +Utilice su contraseña para acceder al panel de administración. diff --git a/common/app/l10n/extract.php b/common/app/l10n/extract.php index 1a04f00..1384827 100755 --- a/common/app/l10n/extract.php +++ b/common/app/l10n/extract.php @@ -13,13 +13,15 @@ * The script scans for the files in the l10n/ folder to know which locales are supported */ -// released versions of moonmoon should immediately return for security -// return; +$root = __DIR__ . '/../../'; -$root = dirname(__FILE__) . '/../../'; -$GLOBALS['english'] = array(); +require_once __DIR__ . '/../app.php'; -include_once $root . '/app/classes/Simplel10n.class.php'; +if ($conf['debug'] !== true) { + die('Please enable the debug mode to use extract.php.'); +} + +$GLOBALS['english'] = array(); /* * This is a file parser to extract localizable strings (in .php files) @@ -27,7 +29,6 @@ include_once $root . '/app/classes/Simplel10n.class.php'; * */ - function extract_l10n_strings($file) { $lines = file($file); $patterns = array('/_g\([\'"](.*?)[\'"]\)/', '/getString\([\'"](.*?)[\'"]\)/',); diff --git a/common/app/l10n/fr.lang b/common/app/l10n/fr.lang index 6247652..4e2a568 100755 --- a/common/app/l10n/fr.lang +++ b/common/app/l10n/fr.lang @@ -90,6 +90,10 @@ Lien du site Lien du Flux +;Unavailable +Indisponible + + ;Not in cache Pas en cache -- cgit v1.2.1