diff --git a/QvitterPlugin.php b/QvitterPlugin.php index face439..d3cfe08 100644 --- a/QvitterPlugin.php +++ b/QvitterPlugin.php @@ -141,6 +141,10 @@ class QvitterPlugin extends Plugin { public function onRouterInitialized($m) { + $m->connect('api/qvitter/hello.json', + array('action' => 'ApiQvitterHello')); + $m->connect('api/qvitter/mark_all_notifications_as_seen.json', + array('action' => 'ApiQvitterMarkAllNotificationsAsSeen')); $m->connect('api/qvitter/favs_and_repeats/:notice_id.json', array('action' => 'ApiFavsAndRepeats'), array('notice_id' => '[0-9]+')); @@ -149,6 +153,8 @@ class QvitterPlugin extends Plugin { 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/qvitter/update_bookmarks.json', array('action' => 'ApiQvitterUpdateBookmarks')); + $m->connect('api/qvitter/set_profile_pref.json', + array('action' => 'ApiQvitterSetProfilePref')); $m->connect('api/qvitter/update_link_color.json', array('action' => 'apiqvitterupdatelinkcolor')); $m->connect('api/qvitter/update_background_color.json', @@ -1020,6 +1026,27 @@ class QvitterPlugin extends Plugin { $notification->selectAdd('ntype'); $notification->selectAdd('count(id) as count'); $notification->whereAdd("(to_profile_id = '".$user_id."')"); + + // the user might have opted out from certain notification types + $current_profile = $user->getProfile(); + $disable_notify_replies_and_mentions = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_replies_and_mentions'); + $disable_notify_favs = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_favs'); + $disable_notify_repeats = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_repeats'); + $disable_notify_follows = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_follows'); + if($disable_notify_replies_and_mentions == '1') { + $notification->whereAdd('qvitternotification.ntype != "mention"'); + $notification->whereAdd('qvitternotification.ntype != "reply"'); + } + if($disable_notify_favs == '1') { + $notification->whereAdd('qvitternotification.ntype != "like"'); + } + if($disable_notify_repeats == '1') { + $notification->whereAdd('qvitternotification.ntype != "repeat"'); + } + if($disable_notify_follows == '1') { + $notification->whereAdd('qvitternotification.ntype != "follow"'); + } + $notification->groupBy('ntype'); $notification->whereAdd("(is_seen = '0')"); $notification->whereAdd("(notice_id IS NOT NULL)"); // sometimes notice_id is NULL, those notifications are corrupt and should be discarded diff --git a/actions/apiqvitterhello.php b/actions/apiqvitterhello.php new file mode 100644 index 0000000..899be93 --- /dev/null +++ b/actions/apiqvitterhello.php @@ -0,0 +1,78 @@ + \\\\_\ · + · \\) \____) · + · · + · · + · · + · Qvitter 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 three of the License or (at · + · your option) any later version. · + · · + · Qvitter is distributed in hope that it will be useful but WITHOUT ANY · + · WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see . · + · · + · Contact h@nnesmannerhe.im if you have any questions. · + · · + · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */ + + +if (!defined('GNUSOCIAL')) { exit(1); } + +class ApiQvitterHelloAction extends ApiAuthAction +{ + + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + protected function prepare(array $args=array()) + { + parent::prepare($args); + + return true; + } + + /** + * Handle the request + * + * @param array $args $_REQUEST data (unused) + * + * @return void + */ + protected function handle() + { + parent::handle(); + + $this->initDocument('json'); + $this->showJsonObjects('hello'); + $this->endDocument('json'); + } +} diff --git a/actions/apiqvittermarkallnotificationsasseen.php b/actions/apiqvittermarkallnotificationsasseen.php new file mode 100644 index 0000000..d70c5da --- /dev/null +++ b/actions/apiqvittermarkallnotificationsasseen.php @@ -0,0 +1,94 @@ + \\\\_\ · + · \\) \____) · + · · + · · + · · + · Qvitter 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 three of the License or (at · + · your option) any later version. · + · · + · Qvitter is distributed in hope that it will be useful but WITHOUT ANY · + · WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see . · + · · + · Contact h@nnesmannerhe.im if you have any questions. · + · · + · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */ + + +if (!defined('GNUSOCIAL')) { exit(1); } + +class ApiQvitterMarkAllNotificationsAsSeenAction extends ApiAuthAction +{ + + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + protected function prepare(array $args=array()) + { + parent::prepare($args); + + return true; + } + + /** + * Handle the request + * + * @param array $args $_REQUEST data (unused) + * + * @return void + */ + protected function handle() + { + parent::handle(); + + $n = new QvitterNotification(); + $n->selectAdd(); + $n->selectAdd('id'); + $n->whereAdd(sprintf('qvitternotification.to_profile_id = "%s"', $n->escape($this->auth_user->id))); + $ids = $n->fetchAll('id'); + $notifications = QvitterNotification::pivotGet('id', $ids); + $notifications = new ArrayWrapper($notifications); + $notifications = $notifications->fetchAll(); + foreach($notifications as $notification) { + if($notification->is_seen == 0) { + $orig = clone($notification); + $notification->is_seen = 1; + $notification->update($orig); + } + } + + $this->initDocument('json'); + $this->showJsonObjects(true); + $this->endDocument('json'); + } +} diff --git a/actions/apiqvittersetprofilepref.php b/actions/apiqvittersetprofilepref.php new file mode 100644 index 0000000..a7ac13b --- /dev/null +++ b/actions/apiqvittersetprofilepref.php @@ -0,0 +1,88 @@ + \\\\_\ · + · \\) \____) · + · · + · · + · · + · Qvitter 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 three of the License or (at · + · your option) any later version. · + · · + · Qvitter is distributed in hope that it will be useful but WITHOUT ANY · + · WARRANTY; without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see . · + · · + · Contact h@nnesmannerhe.im if you have any questions. · + · · + · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */ + + +if (!defined('GNUSOCIAL')) { exit(1); } + +class ApiQvitterSetProfilePrefAction extends ApiAuthAction +{ + var $prefNamespace = null; + var $prefTopic = null; + var $prefData = null; + + protected $needPost = true; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + protected function prepare(array $args=array()) + { + parent::prepare($args); + + $this->prefNamespace = $this->trimmed('namespace'); + $this->prefTopic = $this->trimmed('topic'); + $this->prefData = $this->trimmed('data'); + + return true; + } + + /** + * Handle the request + * + * @param array $args $_REQUEST data (unused) + * + * @return void + */ + protected function handle() + { + parent::handle(); + + // save the new bookmarks + $saved = Profile_prefs::setData($this->scoped, $this->prefNamespace, $this->prefTopic, $this->prefData); + + $this->initDocument('json'); + $this->showJsonObjects($saved); + $this->endDocument('json'); + } +} diff --git a/actions/qvitter.php b/actions/qvitter.php index d35c5e5..2753d72 100644 --- a/actions/qvitter.php +++ b/actions/qvitter.php @@ -251,14 +251,18 @@ class QvitterAction extends ApiAction window.siteLocalOnlyDefaultPath = ; 0) { + $topic_data = new stdClass(); + foreach($qvitter_profile_prefs as $pref) { + $topic_data->{$pref->topic} = $pref->data; + } + print 'window.qvitterProfilePrefs = '.json_encode($topic_data).';'; } else { - print 'window.allBookmarks = false;'; + print 'window.qvitterProfilePrefs = false;'; } } ?> @@ -604,7 +608,7 @@ class QvitterAction extends ApiAction color:/*COLORSTART*//*COLOREND*/; } #unseen-notifications, - .stream-item.notification .not-seen, + .stream-item.notification .not-seen-disc, #top-compose, #logo, .queet-toolbar button, @@ -618,7 +622,8 @@ class QvitterAction extends ApiAction .save-profile-button, .crop-and-save-button, .topbar .global-nav.show-logo:before, - .topbar .global-nav.pulse-logo:before { + .topbar .global-nav.pulse-logo:before, + .dropdown-menu li:not(.dropdown-caret) a:hover { background-color:/*BACKGROUNDCOLORSTART*//*BACKGROUNDCOLOREND*/; } .queet-box-syntax[contenteditable="true"]:focus, diff --git a/classes/NotificationStream.php b/classes/NotificationStream.php index ac54c67..eb17c9d 100644 --- a/classes/NotificationStream.php +++ b/classes/NotificationStream.php @@ -33,20 +33,42 @@ class NotificationStream */ function getNotificationIds($offset, $limit, $since_id, $max_id) { + $notification = new QvitterNotification(); $notification->selectAdd(); $notification->selectAdd('id'); $notification->whereAdd(sprintf('qvitternotification.to_profile_id = "%s"', $notification->escape($this->target->id))); $notification->whereAdd(sprintf('qvitternotification.created >= "%s"', $notification->escape($this->target->created))); + + // the user might have opted out from certain notification types + $current_profile = Profile::current(); + $disable_notify_replies_and_mentions = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_replies_and_mentions'); + $disable_notify_favs = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_favs'); + $disable_notify_repeats = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_repeats'); + $disable_notify_follows = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_follows'); + if($disable_notify_replies_and_mentions == '1') { + $notification->whereAdd('qvitternotification.ntype != "mention"'); + $notification->whereAdd('qvitternotification.ntype != "reply"'); + } + if($disable_notify_favs == '1') { + $notification->whereAdd('qvitternotification.ntype != "like"'); + } + if($disable_notify_repeats == '1') { + $notification->whereAdd('qvitternotification.ntype != "repeat"'); + } + if($disable_notify_follows == '1') { + $notification->whereAdd('qvitternotification.ntype != "follow"'); + } + $notification->limit($offset, $limit); $notification->orderBy('qvitternotification.created DESC'); if($since_id) { - $notification->whereAdd(sprintf('qvitternotification.id > %d', $notification->escape($since_id))); + $notification->whereAdd(sprintf('qvitternotification.id > %d', $notification->escape($since_id))); } - + if($max_id) { - $notification->whereAdd(sprintf('qvitternotification.id <= %d', $notification->escape($max_id))); + $notification->whereAdd(sprintf('qvitternotification.id <= %d', $notification->escape($max_id))); } if (!$notification->find()) { @@ -84,7 +106,7 @@ class NotificationStream return new ArrayWrapper($all); } - - + + } diff --git a/css/qvitter.css b/css/qvitter.css index 06974bb..cfcb5d2 100644 --- a/css/qvitter.css +++ b/css/qvitter.css @@ -481,20 +481,6 @@ body.rtl .dropdown-menu li:not(.dropdown-caret) { text-decoration: none; } .dropdown-menu li:not(.dropdown-caret) a:hover { - background-color: #2271A9; - background: -moz-linear-gradient(top, #2f7eb6 0px, #2271a9 100%); /* FF3.6+ */ - - background: -webkit-gradient(linear, left top, left bottom, color-stop(0px,#2f7eb6), color-stop(100%,#2271a9)); /* Chrome,Safari4+ */ - - background: -webkit-linear-gradient(top, #2f7eb6 0px,#2271a9 100%); /* Chrome10+,Safari5.1+ */ - - background: -o-linear-gradient(top, #2f7eb6 0px,#2271a9 100%); /* Opera 11.10+ */ - - background: -ms-linear-gradient(top, #2f7eb6 0px,#2271a9 100%); /* IE10+ */ - - background: linear-gradient(to bottom, #2f7eb6 0px,#2271a9 100%); /* W3C */ - - background-repeat: repeat-x; color: #FFFFFF; text-decoration: none; } @@ -516,6 +502,37 @@ body.rtl .dropdown-menu li:not(.dropdown-caret) { width:auto; } +.dropdown-menu .row-type-profile-prefs-toggle::before { + position: absolute; + height:24px; + width:18px; + text-align: center; + left: 3px; + font-family: fontAwesome; + content:'\f00c'; + font-size:10px; + line-height: 18px; + } +.dropdown-menu .row-type-profile-prefs-toggle.disabled::before { + content:' '; + } + +/* these toggles are inverted, they appear the the user as disabled when enabled, + since they are enabled by default....*/ +.dropdown-menu a#disable_notify_replies_and_mentions.disabled::before, +.dropdown-menu a#disable_notify_favs.disabled::before, +.dropdown-menu a#disable_notify_repeats.disabled::before, +.dropdown-menu a#disable_notify_follows.disabled::before { + content:'\f00c'; + } +.dropdown-menu a#disable_notify_replies_and_mentions.enabled::before, +.dropdown-menu a#disable_notify_favs.enabled::before, +.dropdown-menu a#disable_notify_repeats.enabled::before, +.dropdown-menu a#disable_notify_follows.enabled::before { + content:' '; + } + + #invite-link { font-weight:bold; @@ -1569,6 +1586,27 @@ body.rtl #footer-spinner-container { line-height: 22px; } +#stream-menu-cog { + display: inline-block; + font-size: 20px; + line-height: 20px; + margin-left: 9px; + opacity: 0.4; + position: relative; + cursor:pointer; + } +#stream-menu-cog::before { + content:'\f013'; + font-family: fontAwesome; + } +#stream-menu-cog.dropped { + opacity:1; + } +#stream-menu-cog .dropdown-menu { + z-index:1000; + display:block; + } + .queet-streams { bottom: 0; color: #999999; @@ -1687,7 +1725,7 @@ body.rtl #footer-spinner-container { background-color:#F6F6F6; } -.stream-item.notification .not-seen { +.stream-item.notification .not-seen-disc { position:absolute; left:-5px; top:50%; diff --git a/js/ajax-functions.js b/js/ajax-functions.js index f61e82c..b1b4035 100644 --- a/js/ajax-functions.js +++ b/js/ajax-functions.js @@ -186,6 +186,23 @@ function getFromAPI(stream, actionOnSuccess) { }); } +/* · + · + · Hello to the API! When saying hello you will e.g. also get headers + · with up-to-date unread notifications count to update etc + · + · @param callback: function to invoke when done + · + · · · · · · · · · · · · · */ + +function helloAPI(callback) { + getFromAPI('qvitter/hello.json',function(){ + if(typeof callback == 'function') { + callback(); + } + }); + } + /* · · @@ -309,6 +326,34 @@ function postNewBackgroundColor(newBackgroundColor) { } +/* · + · + · Set a profile pref + · + · @param namespace: the namespace field in the db table, should be 'qvitter' + · @param topic: the topic field in the db table, + · @param data: the data to set + · @param callback: function to run when finished + · + · · · · · · · · · · · · · */ + +function postSetProfilePref(namespace, topic, data, callback) { + $.ajax({ url: window.apiRoot + 'qvitter/set_profile_pref.json', + cache: false, + type: "POST", + data: { + namespace: namespace, + topic: topic, + data: data + }, + dataType:"json", + error: function(data){ callback(false); }, + success: function(data) { + callback(data); } + }); + } + + /* · · diff --git a/js/dom-functions.js b/js/dom-functions.js index e1d17da..be87621 100644 --- a/js/dom-functions.js +++ b/js/dom-functions.js @@ -37,6 +37,104 @@ · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */ +/* · + · + · Build a menu for a stream, if there is any to build + · + · Stream menus currently support three row types: divider, functions and profile-prefs-toggles + · They are defined in stream-router.js. Function rows run the function in + · the function attribute when clicked. Profile-prefs-toggle rows toggles the + · preference in the attribute when clicked. + · + · @param streamObject: stream object returned by pathToStreamRouter() + · + · · · · · · · · · */ + +function streamObjectGetMenu(streamObject) { + if(typeof streamObject == 'undefined') { + return false; + } + if(streamObject.menu === false) { + return false; + } + + var menuHTML = buildMenuTop(); + $.each(streamObject.menu,function(){ + if(this.type == 'divider') { + menuHTML = menuHTML + buildMenuDivider(); + } + else if(this.type == 'function') { + menuHTML = menuHTML + buildMenuRowFullwidth(this.label, { + class: 'row-type-' + this.type, + 'data-menu-row-type': this.type, + 'data-function-name': this.functionName + }); + } + else if(this.type == 'profile-prefs-toggle') { + + // only prefs in the qvitter namespace is supported + if(this.namespace == 'qvitter') { + + // enabled? + var prefEnabledOrDisabled = 'disabled'; + if(typeof window.qvitterProfilePrefs[this.topic] != 'undefined' + && window.qvitterProfilePrefs[this.topic] !== null + && window.qvitterProfilePrefs[this.topic] != '' + && window.qvitterProfilePrefs[this.topic] !== false + && window.qvitterProfilePrefs[this.topic] != 0 + && window.qvitterProfilePrefs[this.topic] != '0') { + prefEnabledOrDisabled = 'enabled'; + } + + // get row html + menuHTML = menuHTML + buildMenuRowFullwidth(this.label, { + id: this.topic, + class: 'row-type-' + this.type + ' ' + prefEnabledOrDisabled, + 'data-menu-row-type': this.type, + 'data-profile-prefs-topic': this.topic, + 'data-profile-prefs-namespace': this.namespace, + 'data-profile-pref-state': prefEnabledOrDisabled + }); + } + } + }); + + return menuHTML + buildMenuBottom(); + } + +/* · + · + · Menu components + · + · · · · · · · · · */ + +function buildMenuTop() { + return ''; + } +function buildMenuDivider() { + return ''; + } +function buildMenuRowFullwidth(label, attributes) { + var attributesHTML = ''; + $.each(attributes,function(k,v){ + attributesHTML = attributesHTML + ' ' + k + '="' + v + '"'; + }); + return '
  • ' + replaceHtmlSpecialChars(label) + '
  • '; + } +function alignMenuToParent(menu, parent) { + var menuLeft = parent.width()/2 - menu.width() + 15; + var menuTop = parent.height()+5; + menu.css('left', menuLeft + 'px'); + menu.css('top', menuTop + 'px'); + } + /* · · @@ -388,28 +486,6 @@ function addProfileCardToDOM(data) { } -/* · - · - · Adds a profile card before feed element, with data from the first object in the included object - · - · @param data: an object with one or more queet objects - · - · · · · · · · · · */ - -function profileCardFromFirstObject(data,screen_name) { - var first = new Object(); - for (var i in data) { - if (data.hasOwnProperty(i) && typeof(i) !== 'function') { - first = data[i]; - break; - } - } - if(typeof first.user != 'undefined') { - addProfileCardToDOM(first.user); - } - } - - /* · @@ -571,6 +647,9 @@ function setNewCurrentStream(streamObject,setLocation,fallbackId,actionOnSuccess $('#feed-body').removeAttr('data-end-reached'); $('#feed-header-inner h2').css('opacity','0.2'); $('#feed-header-inner h2').html(h2FeedHeader); // update header (could be wrong in cache) + if(streamObject.menu && window.loggedIn) { + $('#feed-header-inner h2').append('
    '); + } $('#feed-header-inner h2').animate({opacity:'1'},1000); // set location bar from stream @@ -598,6 +677,9 @@ function setNewCurrentStream(streamObject,setLocation,fallbackId,actionOnSuccess $('.profile-card,.hover-card,.hover-card-caret').remove(); $('#feed-body').html(''); $('#feed-header-inner h2').html(h2FeedHeader); + if(streamObject.menu && window.loggedIn) { + $('#feed-header-inner h2').append('
    '); + } }); } @@ -718,6 +800,12 @@ function setNewCurrentStream(streamObject,setLocation,fallbackId,actionOnSuccess groupProfileCard(streamObject.nickname); } + // say hello to the api if this is notifications stream, to + // get correct unread notifcation count + if(window.currentStreamObject.name == 'notifications') { + helloAPI(); + } + // start checking for new queets again window.clearInterval(checkForNewQueetsInterval); checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling); @@ -1067,7 +1155,7 @@ function cleanUpAfterCollapseQueet(q) { /* · · - · Get an inline queet box + · Get a queet box, mainly for popups · · @return the html for the queet box · @@ -1499,7 +1587,7 @@ function addToFeed(feed, after, extraClasses, isReply) { // add not seen notification circle $.each($('.notification.not-seen .queet'),function(){ if($(this).children('.not-seen').length<1) { - $(this).prepend('
    '); + $(this).prepend('
    '); } }); } diff --git a/js/misc-functions.js b/js/misc-functions.js index 285b8c7..f304d98 100644 --- a/js/misc-functions.js +++ b/js/misc-functions.js @@ -612,46 +612,57 @@ function appendUserToMentionsSuggestionsArray(user) { function displayOrHideUnreadNotifications(notifications) { var data = $.parseJSON(notifications); + var totNotif = 0; - // if this is notifications page, we use the info from the hidden items in the feed - if(window.currentStream == 'qvitter/statuses/notifications.json') { - var new_queets_num = $('#feed-body').find('.stream-item.notification.hidden').length; - - if(new_queets_num == 0) { - document.title = window.siteTitle; - $('#unseen-notifications').hide(); - } - else { - document.title = window.siteTitle + ' (' + new_queets_num + ')'; - $('#unseen-notifications').html(new_queets_num); - $('#unseen-notifications').show(); - } - } - // all other pages use the header info - else if(data === null || typeof data == 'undefined' || data.length == 0) { - $('#unseen-notifications').hide(); - document.title = window.siteTitle; - } - else { - - var totNotif = 0; + if(data !== null && typeof data != 'undefined') { $.each(data,function(k,v){ totNotif = totNotif + parseInt(v,10); }); + } - if(totNotif>0) { - $('#unseen-notifications').html(totNotif); - document.title = window.siteTitle + ' (' + totNotif + ')'; // update html page title - $('#unseen-notifications').show(); - } - else { - $('#unseen-notifications').hide(); - document.title = window.siteTitle; + if(window.currentStreamObject.name == 'notifications') { + var hiddenNotifications = $('#feed-body').find('.stream-item.hidden:not(.activity)').length; + if(hiddenNotifications>0) { + totNotif = totNotif + hiddenNotifications; } } + if(totNotif>0) { + $('#unseen-notifications').html(totNotif); + document.title = window.siteTitle + ' (' + totNotif + ')'; // update html page title + $('#unseen-notifications').show(); + } + else { + $('#unseen-notifications').hide(); + document.title = window.siteTitle; + } + } +/* · + · + · Mark all notifications as seen + · + · · · · · · · · · · · · · */ + +function markAllNotificationsAsSeen() { + display_spinner(); + getFromAPI('qvitter/mark_all_notifications_as_seen.json',function(data){ + if(data === false) { + showErrorMessage(window.sL.ERRORfailedMarkingAllNotificationsAsRead); + } + else { + helloAPI(function(){ + $('.not-seen-disc').remove(); + $('#new-queets-bar').trigger('click'); // show any hidden notifications (this will also remove the dropdown menu) + remove_spinner(); + }); + } + }); + + } + + /* · · @@ -1196,9 +1207,10 @@ function saveAllBookmarks() { · · · · · · · · · · · · · */ function appendAllBookmarks(bookmarkContainer) { - if(bookmarkContainer) { + if(typeof bookmarkContainer != 'undefined' && bookmarkContainer) { $('#bookmark-container').html(''); - $.each(bookmarkContainer, function(key,obj) { + var bookmarkContainerParsed = JSON.parse(bookmarkContainer); + $.each(bookmarkContainerParsed, function(key,obj) { $('#bookmark-container').append('' + obj.dataStreamHeader + ''); }); } diff --git a/js/qvitter.js b/js/qvitter.js index 6c05cff..5d46428 100644 --- a/js/qvitter.js +++ b/js/qvitter.js @@ -923,7 +923,7 @@ function doLogin(streamObjectToSet) { loadHistoryFromLocalStorage(); // show bookmarks - appendAllBookmarks(window.allBookmarks); + appendAllBookmarks(window.qvitterProfilePrefs.bookmarks); // set stream setNewCurrentStream(streamObjectToSet,true,false,function(){ @@ -1076,6 +1076,108 @@ $('#settingslink').click(function(){ }); +/* · + · + · Show/hide the stream menu dropdown on click + · + · · · · · · · · · · · · · */ + +$('body').on('click','#stream-menu-cog',function(e){ + if(!$(e.target).is('#stream-menu-cog') && $(e.target).closest('#stream-menu-cog').length>0) { + // don't show/hide when clicking inside the menu + } + else if($(this).hasClass('dropped')) { + $(this).removeClass('dropped'); + $(this).children('.dropdown-menu').remove(); + } + else { + $(this).addClass('dropped'); + var menu = $(streamObjectGetMenu(window.currentStreamObject)).appendTo(this); + alignMenuToParent(menu,$(this)); + } + }); + +// hide the stream menu when clicking outside it +$('body').on('click',function(e){ + if(!$(e.target).is('#stream-menu-cog') && $('#stream-menu-cog').hasClass('dropped') && !$(e.target).closest('#stream-menu-cog').length>0) { + $('#stream-menu-cog').children('.dropdown-menu').remove(); + $('#stream-menu-cog').removeClass('dropped'); + } + }); + + +/* · + · + · When clicking a function row in a stream menu – invoke the function + · + · · · · · · · · · · · · · */ + +$('body').on('click','.row-type-function',function(e){ + window[$(this).attr('data-function-name')](); + }); + + +/* · + · + · When toggeling a a profile pref in a dropdown menu + · + · · · · · · · · · · · · · */ + +$('body').on('click','.row-type-profile-prefs-toggle',function(e){ + + var thisToggle = $(this); + + // wait for last toggle to finish before toggeling again + if(thisToggle.hasClass('clicked')) { + return true; + } + + if(thisToggle.attr('data-profile-pref-state') == 'disabled') { + var prefDataToSet = '1'; + } + else if(thisToggle.attr('data-profile-pref-state') == 'enabled') { + var prefDataToSet = '0'; + } + else { // invalid + return true; + } + + thisToggle.addClass('clicked'); + + var prefNamespace = thisToggle.attr('data-profile-prefs-namespace'); + var prefTopic = thisToggle.attr('data-profile-prefs-topic'); + + // only prefs in the 'qvitter' namespace allowed + if(prefNamespace != 'qvitter') { + return true; + } + + // save pref to server + postSetProfilePref(prefNamespace,prefTopic,prefDataToSet,function(data){ + if(data === false) { // error + showErrorMessage(window.sL.ERRORfailedSavingYourSetting + ' (' + prefTopic + ')'); + } + else { // success + thisToggle.removeClass('clicked'); + if(thisToggle.attr('data-profile-pref-state') == 'disabled') { + thisToggle.removeClass('disabled'); + thisToggle.addClass('enabled'); + thisToggle.attr('data-profile-pref-state','enabled'); + window.qvitterProfilePrefs[prefTopic] = '1'; + } + else if(thisToggle.attr('data-profile-pref-state') == 'enabled') { + thisToggle.removeClass('enabled'); + thisToggle.addClass('disabled'); + thisToggle.attr('data-profile-pref-state','disabled'); + window.qvitterProfilePrefs[prefTopic] = '0'; + } + + } + }); + + }); + + /* · · @@ -1397,10 +1499,12 @@ $('body').on('click','a', function(e) { $('body').on('click','.sm-ellipsis',function(){ // hide if($(this).closest('.action-ellipsis-container').children('.dropdown-menu').length > 0) { + $(this).closest('.action-ellipsis-container').removeClass('dropped'); $(this).closest('.action-ellipsis-container').children('.dropdown-menu').remove(); } // show else { + $(this).closest('.action-ellipsis-container').addClass('dropped'); $('.action-ellipsis-container').children('.dropdown-menu').remove(); // remove menu from other queets var streamItemUsername = $(this).closest('.queet').find('.stream-item-header').find('.screen-name').text(); var streamItemUserID = $(this).closest('.queet').find('.stream-item-header').find('.name').attr('data-user-id'); @@ -1426,7 +1530,13 @@ $('body').on('click','.sm-ellipsis',function(){ } }); - +// remove the ellipsis menu when clicking outside it +$('body').on('click',function(e){ + if(!$(e.target).is('.action-ellipsis-container') && $('.action-ellipsis-container.dropped').length>0 && !$(e.target).closest('.action-ellipsis-container').length>0) { + $('.action-ellipsis-container').children('.dropdown-menu').remove(); + $('.action-ellipsis-container').removeClass('dropped'); + } + }); @@ -1578,8 +1688,8 @@ function checkForNewQueets() { if(!$('body').hasClass('loading-newer')) { $('body').addClass('loading-newer'); - // only of logged in and not user stream - if($('#user-container').css('display') == 'block' && $('.stream-item.user').length==0) { + // only if logged in and only for notice or notification streams + if(window.loggedIn && (window.currentStreamObject.type == 'notices' || window.currentStreamObject.type == 'notifications')) { var lastId = $('#feed-body').children('.stream-item').not('.temp-post').attr('data-quitter-id-in-stream'); var addThisStream = window.currentStream; var timeNow = new Date().getTime(); @@ -1588,32 +1698,34 @@ function checkForNewQueets() { $('body').removeClass('loading-newer'); if(addThisStream == window.currentStream) { addToFeed(data, false, 'hidden'); + + // if we have hidden items, show new-queets-bar + var new_queets_num = $('#feed-body').find('.stream-item.hidden:not(.activity)').length; + if(new_queets_num > 0) { + + $('#new-queets-bar').parent().removeClass('hidden'); + + // bar label + if(new_queets_num == 1) { var q_txt = window.sL.newQueet; } + else { var q_txt = window.sL.newQueets; } + if(window.currentStreamObject.name == 'notifications') { + if(new_queets_num == 1) { var q_txt = window.sL.newNotification; } + else { var q_txt = window.sL.newNotifications; } + } + + $('#new-queets-bar').html(q_txt.replace('{new-notice-count}',new_queets_num)); + + // say hello to the api if this is notifications stream, to + // get correct unread notifcation count + if(window.currentStreamObject.name == 'notifications') { + helloAPI(); + } + } + } } }); } - - // if we have hidden items, show new-queets-bar - var new_queets_num = $('#feed-body').find('.stream-item.hidden:not(.activity)').length; - if(new_queets_num > 0) { - - // if this is notifications page, update site title with hidden notification count - if(window.currentStreamObject.name == 'notifications') { - document.title = window.siteTitle + ' (' + new_queets_num + ')'; - } - - $('#new-queets-bar').parent().removeClass('hidden'); - - // text plural - if(new_queets_num == 1) { - var q_txt = ' ' + window.sL.newQueet; - } - else { - var q_txt = ' ' + window.sL.newQueets; - } - - $('#new-queets-bar').html(new_queets_num + q_txt); - } } } @@ -1634,6 +1746,12 @@ $('body').on('click','#new-queets-bar',function(){ hiddenStreamItems.addClass('visible'); hiddenStreamItems.removeClass('hidden'); $('#new-queets-bar').parent().addClass('hidden'); + + // say hello to the api if this is notifications stream, to + // get correct unread notifcation count + if(window.currentStreamObject.name == 'notifications') { + helloAPI(); + } }); @@ -1905,13 +2023,12 @@ function disableOrEnableNavigationButtonsInImagePopup(popUp) { /* · · - · Collapse all open conversations, ellipsis menus and the welcome text on esc or when clicking the margin + · Collapse all open conversations and the welcome text on esc or when clicking the margin · · · · · · · · · · · · · · */ $('body').click(function(event){ - if($(event.target).is('body')) { - $('.action-ellipsis-container').children('.dropdown-menu').remove(); + if($(event.target).is('body') || $(event.target).is('#page-container')) { $('.front-welcome-text.expanded > .show-full-welcome-text').trigger('click'); $.each($('.stream-item.expanded'),function(){ expand_queet($(this), false); @@ -1921,7 +2038,6 @@ $('body').click(function(event){ $(document).keyup(function(e){ if(e.keyCode==27) { // esc - $('.action-ellipsis-container').children('.dropdown-menu').remove(); $('.front-welcome-text.expanded > .show-full-welcome-text').trigger('click'); $.each($('.stream-item.expanded'),function(){ expand_queet($(this), false); diff --git a/js/stream-router.js b/js/stream-router.js index 8cbf724..143c6e0 100644 --- a/js/stream-router.js +++ b/js/stream-router.js @@ -130,7 +130,9 @@ function pathToStreamRouter(path) { stream: false, // the API path nickname: false, // if we can read a nickname/screen_name from the path, add it to this property id: false, // if we can read a id number string from the path, add it to this property - maxIdOrPage: 'maxId' // whether this stream uses 'maxId' or 'page' for paging (maxId is default) + maxIdOrPage: 'maxId', // whether this stream uses 'maxId' or 'page' for paging (maxId is default) + menu: false, // optional menu in the header + type: 'notices' // notices, notifications, users, groups, lists etc. notices is default }; // instance's public timeline @@ -262,6 +264,7 @@ function pathToStreamRouter(path) { streamObject.streamSubHeader = window.sL.memberCount; streamObject.stream = 'statusnet/groups/membership/' + streamObject.nickname + '.json?count=20'; streamObject.maxIdOrPage = 'page'; + streamObject.type = 'users'; return streamObject; } @@ -274,6 +277,7 @@ function pathToStreamRouter(path) { streamObject.streamSubHeader = window.sL.adminCount; streamObject.stream = 'statusnet/groups/admins/' + streamObject.nickname + '.json?count=20'; streamObject.maxIdOrPage = 'page'; + streamObject.type = 'users'; return streamObject; } @@ -290,6 +294,14 @@ function pathToStreamRouter(path) { streamObject.stream = 'statuses/friends_timeline.json?screen_name=' + streamObject.nickname + '&withuserarray=1'; streamObject.parentPath = streamObject.nickname; } + streamObject.menu = [ + { + type: 'profile-prefs-toggle', + namespace: 'qvitter', + topic: 'hide_replies', + label: window.sL.hideRepliesToPeopleIDoNotFollow + } + ]; return streamObject; } @@ -319,6 +331,41 @@ function pathToStreamRouter(path) { streamObject.stream = 'qvitter/statuses/notifications.json'; streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname); streamObject.streamSubHeader = window.sL.notifications; + streamObject.type = 'notifications'; + streamObject.menu = [ + { + type: 'function', + functionName: 'markAllNotificationsAsSeen', + label: window.sL.markAllNotificationsAsSeen + }, + { + type: 'divider' + }, + { + type: 'profile-prefs-toggle', + namespace: 'qvitter', + topic: 'disable_notify_replies_and_mentions', + label: window.sL.notifyRepliesAndMentions + }, + { + type: 'profile-prefs-toggle', + namespace: 'qvitter', + topic: 'disable_notify_favs', + label: window.sL.notifyFavs + }, + { + type: 'profile-prefs-toggle', + namespace: 'qvitter', + topic: 'disable_notify_repeats', + label: window.sL.notifyRepeats + }, + { + type: 'profile-prefs-toggle', + namespace: 'qvitter', + topic: 'disable_notify_follows', + label: window.sL.notifyFollows + } + ]; } return streamObject; } @@ -349,6 +396,7 @@ function pathToStreamRouter(path) { streamObject.streamSubHeader = '' + window.sL.followers; streamObject.stream = 'statuses/followers.json?count=20&screen_name=' + streamObject.nickname + '&withuserarray=1'; streamObject.maxIdOrPage = 'page'; + streamObject.type = 'users'; return streamObject; } @@ -361,6 +409,7 @@ function pathToStreamRouter(path) { streamObject.streamSubHeader = window.sL.following + ''; streamObject.stream = 'statuses/friends.json?count=20&screen_name=' + streamObject.nickname + '&withuserarray=1'; streamObject.maxIdOrPage = 'page'; + streamObject.type = 'users'; return streamObject; } @@ -373,6 +422,7 @@ function pathToStreamRouter(path) { streamObject.streamSubHeader = window.sL.groups; streamObject.stream = 'statusnet/groups/list.json?count=10&screen_name=' + streamObject.nickname + '&withuserarray=1'; streamObject.maxIdOrPage = 'page'; + streamObject.type = 'groups'; return streamObject; } diff --git a/locale/ar.json b/locale/ar.json index d5265a6..8115dbc 100644 --- a/locale/ar.json +++ b/locale/ar.json @@ -31,8 +31,8 @@ "favoritesNoun": "مفضّلة", "requeetNoun": "إعادة تغريد", "requeetsNoun": "إعادة تغريد", - "newQueet": "تغريدة جديدة", - "newQueets": "تغريدة جديدة", + "newQueet": "{new-notice-count} تغريدة جديدة", + "newQueets": "{new-notice-count} تغريدة جديدة", "longmonthsJanuary": "يناير", "longmonthsFebruary": "فبراير", "longmonthsMars": "مارس", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/ast.json b/locale/ast.json index 5776ce9..ba37664 100644 --- a/locale/ast.json +++ b/locale/ast.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoritos", "requeetNoun": "Requeet", "requeetsNoun": "Requeets", - "newQueet": "Queet nuevu", - "newQueets": "Queets nuevos", + "newQueet": "{new-notice-count} Queet nuevu", + "newQueets": "{new-notice-count} Queets nuevos", "longmonthsJanuary": "xineru", "longmonthsFebruary": "febreru", "longmonthsMars": "marzu", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/ca.json b/locale/ca.json index c825985..85ad503 100644 --- a/locale/ca.json +++ b/locale/ca.json @@ -31,8 +31,8 @@ "favoritesNoun": "Preferits", "requeetNoun": "Requeet", "requeetsNoun": "Requeets", - "newQueet": "queet nou", - "newQueets": "queets nous", + "newQueet": "{new-notice-count} queet nou", + "newQueets": "{new-notice-count} queets nous", "longmonthsJanuary": "gener", "longmonthsFebruary": "febrer", "longmonthsMars": "març", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"No s'ha pogut trobar aquesta pàgina", "ERRORnoticeRemoved": "Aquest avís s'ha eliminat.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/de.json b/locale/de.json index f3ad0cd..3a773e9 100644 --- a/locale/de.json +++ b/locale/de.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoriten", "requeetNoun": "Requeet", "requeetsNoun": "Requeets", - "newQueet": "neuer Queet", - "newQueets": "neue Queets", + "newQueet": "n{new-notice-count} euer Queet", + "newQueets": "{new-notice-count} neue Queets", "longmonthsJanuary": "Januar", "longmonthsFebruary": "Februar", "longmonthsMars": "März", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Konnte Seite nicht finden.", "ERRORnoticeRemoved": "Dieser Queet wurde gelöscht.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/en.json b/locale/en.json index 68afe08..b93a7d1 100644 --- a/locale/en.json +++ b/locale/en.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favorites", "requeetNoun": "Repeat", "requeetsNoun": "Repeats", - "newQueet": "new notice", - "newQueets": "new notices", + "newQueet": "{new-notice-count} new notice", + "newQueets": "{new-notice-count} new notices", "longmonthsJanuary": "January", "longmonthsFebruary": "February", "longmonthsMars": "March", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/eo.json b/locale/eo.json index 3466f51..ef3e16f 100644 --- a/locale/eo.json +++ b/locale/eo.json @@ -31,8 +31,8 @@ "favoritesNoun": "Stelsignitaj", "requeetNoun": "Repepo", "requeetsNoun": "Repepoj", - "newQueet": "nova pepo", - "newQueets": "novaj pepoj", + "newQueet": "{new-notice-count} nova pepo", + "newQueets": "{new-notice-count} novaj pepoj", "longmonthsJanuary": "januaro", "longmonthsFebruary": "februaro", "longmonthsMars": "marto", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/es.json b/locale/es.json index 624293b..cf22bdc 100644 --- a/locale/es.json +++ b/locale/es.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoritos", "requeetNoun": "Requeet", "requeetsNoun": "Requeets", - "newQueet": "nuevo Queet", - "newQueets": "nuevos Queets", + "newQueet": "{new-notice-count} nuevo Queet", + "newQueets": "{new-notice-count} nuevos Queets", "longmonthsJanuary": "enero", "longmonthsFebruary": "febrero", "longmonthsMars": "marzo", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"No se pudo encontrar la página.", "ERRORnoticeRemoved": "Este aviso se ha eliminado.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/es_ahorita.json b/locale/es_ahorita.json index 9738a75..9a4fff0 100644 --- a/locale/es_ahorita.json +++ b/locale/es_ahorita.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoritos", "requeetNoun": "Requeet", "requeetsNoun": "Requeets", - "newQueet": "nuevo Queet", - "newQueets": "nuevos Queets", + "newQueet": "{new-notice-count} nuevo Queet", + "newQueets": "{new-notice-count} nuevos Queets", "longmonthsJanuary": "enero", "longmonthsFebruary": "febrero", "longmonthsMars": "marzo", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/eu.json b/locale/eu.json index fe6ca21..0d5c512 100644 --- a/locale/eu.json +++ b/locale/eu.json @@ -31,8 +31,8 @@ "favoritesNoun": "Gogokoak", "requeetNoun": "Bertxio", "requeetsNoun": "Bertxioak", - "newQueet": "Txio berria", - "newQueets": "Txio berriak", + "newQueet": "{new-notice-count} Txio berria", + "newQueets": "{new-notice-count} Txio berriak", "longmonthsJanuary": "Urtarrila", "longmonthsFebruary": "Otsaila", "longmonthsMars": "Martxoa", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/fa.json b/locale/fa.json index 665daf1..a3945c7 100644 --- a/locale/fa.json +++ b/locale/fa.json @@ -31,8 +31,8 @@ "favoritesNoun": "برگزیده", "requeetNoun": "بازتوییت", "requeetsNoun": "بازتوییت", - "newQueet": "توییت جدید", - "newQueets": "توییت جدید", + "newQueet": "{new-notice-count} توییت جدید", + "newQueets": "{new-notice-count} توییت جدید", "longmonthsJanuary": "ژانويه", "longmonthsFebruary": "فوريه", "longmonthsMars": "مارس", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/fi.json b/locale/fi.json index 54ec374..690610f 100644 --- a/locale/fi.json +++ b/locale/fi.json @@ -31,8 +31,8 @@ "favoritesNoun": "Suosikit", "requeetNoun": "Toista", "requeetsNoun": "Toistot", - "newQueet": "uusi ilmoitus", - "newQueets": "uudet ilmoitukset", + "newQueet": "{new-notice-count} uusi ilmoitus", + "newQueets": "{new-notice-count} uudet ilmoitukset", "longmonthsJanuary": "tammikuuta", "longmonthsFebruary": "helmikuuta", "longmonthsMars": "maaliskuuta", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/fr.json b/locale/fr.json index 437e983..a537b08 100644 --- a/locale/fr.json +++ b/locale/fr.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoris", "requeetNoun": "Repartage", "requeetsNoun": "Repartages", - "newQueet": "nouvel avis", - "newQueets": "nouveaux avis", + "newQueet": "{new-notice-count} nouvel avis", + "newQueets": "{new-notice-count} nouveaux avis", "longmonthsJanuary": "janvier", "longmonthsFebruary": "février", "longmonthsMars": "mars", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Impossible de trouver cette page.", "ERRORnoticeRemoved": "Cet avis a été supprimé.", "ERRORnoContactWithServer": "Impossible d'établir une connexion avec le serveur. Il peut être surchargé, ou il peut y avoir un problème avec votre connexion. Réessayez plus tard !", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/gl.json b/locale/gl.json index 9a986bf..d92e3af 100644 --- a/locale/gl.json +++ b/locale/gl.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoritos", "requeetNoun": "Rechouchío", "requeetsNoun": "Rechouchíos", - "newQueet": "novo chío", - "newQueets": "novos chíos", + "newQueet": "{new-notice-count} novo chío", + "newQueets": "{new-notice-count} novos chíos", "longmonthsJanuary": "xaneiro", "longmonthsFebruary": "febreiro", "longmonthsMars": "marzo", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/he.json b/locale/he.json index c199333..342eb0f 100644 --- a/locale/he.json +++ b/locale/he.json @@ -31,8 +31,8 @@ "favoritesNoun": "מועדפות", "requeetNoun": "חזרה", "requeetsNoun": "חזרות", - "newQueet": "הודעה חדשה", - "newQueets": "הודעות חדשות", + "newQueet": "{new-notice-count} הודעה חדשה", + "newQueets": "{new-notice-count} הודעות חדשות", "longmonthsJanuary": "ינואר", "longmonthsFebruary": "פברואר", "longmonthsMars": "מרץ", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/io.json b/locale/io.json index 0de360b..efeb72c 100644 --- a/locale/io.json +++ b/locale/io.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favorati", "requeetNoun": "Repeto", "requeetsNoun": "Repeti", - "newQueet": "nova mesajo", - "newQueets": "nova mesaji", + "newQueet": "{new-notice-count} nova mesajo", + "newQueets": "{new-notice-count} nova mesaji", "longmonthsJanuary": "januaro", "longmonthsFebruary": "februaro", "longmonthsMars": "marto", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"On ne trovis ica pagino.", "ERRORnoticeRemoved": "Ica mesajo esas supresita.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/it.json b/locale/it.json index 84f594d..b831495 100644 --- a/locale/it.json +++ b/locale/it.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoriti", "requeetNoun": "Requeet", "requeetsNoun": "Requeet", - "newQueet": "nuovo Queet", - "newQueets": "nuovi Queet", + "newQueet": "{new-notice-count} nuovo Queet", + "newQueets": "{new-notice-count} nuovi Queet", "longmonthsJanuary": "Gennaio", "longmonthsFebruary": "Febbraio", "longmonthsMars": "Marzo", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/no.json b/locale/no.json index 4517938..68bb092 100644 --- a/locale/no.json +++ b/locale/no.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoritter", "requeetNoun": "Requeet", "requeetsNoun": "Requeeter", - "newQueet": "ny Queet", - "newQueets": "nye Queets", + "newQueet": "{new-notice-count} ny Queet", + "newQueets": "{new-notice-count} nye Queets", "longmonthsJanuary": "Januar", "longmonthsFebruary": "Februar", "longmonthsMars": "Mars", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Kan ikke finne siden.", "ERRORnoticeRemoved": "Denne notisen er slettet.", "ERRORnoContactWithServer": "Kan ikke etablere en kobling til instansen. Dette kan skyldes at den er overbelastet, eller det er et problem med din internet kobling. Vennligst forsøk senere.", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/pt_br.json b/locale/pt_br.json index 0be7f68..57e8745 100644 --- a/locale/pt_br.json +++ b/locale/pt_br.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoritos", "requeetNoun": "Requeet", "requeetsNoun": "Requeets", - "newQueet": "novo Queet", - "newQueets": "novos Queets", + "newQueet": "{new-notice-count} novo Queet", + "newQueets": "{new-notice-count} novos Queets", "longmonthsJanuary": "janeiro", "longmonthsFebruary": "fevereiro", "longmonthsMars": "março", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/sv.json b/locale/sv.json index f0b8564..d2824aa 100644 --- a/locale/sv.json +++ b/locale/sv.json @@ -31,8 +31,8 @@ "favoritesNoun": "Favoriter", "requeetNoun": "återqvittring", "requeetsNoun": "återqvittringar", - "newQueet": "ny qvittring", - "newQueets": "nya qvittringar", + "newQueet": "{new-notice-count} ny qvittring", + "newQueets": "{new-notice-count} nya qvittringar", "longmonthsJanuary": "januari", "longmonthsFebruary": "februari", "longmonthsMars": "mars", @@ -139,5 +139,16 @@ "ERRORcouldNotFindPage":"Sidan hittades inte.", "ERRORnoticeRemoved": "Den här qvittringen är borttagen.", "ERRORnoContactWithServer": "Kan inte ansluta till servern. Servern kanske är överbelastad, eller så har du ett problem med din internetuppkoppling. Försök igen senare!", - "ERRORattachmentUploadFailed": "Uppladdningen misslyckades. Filen är kanske för stor eller av en otillåten typ." + "ERRORattachmentUploadFailed": "Uppladdningen misslyckades. Filen är kanske för stor eller av en otillåten typ.", + "hideRepliesToPeopleIDoNotFollow":"Visa inte svar till folk jag inte följer", + "markAllNotificationsAsSeen":"Markera alla notiser som lästa", + "notifyRepliesAndMentions":"Svar och omnämnanden", + "notifyFavs":"Favoriter", + "notifyRepeats":"Återqvittringar", + "notifyFollows":"Nya följare", + "timelineOptions":"Inställningar för det här flödet", + "ERRORfailedSavingYourSetting":"Misslyckades med att spara din inställning", + "ERRORfailedMarkingAllNotificationsAsRead":"Misslyckades med att markera alla notiser som lästa.", + "newNotification": "{new-notice-count} ny notis", + "newNotifications": "{new-notice-count} nya notiser" } diff --git a/locale/zh_cn.json b/locale/zh_cn.json index 9a22446..6f43fed 100644 --- a/locale/zh_cn.json +++ b/locale/zh_cn.json @@ -31,8 +31,8 @@ "favoritesNoun": "收藏", "requeetNoun": "转推", "requeetsNoun": "转推", - "newQueet": "条新推文", - "newQueets": "条新推文", + "newQueet": "{new-notice-count} 条新推文", + "newQueets": "{new-notice-count} 条新推文", "longmonthsJanuary": "1", "longmonthsFebruary": "2", "longmonthsMars": "3", @@ -138,5 +138,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" } diff --git a/locale/zh_tw.json b/locale/zh_tw.json index 45183e0..1477f60 100644 --- a/locale/zh_tw.json +++ b/locale/zh_tw.json @@ -31,8 +31,8 @@ "favoritesNoun": "收藏", "requeetNoun": "轉推", "requeetsNoun": "轉推", - "newQueet": "条新推文", - "newQueets": "条新推文", + "newQueet": "{new-notice-count} 条新推文", + "newQueets": "{new-notice-count} 条新推文", "longmonthsJanuary": "1", "longmonthsFebruary": "2", "longmonthsMars": "3", @@ -138,5 +138,16 @@ "ERRORcouldNotFindPage":"Could not find that page.", "ERRORnoticeRemoved": "This notice has been removed.", "ERRORnoContactWithServer": "Can not establish a connection to the server. The server could be overloaded, or there might be a problem with your internet connecton. Please try again later!", - "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large." + "ERRORattachmentUploadFailed": "The upload failed. The format might be unsupported or the size too large.", + "hideRepliesToPeopleIDoNotFollow":"Hide replies to people I don't follow", + "markAllNotificationsAsSeen":"Mark all notifications as seen", + "notifyRepliesAndMentions":"Mentions and replies", + "notifyFavs":"Favorites", + "notifyRepeats":"Requeets", + "notifyFollows":"New followers", + "timelineOptions":"Timeline options", + "ERRORfailedSavingYourSetting":"Failed saving your setting", + "ERRORfailedMarkingAllNotificationsAsRead":"Failed marking all notifications as seen.", + "newNotification": "{new-notice-count} new notification", + "newNotifications": "{new-notice-count} new notifications" }