code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Public tag cloud for notices
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Public
 * @package   StatusNet
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008 Mike Cochrane
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }

define('TAGS_PER_PAGE', 100);

/**
 * Public tag cloud for notices
 *
 * @category Personal
 * @package  StatusNet
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008 Mike Cochrane
 * @copyright 2008-2009 StatusNet, Inc.
 * @link     http://status.net/
 */
class PublictagcloudAction extends Action
{
    function isReadOnly($args)
    {
        return true;
    }

    function title()
    {
        // TRANS: Title for public tag cloud.
        return _('Public tag cloud');
    }

    function showPageNotice()
    {
        $this->element('p', 'instructions',
                       // TRANS: Instructions (more used like an explanation/header).
                       // TRANS: %s is the StatusNet sitename.
                       sprintf(_('These are most popular recent tags on %s'),
                               common_config('site', 'name')));
    }

    function showEmptyList()
    {
        // TRANS: This message contains a Markdown URL. The link description is between
        // TRANS: square brackets, and the link between parentheses. Do not separate "]("
        // TRANS: and do not change the URL part.
        $message = _('No one has posted a notice with a [hashtag](%%doc.tags%%) yet.') . ' ';

        if (common_logged_in()) {
            // TRANS: Message shown to a logged in user for the public tag cloud
            // TRANS: while no tags exist yet. "One" refers to the non-existing hashtag.
            $message .= _('Be the first to post one!');
        }
        else {
            // TRANS: Message shown to a anonymous user for the public tag cloud
            // TRANS: while no tags exist yet. "One" refers to the non-existing hashtag.
            // TRANS: This message contains a Markdown URL. The link description is between
            // TRANS: square brackets, and the link between parentheses. Do not separate "]("
            // TRANS: and do not change the URL part.
            $message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
        }

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    function handle()
    {
        parent::handle();
        $this->showPage();
    }

    function showContent()
    {
        // This should probably be cached rather than recalculated
        $tags = new Notice_tag();

        #Need to clear the selection and then only re-add the field
        #we are grouping by, otherwise it's not a valid 'group by'
        #even though MySQL seems to let it slide...
        $tags->selectAdd();
        $tags->selectAdd('tag');

        #Add the aggregated columns...
        $tags->selectAdd('max(notice_id) as last_notice_id');
        $calc = common_sql_weight('created', common_config('tag', 'dropoff'));
        $cutoff = sprintf("notice_tag.created > '%s'",
                          common_sql_date(time() - common_config('tag', 'cutoff')));
        $tags->selectAdd($calc . ' as weight');
        $tags->whereAdd($cutoff);
        $tags->groupBy('tag');
        $tags->orderBy('weight DESC');

        $tags->limit(TAGS_PER_PAGE);

        $cnt = $tags->find();

        if ($cnt > 0) {
            $this->elementStart('div', array('id' => 'tagcloud',
                                             'class' => 'section'));

            $tw = array();
            $sum = 0;
            while ($tags->fetch()) {
                $tw[$tags->tag] = $tags->weight;
                $sum += $tags->weight;
            }

            ksort($tw);

            $this->elementStart('ul', 'tags xoxo tag-cloud');
            foreach ($tw as $tag => $weight) {
                if ($sum) {
                    $weightedSum = $weight/$sum;
                } else {
                    $weightedSum = 0.5;
                }
                $this->showTag($tag, $weight, $weightedSum);
            }
            $this->elementEnd('ul');

            $this->elementEnd('div');
        } else {
            $this->showEmptyList();
        }
    }

    function showTag($tag, $weight, $relative)
    {
        if ($relative > 0.1) {
            $rel =  'tag-cloud-7';
        } else if ($relative > 0.05) {
            $rel = 'tag-cloud-6';
        } else if ($relative > 0.02) {
            $rel = 'tag-cloud-5';
        } else if ($relative > 0.01) {
            $rel = 'tag-cloud-4';
        } else if ($relative > 0.005) {
            $rel = 'tag-cloud-3';
        } else if ($relative > 0.002) {
            $rel = 'tag-cloud-2';
        } else {
            $rel = 'tag-cloud-1';
        }

        $this->elementStart('li', $rel);
        $this->element('a', array('href' => common_local_url('tag', array('tag' => $tag))),
                       $tag);
        $this->elementEnd('li');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Attachment tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Attachment tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class AttachmentTagCloudSection extends TagCloudSection
{
    function title()
    {
        // TRANS: Title.
        return _('Tags for this attachment');
    }

    function showTag($tag, $weight, $relative)
    {
        if ($relative > 0.5) {
            $rel =  'tag-cloud-7';
        } else if ($relative > 0.4) {
            $rel = 'tag-cloud-6';
        } else if ($relative > 0.3) {
            $rel = 'tag-cloud-5';
        } else if ($relative > 0.2) {
            $rel = 'tag-cloud-4';
        } else if ($relative > 0.1) {
            $rel = 'tag-cloud-3';
        } else if ($relative > 0.05) {
            $rel = 'tag-cloud-2';
        } else {
            $rel = 'tag-cloud-1';
        }

        $this->out->elementStart('li', $rel);
        $this->out->element('a', array('href' => $this->tagUrl($tag)),
                       $tag);
        $this->out->elementEnd('li');
    }

    function getTags()
    {
        $notice_tag = new Notice_tag;
        $query = 'select tag,count(tag) as weight from notice_tag join file_to_post on (notice_tag.notice_id=post_id) join notice on notice_id = notice.id where file_id=' . $notice_tag->escape($this->out->attachment->id) . ' group by tag order by weight desc';
        $notice_tag->query($query);
        return $notice_tag;
    }
}

license: mit


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Group tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class GroupTagCloudSection extends TagCloudSection
{
    var $group = null;

    function __construct($out=null, $group=null)
    {
        parent::__construct($out);
        $this->group = $group;
    }

    function title()
    {
        // TRANS: Title for group tag cloud section.
        // TRANS: %s is a group name.
        return _('Tags');
    }

    function getTags()
    {
        $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
        // @fixme should we use the cutoff too? Doesn't help with indexing per-group.

        $names = $this->group->getAliases();

        $names = array_merge(array($this->group->nickname), $names);

        // XXX This is dumb.

        $quoted = array();

        foreach ($names as $name) {
            $quoted[] = "'$name'";
        }

        $namestring = implode(',', $quoted);

        $qry = 'SELECT notice_tag.tag, '.
          $weightexpr . ' as weight ' .
          'FROM notice_tag JOIN notice ' .
          'ON notice_tag.notice_id = notice.id ' .
          'JOIN group_inbox on group_inbox.notice_id = notice.id ' .
          'WHERE group_inbox.group_id = %d ' .
          'AND notice_tag.tag not in (%s) '.
          'GROUP BY notice_tag.tag ' .
          'ORDER BY weight DESC ';

        $limit = TAGS_PER_SECTION;
        $offset = 0;

        if (common_config('db','type') == 'pgsql') {
            $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
        } else {
            $qry .= ' LIMIT ' . $offset . ', ' . $limit;
        }

        $tag = Memcached_DataObject::cachedQuery('Notice_tag',
                                                 sprintf($qry,
                                                         $this->group->id,
                                                         $namestring),
                                                 3600);
        return $tag;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class InboxTagCloudSection extends TagCloudSection
{
    const MAX_NOTICES = 1024;   // legacy value for "Inbox" table size when that existed

    protected $target = null;

    function __construct($out=null, Profile $target)
    {
        parent::__construct($out);
        $this->target = $target;
    }

    function title()
    {
        // TRANS: Title for inbox tag cloud section.
        return _m('TITLE', 'Trends');
    }

    function getTags()
    {
        // FIXME: Get the Profile::current() value some other way
        // to avoid confusion between background stuff and session.
        $stream = new InboxNoticeStream($this->target, Profile::current());

        $ids = $stream->getNoticeIds(0, self::MAX_NOTICES, null, null);

        if (empty($ids)) {
            $tag = array();
        } else {
            $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
            // @fixme should we use the cutoff too? Doesn't help with indexing per-user.

            $qry = 'SELECT notice_tag.tag, '.
                $weightexpr . ' as weight ' .
                'FROM notice_tag JOIN notice ' .
                'ON notice_tag.notice_id = notice.id ' .
                'WHERE notice.id in (' . implode(',', $ids) . ')'.
                'GROUP BY notice_tag.tag ' .
                'ORDER BY weight DESC ';

            $limit = TAGS_PER_SECTION;
            $offset = 0;

            if (common_config('db','type') == 'pgsql') {
                $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
            } else {
                $qry .= ' LIMIT ' . $offset . ', ' . $limit;
            }

            $t = new Notice_tag();

            $t->query($qry);

            $tag = array();

            while ($t->fetch()) {
                $tag[] = clone($t);
            }
        }

        return new ArrayWrapper($tag);
    }

    function showMore()
    {
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class PersonalTagCloudSection extends TagCloudSection
{
    protected $profile = null;

    function __construct(HTMLOutputter $out, Profile $profile)
    {
        parent::__construct($out);
        $this->profile = $profile;
    }

    function title()
    {
        // TRANS: Title for personal tag cloud section.
        return _m('TITLE','Tags');
    }

    function getTags()
    {
        $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
        // @fixme should we use the cutoff too? Doesn't help with indexing per-user.

        $qry = 'SELECT notice_tag.tag, '.
          $weightexpr . ' as weight ' .
          'FROM notice_tag JOIN notice ' .
          'ON notice_tag.notice_id = notice.id ' .
          'WHERE notice.profile_id = %d ' .
          'GROUP BY notice_tag.tag ' .
          'ORDER BY weight DESC ';

        $limit = TAGS_PER_SECTION;
        $offset = 0;

        if (common_config('db','type') == 'pgsql') {
            $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
        } else {
            $qry .= ' LIMIT ' . $offset . ', ' . $limit;
        }

        $tag = Memcached_DataObject::cachedQuery('Notice_tag',
                                                 sprintf($qry,
                                                         $this->profile->getID()),
                                                 3600);
        return $tag;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Public tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Public tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class PublicTagCloudSection extends TagCloudSection
{
    function __construct($out=null)
    {
        parent::__construct($out);
    }

    function title()
    {
        // TRANS: Title for inbox tag cloud section.
        return _m('TITLE', 'Trends');
    }

    function getTags()
    {
        $profile = Profile::current();

        if (empty($profile)) {
            $keypart = sprintf('Notice:public_tag_cloud:null');
        } else {
            $keypart = sprintf('Notice:public_tag_cloud:%d', $profile->id);
        }

        $tag = Memcached_DataObject::cacheGet($keypart);

        if ($tag === false) {

            $stream = new PublicNoticeStream($profile);

            $ids = $stream->getNoticeIds(0, 500, null, null);

            if (empty($ids)) {
                $tag = array();
            } else {
                $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
                // @fixme should we use the cutoff too? Doesn't help with indexing per-user.

                $qry = 'SELECT notice_tag.tag, '.
                    $weightexpr . ' as weight ' .
                    'FROM notice_tag JOIN notice ' .
                    'ON notice_tag.notice_id = notice.id ' .
                    'WHERE notice.id in (' . implode(',', $ids) . ') '.
                    'GROUP BY notice_tag.tag ' .
                    'ORDER BY weight DESC ';

                $limit = TAGS_PER_SECTION;
                $offset = 0;

                if (common_config('db','type') == 'pgsql') {
                    $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
                } else {
                    $qry .= ' LIMIT ' . $offset . ', ' . $limit;
                }

                $t = new Notice_tag();

                $t->query($qry);

                $tag = array();

                while ($t->fetch()) {
                    $tag[] = clone($t);
                }
            }

            Memcached_DataObject::cacheSet($keypart, $tag, 60 * 60 * 24);
        }

        return new ArrayWrapper($tag);
    }

    function showMore()
    {
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */

class SubPeopleTagCloudSection extends TagCloudSection
{
    function getTags()
    {
        $qry = $this->query();
        $limit = TAGS_PER_SECTION;
        $offset = 0;

        if (common_config('db','type') == 'pgsql') {
            $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
        } else {
            $qry .= ' LIMIT ' . $offset . ', ' . $limit;
        }

        $profile_tag = Memcached_DataObject::cachedQuery('Profile_tag',
                                                 sprintf($qry,
                                                         $this->out->user->id));
        return $profile_tag;
    }

    function tagUrl($tag) {
        return common_local_url('peopletag', array('tag' => $tag));
    }

    function showTag($tag, $weight, $relative) {
        $rel = 'tag-cloud-';
        $rel .= 1+intval(7 * $relative * $weight - 0.01);

        $this->out->elementStart('li', $rel);
        $this->out->element('a', array('href' => $this->tagUrl($tag)), $tag);
        $this->out->elementEnd('li');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscribersPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as self-tagged');
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged group by tag order by weight desc';

        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on  profile_list.tag =  profile_tag.tag and profile_list.tagger =  profile_tag.tagger and profile_tag.tagger = subscriber where subscribed=%d and subscribed != subscriber and profile_tag.tagger = tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';

//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscribed where subscriber=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscribersPeopleTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as tagged');
    }

    function tagUrl($tag) {
        $nickname = $this->out->profile->nickname;
        return common_local_url('subscribers', array('nickname' => $nickname, 'tag' => $tag));
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagged and subscribed=tagger where subscribed=%d and subscriber != subscribed group by tag order by weight desc';
        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagged and subscribed=profile_tag.tagger and profile_tag.tagger = profile_list.tagger and profile_tag.tag = profile_list.tag where subscribed=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscriptionsPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as self-tagged');
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscriber != subscribed and tagger = tagged group by tag order by weight desc';

        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on profile_tag.tagger = subscribed and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_tag.tagger where subscriber=%d and subscribed != subscriber and profile_tag.tagger = profile_tag.tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';

//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscriptionsPeopleTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as tagged');
    }

    function tagUrl($tag) {
        $nickname = $this->out->profile->nickname;
        return common_local_url('subscriptions', array('nickname' => $nickname, 'tag' => $tag));
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagger and subscribed=tagged where subscriber=%d and subscriber != subscribed group by tag order by weight desc';
        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagger and subscribed=tagged and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_list.tagger where subscriber=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for sections showing tag clouds
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

define('TAGS_PER_SECTION', 10);

/**
 * Base class for sections
 *
 * These are the widgets that show interesting data about a person
 * group, or site.
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class TagCloudSection extends Section
{
    function showContent()
    {
        $tags = $this->getTags();

        if (!$tags) {
            // TRANS: Content displayed in a tag cloud section if there are no tags.
            $this->out->element('p', null, _m('NOTAGS','None'));
            return false;
        }

        $cnt = 0;

        $tw = array();
        $sum = 0;

        while ($tags->fetch() && ++$cnt <= TAGS_PER_SECTION) {
            $tw[$tags->tag] = $tags->weight;
            $sum += $tags->weight;
        }

        if ($cnt == 0) {
            // TRANS: Content displayed in a tag cloud section if there are no tags.
            $this->out->element('p', null, _m('NOTAGS','None'));
            return false;
        }

        ksort($tw);

        $this->out->elementStart('ul', 'tags xoxo tag-cloud');
        foreach ($tw as $tag => $weight) {
            $this->showTag($tag, $weight, ($sum == 0) ? 0 : $weight/$sum);
        }
        $this->out->elementEnd('ul');

        return ($cnt > TAGS_PER_SECTION);
    }

    function getTags()
    {
        return null;
    }

    function showTag($tag, $weight, $relative)
    {
        if ($relative > 0.1) {
            $rel =  'tag-cloud-7';
        } else if ($relative > 0.05) {
            $rel = 'tag-cloud-6';
        } else if ($relative > 0.02) {
            $rel = 'tag-cloud-5';
        } else if ($relative > 0.01) {
            $rel = 'tag-cloud-4';
        } else if ($relative > 0.005) {
            $rel = 'tag-cloud-3';
        } else if ($relative > 0.002) {
            $rel = 'tag-cloud-2';
        } else {
            $rel = 'tag-cloud-1';
        }

        $this->out->elementStart('li', $rel);
        $this->out->element('a', array('href' => $this->tagUrl($tag)),
                       $tag);
        $this->out->elementEnd('li');
    }

    function tagUrl($tag)
    {
        if ($this->out instanceof ShowstreamAction) {
            return common_local_url('showstream', array('nickname' => $this->out->getTarget()->getNickname(), 'tag' => $tag));
        }
        return common_local_url('tag', array('tag' => $tag));
    }

    function divId()
    {
        return 'tagcloud';
    }
}


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-08 18:20+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. TRANS: Title for personal tag cloud section.
#: lib/personaltagcloudsection.php:54
msgctxt "TITLE"
msgid "Tags"
msgstr ""

#. TRANS: Content displayed in a tag cloud section if there are no tags.
#: lib/tagcloudsection.php:56 lib/tagcloudsection.php:72
msgctxt "NOTAGS"
msgid "None"
msgstr ""

#. TRANS: Title for inbox tag cloud section.
#: lib/inboxtagcloudsection.php:56 lib/publictagcloudsection.php:53
msgctxt "TITLE"
msgid "Trends"
msgstr ""

#. TRANS: Menu item in search group navigation panel.
#: TagCloudPlugin.php:29
msgctxt "MENU"
msgid "Recent tags"
msgstr ""

#. TRANS: Plugin description.
#: TagCloudPlugin.php:68
msgid "Adds tag clouds to stream pages"
msgstr ""


code:
The TagSub plugin allows following all messages with a given tag.

Installation
============
This plugin is enabled by default

Settings
========
none

path: plugins/TagSub/README


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * A plugin to enable local tab subscription
 *
 * PHP version 5
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  TagSubPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * TagSub plugin main class
 *
 * @category  TagSubPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brionv@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class TagSubPlugin extends Plugin
{
    const PLUGIN_VERSION = '0.1.1';

    /**
     * Database schema setup
     *
     * @return bool hook value; true means continue processing, false means stop.
     * @see Schema
     *
     */
    public function onCheckSchema()
    {
        $schema = Schema::get();
        $schema->ensureTable('tagsub', TagSub::schemaDef());
        return true;
    }

    /**
     * Map URLs to actions
     *
     * @param URLMapper $m path-to-action mapper
     *
     * @return boolean hook value; true means continue processing, false means stop.
     */
    public function onRouterInitialized(URLMapper $m)
    {
        $m->connect('tag/:tag/subscribe',
                    ['action' => 'tagsub'],
                    ['tag' => Router::REGEX_TAG]);

        $m->connect('tag/:tag/unsubscribe',
                    ['action' => 'tagunsub'],
                    ['tag' => Router::REGEX_TAG]);

        $m->connect(':nickname/tag-subscriptions',
                    ['action' => 'tagsubs'],
                    ['nickname' => Nickname::DISPLAY_FMT]);

        return true;
    }

    /**
     * Plugin version data
     *
     * @param array &$versions array of version data
     *
     * @return bool true hook value
     */
    public function onPluginVersion(array &$versions)
    {
        $versions[] = ['name' => 'TagSub',
            'version' => self::PLUGIN_VERSION,
            'author' => 'Brion Vibber',
            'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/TagSub',
            'rawdescription' =>
            // TRANS: Plugin description.
                _m('Plugin to allow following all messages with a given tag.')];
        return true;
    }

    /**
     * Hook inbox delivery setup so tag subscribers receive all
     * notices with that tag in their inbox.
     *
     * Currently makes no distinction between local messages and
     * remote ones which happen to come in to the system. Remote
     * notices that don't come in at all won't ever reach this.
     *
     * @param Notice $notice
     * @param array $ni in/out map of profile IDs to inbox constants
     * @return boolean hook result
     */
    public function onStartNoticeWhoGets(Notice $notice, array &$ni)
    {
        foreach ($notice->getTags() as $tag) {
            $tagsub = new TagSub();
            $tagsub->tag = $tag;
            $tagsub->find();

            while ($tagsub->fetch()) {
                // These constants are currently not actually used, iirc
                $ni[$tagsub->profile_id] = NOTICE_INBOX_SOURCE_SUB;
            }
        }
        return true;
    }

    /**
     *
     * @param TagAction $action
     * @return boolean hook result
     */
    public function onStartTagShowContent(TagAction $action)
    {
        $user = common_current_user();
        if ($user) {
            $tag = $action->trimmed('tag');
            $tagsub = TagSub::pkeyGet(array('tag' => $tag,
                'profile_id' => $user->id));
            if ($tagsub) {
                $form = new TagUnsubForm($action, $tag);
            } else {
                $form = new TagSubForm($action, $tag);
            }
            $action->elementStart('div', 'entity_actions');
            $action->elementStart('ul');
            $action->elementStart('li', 'entity_subscribe');
            $form->show();
            $action->elementEnd('li');
            $action->elementEnd('ul');
            $action->elementEnd('div');
        }
        return true;
    }

    /**
     * Menu item for personal subscriptions/groups area
     *
     * @param Widget $widget Widget being executed
     *
     * @return boolean hook return
     * @throws Exception
     */
    public function onEndSubGroupNav($widget)
    {
        $action = $widget->out;
        $action_name = $action->trimmed('action');

        $action->menuItem(
            common_local_url('tagsubs', array('nickname' => $action->user->nickname)),
            // TRANS: SubMirror plugin menu item on user settings page.
            _m('MENU', 'Tags'),
            // TRANS: SubMirror plugin tooltip for user settings menu item.
            _m('Configure tag subscriptions'),
            $action_name == 'tagsubs' && $action->arg('nickname') == $action->user->nickname
        );

        return true;
    }

    public function onEndDefaultLocalNav($menu, $user)
    {
        $user = $user ? $user : common_current_user();

        if (!empty($user)) {
            $tags = TagSub::forProfile($user->getProfile());

            if (!empty($tags) && count($tags) > 0) {
                $tagSubMenu = new TagSubMenu($menu->out, $user, $tags);
                // TRANS: Menu item text for tags submenu.
                $menu->submenu(_m('Tags'), $tagSubMenu);
            }
        }

        return true;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008-2011, StatusNet, Inc.
 *
 * Tag subscription action.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5
 *
 * @category  Action
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Tag subscription action
 *
 * Takes parameters:
 *
 *    - token: session token to prevent CSRF attacks
 *    - ajax: boolean; whether to return Ajax or full-browser results
 *
 * Only works if the current user is logged in.
 *
 * @category  Action
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2008-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */
class TagsubAction extends Action
{
    public $user;
    public $tag;

    /**
     * Check pre-requisites and instantiate attributes
     *
     * @param Array $args array of arguments (URL, GET, POST)
     *
     * @return boolean success flag
     * @throws ClientException
     */
    public function prepare(array $args = array())
    {
        parent::prepare($args);
        if ($this->boolean('ajax')) {
            GNUsocial::setApi(true);
        }

        // Only allow POST requests

        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            // TRANS: Client error displayed trying to perform any request method other than POST.
            // TRANS: Do not translate POST.
            $this->clientError(_m('This action only accepts POST requests.'));
        }

        // CSRF protection

        $token = $this->trimmed('token');

        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token is not okay.
            $this->clientError(_m('There was a problem with your session token.' .
                ' Try again, please.'));
        }

        // Only for logged-in users

        $this->user = common_current_user();

        if (empty($this->user)) {
            // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
            $this->clientError(_m('Not logged in.'));
        }

        // Profile to subscribe to

        $this->tag = $this->arg('tag');

        if (empty($this->tag)) {
            // TRANS: Client error displayed trying to subscribe to a non-existing profile.
            $this->clientError(_m('No such profile.'));
        }

        return true;
    }

    /**
     * Handle request
     *
     * Does the subscription and returns results.
     *
     * @return void
     * @throws ClientException
     */
    public function handle()
    {
        // Throws exception on error

        TagSub::start(
            $this->user->getProfile(),
            $this->tag
        );

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Page title when tag subscription succeeded.
            $this->element('title', null, _m('Subscribed'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $unsubscribe = new TagUnsubForm($this, $this->tag);
            $unsubscribe->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            $url = common_local_url(
                'tag',
                array('tag' => $this->tag)
            );
            common_redirect($url, 303);
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * List of a user's subscriptions
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Social
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) {
    exit(1);
}

/**
 * A list of the user's subscriptions
 *
 * @category Social
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class TagSubsAction extends GalleryAction
{
    public function title()
    {
        if ($this->page == 1) {
            // TRANS: Header for subscriptions overview for a user (first page).
            // TRANS: %s is a user nickname.
            return sprintf(_m('%s\'s tag subscriptions'), $this->getTarget()->getNickname());
        } else {
            // TRANS: Header for subscriptions overview for a user (not first page).
            // TRANS: %1$s is a user nickname, %2$d is the page number.
            return sprintf(
                _m('%1$s\'s tag subscriptions, page %2$d'),
                $this->getTarget()->getNickname(),
                $this->page
            );
        }
    }

    public function showPageNotice()
    {
        if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) {
            $this->element(
                'p',
                null,
                // TRANS: Page notice for page with an overview of all tag subscriptions
                // TRANS: of the logged in user's own profile.
                _m('You have subscribed to receive all notices on this site containing the following tags:')
            );
        } else {
            $this->element(
                'p',
                null,
                // TRANS: Page notice for page with an overview of all subscriptions of a user other
                // TRANS: than the logged in user. %s is the user nickname.
                sprintf(
                    _m('%s has subscribed to receive all notices on this site containing the following tags:'),
                    $this->getTarget()->getNickname()
                )
            );
        }
    }

    public function showContent()
    {
        if (Event::handle('StartShowTagSubscriptionsContent', array($this))) {
            parent::showContent();

            $offset = ($this->page - 1) * PROFILES_PER_PAGE;
            $limit = PROFILES_PER_PAGE + 1;

            $cnt = 0;

            $tagsub = new TagSub();
            $tagsub->profile_id = $this->getTarget()->getID();
            $tagsub->limit($limit, $offset);
            $tagsub->find();

            if ($tagsub->N) {
                $list = new TagSubscriptionsList($tagsub, $this->getTarget(), $this);
                $cnt = $list->show();
                if (0 == $cnt) {
                    $this->showEmptyListMessage();
                }
            } else {
                $this->showEmptyListMessage();
            }

            $this->pagination(
                $this->page > 1,
                $cnt > PROFILES_PER_PAGE,
                $this->page,
                'tagsubs',
                array('nickname' => $this->getTarget()->getNickname())
            );

            Event::handle('EndShowTagSubscriptionsContent', array($this));
        }
    }

    public function showEmptyListMessage()
    {
        if (common_logged_in()) {
            if ($this->scoped->sameAs($this->getTarget())) {
                // TRANS: Tag subscription list text when the logged in user has no tag subscriptions.
                $message = _m('You are not listening to any hash tags right now. You can push the "Subscribe" button ' .
                    'on any hashtag page to automatically receive any public messages on this site that use that ' .
                    'tag, even if you are not subscribed to the poster.');
            } else {
                // TRANS: Tag subscription list text when looking at the subscriptions for a of a user other
                // TRANS: than the logged in user that has no tag subscriptions. %s is the user nickname.
                $message = sprintf(_m('%s is not following any tags.'), $this->getTarget()->getNickname());
            }
        } else {
            // TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
            // TRANS: as an anonymous user. %s is the user nickname.
            $message = sprintf(_m('%s is not following any tags.'), $this->getTarget()->getNickname());
        }

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }
}

// XXX SubscriptionsList and SubscriptionList are dangerously close

class TagSubscriptionsList extends SubscriptionList
{
    public function newListItem($tagsub)
    {
        return new TagSubscriptionsListItem($tagsub, $this->owner, $this->action);
    }
}

class TagSubscriptionsListItem extends SubscriptionListItem
{
    public function startItem()
    {
        $this->out->elementStart('li', array('class' => 'tagsub'));
    }

    public function showProfile()
    {
        $tagsub = $this->getTarget();
        $tag = $tagsub->tag;

        // Relevant portion!
        $cur = common_current_user();
        if (!empty($cur) && $cur->id == $this->owner->id) {
            $this->showOwnerControls();
        }

        $url = common_local_url('tag', array('tag' => $tag));
        // TRANS: %1$s is a URL to a tag, %2$s is a tag,
        // TRANS: %3$s a date string.
        $linkline = sprintf(
            _m('#%2$s since %3$s'),
            htmlspecialchars($url),
            htmlspecialchars($tag),
            common_date_string($tagsub->created)
        );

        $this->out->elementStart('div', 'tagsub-item');
        $this->out->raw($linkline);
        $this->out->element('div', array('style' => 'clear: both'));
        $this->out->elementEnd('div');
    }

    public function showActions()
    {
    }

    public function showOwnerControls()
    {
        $this->out->elementStart('div', 'entity_actions');

        $tagsub = $this->target;
        $form = new TagUnsubForm($this->out, $tagsub->tag);
        $form->show();

        $this->out->elementEnd('div');
        return;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008-2011, StatusNet, Inc.
 *
 * Tag subscription action.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5
 *
 * @category  Action
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Tag unsubscription action
 *
 * Takes parameters:
 *
 *    - token: session token to prevent CSRF attacks
 *    - ajax: boolean; whether to return Ajax or full-browser results
 *
 * Only works if the current user is logged in.
 *
 * @category  Action
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2008-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */
class TagunsubAction extends TagsubAction
{
    /**
     * Handle request
     *
     * Does the subscription and returns results.
     *
     * @return void
     * @throws ClientException
     */
    public function handle()
    {
        // Throws exception on error

        TagSub::cancel(
            $this->user->getProfile(),
            $this->tag
        );

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Page title when tag unsubscription succeeded.
            $this->element('title', null, _m('Unsubscribed'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $subscribe = new TagSubForm($this, $this->tag);
            $subscribe->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            $url = common_local_url(
                'tag',
                array('tag' => $this->tag)
            );
            common_redirect($url, 303);
        }
    }
}


code:
<?php
/**
 * Data class to store local tag subscriptions
 *
 * PHP version 5
 *
 * @category TagSubPlugin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * For storing the tag subscriptions
 *
 * @category PollPlugin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * @see      DB_DataObject
 */
class TagSub extends Managed_DataObject
{
    public $__table = 'tagsub'; // table name
    public $tag;         // text
    public $profile_id;  // int -> profile.id
    public $created;     // datetime

    /**
     * The One True Thingy that must be defined and declared.
     */
    public static function schemaDef()
    {
        return array(
            'description' => 'TagSubPlugin tag subscription records',
            'fields' => array(
                'tag' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'hash tag associated with this subscription'),
                'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile ID of subscribing user'),
                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
            ),
            'primary key' => array('tag', 'profile_id'),
            'foreign keys' => array(
                'tagsub_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
            ),
            'indexes' => array(
                'tagsub_created_idx' => array('created'),
                'tagsub_profile_id_tag_idx' => array('profile_id', 'tag'),
            ),
        );
    }

    /**
     * Start a tag subscription!
     *
     * @param profile $profile subscriber
     * @param string $tag subscribee
     * @return TagSub
     */
    public static function start(Profile $profile, $tag)
    {
        $ts = new TagSub();
        $ts->tag = $tag;
        $ts->profile_id = $profile->id;
        $ts->created = common_sql_now();
        $ts->insert();
        self::blow('tagsub:by_profile:%d', $profile->id);
        return $ts;
    }

    /**
     * End a tag subscription!
     *
     * @param profile $profile subscriber
     * @param string $tag subscribee
     */
    public static function cancel(Profile $profile, $tag)
    {
        $ts = TagSub::pkeyGet(array('tag' => $tag,
            'profile_id' => $profile->id));
        if ($ts) {
            $ts->delete();
            self::blow('tagsub:by_profile:%d', $profile->id);
        }
    }

    public static function forProfile(Profile $profile)
    {
        $tags = array();

        $keypart = sprintf('tagsub:by_profile:%d', $profile->id);
        $tagstring = self::cacheGet($keypart);

        if ($tagstring !== false) { // cache hit
            if (!empty($tagstring)) {
                $tags = explode(',', $tagstring);
            }
        } else {
            $tagsub = new TagSub();
            $tagsub->profile_id = $profile->id;
            $tagsub->selectAdd();
            $tagsub->selectAdd('tag');

            if ($tagsub->find()) {
                $tags = $tagsub->fetchAll('tag');
            }

            self::cacheSet($keypart, implode(',', $tags));
        }

        return $tags;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for subscribing to a tag
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  TagSubPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Form for subscribing to a user
 *
 * @category TagSubPlugin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class TagSubForm extends Form
{
    /**
     * Name of tag to subscribe to
     */
    public $tag = '';

    /**
     * Constructor
     *
     * @param HTMLOutputter $out output channel
     * @param string $tag name of tag to subscribe to
     */
    public function __construct($out = null, $tag = null)
    {
        parent::__construct($out);

        $this->tag = $tag;
    }

    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    public function id()
    {
        return 'tag-subscribe-' . $this->tag;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    public function formClass()
    {
        // class to match existing styles...
        return 'form_user_subscribe ajax';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    public function action()
    {
        return common_local_url('tagsub', array('tag' => $this->tag));
    }

    /**
     * Legend of the Form
     *
     * @return void
     * @throws Exception
     */
    public function formLegend()
    {
        // TRANS: Form legend.
        $this->out->element('legend', null, _m('Subscribe to this tag'));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    public function formData()
    {
        $this->out->hidden(
            'subscribeto-' . $this->tag,
            $this->tag,
            'subscribeto'
        );
    }

    /**
     * Action elements
     *
     * @return void
     * @throws Exception
     */
    public function formActions()
    {
        // TRANS: Submit button text to subscribe to a tag.
        $this->out->submit(
            'submit',
            _m('BUTTON', 'Subscribe'),
            // TRANS: Submit button title to subscribe to a tag.
            'submit',
            null,
            _m('Subscribe to this tag.')
        );
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for subscribing to a tag
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  TagSubPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Form for subscribing to a user
 *
 * @category TagSubPlugin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class TagUnsubForm extends TagSubForm
{
    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    public function id()
    {
        return 'tag-unsubscribe-' . $this->tag;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    public function formClass()
    {
        // class to match existing styles...
        return 'form_user_unsubscribe ajax';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    public function action()
    {
        return common_local_url('tagunsub', array('tag' => $this->tag));
    }

    /**
     * Legend of the Form
     *
     * @return void
     * @throws Exception
     */
    public function formLegend()
    {
        // TRANS: Form legend.
        $this->out->element('legend', null, _m('Unsubscribe from this tag'));
    }

    /**
     * Action elements
     *
     * @return void
     * @throws Exception
     */
    public function formActions()
    {
        // TRANS: Submit button text to unsubscribe from a tag.
        $this->out->submit(
            'submit',
            _m('BUTTON', 'Unsubscribe'),
            // TRANS: Submit button title to unsubscribe from a tag.
            'submit',
            null,
            _m('Unsubscribe from this tag.')
        );
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Menu to show tags you're subscribed to
 *
 * PHP version 5
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Menu
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * Class comment
 *
 * @category  General
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class TagSubMenu extends MoreMenu
{
    protected $user;
    protected $tags;

    public function __construct($out, $user, $tags)
    {
        parent::__construct($out);
        $this->user = $user;
        $this->tags = $tags;
    }

    public function getItems()
    {
        $items = array();

        foreach ($this->tags as $tag) {
            if (!empty($tag)) {
                $items[] = array('tag',
                    array('tag' => $tag),
                    sprintf('#%s', $tag),
                    // TRANS: Menu item title. %s is a tag.
                    sprintf(_('Notices tagged with "%s".'), $tag));
            }
        }

        return $items;
    }

    public function tag()
    {
        return 'tagsubs';
    }

    public function seeAllItem()
    {
        return array('tagsubs',
            array('nickname' => $this->user->nickname),
            _('See all'),
            _('See all tags you are following'));
    }
}


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-13 00:46+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. TRANS: Header for subscriptions overview for a user (first page).
#. TRANS: %s is a user nickname.
#: actions/tagsubs.php:51
#, php-format
msgid "%s's tag subscriptions"
msgstr ""

#: actions/tagsubs.php:56
#, php-format
msgid "%1$s's tag subscriptions, page %2$d"
msgstr ""

#. TRANS: Page notice for page with an overview of all tag subscriptions
#. TRANS: of the logged in user's own profile.
#: actions/tagsubs.php:71
msgid ""
"You have subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#: actions/tagsubs.php:80
#, php-format
msgid ""
"%s has subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Tag subscription list text when the logged in user has no tag subscriptions.
#: actions/tagsubs.php:130
msgid ""
"You are not listening to any hash tags right now. You can push the "
"\"Subscribe\" button on any hashtag page to automatically receive any public "
"messages on this site that use that tag, even if you are not subscribed to "
"the poster."
msgstr ""

#. TRANS: Tag subscription list text when looking at the subscriptions for a of a user other
#. TRANS: than the logged in user that has no tag subscriptions. %s is the user nickname.
#. TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
#. TRANS: as an anonymous user. %s is the user nickname.
#: actions/tagsubs.php:136 actions/tagsubs.php:141
#, php-format
msgid "%s is not following any tags."
msgstr ""

#: actions/tagsubs.php:182
#, php-format
msgid "#%2$s since %3$s"
msgstr ""

#. TRANS: Client error displayed trying to perform any request method other than POST.
#. TRANS: Do not translate POST.
#: actions/tagsub.php:79
msgid "This action only accepts POST requests."
msgstr ""

#. TRANS: Client error displayed when the session token is not okay.
#: actions/tagsub.php:88
msgid "There was a problem with your session token. Try again, please."
msgstr ""

#. TRANS: Error message displayed when trying to perform an action that requires a logged in user.
#: actions/tagsub.php:98
msgid "Not logged in."
msgstr ""

#. TRANS: Client error displayed trying to subscribe to a non-existing profile.
#: actions/tagsub.php:107
msgid "No such profile."
msgstr ""

#. TRANS: Page title when tag subscription succeeded.
#: actions/tagsub.php:134
msgid "Subscribed"
msgstr ""

#. TRANS: Page title when tag unsubscription succeeded.
#: actions/tagunsub.php:77
msgid "Unsubscribed"
msgstr ""

#. TRANS: Plugin description.
#: TagSubPlugin.php:106
msgid "Plugin to allow following all messages with a given tag."
msgstr ""

#. TRANS: SubMirror plugin menu item on user settings page.
#: TagSubPlugin.php:181
msgctxt "MENU"
msgid "Tags"
msgstr ""

#. TRANS: SubMirror plugin tooltip for user settings menu item.
#: TagSubPlugin.php:183
msgid "Configure tag subscriptions"
msgstr ""

#. TRANS: Menu item text for tags submenu.
#: TagSubPlugin.php:200
msgid "Tags"
msgstr ""

#. TRANS: Form legend.
#: forms/tagsub.php:109
msgid "Subscribe to this tag"
msgstr ""

#: forms/tagsub.php:137
msgctxt "BUTTON"
msgid "Subscribe"
msgstr ""

#: forms/tagsub.php:141
msgid "Subscribe to this tag."
msgstr ""

#. TRANS: Form legend.
#: forms/tagunsub.php:91
msgid "Unsubscribe from this tag"
msgstr ""

#: forms/tagunsub.php:105
msgctxt "BUTTON"
msgid "Unsubscribe"
msgstr ""

#: forms/tagunsub.php:109
msgid "Unsubscribe from this tag."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:43+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Afrikaans (http://www.transifex.com/gnu-social/gnu-social/language/af/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: af\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Form legend.
#: forms/tagunsub.php:90
msgid "Unsubscribe from this tag"
msgstr ""

#. TRANS: Submit button text to unsubscribe from a tag.
#: forms/tagunsub.php:101
msgctxt "BUTTON"
msgid "Unsubscribe"
msgstr ""

#. TRANS: Submit button title to unsubscribe from a tag.
#: forms/tagunsub.php:103
msgid "Unsubscribe from this tag."
msgstr ""

#. TRANS: Form legend.
#: forms/tagsub.php:108
msgid "Subscribe to this tag"
msgstr ""

#. TRANS: Submit button text to subscribe to a tag.
#: forms/tagsub.php:131
msgctxt "BUTTON"
msgid "Subscribe"
msgstr ""

#. TRANS: Submit button title to subscribe to a tag.
#: forms/tagsub.php:133
msgid "Subscribe to this tag."
msgstr ""

#. TRANS: Page title when tag unsubscription succeeded.
#: actions/tagunsub.php:76
msgid "Unsubscribed"
msgstr ""

#. TRANS: Header for subscriptions overview for a user (first page).
#. TRANS: %s is a user nickname.
#: actions/tagsubs.php:51
#, php-format
msgid "%s's tag subscriptions"
msgstr ""

#. TRANS: Header for subscriptions overview for a user (not first page).
#. TRANS: %1$s is a user nickname, %2$d is the page number.
#: actions/tagsubs.php:55
#, php-format
msgid "%1$s's tag subscriptions, page %2$d"
msgstr ""

#. TRANS: Page notice for page with an overview of all tag subscriptions
#. TRANS: of the logged in user's own profile.
#: actions/tagsubs.php:68
msgid ""
"You have subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Page notice for page with an overview of all subscriptions of a user
#. other
#. TRANS: than the logged in user. %s is the user nickname.
#: actions/tagsubs.php:73
#, php-format
msgid ""
"%s has subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Tag subscription list text when the logged in user has no tag
#. subscriptions.
#: actions/tagsubs.php:118
msgid ""
"You are not listening to any hash tags right now. You can push the "
"\"Subscribe\" button on any hashtag page to automatically receive any public"
" messages on this site that use that tag, even if you are not subscribed to "
"the poster."
msgstr ""

#. TRANS: Tag subscription list text when looking at the subscriptions for a
#. of a user other
#. TRANS: than the logged in user that has no tag subscriptions. %s is the
#. user nickname.
#. TRANS: Subscription list text when looking at the subscriptions for a of a
#. user that has none
#. TRANS: as an anonymous user. %s is the user nickname.
#: actions/tagsubs.php:124 actions/tagsubs.php:130
#, php-format
msgid "%s is not following any tags."
msgstr ""

#. TRANS: %1$s is a URL to a tag, %2$s is a tag,
#. TRANS: %3$s a date string.
#: actions/tagsubs.php:170
#, php-format
msgid "#%2$s since %3$s"
msgstr ""

#. TRANS: Client error displayed trying to perform any request method other
#. than POST.
#. TRANS: Do not translate POST.
#: actions/tagsub.php:78
msgid "This action only accepts POST requests."
msgstr ""

#. TRANS: Client error displayed when the session token is not okay.
#: actions/tagsub.php:87
msgid "There was a problem with your session token. Try again, please."
msgstr ""

#. TRANS: Error message displayed when trying to perform an action that
#. requires a logged in user.
#: actions/tagsub.php:97
msgid "Not logged in."
msgstr "Nie aangeteken nie."

#. TRANS: Client error displayed trying to subscribe to a non-existing
#. profile.
#: actions/tagsub.php:106
msgid "No such profile."
msgstr ""

#. TRANS: Page title when tag subscription succeeded.
#: actions/tagsub.php:132
msgid "Subscribed"
msgstr ""

#. TRANS: Plugin description.
#: TagSubPlugin.php:100
msgid "Plugin to allow following all messages with a given tag."
msgstr ""

#. TRANS: SubMirror plugin menu item on user settings page.
#: TagSubPlugin.php:173
msgctxt "MENU"
msgid "Tags"
msgstr "Etikette"

#. TRANS: SubMirror plugin tooltip for user settings menu item.
#: TagSubPlugin.php:175
msgid "Configure tag subscriptions"
msgstr ""

#. TRANS: Menu item text for tags submenu.
#: TagSubPlugin.php:192
msgid "Tags"
msgstr "Etikette"


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2011 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 12:33+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Arabic (http://www.transifex.com/gnu-social/gnu-social/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Form legend.
#: forms/tagunsub.php:90
msgid "Unsubscribe from this tag"
msgstr ""

#. TRANS: Submit button text to unsubscribe from a tag.
#: forms/tagunsub.php:101
msgctxt "BUTTON"
msgid "Unsubscribe"
msgstr "ألغِ الاشتراك"

#. TRANS: Submit button title to unsubscribe from a tag.
#: forms/tagunsub.php:103
msgid "Unsubscribe from this tag."
msgstr ""

#. TRANS: Form legend.
#: forms/tagsub.php:108
msgid "Subscribe to this tag"
msgstr "اشتراك بهذا الوسم"

#. TRANS: Submit button text to subscribe to a tag.
#: forms/tagsub.php:131
msgctxt "BUTTON"
msgid "Subscribe"
msgstr "اشترك"

#. TRANS: Submit button title to subscribe to a tag.
#: forms/tagsub.php:133
msgid "Subscribe to this tag."
msgstr "اشترك بهذا الوسم."

#. TRANS: Page title when tag unsubscription succeeded.
#: actions/tagunsub.php:76
msgid "Unsubscribed"
msgstr "أُلغيَ الاشتراك"

#. TRANS: Header for subscriptions overview for a user (first page).
#. TRANS: %s is a user nickname.
#: actions/tagsubs.php:51
#, php-format
msgid "%s's tag subscriptions"
msgstr ""

#. TRANS: Header for subscriptions overview for a user (not first page).
#. TRANS: %1$s is a user nickname, %2$d is the page number.
#: actions/tagsubs.php:55
#, php-format
msgid "%1$s's tag subscriptions, page %2$d"
msgstr ""

#. TRANS: Page notice for page with an overview of all tag subscriptions
#. TRANS: of the logged in user's own profile.
#: actions/tagsubs.php:68
msgid ""
"You have subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Page notice for page with an overview of all subscriptions of a user
#. other
#. TRANS: than the logged in user. %s is the user nickname.
#: actions/tagsubs.php:73
#, php-format
msgid ""
"%s has subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Tag subscription list text when the logged in user has no tag
#. subscriptions.
#: actions/tagsubs.php:118
msgid ""
"You are not listening to any hash tags right now. You can push the "
"\"Subscribe\" button on any hashtag page to automatically receive any public"
" messages on this site that use that tag, even if you are not subscribed to "
"the poster."
msgstr ""

#. TRANS: Tag subscription list text when looking at the subscriptions for a
#. of a user other
#. TRANS: than the logged in user that has no tag subscriptions. %s is the
#. user nickname.
#. TRANS: Subscription list text when looking at the subscriptions for a of a
#. user that has none
#. TRANS: as an anonymous user. %s is the user nickname.
#: actions/tagsubs.php:124 actions/tagsubs.php:130
#, php-format
msgid "%s is not following any tags."
msgstr ""

#. TRANS: %1$s is a URL to a tag, %2$s is a tag,
#. TRANS: %3$s a date string.
#: actions/tagsubs.php:170
#, php-format
msgid "#%2$s since %3$s"
msgstr ""

#. TRANS: Client error displayed trying to perform any request method other
#. than POST.
#. TRANS: Do not translate POST.
#: actions/tagsub.php:78
msgid "This action only accepts POST requests."
msgstr "هذا الإجراء يقبل طلبات POST فقط."

#. TRANS: Client error displayed when the session token is not okay.
#: actions/tagsub.php:87
msgid "There was a problem with your session token. Try again, please."
msgstr ""

#. TRANS: Error message displayed when trying to perform an action that
#. requires a logged in user.
#: actions/tagsub.php:97
msgid "Not logged in."
msgstr "لست والجًا."

#. TRANS: Client error displayed trying to subscribe to a non-existing
#. profile.
#: actions/tagsub.php:106
msgid "No such profile."
msgstr "لا يوجد ملف شخصي بهذا الاسم."

#. TRANS: Page title when tag subscription succeeded.
#: actions/tagsub.php:132
msgid "Subscribed"
msgstr "مُشترك"

#. TRANS: Plugin description.
#: TagSubPlugin.php:100
msgid "Plugin to allow following all messages with a given tag."
msgstr ""

#. TRANS: SubMirror plugin menu item on user settings page.
#: TagSubPlugin.php:173
msgctxt "MENU"
msgid "Tags"
msgstr "الوسوم"

#. TRANS: SubMirror plugin tooltip for user settings menu item.
#: TagSubPlugin.php:175
msgid "Configure tag subscriptions"
msgstr ""

#. TRANS: Menu item text for tags submenu.
#: TagSubPlugin.php:192
msgid "Tags"
msgstr "الوسوم"


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:43+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (Egypt) (http://www.transifex.com/gnu-social/gnu-social/language/ar_EG/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar_EG\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Form legend.
#: forms/tagunsub.php:90
msgid "Unsubscribe from this tag"
msgstr ""

#. TRANS: Submit button text to unsubscribe from a tag.
#: forms/tagunsub.php:101
msgctxt "BUTTON"
msgid "Unsubscribe"
msgstr ""

#. TRANS: Submit button title to unsubscribe from a tag.
#: forms/tagunsub.php:103
msgid "Unsubscribe from this tag."
msgstr ""

#. TRANS: Form legend.
#: forms/tagsub.php:108
msgid "Subscribe to this tag"
msgstr ""

#. TRANS: Submit button text to subscribe to a tag.
#: forms/tagsub.php:131
msgctxt "BUTTON"
msgid "Subscribe"
msgstr ""

#. TRANS: Submit button title to subscribe to a tag.
#: forms/tagsub.php:133
msgid "Subscribe to this tag."
msgstr ""

#. TRANS: Page title when tag unsubscription succeeded.
#: actions/tagunsub.php:76
msgid "Unsubscribed"
msgstr ""

#. TRANS: Header for subscriptions overview for a user (first page).
#. TRANS: %s is a user nickname.
#: actions/tagsubs.php:51
#, php-format
msgid "%s's tag subscriptions"
msgstr ""

#. TRANS: Header for subscriptions overview for a user (not first page).
#. TRANS: %1$s is a user nickname, %2$d is the page number.
#: actions/tagsubs.php:55
#, php-format
msgid "%1$s's tag subscriptions, page %2$d"
msgstr ""

#. TRANS: Page notice for page with an overview of all tag subscriptions
#. TRANS: of the logged in user's own profile.
#: actions/tagsubs.php:68
msgid ""
"You have subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Page notice for page with an overview of all subscriptions of a user
#. other
#. TRANS: than the logged in user. %s is the user nickname.
#: actions/tagsubs.php:73
#, php-format
msgid ""
"%s has subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Tag subscription list text when the logged in user has no tag
#. subscriptions.
#: actions/tagsubs.php:118
msgid ""
"You are not listening to any hash tags right now. You can push the "
"\"Subscribe\" button on any hashtag page to automatically receive any public"
" messages on this site that use that tag, even if you are not subscribed to "
"the poster."
msgstr ""

#. TRANS: Tag subscription list text when looking at the subscriptions for a
#. of a user other
#. TRANS: than the logged in user that has no tag subscriptions. %s is the
#. user nickname.
#. TRANS: Subscription list text when looking at the subscriptions for a of a
#. user that has none
#. TRANS: as an anonymous user. %s is the user nickname.
#: actions/tagsubs.php:124 actions/tagsubs.php:130
#, php-format
msgid "%s is not following any tags."
msgstr ""

#. TRANS: %1$s is a URL to a tag, %2$s is a tag,
#. TRANS: %3$s a date string.
#: actions/tagsubs.php:170
#, php-format
msgid "#%2$s since %3$s"
msgstr ""

#. TRANS: Client error displayed trying to perform any request method other
#. than POST.
#. TRANS: Do not translate POST.
#: actions/tagsub.php:78
msgid "This action only accepts POST requests."
msgstr ""

#. TRANS: Client error displayed when the session token is not okay.
#: actions/tagsub.php:87
msgid "There was a problem with your session token. Try again, please."
msgstr ""

#. TRANS: Error message displayed when trying to perform an action that
#. requires a logged in user.
#: actions/tagsub.php:97
msgid "Not logged in."
msgstr "لست والجًا."

#. TRANS: Client error displayed trying to subscribe to a non-existing
#. profile.
#: actions/tagsub.php:106
msgid "No such profile."
msgstr ""

#. TRANS: Page title when tag subscription succeeded.
#: actions/tagsub.php:132
msgid "Subscribed"
msgstr "مُشترك"

#. TRANS: Plugin description.
#: TagSubPlugin.php:100
msgid "Plugin to allow following all messages with a given tag."
msgstr ""

#. TRANS: SubMirror plugin menu item on user settings page.
#: TagSubPlugin.php:173
msgctxt "MENU"
msgid "Tags"
msgstr "الوسوم"

#. TRANS: SubMirror plugin tooltip for user settings menu item.
#: TagSubPlugin.php:175
msgid "Configure tag subscriptions"
msgstr ""

#. TRANS: Menu item text for tags submenu.
#: TagSubPlugin.php:192
msgid "Tags"
msgstr "الوسوم"


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:29+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Asturian (http://www.transifex.com/gnu-social/gnu-social/language/ast/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ast\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Form legend.
#: forms/tagunsub.php:90
msgid "Unsubscribe from this tag"
msgstr ""

#. TRANS: Submit button text to unsubscribe from a tag.
#: forms/tagunsub.php:101
msgctxt "BUTTON"
msgid "Unsubscribe"
msgstr ""

#. TRANS: Submit button title to unsubscribe from a tag.
#: forms/tagunsub.php:103
msgid "Unsubscribe from this tag."
msgstr ""

#. TRANS: Form legend.
#: forms/tagsub.php:108
msgid "Subscribe to this tag"
msgstr ""

#. TRANS: Submit button text to subscribe to a tag.
#: forms/tagsub.php:131
msgctxt "BUTTON"
msgid "Subscribe"
msgstr ""

#. TRANS: Submit button title to subscribe to a tag.
#: forms/tagsub.php:133
msgid "Subscribe to this tag."
msgstr ""

#. TRANS: Page title when tag unsubscription succeeded.
#: actions/tagunsub.php:76
msgid "Unsubscribed"
msgstr ""

#. TRANS: Header for subscriptions overview for a user (first page).
#. TRANS: %s is a user nickname.
#: actions/tagsubs.php:51
#, php-format
msgid "%s's tag subscriptions"
msgstr ""

#. TRANS: Header for subscriptions overview for a user (not first page).
#. TRANS: %1$s is a user nickname, %2$d is the page number.
#: actions/tagsubs.php:55
#, php-format
msgid "%1$s's tag subscriptions, page %2$d"
msgstr ""

#. TRANS: Page notice for page with an overview of all tag subscriptions
#. TRANS: of the logged in user's own profile.
#: actions/tagsubs.php:68
msgid ""
"You have subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Page notice for page with an overview of all subscriptions of a user
#. other
#. TRANS: than the logged in user. %s is the user nickname.
#: actions/tagsubs.php:73
#, php-format
msgid ""
"%s has subscribed to receive all notices on this site containing the "
"following tags:"
msgstr ""

#. TRANS: Tag subscription list text when the logged in user has no tag
#. subscriptions.
#: actions/tagsubs.php:118
msgid ""
"You are not listening to any hash tags right now. You can push the "
"\"Subscribe\" button on any hashtag page to automatically receive any public"
" messages on this site that use that tag, even if you are not subscribed to "
"the poster."
msgstr ""

#. TRANS: Tag subscription list text when looking at the subscriptions for a
#. of a user other
#. TRANS: than the logged in user that has no tag subscriptions. %s is the
#. user nickname.
#. TRANS: Subscription list text when looking at the subscriptions for a of a
#. user that has none
#. TRANS: as an anonymous user. %s is the user nickname.
#: actions/tagsubs.php:124 actions/tagsubs.php:130
#, php-format
msgid "%s is not following any tags."
msgstr ""

#. TRANS: %1$s is a URL to a tag, %2$s is a tag,
#. TRANS: %3$s a date string.
#: actions/tagsubs.php:170
#, php-format
msgid "#%2$s since %3$s"
msgstr ""

#. TRANS: Client error displayed trying to perform any request method other
#. than POST.
#. TRANS: Do not translate POST.
#: actions/tagsub.php:78
msgid "This action only accepts POST requests."
msgstr ""

#. TRANS: Client error displayed when the session token is not okay.
#: actions/tagsub.php:87
msgid "There was a problem with your session token. Try again, please."
msgstr ""

#. TRANS: Error message displayed when trying to perform an action that
#. requires a logged in user.
#: actions/tagsub.php:97
msgid "Not logged in."
msgstr ""

#. TRANS: Client error displayed trying to subscribe to a non-existing
#. profile.
#: actions/tagsub.php:106
msgid "No such profile."
msgstr ""

#. TRANS: Page title when tag subscription succeeded.
#: actions/tagsub.php:132
msgid "Subscribed"
msgstr ""

#. TRANS: Plugin description.
#: TagSubPlugin.php:100
msgid "Plugin to allow following all messages with a given tag."
msgstr ""

#. TRANS: SubMirror plugin menu item on user settings page.
#: TagSubPlugin.php:173
msgctxt "MENU"
msgid "Tags"
msgstr ""

#. TRANS: SubMirror plugin tooltip for user settings menu item.
#: TagSubPlugin.php:175
msgid "Configure tag subscriptions"
msgstr ""

#. TRANS: Menu item text for tags submenu.
#: TagSubPlugin.php:192
msgid "Tags"
msgstr ""