add top writer to dashboard

master
Jean-Christian Paul Denis 2021-11-06 21:15:51 +01:00
parent f5f2a9636a
commit acce51b890
Signed by: JcDenis
GPG Key ID: 1B5B8C5B90B6C951
8 changed files with 486 additions and 250 deletions

View File

@ -1,6 +1,8 @@
0.8.2 - dev dev
- [ ] literal rank of writer depending of num of com - [ ] literal rank of writer depending of num of com
- [ ] add dashboard module - add dashboard module
- update translations
- update to PSR12
0.8.1 - 2021.09.17 0.8.1 - 2021.09.17
- fix plurals and better translation - fix plurals and better translation

View File

@ -10,9 +10,193 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { if (!defined('DC_CONTEXT_ADMIN')) {
return null; return null;
} }
require dirname(__FILE__) . '/_widgets.php'; require dirname(__FILE__) . '/_widgets.php';
# Dashboard item and user preference
$core->addBehavior(
'adminDashboardItems',
['topWriterAdmin', 'adminDashboardItems']
);
$core->addBehavior(
'adminDashboardOptionsForm',
['topWriterAdmin', 'adminDashboardOptionsForm']
);
$core->addBehavior(
'adminAfterDashboardOptionsUpdate',
['topWriterAdmin', 'adminAfterDashboardOptionsUpdate']
);
/**
* @ingroup DC_PLUGIN_TOPWRITER
* @brief Display most active users - admin methods.
* @since 2.6
*/
class topWriterAdmin
{
public static function adminDashboardItems(dcCore $core, $__dashboard_items)
{
$pref = self::setDefaultPref($core);
# top posts
if ($pref['topWriterPostsItems']) {
$lines = topWriter::posts($core, $pref['topWriterPostsPeriod'], $pref['topWriterPostsLimit']);
if (empty($lines)) {
return null;
}
$li = [];
foreach ($lines as $k => $line) {
$li[] = sprintf('<li><strong>%s</strong> %s (%s)</li>', $k, $line['author'], $line['count']);
}
# Display
$__dashboard_items[0][] = '<div class="box small" id="topWriterPostsItems">' .
'<h3>' . html::escapeHTML(__('Top writer: entries')) . '</h3>' .
'<ul>' . implode('', $li) . '</ul>' .
'</div>';
}
# top comments
if ($pref['topWriterCommentsItems']) {
$lines = topWriter::comments($core, $pref['topWriterCommentsPeriod'], $pref['topWriterCommentsLimit']);
if (empty($lines)) {
return null;
}
$li = [];
foreach ($lines as $k => $line) {
$li[] = sprintf('<li><strong>%s</strong> %s (%s)</li>', $k, $line['author'], $line['count']);
}
# Display
$__dashboard_items[0][] = '<div class="box small" id="topWriterCommentsItems">' .
'<h3>' . html::escapeHTML(__('Top writer: comments')) . '</h3>' .
'<ul>' . implode('', $li) . '</ul>' .
'</div>';
}
}
public static function adminDashboardOptionsForm(dcCore $core)
{
$pref = self::setDefaultPref($core);
echo
'<div class="fieldset">' .
'<h4>' . __('Top writer: entries') . '</h4>' .
'<p><label class="classic" for="topWriterPostsItems">' .
form::checkbox('topWriterPostsItems', 1, $pref['topWriterPostsItems']) . ' ' .
__('Show') . '</label></p>' .
'<p><label class="classic" for="topWriterPostsPeriod">' . __('Period:') . ' </label>' .
form::combo('topWriterPostsPeriod', topWriter::periods(), $pref['topWriterPostsPeriod']) . '</p>' .
'<p><label class="classic" for="topWriterPostsLimit">' . __('Limit:') . ' </label>' .
form::number('topWriterPostsLimit', ['min' => 1, 'max' => 20, 'default' => $pref['topWriterPostsLimit']]) . '</p>' .
'</div>' .
'<div class="fieldset">' .
'<h4>' . __('Top writer: comments') . '</h4>' .
'<p><label class="classic" for="topWriterCommentsItems">' .
form::checkbox('topWriterCommentsItems', 1, $pref['topWriterCommentsItems']) . ' ' .
__('Show') . '</label></p>' .
'<p><label class="classic" for="topWriterCommentsPeriod">' . __('Period:') . ' </label>' .
form::combo('topWriterCommentsPeriod', topWriter::periods(), $pref['topWriterCommentsPeriod']) . '</p>' .
'<p><label class="classic" for="topWriterCommentsLimit">' . __('Limit:') . ' </label>' .
form::number('topWriterCommentsLimit', ['min' => 1, 'max' => 20, 'default' => $pref['topWriterCommentsLimit']]) . '</p>' .
'</div>';
}
public static function adminAfterDashboardOptionsUpdate($user_id)
{
global $core;
$core->auth->user_prefs->dashboard->put(
'topWriterPostsItems',
!empty($_POST['topWriterPostsItems']),
'boolean'
);
$core->auth->user_prefs->dashboard->put(
'topWriterPostsPeriod',
(string) $_POST['topWriterPostsPeriod'],
'string'
);
$core->auth->user_prefs->dashboard->put(
'topWriterPostsLimit',
(int) $_POST['topWriterPostsLimit'],
'integer'
);
$core->auth->user_prefs->dashboard->put(
'topWriterCommentsItems',
!empty($_POST['topWriterCommentsItems']),
'boolean'
);
$core->auth->user_prefs->dashboard->put(
'topWriterCommentsPeriod',
(string) $_POST['topWriterCommentsPeriod'],
'string'
);
$core->auth->user_prefs->dashboard->put(
'topWriterCommentsLimit',
(int) $_POST['topWriterCommentsLimit'],
'integer'
);
}
private static function setDefaultPref($core)
{
if (!$core->auth->user_prefs->dashboard->prefExists('topWriterPostsItems')) {
$core->auth->user_prefs->dashboard->put(
'topWriterPostsItems',
false,
'boolean'
);
}
if (!$core->auth->user_prefs->dashboard->prefExists('topWriterPostsPeriod')) {
$core->auth->user_prefs->dashboard->put(
'topWriterPostsPeriod',
'month',
'string'
);
}
if (!$core->auth->user_prefs->dashboard->prefExists('topWriterPostsLimit')) {
$core->auth->user_prefs->dashboard->put(
'topWriterPostsLimit',
10,
'integer'
);
}
if (!$core->auth->user_prefs->dashboard->prefExists('topWriterCommentsItems')) {
$core->auth->user_prefs->dashboard->put(
'topWriterCommentsItems',
false,
'boolean'
);
}
if (!$core->auth->user_prefs->dashboard->prefExists('topWriterCommentsPeriod')) {
$core->auth->user_prefs->dashboard->put(
'topWriterCommentsPeriod',
'month',
'string'
);
}
if (!$core->auth->user_prefs->dashboard->prefExists('topWriterCommentsLimit')) {
$core->auth->user_prefs->dashboard->put(
'topWriterCommentsLimit',
10,
'integer'
);
}
return [
'topWriterPostsItems' => $core->auth->user_prefs->dashboard->get('topWriterPostsItems'),
'topWriterPostsPeriod' => $core->auth->user_prefs->dashboard->get('topWriterPostsPeriod'),
'topWriterPostsLimit' => $core->auth->user_prefs->dashboard->get('topWriterPostsLimit') ?? 10,
'topWriterCommentsItems' => $core->auth->user_prefs->dashboard->get('topWriterCommentsItems'),
'topWriterCommentsPeriod' => $core->auth->user_prefs->dashboard->get('topWriterCommentsPeriod'),
'topWriterCommentsLimit' => $core->auth->user_prefs->dashboard->get('topWriterCommentsLimit') ?? 10
];
}
}

View File

@ -10,7 +10,6 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { if (!defined('DC_RC_PATH')) {
return null; return null;
} }

17
_prepend.php 100644
View File

@ -0,0 +1,17 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return;
}
$__autoload['topWriter'] = dirname(__FILE__) . '/inc/class.topwriter.php';

View File

@ -10,7 +10,6 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { if (!defined('DC_RC_PATH')) {
return null; return null;
} }

View File

@ -10,7 +10,6 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { if (!defined('DC_RC_PATH')) {
return null; return null;
} }
@ -33,7 +32,7 @@ class topWriterWidget
->addTitle(__('Top comments')) ->addTitle(__('Top comments'))
->setting( ->setting(
'text', 'text',
__('Text:'), __('Text:') . ' (%rank%, %author%, %count%)',
'%author% (%count%)', '%author% (%count%)',
'text' 'text'
) )
@ -42,13 +41,7 @@ class topWriterWidget
__('Period:'), __('Period:'),
'year', 'year',
'combo', 'combo',
[ topWriter::periods()
__('day') => 'day',
__('week') => 'week',
__('month') => 'month',
__('year') => 'year',
__('from begining') => ''
]
) )
->setting( ->setting(
'sort', 'sort',
@ -89,7 +82,7 @@ class topWriterWidget
->addTitle(__('Top entries')) ->addTitle(__('Top entries'))
->setting( ->setting(
'text', 'text',
__('Text:'), __('Text:') . ' (%rank%, %author%, %count%)',
'%author% (%count%)', '%author% (%count%)',
'text' 'text'
) )
@ -98,17 +91,12 @@ class topWriterWidget
__('Period:'), __('Period:'),
'year', 'year',
'combo', 'combo',
[ topWriter::periods()
__('day') => 'day',
__('week') => 'week',
__('month') => 'month',
__('year') => 'year',
__('from begining') => ''
]
) )
->setting( ->setting(
'sort', 'sort',
__('Sort:'),'desc', __('Sort:'),
'desc',
'combo', 'combo',
[ [
__('Ascending') => 'asc', __('Ascending') => 'asc',
@ -131,85 +119,15 @@ class topWriterWidget
{ {
global $core; global $core;
if ($w->offline) { if ($w->offline
|| ($w->homeonly == 1 && !$core->url->isHome($core->url->type))
|| ($w->homeonly == 2 && $core->url->isHome($core->url->type))
) {
return null; return null;
} }
if (($w->homeonly == 1 && !$core->url->isHome($core->url->type)) $lines = topWriter::comments($core, $w->period, $w->limit, $w->sort == 'desc', $w->exclude);
|| ($w->homeonly == 2 && $core->url->isHome($core->url->type))) { if (empty($lines)) {
return null;
}
$req =
'SELECT COUNT(*) AS count, comment_email ' .
"FROM " . $core->prefix . "post P, " . $core->prefix . "comment C " .
'WHERE P.post_id=C.post_id ' .
"AND blog_id='" . $core->con->escape($core->blog->id) . "' " .
'AND post_status=1 AND comment_status=1 ' .
self::period('comment_dt', $w->period);
if ($w->exclude) {
$req .=
'AND comment_email NOT IN (' .
' SELECT U.user_email ' .
' FROM ' . $core->prefix . 'user U' .
' INNER JOIN ' . $core->prefix . 'post P ON P.user_id = U.user_id ' .
" WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " .
' GROUP BY U.user_email) ';
}
$req .=
'GROUP BY comment_email ' .
'ORDER BY count ' . ($w->sort == 'asc' ? 'ASC' : 'DESC') . ' ' .
$core->con->limit(abs((integer) $w->limit));
$rs = $core->con->select($req);
if ($rs->isEmpty()) {
return null;
}
$content = '';
$i = 0;
while($rs->fetch()) {
$user = $core->con->select(
"SELECT * FROM " . $core->prefix . "comment " .
"WHERE comment_email='" . $rs->comment_email . "' " .
'ORDER BY comment_dt DESC'
);
if (!$user->comment_author) {
continue;
}
$i++;
$rank = '<span class="topcomments-rank">' . $i . '</span>';
if ($user->comment_site) {
$author = '<a href="' . $user->comment_site . '" title="' .
__('Author link') . '">' . $user->comment_author . '</a>';
} else {
$author = $user->comment_author;
}
$author = '<span class="topcomments-author">' . $author . '</span>';
if ($rs->count == 0) {
$count = __('no comments');
} else {
$count = sprintf(__('one comment', '%s comments', $rs->count), $rs->count);
}
$content .= sprintf(
'<li>%s</li>',
str_replace(
['%rank%', '%author%', '%count%'],
[$rank, $author, $count],
$w->text
)
);
}
if ($i < 1) {
return null; return null;
} }
@ -218,7 +136,7 @@ class topWriterWidget
'topcomments ' . $w->class, 'topcomments ' . $w->class,
'', '',
($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') . ($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') .
sprintf('<ul>%s</ul>', $content) sprintf('<ul>%s</ul>', implode('', self::lines($lines, 'comments', $w->text)))
); );
} }
@ -226,80 +144,15 @@ class topWriterWidget
{ {
global $core; global $core;
if ($w->offline) { if ($w->offline
|| ($w->homeonly == 1 && !$core->url->isHome($core->url->type))
|| ($w->homeonly == 2 && $core->url->isHome($core->url->type))
) {
return null; return null;
} }
if (($w->homeonly == 1 && !$core->url->isHome($core->url->type)) $lines = topWriter::posts($core, $w->period, $w->limit, $w->sort == 'desc');
|| ($w->homeonly == 2 && $core->url->isHome($core->url->type))) { if (empty($lines)) {
return null;
}
$rs = $core->con->select(
'SELECT COUNT(*) AS count, U.user_id ' .
"FROM " . $core->prefix . "post P " .
'INNER JOIN ' . $core->prefix . 'user U ON U.user_id = P.user_id ' .
"WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " .
'AND post_status=1 AND user_status=1 ' .
self::period('post_dt', $w->period) .
'GROUP BY U.user_id ' .
'ORDER BY count ' . ($w->sort == 'asc' ? 'ASC' : 'DESC') . ', U.user_id ASC ' .
$core->con->limit(abs((integer) $w->limit)));
if ($rs->isEmpty()) {
return null;
}
$content = '';
$i = 0;
while($rs->fetch()) {
$user = $core->con->select(
"SELECT * FROM " . $core->prefix . "user WHERE user_id='" . $rs->user_id . "' "
);
$author = dcUtils::getUserCN(
$user->user_id,
$user->user_name,
$user->user_firstname,
$user->user_displayname
);
if (empty($author)) {
continue;
}
$i++;
$rank = '<span class="topentries-rank">' . $i . '</span>';
$core->blog->settings->addNamespace('authormode');
if ($core->blog->settings->authormode->authormode_active) {
$author = '<a href="' .
$core->blog->url . $core->url->getBase("author") . '/' . $user->user_id . '" ' .
'title="' . __('Author posts') . '">' . $author . '</a>';
}
elseif ($user->user_url) {
$author = '<a href="' . $user->user_url . '" title="' .
__('Author link') . '">' . $author . '</a>';
}
$author = '<span class="topentries-author">' . $author . '</span>';
if ($rs->count == 0) {
$count = __('no entries');
} else {
$count = sprintf(__('one entry', '%s entries', $rs->count), $rs->count);
}
$content .= sprintf(
'<li>%s</li>',
str_replace(
['%rank%', '%author%', '%count%'],
[$rank, $author, $count],
$w->text
)
);
}
if ($i < 1) {
return null; return null;
} }
@ -308,35 +161,26 @@ class topWriterWidget
'topentries ' . $w->class, 'topentries ' . $w->class,
'', '',
($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') . ($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') .
sprintf('<ul>%s</ul>', $content) sprintf('<ul>%s</ul>', implode('', self::lines($lines, 'posts', $w->text)))
); );
} }
private static function period($t, $p) private static function lines($lines, $id, $text)
{ {
$pat = '%Y-%m-%d %H:%M:%S'; $li = [];
switch($p) { foreach ($lines as $k => $line) {
case 'day': $rank = '<span class="top' . $id . '-rank">' . $k . '</span>';
return $author = '<span class="top' . $id . '-author">' . (empty($line['author_link']) ? $line['author'] : $line['author_link']) . '</span>';
"AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24) . "' "; $li[] = sprintf(
break; '<li>%s</li>',
str_replace(
case 'week': ['%rank%', '%author%', '%count%'],
return [$rank, $author, $line['count']],
"AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24*7) . "' "; $text
break; )
);
case 'month':
return
"AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24*30) . "' ";
break;
case 'year':
return
"AND $t > TIMESTAMP '" . dt::str($pat, time() - 3600*24*30*12) . "' ";
break;
} }
return ''; return $li;
} }
} }

View File

@ -0,0 +1,189 @@
<?php
/**
* @brief topWriter, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis, Pierre Van Glabeke
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return;
}
class topWriter
{
public static function posts(dcCore $core, string $period, int $limit, bool $sort_desc = true)
{
$req = 'SELECT COUNT(*) AS count, U.user_id ' .
'FROM ' . $core->prefix . 'post P ' .
'INNER JOIN ' . $core->prefix . 'user U ON U.user_id = P.user_id ' .
"WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " .
'AND post_status=1 AND user_status=1 ' .
self::period('post_dt', $period) .
'GROUP BY U.user_id ' .
'ORDER BY count ' . ($sort_desc ? 'DESC' : 'ASC') . ' , U.user_id ASC ' .
$core->con->limit(abs((int) $limit));
$rs = $core->con->select($req);
if ($rs->isEmpty()) {
return null;
}
$core->blog->settings->addNamespace('authormode');
$res = [];
$i = 0;
while ($rs->fetch()) {
$user = $core->con->select(
'SELECT * FROM ' . $core->prefix . "user WHERE user_id='" . $rs->user_id . "' "
);
if ($user->isEmpty()) {
continue;
}
$author = dcUtils::getUserCN(
$user->user_id,
$user->user_name,
$user->user_firstname,
$user->user_displayname
);
if (empty($author)) {
continue;
}
$i++;
if ($core->blog->settings->authormode->authormode_active) {
$res[$i]['author_link'] = '<a href="' .
$core->blog->url . $core->url->getBase('author') . '/' . $user->user_id . '" ' .
'title="' . __('Author posts') . '">' . $author . '</a>';
} elseif ($user->user_url) {
$res[$i]['author_link'] = '<a href="' . $user->user_url . '" title="' .
__('Author link') . '">' . $author . '</a>';
}
$res[$i]['author'] = $author;
if ($rs->count == 0) {
$res[$i]['count'] = __('no entries');
} else {
$res[$i]['count'] = sprintf(__('one entry', '%s entries', $rs->count), $rs->count);
}
}
if (!$i) {
return null;
}
return $res;
}
public static function comments(dcCore $core, string $period, int $limit, bool $sort_desc = true, $exclude = false)
{
$req = 'SELECT COUNT(*) AS count, comment_email ' .
'FROM ' . $core->prefix . 'post P, ' . $core->prefix . 'comment C ' .
'WHERE P.post_id=C.post_id ' .
"AND blog_id='" . $core->con->escape($core->blog->id) . "' " .
'AND post_status=1 AND comment_status=1 ' .
self::period('comment_dt', $period);
if ($exclude) {
$req .= 'AND comment_email NOT IN (' .
' SELECT U.user_email ' .
' FROM ' . $core->prefix . 'user U' .
' INNER JOIN ' . $core->prefix . 'post P ON P.user_id = U.user_id ' .
" WHERE blog_id='" . $core->con->escape($core->blog->id) . "' " .
' GROUP BY U.user_email) ';
}
$req .= 'GROUP BY comment_email ' .
'ORDER BY count ' . ($sort_desc ? 'DESC' : 'ASC') . ' ' .
$core->con->limit(abs((int) $limit));
$rs = $core->con->select($req);
if ($rs->isEmpty()) {
return null;
}
$res = [];
$i = 0;
while ($rs->fetch()) {
$user = $core->con->select(
'SELECT * FROM ' . $core->prefix . 'comment ' .
"WHERE comment_email='" . $rs->comment_email . "' " .
'ORDER BY comment_dt DESC'
);
if (!$user->comment_author) {
continue;
}
$i++;
if ($user->comment_site) {
$res[$i]['author_link'] = '<a href="' . $user->comment_site . '" title="' .
__('Author link') . '">' . $user->comment_author . '</a>';
}
$res[$i]['author'] = $user->comment_author;
if ($rs->count == 0) {
$res[$i]['count'] = __('no comments');
} else {
$res[$i]['count'] = sprintf(__('one comment', '%s comments', $rs->count), $rs->count);
}
}
if (!$i) {
return null;
}
return $res;
}
private static function period(string $field, string $period): string
{
$pattern = '%Y-%m-%d %H:%M:%S';
$time = 0;
switch ($period) {
case 'day':
$time = 3600 * 24;
break;
case 'week':
$time = 3600 * 24 * 7;
break;
case 'month':
$time = 3600 * 24 * 30;
break;
case 'year':
$time = 3600 * 24 * 30 * 12;
break;
default:
return '';
break;
}
return "AND $field > TIMESTAMP '" . dt::str($pattern, time() - $time) . "' ";
}
public static function periods()
{
return [
__('last day') => 'day',
__('last week') => 'week',
__('last month') => 'month',
__('last year') => 'year',
__('from begining') => ''
];
}
}

View File

@ -1,69 +1,48 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: topWriter 0.8.1\n" "Project-Id-Version: topWriter 0.8.1\n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: 2021-09-25T16:39:29+00:00\n" "PO-Revision-Date: 2021-11-06T20:12:30+00:00\n"
"Last-Translator: Jean-Christian Denis\n" "Last-Translator: Jean-Christian Denis\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "Top writer: entries"
msgstr "Top rédacteur : billets"
msgid "Top writer: comments" msgid "Top writer: comments"
msgstr "Top rédacteur : commentaires" msgstr "Top rédacteur : commentaires"
msgid "Period:"
msgstr "Période :"
msgid "Limit:"
msgstr "Limite :"
msgid "List users who write more comments" msgid "List users who write more comments"
msgstr "Liste les utilisateurs qui ont écrit le plus de commentaires" msgstr "Liste les utilisateurs qui ont écrit le plus de commentaires"
msgid "Top comments" msgid "Top comments"
msgstr "Top commentaires" msgstr "Top commentaires"
msgid "Period:"
msgstr "Période :"
msgid "day"
msgstr "jour"
msgid "week"
msgstr "semaine"
msgid "month"
msgstr "mois"
msgid "year"
msgstr "année"
msgid "from begining"
msgstr "depuis le début"
msgid "Limit:"
msgstr "Limite :"
msgid "Exclude post writer from list" msgid "Exclude post writer from list"
msgstr "Exclure de la liste les auteurs de billets" msgstr "Exclure de la liste les auteurs de billets"
msgid "Top writer: entries"
msgstr "Top rédacteur : billets"
msgid "List users who write more posts" msgid "List users who write more posts"
msgstr "Liste les utilisateurs qui ont écrit le plus de billets" msgstr "Liste les utilisateurs qui ont écrit le plus de billets"
msgid "Top entries" msgid "Top entries"
msgstr "Top billets" msgstr "Top billets"
msgid "Author link"
msgstr "Lien vers l'auteur"
msgid "one comment"
msgid_plural "%s comments"
msgstr[0] "un commentaire"
msgstr[1] "%s commentaires"
msgid "Author posts" msgid "Author posts"
msgstr "Billets de l'auteur" msgstr "Billets de l'auteur"
msgid "Author link"
msgstr "Lien vers l'auteur"
msgid "no entries" msgid "no entries"
msgstr "aucun billet" msgstr "aucun billet"
@ -72,6 +51,29 @@ msgid_plural "%s entries"
msgstr[0] "une publication" msgstr[0] "une publication"
msgstr[1] "%s publications" msgstr[1] "%s publications"
msgid "no comments"
msgstr "aucun commentaire"
msgid "one comment"
msgid_plural "%s comments"
msgstr[0] "un commentaire"
msgstr[1] "%s commentaires"
msgid "last day"
msgstr "dernier jour"
msgid "last week"
msgstr "dernière semaine"
msgid "last month"
msgstr "dernier mois"
msgid "last year"
msgstr "dernière année"
msgid "from begining"
msgstr "depuis le début"
msgid "Ranking of the most prolific writers and/or commentators" msgid "Ranking of the most prolific writers and/or commentators"
msgstr "Classement des plus prolifiques rédacteurs et/ou commentateurs" msgstr "Classement des plus prolifiques rédacteurs et/ou commentateurs"