From e602d2ad4d9baadf8cf72006a7a05daf465f94ae Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Dec 2015 09:41:46 -0500 Subject: [PATCH 01/19] closes #3932 --- public/less/admin/bootstrap/alerts.less | 5 + public/less/admin/bootstrap/badges.less | 9 +- public/less/admin/bootstrap/bootstrap.less | 6 + .../less/admin/bootstrap/button-groups.less | 9 +- public/less/admin/bootstrap/buttons.less | 18 +- public/less/admin/bootstrap/carousel.less | 29 +-- public/less/admin/bootstrap/close.less | 1 + .../admin/bootstrap/component-animations.less | 3 +- public/less/admin/bootstrap/dropdowns.less | 9 +- public/less/admin/bootstrap/forms.less | 129 +++++++++--- public/less/admin/bootstrap/glyphicons.less | 75 ++++++- public/less/admin/bootstrap/input-groups.less | 11 +- public/less/admin/bootstrap/jumbotron.less | 11 +- public/less/admin/bootstrap/list-group.less | 12 +- public/less/admin/bootstrap/media.less | 19 ++ public/less/admin/bootstrap/mixins.less | 1 + .../bootstrap/mixins/background-variant.less | 3 +- .../less/admin/bootstrap/mixins/buttons.less | 25 ++- .../bootstrap/mixins/grid-framework.less | 4 +- public/less/admin/bootstrap/mixins/grid.less | 8 +- .../admin/bootstrap/mixins/hide-text.less | 4 +- .../admin/bootstrap/mixins/list-group.less | 3 +- .../admin/bootstrap/mixins/pagination.less | 3 +- .../admin/bootstrap/mixins/reset-text.less | 18 ++ .../mixins/responsive-visibility.less | 2 +- .../admin/bootstrap/mixins/text-emphasis.less | 3 +- .../bootstrap/mixins/vendor-prefixes.less | 6 +- public/less/admin/bootstrap/modals.less | 6 +- public/less/admin/bootstrap/navbar.less | 2 +- public/less/admin/bootstrap/navs.less | 2 - public/less/admin/bootstrap/normalize.less | 19 +- public/less/admin/bootstrap/pagination.less | 7 +- public/less/admin/bootstrap/panels.less | 12 +- public/less/admin/bootstrap/popovers.less | 12 +- public/less/admin/bootstrap/print.less | 6 - .../admin/bootstrap/responsive-embed.less | 16 +- public/less/admin/bootstrap/scaffolding.less | 11 ++ public/less/admin/bootstrap/tables.less | 6 +- public/less/admin/bootstrap/theme.less | 33 +++- public/less/admin/bootstrap/tooltip.less | 10 +- public/less/admin/bootstrap/type.less | 4 +- public/less/admin/bootstrap/utilities.less | 1 - public/less/admin/bootstrap/variables.less | 184 +++++++++--------- 43 files changed, 511 insertions(+), 246 deletions(-) create mode 100644 public/less/admin/bootstrap/mixins/reset-text.less diff --git a/public/less/admin/bootstrap/alerts.less b/public/less/admin/bootstrap/alerts.less index df070b8ab2..c4199db927 100644 --- a/public/less/admin/bootstrap/alerts.less +++ b/public/less/admin/bootstrap/alerts.less @@ -18,6 +18,7 @@ // Specified for the h4 to prevent conflicts of changing @headings-color color: inherit; } + // Provide class for links that match alerts .alert-link { font-weight: @alert-link-font-weight; @@ -28,6 +29,7 @@ > ul { margin-bottom: 0; } + > p + p { margin-top: 5px; } @@ -57,12 +59,15 @@ .alert-success { .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text); } + .alert-info { .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text); } + .alert-warning { .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text); } + .alert-danger { .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text); } diff --git a/public/less/admin/bootstrap/badges.less b/public/less/admin/bootstrap/badges.less index b27c405a30..6ee16dca41 100644 --- a/public/less/admin/bootstrap/badges.less +++ b/public/less/admin/bootstrap/badges.less @@ -12,7 +12,7 @@ font-weight: @badge-font-weight; color: @badge-color; line-height: @badge-line-height; - vertical-align: baseline; + vertical-align: middle; white-space: nowrap; text-align: center; background-color: @badge-bg; @@ -28,7 +28,9 @@ position: relative; top: -1px; } - .btn-xs & { + + .btn-xs &, + .btn-group-xs > .btn & { top: 0; padding: 1px 5px; } @@ -49,12 +51,15 @@ color: @badge-active-color; background-color: @badge-active-bg; } + .list-group-item > & { float: right; } + .list-group-item > & + & { margin-right: 5px; } + .nav-pills > li > a > & { margin-left: 3px; } diff --git a/public/less/admin/bootstrap/bootstrap.less b/public/less/admin/bootstrap/bootstrap.less index 61b77474f9..1c0477805f 100644 --- a/public/less/admin/bootstrap/bootstrap.less +++ b/public/less/admin/bootstrap/bootstrap.less @@ -1,3 +1,9 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + // Core variables and mixins @import "variables.less"; @import "mixins.less"; diff --git a/public/less/admin/bootstrap/button-groups.less b/public/less/admin/bootstrap/button-groups.less index f84febbd56..293245a650 100644 --- a/public/less/admin/bootstrap/button-groups.less +++ b/public/less/admin/bootstrap/button-groups.less @@ -36,6 +36,7 @@ margin-left: -5px; // Offset the first child's margin &:extend(.clearfix all); + .btn, .btn-group, .input-group { float: left; @@ -71,13 +72,13 @@ .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { border-radius: 0; } -.btn-group > .btn-group:first-child { +.btn-group > .btn-group:first-child:not(:last-child) { > .btn:last-child, > .dropdown-toggle { .border-right-radius(0); } } -.btn-group > .btn-group:last-child > .btn:first-child { +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { .border-left-radius(0); } @@ -172,12 +173,12 @@ border-radius: 0; } &:first-child:not(:last-child) { - border-top-right-radius: @border-radius-base; + .border-top-radius(@btn-border-radius-base); .border-bottom-radius(0); } &:last-child:not(:first-child) { - border-bottom-left-radius: @border-radius-base; .border-top-radius(0); + .border-bottom-radius(@btn-border-radius-base); } } .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { diff --git a/public/less/admin/bootstrap/buttons.less b/public/less/admin/bootstrap/buttons.less index 40553c6386..9cbb8f416f 100644 --- a/public/less/admin/bootstrap/buttons.less +++ b/public/less/admin/bootstrap/buttons.less @@ -17,7 +17,7 @@ background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 border: 1px solid transparent; white-space: nowrap; - .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base); + .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base); .user-select(none); &, @@ -47,10 +47,16 @@ &[disabled], fieldset[disabled] & { cursor: @cursor-disabled; - pointer-events: none; // Future-proof disabling of clicks .opacity(.65); .box-shadow(none); } + + a& { + &.disabled, + fieldset[disabled] & { + pointer-events: none; // Future-proof disabling of clicks on `` elements + } + } } @@ -107,7 +113,7 @@ &:hover, &:focus { color: @link-hover-color; - text-decoration: underline; + text-decoration: @link-hover-decoration; background-color: transparent; } &[disabled], @@ -126,14 +132,14 @@ .btn-lg { // line-height: ensure even-numbered height of button next to large input - .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large); + .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large); } .btn-sm { // line-height: ensure proper height of button next to small input - .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); + .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small); } .btn-xs { - .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small); + .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small); } diff --git a/public/less/admin/bootstrap/carousel.less b/public/less/admin/bootstrap/carousel.less index 5724d8a56e..252011e9e2 100644 --- a/public/less/admin/bootstrap/carousel.less +++ b/public/less/admin/bootstrap/carousel.less @@ -27,24 +27,24 @@ // WebKit CSS3 transforms for supported devices @media all and (transform-3d), (-webkit-transform-3d) { - transition: transform .6s ease-in-out; - backface-visibility: hidden; - perspective: 1000; + .transition-transform(~'0.6s ease-in-out'); + .backface-visibility(~'hidden'); + .perspective(1000px); &.next, &.active.right { - transform: translate3d(100%, 0, 0); + .translate3d(100%, 0, 0); left: 0; } &.prev, &.active.left { - transform: translate3d(-100%, 0, 0); + .translate3d(-100%, 0, 0); left: 0; } &.next.left, &.prev.right, &.active { - transform: translate3d(0, 0, 0); + .translate3d(0, 0, 0); left: 0; } } @@ -101,6 +101,7 @@ color: @carousel-control-color; text-align: center; text-shadow: @carousel-text-shadow; + background-color: rgba(0, 0, 0, 0); // Fix IE9 click-thru bug // We can't have this transition here because WebKit cancels the carousel // animation if you trip this while in the middle of another animation. @@ -130,6 +131,7 @@ .glyphicon-chevron-right { position: absolute; top: 50%; + margin-top: -10px; z-index: 5; display: inline-block; } @@ -147,7 +149,7 @@ .icon-next { width: 20px; height: 20px; - margin-top: -10px; + line-height: 1; font-family: serif; } @@ -195,6 +197,7 @@ // Internet Explorer 8-9 does not support clicks on elements without a set // `background-color`. We cannot use `filter` since that's not viewed as a // background color by the browser. Thus, a hack is needed. + // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer // // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we // set alpha transparency for the best results possible. @@ -238,18 +241,18 @@ .glyphicon-chevron-right, .icon-prev, .icon-next { - width: 30px; - height: 30px; - margin-top: -15px; - font-size: 30px; + width: (@carousel-control-font-size * 1.5); + height: (@carousel-control-font-size * 1.5); + margin-top: (@carousel-control-font-size / -2); + font-size: (@carousel-control-font-size * 1.5); } .glyphicon-chevron-left, .icon-prev { - margin-left: -15px; + margin-left: (@carousel-control-font-size / -2); } .glyphicon-chevron-right, .icon-next { - margin-right: -15px; + margin-right: (@carousel-control-font-size / -2); } } diff --git a/public/less/admin/bootstrap/close.less b/public/less/admin/bootstrap/close.less index 9b4e74f2b8..6d5bfe087a 100644 --- a/public/less/admin/bootstrap/close.less +++ b/public/less/admin/bootstrap/close.less @@ -23,6 +23,7 @@ // Additional properties for button version // iOS requires the button element instead of an anchor tag. // If you want the anchor version, it requires `href="#"`. + // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile button& { padding: 0; cursor: pointer; diff --git a/public/less/admin/bootstrap/component-animations.less b/public/less/admin/bootstrap/component-animations.less index 967715d98b..0bcee910ac 100644 --- a/public/less/admin/bootstrap/component-animations.less +++ b/public/less/admin/bootstrap/component-animations.less @@ -17,9 +17,8 @@ .collapse { display: none; - visibility: hidden; - &.in { display: block; visibility: visible; } + &.in { display: block; } tr&.in { display: table-row; } tbody&.in { display: table-row-group; } } diff --git a/public/less/admin/bootstrap/dropdowns.less b/public/less/admin/bootstrap/dropdowns.less index 84a48c1413..f6876c1a9b 100644 --- a/public/less/admin/bootstrap/dropdowns.less +++ b/public/less/admin/bootstrap/dropdowns.less @@ -10,12 +10,14 @@ height: 0; margin-left: 2px; vertical-align: middle; - border-top: @caret-width-base solid; + border-top: @caret-width-base dashed; + border-top: @caret-width-base solid ~"\9"; // IE8 border-right: @caret-width-base solid transparent; border-left: @caret-width-base solid transparent; } // The dropdown wrapper (div) +.dropup, .dropdown { position: relative; } @@ -183,14 +185,15 @@ // Reverse the caret .caret { border-top: 0; - border-bottom: @caret-width-base solid; + border-bottom: @caret-width-base dashed; + border-bottom: @caret-width-base solid ~"\9"; // IE8 content: ""; } // Different positioning for bottom up menu .dropdown-menu { top: auto; bottom: 100%; - margin-bottom: 1px; + margin-bottom: 2px; } } diff --git a/public/less/admin/bootstrap/forms.less b/public/less/admin/bootstrap/forms.less index 1bcc2b6b97..e8b071a138 100644 --- a/public/less/admin/bootstrap/forms.less +++ b/public/less/admin/bootstrap/forms.less @@ -56,7 +56,6 @@ input[type="checkbox"] { line-height: normal; } -// Set the height of file controls to match text inputs input[type="file"] { display: block; } @@ -123,7 +122,7 @@ output { background-color: @input-bg; background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 border: 1px solid @input-border; - border-radius: @input-border-radius; + border-radius: @input-border-radius; // Note: This has no effect on s in CSS. .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s"); @@ -133,6 +132,12 @@ output { // Placeholder .placeholder(); + // Unstyle the caret on `` background color -@input-bg: transparent; +@input-bg: #fff; //** `` background color -@input-bg-disabled: transparent; +@input-bg-disabled: @gray-lighter; //** Text color for ``s @input-color: @gray; //** `` border color -@input-border: transparent; +@input-border: #ccc; // TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4 //** Default `.form-control` border radius @@ -203,7 +203,7 @@ @input-border-focus: #66afe9; //** Placeholder text color -@input-color-placeholder: @gray-light; +@input-color-placeholder: #999; //** Default `.form-control` height @input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2); @@ -219,7 +219,7 @@ @legend-border-color: #e5e5e5; //** Background color for textual input addons -@input-group-addon-bg: transparent; +@input-group-addon-bg: @gray-lighter; //** Border color for textual input addons @input-group-addon-border-color: @input-border; @@ -241,11 +241,11 @@ @dropdown-divider-bg: #e5e5e5; //** Dropdown link text color. -@dropdown-link-color: @text-color; +@dropdown-link-color: @gray-dark; //** Hover color for dropdown links. @dropdown-link-hover-color: darken(@gray-dark, 5%); //** Hover background for dropdown links. -@dropdown-link-hover-bg: @gray-lighter; +@dropdown-link-hover-bg: #f5f5f5; //** Active dropdown menu item text color. @dropdown-link-active-color: @component-active-color; @@ -259,7 +259,7 @@ @dropdown-header-color: @gray-light; //** Deprecated `@dropdown-caret-color` as of v3.1.0 -@dropdown-caret-color: @gray-light; +@dropdown-caret-color: #000; //-- Z-index master list @@ -357,45 +357,45 @@ //## // Basics of a navbar -@navbar-height: 64px; +@navbar-height: 50px; @navbar-margin-bottom: @line-height-computed; @navbar-border-radius: @border-radius-base; @navbar-padding-horizontal: floor((@grid-gutter-width / 2)); @navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2); @navbar-collapse-max-height: 340px; -@navbar-default-color: @gray-light; -@navbar-default-bg: #fff; -@navbar-default-border: transparent; +@navbar-default-color: #777; +@navbar-default-bg: #f8f8f8; +@navbar-default-border: darken(@navbar-default-bg, 6.5%); // Navbar links -@navbar-default-link-color: @gray; -@navbar-default-link-hover-color: @gray-dark; +@navbar-default-link-color: #777; +@navbar-default-link-hover-color: #333; @navbar-default-link-hover-bg: transparent; -@navbar-default-link-active-color: @gray-dark; +@navbar-default-link-active-color: #555; @navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%); @navbar-default-link-disabled-color: #ccc; @navbar-default-link-disabled-bg: transparent; // Navbar brand label @navbar-default-brand-color: @navbar-default-link-color; -@navbar-default-brand-hover-color: @navbar-default-link-hover-color; +@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%); @navbar-default-brand-hover-bg: transparent; // Navbar toggle -@navbar-default-toggle-hover-bg: transparent; -@navbar-default-toggle-icon-bar-bg: rgba(0,0,0,0.5); -@navbar-default-toggle-border-color: transparent; +@navbar-default-toggle-hover-bg: #ddd; +@navbar-default-toggle-icon-bar-bg: #888; +@navbar-default-toggle-border-color: #ddd; //=== Inverted navbar // Reset inverted navbar basics -@navbar-inverse-color: @gray-light; -@navbar-inverse-bg: @brand-primary; -@navbar-inverse-border: transparent; +@navbar-inverse-color: lighten(@gray-light, 15%); +@navbar-inverse-bg: #222; +@navbar-inverse-border: darken(@navbar-inverse-bg, 10%); // Inverted navbar links -@navbar-inverse-link-color: lighten(@brand-primary, 30%); +@navbar-inverse-link-color: lighten(@gray-light, 15%); @navbar-inverse-link-hover-color: #fff; @navbar-inverse-link-hover-bg: transparent; @navbar-inverse-link-active-color: @navbar-inverse-link-hover-color; @@ -408,10 +408,10 @@ @navbar-inverse-brand-hover-color: #fff; @navbar-inverse-brand-hover-bg: transparent; -// Inverted navbar toggle\ -@navbar-inverse-toggle-hover-bg: transparent; -@navbar-inverse-toggle-icon-bar-bg: rgba(0,0,0,0.5); -@navbar-inverse-toggle-border-color: transparent; +// Inverted navbar toggle +@navbar-inverse-toggle-hover-bg: #333; +@navbar-inverse-toggle-icon-bar-bg: #fff; +@navbar-inverse-toggle-border-color: #333; //== Navs @@ -426,15 +426,15 @@ @nav-disabled-link-hover-color: @gray-light; //== Tabs -@nav-tabs-border-color: transparent; +@nav-tabs-border-color: #ddd; @nav-tabs-link-hover-border-color: @gray-lighter; -@nav-tabs-active-link-hover-bg: transparent; +@nav-tabs-active-link-hover-bg: @body-bg; @nav-tabs-active-link-hover-color: @gray; -@nav-tabs-active-link-hover-border-color: transparent; +@nav-tabs-active-link-hover-border-color: #ddd; -@nav-tabs-justified-link-border-color: @nav-tabs-border-color; +@nav-tabs-justified-link-border-color: #ddd; @nav-tabs-justified-active-link-border-color: @body-bg; //== Pills @@ -486,8 +486,8 @@ @jumbotron-padding: 30px; @jumbotron-color: inherit; -@jumbotron-bg: #f9f9f9; -@jumbotron-heading-color: @headings-color; +@jumbotron-bg: @gray-lighter; +@jumbotron-heading-color: inherit; @jumbotron-font-size: ceil((@font-size-base * 1.5)); @jumbotron-heading-font-size: ceil((@font-size-base * 4.5)); @@ -496,20 +496,20 @@ // //## Define colors for form feedback states and, by default, alerts. -@state-success-text: @brand-success; +@state-success-text: #3c763d; @state-success-bg: #dff0d8; @state-success-border: darken(spin(@state-success-bg, -10), 5%); -@state-info-text: @brand-info; -@state-info-bg: #e1bee7; +@state-info-text: #31708f; +@state-info-bg: #d9edf7; @state-info-border: darken(spin(@state-info-bg, -10), 7%); -@state-warning-text: @brand-warning; -@state-warning-bg: #ffe0b2; +@state-warning-text: #8a6d3b; +@state-warning-bg: #fcf8e3; @state-warning-border: darken(spin(@state-warning-bg, -10), 5%); -@state-danger-text: @brand-danger; -@state-danger-bg: #f9bdbb; +@state-danger-text: #a94442; +@state-danger-bg: #f2dede; @state-danger-border: darken(spin(@state-danger-bg, -10), 5%); @@ -522,7 +522,7 @@ //** Tooltip text color @tooltip-color: #fff; //** Tooltip background color -@tooltip-bg: #727272; +@tooltip-bg: #000; @tooltip-opacity: .9; //** Tooltip arrow width @@ -540,9 +540,9 @@ //** Popover maximum width @popover-max-width: 276px; //** Popover border color -@popover-border-color: transparent; +@popover-border-color: rgba(0,0,0,.2); //** Popover fallback border color -@popover-fallback-border-color: transparent; +@popover-fallback-border-color: #ccc; //** Popover title background color @popover-title-bg: darken(@popover-bg, 3%); @@ -555,7 +555,7 @@ //** Popover outer arrow width @popover-arrow-outer-width: (@popover-arrow-width + 1); //** Popover outer arrow color -@popover-arrow-outer-color: fadein(@popover-border-color, 7.5%); +@popover-arrow-outer-color: fadein(@popover-border-color, 5%); //** Popover outer arrow fallback color @popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%); @@ -598,7 +598,7 @@ //** Background color of modal content area @modal-content-bg: #fff; //** Modal content border color -@modal-content-border-color: transparent; +@modal-content-border-color: rgba(0,0,0,.2); //** Modal content border color **for IE8** @modal-content-fallback-border-color: #999; @@ -607,7 +607,7 @@ //** Modal backdrop opacity @modal-backdrop-opacity: .5; //** Modal header border color -@modal-header-border-color: transparent; +@modal-header-border-color: #e5e5e5; //** Modal footer border color @modal-footer-border-color: @modal-header-border-color; @@ -720,21 +720,21 @@ @panel-primary-border: @brand-primary; @panel-primary-heading-bg: @brand-primary; -@panel-success-text: #fff; +@panel-success-text: @state-success-text; @panel-success-border: @state-success-border; -@panel-success-heading-bg: @brand-success; +@panel-success-heading-bg: @state-success-bg; -@panel-info-text: #fff; +@panel-info-text: @state-info-text; @panel-info-border: @state-info-border; -@panel-info-heading-bg: @brand-info; +@panel-info-heading-bg: @state-info-bg; -@panel-warning-text: #fff; +@panel-warning-text: @state-warning-text; @panel-warning-border: @state-warning-border; -@panel-warning-heading-bg: @brand-warning; +@panel-warning-heading-bg: @state-warning-bg; -@panel-danger-text: #fff; +@panel-danger-text: @state-danger-text; @panel-danger-border: @state-danger-border; -@panel-danger-heading-bg: @brand-danger; +@panel-danger-heading-bg: @state-danger-bg; //== Thumbnails @@ -760,8 +760,8 @@ // //## -@well-bg: #f9f9f9; -@well-border: transparent; +@well-bg: #f5f5f5; +@well-border: darken(@well-bg, 7%); //== Badges @@ -778,7 +778,7 @@ //** Badge background color in active nav link @badge-active-bg: #fff; -@badge-font-weight: normal; +@badge-font-weight: bold; @badge-line-height: 1; @badge-border-radius: 10px; @@ -820,9 +820,9 @@ // //## -@close-font-weight: normal; +@close-font-weight: bold; @close-color: #000; -@close-text-shadow: none; +@close-text-shadow: 0 1px 0 #fff; //== Code @@ -863,5 +863,7 @@ @page-header-border-color: @gray-lighter; //** Width of horizontal description list titles @dl-horizontal-offset: @component-offset-horizontal; +//** Point at which .dl-horizontal becomes horizontal +@dl-horizontal-breakpoint: @grid-float-breakpoint; //** Horizontal line color. @hr-border: @gray-lighter; From 33a3a56fd7d5a0a415fe5ca7b453c56f735ee62f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Dec 2015 10:04:58 -0500 Subject: [PATCH 02/19] Fixed issue where -w and -a flags didn't work in NodeBB reset. --- src/reset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reset.js b/src/reset.js index ce1b585a01..eae981ba5f 100644 --- a/src/reset.js +++ b/src/reset.js @@ -123,7 +123,7 @@ function resetPlugins(callback) { } function resetWidgets(callback) { - require('./src/widgets').reset(function(err) { + require('./widgets').reset(function(err) { winston.info('[reset] All Widgets moved to Draft Zone'); if (typeof callback === 'function') { callback(err); From 9db0f59432b1724f1348763950c1b38f30aa2868 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Dec 2015 11:20:21 -0500 Subject: [PATCH 03/19] part of #3912 --- public/language/en_GB/notifications.json | 2 ++ src/notifications.js | 45 ++++++++++++++++++++++++ src/socket.io/helpers.js | 3 +- src/user/notifications.js | 33 +++++++---------- 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/public/language/en_GB/notifications.json b/public/language/en_GB/notifications.json index f9b569170d..3048f082b9 100644 --- a/public/language/en_GB/notifications.json +++ b/public/language/en_GB/notifications.json @@ -17,6 +17,8 @@ "moved_your_post": "%1 has moved your post to %2", "moved_your_topic": "%1 has moved %2", "favourited_your_post_in": "%1 has favourited your post in %2.", + "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.", + "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.", "user_flagged_post_in": "%1 flagged a post in %2", "user_posted_to" : "%1 has posted a reply to: %2", "user_posted_topic": "%1 has posted a new topic: %2", diff --git a/src/notifications.js b/src/notifications.js index 2cd372923e..ec77cb4a99 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -331,5 +331,50 @@ var async = require('async'), }); }; + Notifications.merge = function(notifications, callback) { + // When passed a set of notification objects, merge any that can be merged + var mergeIds = ['notifications:favourited_your_post_in'], + isolated, modifyIndex; + + notifications = mergeIds.reduce(function(notifications, mergeId) { + isolated = notifications.filter(function(notifObj) { + return notifObj.mergeId === mergeId; + }); + + if (isolated.length <= 1) { + return notifications; // Nothing to merge + } + + modifyIndex = notifications.indexOf(isolated[0]); + + switch(mergeId) { + case 'notifications:favourited_your_post_in': + var usernames = isolated.map(function(notifObj) { + return notifObj.user.username; + }); + var numUsers = usernames.length; + + // Update bodyShort + if (numUsers === 2) { + isolated[0].bodyShort = '[[notifications:favourited_your_post_in_dual, ' + usernames.join(', ') + ', Welcome to your NodeBB!]]' + } else { + isolated[0].bodyShort = '[[notifications:favourited_your_post_in_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', Welcome to your NodeBB!]]' + } + break; + } + + // Filter out duplicates + return notifications.filter(function(notifObj, idx) { + return notifObj.mergeId !== mergeId || idx === modifyIndex; + }); + }, notifications); + + plugins.fireHook('filter:notifications.merge', { + notifications: notifications + }, function(err, data) { + callback(err, data.notifications); + }); + }; + }(exports)); diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index 5b6a2a2e67..19e46871b3 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -69,7 +69,8 @@ SocketHelpers.sendNotificationToPostOwner = function(pid, fromuid, notification) bodyLong: results.postObj.content, pid: pid, nid: 'post:' + pid + ':uid:' + fromuid, - from: fromuid + from: fromuid, + mergeId: notification }, function(err, notification) { if (!err && notification) { notifications.push(notification, [postData.uid]); diff --git a/src/user/notifications.js b/src/user/notifications.js index 477a9cf53f..5a30149eef 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -64,28 +64,21 @@ var async = require('async'), } function getNotificationsFromSet(set, read, uid, start, stop, callback) { - db.getSortedSetRevRange(set, start, stop, function(err, nids) { - if (err) { - return callback(err); - } - - if(!Array.isArray(nids) || !nids.length) { - return callback(null, []); - } - - UserNotifications.getNotifications(nids, uid, function(err, notifications) { - if (err) { - return callback(err); + async.waterfall([ + async.apply(db.getSortedSetRevRange, set, start, stop), + function(nids, next) { + if(!Array.isArray(nids) || !nids.length) { + return callback(null, []); } + UserNotifications.getNotifications(nids, uid, next); + }, + function(notifs, next) { var deletedNids = []; - notifications.forEach(function(notification, index) { + notifs.forEach(function(notification, index) { if (!notification) { - if (process.env.NODE_ENV === 'development') { - winston.info('[notifications.get] nid ' + nids[index] + ' not found. Removing.'); - } - + winston.verbose('[notifications.get] nid ' + nids[index] + ' not found. Removing.'); deletedNids.push(nids[index]); } else { notification.read = read; @@ -97,9 +90,9 @@ var async = require('async'), db.sortedSetRemove(set, deletedNids); } - callback(null, notifications); - }); - }); + notifications.merge(notifs, next); + } + ], callback); } UserNotifications.getNotifications = function(nids, uid, callback) { From 05df8900db4fab06ede2b15c4e133c2ebfa17f72 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Dec 2015 12:15:24 -0500 Subject: [PATCH 04/19] closes #3912 --- public/language/en_GB/notifications.json | 8 ++++++++ src/notifications.js | 20 +++++++++++++++----- src/socket.io/helpers.js | 3 ++- src/socket.io/posts/flag.js | 4 +++- src/socket.io/user.js | 3 ++- src/topics/follow.js | 4 +++- 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/public/language/en_GB/notifications.json b/public/language/en_GB/notifications.json index 3048f082b9..0692155373 100644 --- a/public/language/en_GB/notifications.json +++ b/public/language/en_GB/notifications.json @@ -14,15 +14,23 @@ "new_message_from": "New message from %1", "upvoted_your_post_in": "%1 has upvoted your post in %2.", + "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.", + "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.", "moved_your_post": "%1 has moved your post to %2", "moved_your_topic": "%1 has moved %2", "favourited_your_post_in": "%1 has favourited your post in %2.", "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.", "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.", "user_flagged_post_in": "%1 flagged a post in %2", + "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3", + "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3", "user_posted_to" : "%1 has posted a reply to: %2", + "user_posted_to_dual" : "%1 and %2 have posted replies to: %3", + "user_posted_to_multiple" : "%1 and %2 others have posted replies to: %3", "user_posted_topic": "%1 has posted a new topic: %2", "user_started_following_you": "%1 started following you.", + "user_started_following_you_dual": "%1 and %2 started following you.", + "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", "email-confirmed": "Email Confirmed", diff --git a/src/notifications.js b/src/notifications.js index ec77cb4a99..c09f438fc9 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -333,12 +333,18 @@ var async = require('async'), Notifications.merge = function(notifications, callback) { // When passed a set of notification objects, merge any that can be merged - var mergeIds = ['notifications:favourited_your_post_in'], + var mergeIds = [ + 'notifications:favourited_your_post_in', + 'notifications:upvoted_your_post_in', + 'notifications:user_started_following_you', + 'notifications:user_posted_to', + 'notifications:user_flagged_post_in' + ], isolated, modifyIndex; notifications = mergeIds.reduce(function(notifications, mergeId) { isolated = notifications.filter(function(notifObj) { - return notifObj.mergeId === mergeId; + return notifObj.mergeId.split('|')[0] === mergeId; }); if (isolated.length <= 1) { @@ -348,7 +354,11 @@ var async = require('async'), modifyIndex = notifications.indexOf(isolated[0]); switch(mergeId) { - case 'notifications:favourited_your_post_in': + case 'notifications:favourited_your_post_in': // intentional fall-through + case 'notifications:upvoted_your_post_in': + case 'notifications:user_started_following_you': + case 'notifications:user_posted_to': + case 'notifications:user_flagged_post_in': var usernames = isolated.map(function(notifObj) { return notifObj.user.username; }); @@ -356,9 +366,9 @@ var async = require('async'), // Update bodyShort if (numUsers === 2) { - isolated[0].bodyShort = '[[notifications:favourited_your_post_in_dual, ' + usernames.join(', ') + ', Welcome to your NodeBB!]]' + isolated[0].bodyShort = '[[' + mergeId.split('|') + '_dual, ' + usernames.join(', ') + ', ' + isolated[0].topicTitle + ']]' } else { - isolated[0].bodyShort = '[[notifications:favourited_your_post_in_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', Welcome to your NodeBB!]]' + isolated[0].bodyShort = '[[' + mergeId.split('|') + '_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', ' + isolated[0].topicTitle + ']]' } break; } diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index 19e46871b3..789ec1660a 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -70,7 +70,8 @@ SocketHelpers.sendNotificationToPostOwner = function(pid, fromuid, notification) pid: pid, nid: 'post:' + pid + ':uid:' + fromuid, from: fromuid, - mergeId: notification + mergeId: notification + '|' + postData.tid, + topicTitle: results.topicTitle }, function(err, notification) { if (!err && notification) { notifications.push(notification, [postData.uid]); diff --git a/src/socket.io/posts/flag.js b/src/socket.io/posts/flag.js index aa82e84626..d3f4007e01 100644 --- a/src/socket.io/posts/flag.js +++ b/src/socket.io/posts/flag.js @@ -84,7 +84,9 @@ module.exports = function(SocketPosts) { bodyLong: post.content, pid: data.pid, nid: 'post_flag:' + data.pid + ':uid:' + socket.uid, - from: socket.uid + from: socket.uid, + mergeId: 'notifications:user_flagged_post_in|' + data.pid, + topicTitle: post.topic.title }, function(err, notification) { if (err || !notification) { return next(err); diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 14b0c2c828..3a19d62d63 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -142,7 +142,8 @@ SocketUser.follow = function(socket, data, callback) { bodyShort: '[[notifications:user_started_following_you, ' + userData.username + ']]', nid: 'follow:' + data.uid + ':uid:' + socket.uid, from: socket.uid, - path: '/user/' + userData.userslug + path: '/user/' + userData.userslug, + mergeId: 'notifications:user_started_following_you' }, next); }, function(notification, next) { diff --git a/src/topics/follow.js b/src/topics/follow.js index e05a705c51..250f571dc4 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -137,7 +137,9 @@ module.exports = function(Topics) { pid: postData.pid, nid: 'new_post:tid:' + postData.topic.tid + ':pid:' + postData.pid + ':uid:' + exceptUid, tid: postData.topic.tid, - from: exceptUid + from: exceptUid, + mergeId: 'notifications:user_posted_to|' + postData.topic.tid, + topicTitle: title }, function(err, notification) { if (err) { return next(err); From 9f5815555a6f6a44ab2aeee0e19558ae2dc88690 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Dec 2015 13:56:12 -0500 Subject: [PATCH 05/19] fixed null error with notif grouping --- src/notifications.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/notifications.js b/src/notifications.js index c09f438fc9..cda7fae2fd 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -344,6 +344,10 @@ var async = require('async'), notifications = mergeIds.reduce(function(notifications, mergeId) { isolated = notifications.filter(function(notifObj) { + if (!notifObj.hasOwnProperty('mergeId')) { + return false; + } + return notifObj.mergeId.split('|')[0] === mergeId; }); From 40f0076b77ad7298c6dd0e88cb5e73fe08603e87 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Dec 2015 14:30:58 -0500 Subject: [PATCH 06/19] fixed bug with notif merging --- src/notifications.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index cda7fae2fd..2340f50dba 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -340,7 +340,7 @@ var async = require('async'), 'notifications:user_posted_to', 'notifications:user_flagged_post_in' ], - isolated, modifyIndex; + isolated, differentiator, modifyIndex; notifications = mergeIds.reduce(function(notifications, mergeId) { isolated = notifications.filter(function(notifObj) { @@ -355,6 +355,8 @@ var async = require('async'), return notifications; // Nothing to merge } + differentiator = isolated[0].mergeId.split('|')[1]; + modifyIndex = notifications.indexOf(isolated[0]); switch(mergeId) { @@ -370,16 +372,16 @@ var async = require('async'), // Update bodyShort if (numUsers === 2) { - isolated[0].bodyShort = '[[' + mergeId.split('|') + '_dual, ' + usernames.join(', ') + ', ' + isolated[0].topicTitle + ']]' + isolated[0].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + ', ' + isolated[0].topicTitle + ']]' } else { - isolated[0].bodyShort = '[[' + mergeId.split('|') + '_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', ' + isolated[0].topicTitle + ']]' + isolated[0].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', ' + isolated[0].topicTitle + ']]' } break; } // Filter out duplicates return notifications.filter(function(notifObj, idx) { - return notifObj.mergeId !== mergeId || idx === modifyIndex; + return notifObj.mergeId !== mergeId + '|' + differentiator || idx === modifyIndex; }); }, notifications); From f4187fc67154dd601f9ba29369fcc00b3a60f2f2 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Dec 2015 15:33:00 -0500 Subject: [PATCH 07/19] fixing crash with deleted notifications --- src/user/notifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/user/notifications.js b/src/user/notifications.js index 5a30149eef..b085e7654d 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -78,8 +78,8 @@ var async = require('async'), notifs.forEach(function(notification, index) { if (!notification) { - winston.verbose('[notifications.get] nid ' + nids[index] + ' not found. Removing.'); - deletedNids.push(nids[index]); + winston.verbose('[notifications.get] nid ' + notification.nid + ' not found. Removing.'); + deletedNids.push(notification.nid); } else { notification.read = read; notification.readClass = !notification.read ? 'unread' : ''; From 8b04b4fe504f5d32e17fd37ec7f3a539b73a36b5 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 16 Dec 2015 16:55:50 -0500 Subject: [PATCH 08/19] up persona --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d885bbc9d..295ff26a0c 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "nodebb-plugin-spam-be-gone": "0.4.5", "nodebb-rewards-essentials": "0.0.6", "nodebb-theme-lavender": "3.0.2", - "nodebb-theme-persona": "4.0.44", + "nodebb-theme-persona": "4.0.45", "nodebb-theme-vanilla": "5.0.17", "nodebb-widget-essentials": "2.0.5", "nodemailer": "0.7.1", From 23c2fb2b52cf8d5dadf6fdde59b73b6905a8e12f Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 16 Dec 2015 17:24:07 -0500 Subject: [PATCH 09/19] un-nuking @julianlam :rage1: also fixed for latest BS --- public/less/admin/bootstrap/variables.less | 182 ++++++++++----------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/public/less/admin/bootstrap/variables.less b/public/less/admin/bootstrap/variables.less index b057ef5bf9..d0cf54f043 100644 --- a/public/less/admin/bootstrap/variables.less +++ b/public/less/admin/bootstrap/variables.less @@ -1,4 +1,4 @@ -// +// Paper 3.3.5 // Variables // -------------------------------------------------- @@ -9,16 +9,16 @@ @gray-base: #000; @gray-darker: lighten(@gray-base, 13.5%); // #222 -@gray-dark: lighten(@gray-base, 20%); // #333 -@gray: lighten(@gray-base, 33.5%); // #555 -@gray-light: lighten(@gray-base, 46.7%); // #777 +@gray-dark: #212121; +@gray: #666; +@gray-light: #bbb; @gray-lighter: lighten(@gray-base, 93.5%); // #eee -@brand-primary: darken(#428bca, 6.5%); // #337ab7 -@brand-success: #5cb85c; -@brand-info: #5bc0de; -@brand-warning: #f0ad4e; -@brand-danger: #d9534f; +@brand-primary: #2196F3; +@brand-success: #4CAF50; +@brand-info: #9C27B0; +@brand-warning: #ff9800; +@brand-danger: #e51c23; //== Scaffolding @@ -28,7 +28,7 @@ //** Background color for ``. @body-bg: #fff; //** Global text color on ``. -@text-color: @gray-dark; +@text-color: @gray; //** Global textual link color. @link-color: @brand-primary; @@ -42,33 +42,33 @@ // //## Font, line-height, and color for body text, headings, and more. -@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-sans-serif: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; @font-family-serif: Georgia, "Times New Roman", Times, serif; //** Default monospace fonts for ``, ``, and `
`.
 @font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
 @font-family-base:        @font-family-sans-serif;
 
-@font-size-base:          14px;
+@font-size-base:          13px;
 @font-size-large:         ceil((@font-size-base * 1.25)); // ~18px
 @font-size-small:         ceil((@font-size-base * 0.85)); // ~12px
 
-@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px
-@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px
-@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px
-@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px
-@font-size-h5:            @font-size-base;
-@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px
+@font-size-h1:            56px;
+@font-size-h2:            45px;
+@font-size-h3:            34px;
+@font-size-h4:            24px;
+@font-size-h5:            20px;
+@font-size-h6:            14px;
 
 //** Unit-less `line-height` for use in components like buttons.
-@line-height-base:        1.428571429; // 20/14
+@line-height-base:        1.846; // 20/14
 //** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
 @line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px
 
 //** By default, this inherits from the ``.
 @headings-font-family:    inherit;
-@headings-font-weight:    500;
+@headings-font-weight:    400;
 @headings-line-height:    1.1;
-@headings-color:          inherit;
+@headings-color:          #444;
 
 
 //== Iconography
@@ -88,7 +88,7 @@
 //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
 
 @padding-base-vertical:     6px;
-@padding-base-horizontal:   12px;
+@padding-base-horizontal:   16px;
 
 @padding-large-vertical:    10px;
 @padding-large-horizontal:  16px;
@@ -102,9 +102,9 @@
 @line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
 @line-height-small:         1.5;
 
-@border-radius-base:        4px;
-@border-radius-large:       6px;
-@border-radius-small:       3px;
+@border-radius-base:        0px;
+@border-radius-large:       0px;
+@border-radius-small:       0px;
 
 //** Global color for active items (e.g., navs or dropdowns).
 @component-active-color:    #fff;
@@ -144,29 +144,29 @@
 
 @btn-font-weight:                normal;
 
-@btn-default-color:              #333;
+@btn-default-color:              #444;
 @btn-default-bg:                 #fff;
-@btn-default-border:             #ccc;
+@btn-default-border:             transparent;
 
 @btn-primary-color:              #fff;
 @btn-primary-bg:                 @brand-primary;
-@btn-primary-border:             darken(@btn-primary-bg, 5%);
+@btn-primary-border:             transparent;
 
 @btn-success-color:              #fff;
 @btn-success-bg:                 @brand-success;
-@btn-success-border:             darken(@btn-success-bg, 5%);
+@btn-success-border:             transparent;
 
 @btn-info-color:                 #fff;
 @btn-info-bg:                    @brand-info;
-@btn-info-border:                darken(@btn-info-bg, 5%);
+@btn-info-border:                transparent;
 
 @btn-warning-color:              #fff;
 @btn-warning-bg:                 @brand-warning;
-@btn-warning-border:             darken(@btn-warning-bg, 5%);
+@btn-warning-border:             transparent;
 
 @btn-danger-color:               #fff;
 @btn-danger-bg:                  @brand-danger;
-@btn-danger-border:              darken(@btn-danger-bg, 5%);
+@btn-danger-border:              transparent;
 
 @btn-link-disabled-color:        @gray-light;
 
@@ -181,14 +181,14 @@
 //##
 
 //** `` background color
-@input-bg:                       #fff;
+@input-bg:                       transparent;
 //** `` background color
-@input-bg-disabled:              @gray-lighter;
+@input-bg-disabled:              transparent;
 
 //** Text color for ``s
 @input-color:                    @gray;
 //** `` border color
-@input-border:                   #ccc;
+@input-border:                   transparent;
 
 // TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
 //** Default `.form-control` border radius
@@ -203,7 +203,7 @@
 @input-border-focus:             #66afe9;
 
 //** Placeholder text color
-@input-color-placeholder:        #999;
+@input-color-placeholder:        @gray-light;
 
 //** Default `.form-control` height
 @input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);
@@ -219,7 +219,7 @@
 @legend-border-color:            #e5e5e5;
 
 //** Background color for textual input addons
-@input-group-addon-bg:           @gray-lighter;
+@input-group-addon-bg:           transparent;
 //** Border color for textual input addons
 @input-group-addon-border-color: @input-border;
 
@@ -241,11 +241,11 @@
 @dropdown-divider-bg:            #e5e5e5;
 
 //** Dropdown link text color.
-@dropdown-link-color:            @gray-dark;
+@dropdown-link-color:            @text-color;
 //** Hover color for dropdown links.
 @dropdown-link-hover-color:      darken(@gray-dark, 5%);
 //** Hover background for dropdown links.
-@dropdown-link-hover-bg:         #f5f5f5;
+@dropdown-link-hover-bg:         @gray-lighter;
 
 //** Active dropdown menu item text color.
 @dropdown-link-active-color:     @component-active-color;
@@ -259,7 +259,7 @@
 @dropdown-header-color:          @gray-light;
 
 //** Deprecated `@dropdown-caret-color` as of v3.1.0
-@dropdown-caret-color:           #000;
+@dropdown-caret-color:           @gray-light;
 
 
 //-- Z-index master list
@@ -357,45 +357,45 @@
 //##
 
 // Basics of a navbar
-@navbar-height:                    50px;
+@navbar-height:                    64px;
 @navbar-margin-bottom:             @line-height-computed;
 @navbar-border-radius:             @border-radius-base;
 @navbar-padding-horizontal:        floor((@grid-gutter-width / 2));
 @navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);
 @navbar-collapse-max-height:       340px;
 
-@navbar-default-color:             #777;
-@navbar-default-bg:                #f8f8f8;
-@navbar-default-border:            darken(@navbar-default-bg, 6.5%);
+@navbar-default-color:             @gray-light;
+@navbar-default-bg:                #fff;
+@navbar-default-border:            transparent;
 
 // Navbar links
-@navbar-default-link-color:                #777;
-@navbar-default-link-hover-color:          #333;
+@navbar-default-link-color:                @gray;
+@navbar-default-link-hover-color:          @gray-dark;
 @navbar-default-link-hover-bg:             transparent;
-@navbar-default-link-active-color:         #555;
+@navbar-default-link-active-color:         @gray-dark;
 @navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);
 @navbar-default-link-disabled-color:       #ccc;
 @navbar-default-link-disabled-bg:          transparent;
 
 // Navbar brand label
 @navbar-default-brand-color:               @navbar-default-link-color;
-@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);
+@navbar-default-brand-hover-color:         @navbar-default-link-hover-color;
 @navbar-default-brand-hover-bg:            transparent;
 
 // Navbar toggle
-@navbar-default-toggle-hover-bg:           #ddd;
-@navbar-default-toggle-icon-bar-bg:        #888;
-@navbar-default-toggle-border-color:       #ddd;
+@navbar-default-toggle-hover-bg:           transparent;
+@navbar-default-toggle-icon-bar-bg:        rgba(0,0,0,0.5);
+@navbar-default-toggle-border-color:       transparent;
 
 
 //=== Inverted navbar
 // Reset inverted navbar basics
-@navbar-inverse-color:                      lighten(@gray-light, 15%);
-@navbar-inverse-bg:                         #222;
-@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);
+@navbar-inverse-color:                      @gray-light;
+@navbar-inverse-bg:                         @brand-primary;
+@navbar-inverse-border:                     transparent;
 
 // Inverted navbar links
-@navbar-inverse-link-color:                 lighten(@gray-light, 15%);
+@navbar-inverse-link-color:                 lighten(@brand-primary, 30%);
 @navbar-inverse-link-hover-color:           #fff;
 @navbar-inverse-link-hover-bg:              transparent;
 @navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;
@@ -408,10 +408,10 @@
 @navbar-inverse-brand-hover-color:          #fff;
 @navbar-inverse-brand-hover-bg:             transparent;
 
-// Inverted navbar toggle
-@navbar-inverse-toggle-hover-bg:            #333;
-@navbar-inverse-toggle-icon-bar-bg:         #fff;
-@navbar-inverse-toggle-border-color:        #333;
+// Inverted navbar toggle\
+@navbar-inverse-toggle-hover-bg:            transparent;
+@navbar-inverse-toggle-icon-bar-bg:         rgba(0,0,0,0.5);
+@navbar-inverse-toggle-border-color:        transparent;
 
 
 //== Navs
@@ -426,15 +426,15 @@
 @nav-disabled-link-hover-color:             @gray-light;
 
 //== Tabs
-@nav-tabs-border-color:                     #ddd;
+@nav-tabs-border-color:                     transparent;
 
 @nav-tabs-link-hover-border-color:          @gray-lighter;
 
-@nav-tabs-active-link-hover-bg:             @body-bg;
+@nav-tabs-active-link-hover-bg:             transparent;
 @nav-tabs-active-link-hover-color:          @gray;
-@nav-tabs-active-link-hover-border-color:   #ddd;
+@nav-tabs-active-link-hover-border-color:   transparent;
 
-@nav-tabs-justified-link-border-color:            #ddd;
+@nav-tabs-justified-link-border-color:            @nav-tabs-border-color;
 @nav-tabs-justified-active-link-border-color:     @body-bg;
 
 //== Pills
@@ -486,8 +486,8 @@
 
 @jumbotron-padding:              30px;
 @jumbotron-color:                inherit;
-@jumbotron-bg:                   @gray-lighter;
-@jumbotron-heading-color:        inherit;
+@jumbotron-bg:                   #f9f9f9;
+@jumbotron-heading-color:        @headings-color;
 @jumbotron-font-size:            ceil((@font-size-base * 1.5));
 @jumbotron-heading-font-size:    ceil((@font-size-base * 4.5));
 
@@ -496,20 +496,20 @@
 //
 //## Define colors for form feedback states and, by default, alerts.
 
-@state-success-text:             #3c763d;
+@state-success-text:             @brand-success;
 @state-success-bg:               #dff0d8;
 @state-success-border:           darken(spin(@state-success-bg, -10), 5%);
 
-@state-info-text:                #31708f;
-@state-info-bg:                  #d9edf7;
+@state-info-text:                @brand-info;
+@state-info-bg:                  #e1bee7;
 @state-info-border:              darken(spin(@state-info-bg, -10), 7%);
 
-@state-warning-text:             #8a6d3b;
-@state-warning-bg:               #fcf8e3;
+@state-warning-text:             @brand-warning;
+@state-warning-bg:               #ffe0b2;
 @state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);
 
-@state-danger-text:              #a94442;
-@state-danger-bg:                #f2dede;
+@state-danger-text:              @brand-danger;
+@state-danger-bg:                #f9bdbb;
 @state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);
 
 
@@ -522,7 +522,7 @@
 //** Tooltip text color
 @tooltip-color:               #fff;
 //** Tooltip background color
-@tooltip-bg:                  #000;
+@tooltip-bg:                  #727272;
 @tooltip-opacity:             .9;
 
 //** Tooltip arrow width
@@ -540,9 +540,9 @@
 //** Popover maximum width
 @popover-max-width:                   276px;
 //** Popover border color
-@popover-border-color:                rgba(0,0,0,.2);
+@popover-border-color:                transparent;
 //** Popover fallback border color
-@popover-fallback-border-color:       #ccc;
+@popover-fallback-border-color:       transparent;
 
 //** Popover title background color
 @popover-title-bg:                    darken(@popover-bg, 3%);
@@ -555,7 +555,7 @@
 //** Popover outer arrow width
 @popover-arrow-outer-width:           (@popover-arrow-width + 1);
 //** Popover outer arrow color
-@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);
+@popover-arrow-outer-color:           fadein(@popover-border-color, 7.5%);
 //** Popover outer arrow fallback color
 @popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);
 
@@ -598,7 +598,7 @@
 //** Background color of modal content area
 @modal-content-bg:                             #fff;
 //** Modal content border color
-@modal-content-border-color:                   rgba(0,0,0,.2);
+@modal-content-border-color:                   transparent;
 //** Modal content border color **for IE8**
 @modal-content-fallback-border-color:          #999;
 
@@ -607,7 +607,7 @@
 //** Modal backdrop opacity
 @modal-backdrop-opacity:      .5;
 //** Modal header border color
-@modal-header-border-color:   #e5e5e5;
+@modal-header-border-color:   transparent;
 //** Modal footer border color
 @modal-footer-border-color:   @modal-header-border-color;
 
@@ -720,21 +720,21 @@
 @panel-primary-border:        @brand-primary;
 @panel-primary-heading-bg:    @brand-primary;
 
-@panel-success-text:          @state-success-text;
+@panel-success-text:          #fff;
 @panel-success-border:        @state-success-border;
-@panel-success-heading-bg:    @state-success-bg;
+@panel-success-heading-bg:    @brand-success;
 
-@panel-info-text:             @state-info-text;
+@panel-info-text:             #fff;
 @panel-info-border:           @state-info-border;
-@panel-info-heading-bg:       @state-info-bg;
+@panel-info-heading-bg:       @brand-info;
 
-@panel-warning-text:          @state-warning-text;
+@panel-warning-text:          #fff;
 @panel-warning-border:        @state-warning-border;
-@panel-warning-heading-bg:    @state-warning-bg;
+@panel-warning-heading-bg:    @brand-warning;
 
-@panel-danger-text:           @state-danger-text;
+@panel-danger-text:           #fff;
 @panel-danger-border:         @state-danger-border;
-@panel-danger-heading-bg:     @state-danger-bg;
+@panel-danger-heading-bg:     @brand-danger;
 
 
 //== Thumbnails
@@ -760,8 +760,8 @@
 //
 //##
 
-@well-bg:                     #f5f5f5;
-@well-border:                 darken(@well-bg, 7%);
+@well-bg:                     #f9f9f9;
+@well-border:                 transparent;
 
 
 //== Badges
@@ -778,7 +778,7 @@
 //** Badge background color in active nav link
 @badge-active-bg:             #fff;
 
-@badge-font-weight:           bold;
+@badge-font-weight:           normal;
 @badge-line-height:           1;
 @badge-border-radius:         10px;
 
@@ -820,9 +820,9 @@
 //
 //##
 
-@close-font-weight:           bold;
+@close-font-weight:           normal;
 @close-color:                 #000;
-@close-text-shadow:           0 1px 0 #fff;
+@close-text-shadow:           none;
 
 
 //== Code

From 3ce9d0ac2fce36cf38a7d56c1198da0bea2ab6a2 Mon Sep 17 00:00:00 2001
From: psychobunny 
Date: Wed, 16 Dec 2015 17:39:21 -0500
Subject: [PATCH 10/19] fixed ordered lists in post content

---
 public/less/mixins.less | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/public/less/mixins.less b/public/less/mixins.less
index c7d49d31c0..a96acc6c84 100644
--- a/public/less/mixins.less
+++ b/public/less/mixins.less
@@ -69,6 +69,10 @@
 
 		margin-bottom: 10px;
 	}
+
+	ol {
+		margin-bottom: 10px;
+	}
 }
 
 .user-icon-style(@size: 32px, @font-size: 1.5rem, @border-radius: inherit) {

From 065bb8ebc4dd8a67f8be6840a1e1e8993132b7a5 Mon Sep 17 00:00:00 2001
From: Julian Lam 
Date: Thu, 17 Dec 2015 09:35:41 -0500
Subject: [PATCH 11/19] #3962

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 295ff26a0c..1d14bde1de 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
     "mkdirp": "~0.5.0",
     "morgan": "^1.3.2",
     "nconf": "~0.8.2",
-    "nodebb-plugin-composer-default": "1.0.24",
+    "nodebb-plugin-composer-default": "1.0.25",
     "nodebb-plugin-dbsearch": "0.3.0",
     "nodebb-plugin-emoji-extended": "0.4.17",
     "nodebb-plugin-markdown": "4.0.9",

From bdeb97e225e0b87b89fe529a18495694f0bd30af Mon Sep 17 00:00:00 2001
From: Julian Lam 
Date: Thu, 17 Dec 2015 09:40:53 -0500
Subject: [PATCH 12/19] updating composer minver again

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 1d14bde1de..44b1847559 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
     "mkdirp": "~0.5.0",
     "morgan": "^1.3.2",
     "nconf": "~0.8.2",
-    "nodebb-plugin-composer-default": "1.0.25",
+    "nodebb-plugin-composer-default": "1.0.26",
     "nodebb-plugin-dbsearch": "0.3.0",
     "nodebb-plugin-emoji-extended": "0.4.17",
     "nodebb-plugin-markdown": "4.0.9",

From 0af11c5c0c08e226ea155e84d3a8e09866ee7ca4 Mon Sep 17 00:00:00 2001
From: Julian Lam 
Date: Thu, 17 Dec 2015 14:01:08 -0500
Subject: [PATCH 13/19] fallbacks for new notification groupings

---
 public/language/ar/notifications.json        | 10 ++++++++++
 public/language/bg/notifications.json        | 10 ++++++++++
 public/language/bn/notifications.json        | 10 ++++++++++
 public/language/cs/notifications.json        | 10 ++++++++++
 public/language/da/notifications.json        | 10 ++++++++++
 public/language/de/notifications.json        | 10 ++++++++++
 public/language/el/notifications.json        | 10 ++++++++++
 public/language/en@pirate/notifications.json | 10 ++++++++++
 public/language/en_US/notifications.json     | 10 ++++++++++
 public/language/es/notifications.json        | 10 ++++++++++
 public/language/et/notifications.json        | 10 ++++++++++
 public/language/fa_IR/notifications.json     | 10 ++++++++++
 public/language/fi/notifications.json        | 10 ++++++++++
 public/language/fr/notifications.json        | 10 ++++++++++
 public/language/gl/notifications.json        | 10 ++++++++++
 public/language/he/notifications.json        | 10 ++++++++++
 public/language/hu/notifications.json        | 10 ++++++++++
 public/language/id/notifications.json        | 10 ++++++++++
 public/language/it/notifications.json        | 10 ++++++++++
 public/language/ja/notifications.json        | 10 ++++++++++
 public/language/ko/notifications.json        | 10 ++++++++++
 public/language/lt/notifications.json        | 10 ++++++++++
 public/language/ms/notifications.json        | 10 ++++++++++
 public/language/nb/notifications.json        | 10 ++++++++++
 public/language/nl/notifications.json        | 14 ++++++++++++--
 public/language/pl/notifications.json        | 10 ++++++++++
 public/language/pt_BR/notifications.json     | 10 ++++++++++
 public/language/ro/notifications.json        | 10 ++++++++++
 public/language/ru/notifications.json        | 10 ++++++++++
 public/language/rw/notifications.json        | 10 ++++++++++
 public/language/sc/notifications.json        | 10 ++++++++++
 public/language/sk/notifications.json        | 10 ++++++++++
 public/language/sl/notifications.json        | 10 ++++++++++
 public/language/sr/notifications.json        | 10 ++++++++++
 public/language/sv/notifications.json        | 10 ++++++++++
 public/language/th/notifications.json        | 10 ++++++++++
 public/language/tr/notifications.json        | 10 ++++++++++
 public/language/vi/notifications.json        | 10 ++++++++++
 public/language/zh_CN/notifications.json     | 10 ++++++++++
 public/language/zh_TW/notifications.json     | 10 ++++++++++
 40 files changed, 402 insertions(+), 2 deletions(-)

diff --git a/public/language/ar/notifications.json b/public/language/ar/notifications.json
index 04fb977999..76b34aa3b1 100644
--- a/public/language/ar/notifications.json
+++ b/public/language/ar/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "لديك تنبيهات غير مقروءة.",
     "new_message_from": "رسالة جديدة من %1",
     "upvoted_your_post_in": "%1 أضاف صوتًا إيجابيا إلى مشاركتك في %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 أضاف مشاركتك في %2 إلى مفضلته.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 أشعَرَ بمشاركة مخلة في %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 أضاف ردا إلى: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 أنشأ موضوعًا جديدًا: %2",
     "user_started_following_you": "%1 صار يتابعك.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "تم التحقق من عنوان البريد الإلكتروني",
     "email-confirmed-message": "شكرًا على إثبات صحة عنوان بريدك الإلكتروني. صار حسابك مفعلًا بالكامل.",
diff --git a/public/language/bg/notifications.json b/public/language/bg/notifications.json
index 960c14058d..900cc77153 100644
--- a/public/language/bg/notifications.json
+++ b/public/language/bg/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Имате непрочетени известия",
     "new_message_from": "Ново съобщение от %1",
     "upvoted_your_post_in": "%1 гласува положително за Ваша публикация в %2.",
+    "upvoted_your_post_in_dual": "%1 и %2 гласуваха положително за Ваша публикация в %3.",
+    "upvoted_your_post_in_multiple": "%1 и %2 други гласуваха положително за Ваша публикация в %3.",
     "moved_your_post": "%1 премести публикацията Ви в %2",
     "moved_your_topic": "%1 премести %2",
     "favourited_your_post_in": "%1 отбеляза Ваша публикация в %2 като любима.",
+    "favourited_your_post_in_dual": "%1 и %2 отбелязаха Ваша публикация в %3 като любима.",
+    "favourited_your_post_in_multiple": "%1 и %2 други отбелязаха Ваша публикация в %3 като любима.",
     "user_flagged_post_in": "%1 докладва Ваша публикация в %2",
+    "user_flagged_post_in_dual": "%1 и %2 докладваха Ваша публикация в %3",
+    "user_flagged_post_in_multiple": "%1 и %2 други докладваха Ваша публикация в %3",
     "user_posted_to": "%1 публикува отговор на: %2",
+    "user_posted_to_dual": "%1 и %2 публикуваха отговори на: %3",
+    "user_posted_to_multiple": "%1 и %2 други публикуваха отговори на: %3",
     "user_posted_topic": "%1 публикува нова тема: %2",
     "user_started_following_you": "%1 започна да Ви следва.",
+    "user_started_following_you_dual": "%1 и %2 започнаха да Ви следват.",
+    "user_started_following_you_multiple": "%1 и %2 започнаха да Ви следват.",
     "new_register": "%1 изпрати заявка за регистрация.",
     "email-confirmed": "Е-пощата беше потвърдена",
     "email-confirmed-message": "Благодарим Ви, че потвърдихте е-пощата си. Акаунтът Ви е вече напълно активиран.",
diff --git a/public/language/bn/notifications.json b/public/language/bn/notifications.json
index 887c120059..67900e08bf 100644
--- a/public/language/bn/notifications.json
+++ b/public/language/bn/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "আপনার অপঠিত বিজ্ঞপ্তি আছে।",
     "new_message_from": "%1 থেকে নতুন বার্তা",
     "upvoted_your_post_in": "%1 , %2 এ আপানার পোষ্টকে আপভোট করেছেন। ",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 একটি উত্তর দিয়েছেন: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 আপনাকে অনুসরন করা শুরু করেছেন।",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "ইমেইল নিশ্চিত করা হয়েছে",
     "email-confirmed-message": "আপনার ইমেইল যাচাই করার জন্য আপনাকে ধন্যবাদ। আপনার অ্যাকাউন্টটি এখন সম্পূর্ণরূপে সক্রিয়।",
diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json
index 1d9b507b33..d8583da969 100644
--- a/public/language/cs/notifications.json
+++ b/public/language/cs/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "You have unread notifications.",
     "new_message_from": "New message from %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 has posted a reply to: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email Confirmed",
     "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
diff --git a/public/language/da/notifications.json b/public/language/da/notifications.json
index 0952b1eab7..af2a4476f2 100644
--- a/public/language/da/notifications.json
+++ b/public/language/da/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Du har ulæste notifikationer.",
     "new_message_from": "Ny besked fra %1",
     "upvoted_your_post_in": "%1 har upvotet dit indlæg i %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 har flyttet dit indlæg til %2",
     "moved_your_topic": "%1 har flyttet %2",
     "favourited_your_post_in": "%1 har favoriseret dit indlæg i %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 har anmeldt et indlæg i %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 har skrevet et svar til: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 har oprettet en ny tråd: %2",
     "user_started_following_you": "%1 har valgt at følge dig.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 har sendt en registrerings anmodning.",
     "email-confirmed": "Email bekræftet",
     "email-confirmed-message": "Tak fordi du validerede din email. Din konto er nu fuldt ud aktiveret.",
diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json
index 175a55e39f..073425aad6 100644
--- a/public/language/de/notifications.json
+++ b/public/language/de/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Du hast ungelesene Benachrichtigungen.",
     "new_message_from": "Neue Nachricht von %1",
     "upvoted_your_post_in": "%1 hat deinen Beitrag in %2 positiv bewertet.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 hat deinen Beitrag nach %2 verschoben.",
     "moved_your_topic": "%1 hat %2 verschoben.",
     "favourited_your_post_in": "%1 hat deinen Beitrag in %2 favorisiert.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 hat einen Beitrag in %2 gemeldet",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 hat auf %2 geantwortet.",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 hat ein neues Thema erstellt: %2",
     "user_started_following_you": "%1 folgt dir jetzt.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 hat eine Registrationsanfrage geschickt.",
     "email-confirmed": "E-Mail bestätigt",
     "email-confirmed-message": "Vielen Dank für Ihre E-Mail-Validierung. Ihr Konto ist nun vollständig aktiviert.",
diff --git a/public/language/el/notifications.json b/public/language/el/notifications.json
index 5d0447dea8..0ef1347183 100644
--- a/public/language/el/notifications.json
+++ b/public/language/el/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Έχεις μη αναγνωσμένες ειδοποιήσεις.",
     "new_message_from": "Νέο μήνυμα από τον/την %1",
     "upvoted_your_post_in": "Ο/Η %1 υπερψήφισε την δημοσίευσή σου στο %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "Η δημοσίευσή σου στο %2 αρέσει στον/ην %1.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "Ο/Η %1 επεσήμανε μια δημοσίευσή σου στο %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "Ο/Η %1 έγραψε μια απάντηση στο: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "Ο/Η %1 σε ακολουθεί.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Το Εmail Επιβεβαιώθηκε",
     "email-confirmed-message": "Ευχαριστούμε που επιβεβαίωσες το email σου. Ο λογαριασμός σου είναι πλέον πλήρως ενεργοποιημένος.",
diff --git a/public/language/en@pirate/notifications.json b/public/language/en@pirate/notifications.json
index e6986f0684..3efe38a794 100644
--- a/public/language/en@pirate/notifications.json
+++ b/public/language/en@pirate/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "You have unread notifications.",
     "new_message_from": "New message from %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 has posted a reply to: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email Confirmed",
     "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
diff --git a/public/language/en_US/notifications.json b/public/language/en_US/notifications.json
index 1d5a798c26..f7f6f404a8 100644
--- a/public/language/en_US/notifications.json
+++ b/public/language/en_US/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "You have unread notifications.",
     "new_message_from": "New message from %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favorited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 has posted a reply to: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email Confirmed",
     "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
diff --git a/public/language/es/notifications.json b/public/language/es/notifications.json
index c9e5798685..506f9f83c4 100644
--- a/public/language/es/notifications.json
+++ b/public/language/es/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Tienes notificaciones sin leer.",
     "new_message_from": "Nuevo mensaje de %1",
     "upvoted_your_post_in": "%1 ha votado positivamente tu respuesta en %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 su tema ha sido movido a %2",
     "moved_your_topic": "%1 se ha movido %2",
     "favourited_your_post_in": "%1 ha marcado como favorito su publicación en %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 ha reportado una respuesta en %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 ha respondido a: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 ha publicado un nuevo tema: %2",
     "user_started_following_you": "%1 comenzó a seguirte.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 envió una solicitud de registro.",
     "email-confirmed": "Correo electrónico confirmado",
     "email-confirmed-message": "Gracias por validar tu correo electrónico. Tu cuenta ya está completamente activa.",
diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json
index beaf377781..9f5bc10fd8 100644
--- a/public/language/et/notifications.json
+++ b/public/language/et/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Sul ei ole lugemata teateid.",
     "new_message_from": "Uus sõnum kasutajalt %1",
     "upvoted_your_post_in": "%1 hääletas sinu postituse poolt  teemas %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 märgistas sinu postituse lemmikuks teemas %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 raporteeris postitust %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "Kasutaja %1 postitas vastuse teemasse %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 on postitanud uue teema: %2",
     "user_started_following_you": "%1 hakkas sind jälgima.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 saatis registreerimistaotluse.",
     "email-confirmed": "Emaili aadress kinnitatud",
     "email-confirmed-message": "Täname, et kinnitasite oma emaili aadressi. Teie kasutaja on nüüd täielikult aktiveeritud.",
diff --git a/public/language/fa_IR/notifications.json b/public/language/fa_IR/notifications.json
index 276db73036..7ca96bd4e6 100644
--- a/public/language/fa_IR/notifications.json
+++ b/public/language/fa_IR/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "شما آگاه‌سازی‌های نخوانده دارید.",
     "new_message_from": "پیام تازه از %1",
     "upvoted_your_post_in": "%1 امتیاز مثبت به دیدگاه شما در %2 داده",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 پست شما را به %2 انتقال داده است",
     "moved_your_topic": "%2 %1 را منتقل کرده است",
     "favourited_your_post_in": "%1 دیدگاه شما را در %2 برگزیده کرده.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 دیدگاه شما را در %2 علامتدار کرده",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "پاسخ دادن به %2 از سوی %1",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 یک جستار جدید ارسال کرده: %2",
     "user_started_following_you": "%1 شروع به دنبال کردن شما کرده",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 یک درخواست ثبت نام ارسال کرده است",
     "email-confirmed": "رایانامه تایید شد",
     "email-confirmed-message": "بابت تایید ایمیلتان سپاس‌گزاریم. حساب کاربری شما اکنون به صورت کامل فعال شده است.",
diff --git a/public/language/fi/notifications.json b/public/language/fi/notifications.json
index f3c309f82b..377ea60e91 100644
--- a/public/language/fi/notifications.json
+++ b/public/language/fi/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Sinulla on lukemattomia ilmoituksia.",
     "new_message_from": "Uusi viesti käyttäjältä %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 on vastannut viestiin: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 on kirjoittanut uuden aiheen: %2",
     "user_started_following_you": "%1 alkoi seurata sinua.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Sähköpostiosoite vahvistettu",
     "email-confirmed-message": "Kiitos sähköpostiosoitteesi vahvistamisesta. Käyttäjätilisi on nyt täysin aktivoitu.",
diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json
index a15584d512..d66e72dc24 100644
--- a/public/language/fr/notifications.json
+++ b/public/language/fr/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Vous avez des notifications non-lues",
     "new_message_from": "Nouveau message de %1",
     "upvoted_your_post_in": "%1 a voté pour votre message dans %2.",
+    "upvoted_your_post_in_dual": "%1 et %2 ont voté pour votre message dans %3.",
+    "upvoted_your_post_in_multiple": "%1 et %2 autres on voté pour votre message dans %3.",
     "moved_your_post": "%1 a déplacé votre message vers %2",
     "moved_your_topic": "%1 a déplacé %2.",
     "favourited_your_post_in": "%1 a mis votre message en favoris dans %2.",
+    "favourited_your_post_in_dual": "%1 et %2 ont mis votre message dans %3 en favori.",
+    "favourited_your_post_in_multiple": "%1 et %2 autres on mis votre message en favori %3.",
     "user_flagged_post_in": "%1 a signalé un message dans %2.",
+    "user_flagged_post_in_dual": "%1 et %2 ont signalé un message dans %3",
+    "user_flagged_post_in_multiple": "%1 et %2 autres on signalé un message dans %3",
     "user_posted_to": "%1 a répondu à : %2",
+    "user_posted_to_dual": "%1 et %2 ont posté une réponse à : %3",
+    "user_posted_to_multiple": "%1 et %2 autres ont posté une réponse à : %3",
     "user_posted_topic": "%1 a posté un nouveau sujet: %2.",
     "user_started_following_you": "%1 vous suit.",
+    "user_started_following_you_dual": "%1 et %2 vous suivent.",
+    "user_started_following_you_multiple": "%1 et %2 autres vous suivent.",
     "new_register": "%1 a envoyé une demande d'incription.",
     "email-confirmed": "Email vérifié",
     "email-confirmed-message": "Merci pour la validation de votre adresse email. Votre compte est désormais activé.",
diff --git a/public/language/gl/notifications.json b/public/language/gl/notifications.json
index 17547336f7..5c91bd8677 100644
--- a/public/language/gl/notifications.json
+++ b/public/language/gl/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Tes notificacións non lidas",
     "new_message_from": "Nova mensaxe de %1",
     "upvoted_your_post_in": "%1 votoute positivo en %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 moveu a túa publicación a%2",
     "moved_your_topic": "%1 foi movido %2",
     "favourited_your_post_in": "%1 marcou favorita a túa publicación en %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 reportou unha mensaxe en %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 publicou unha resposta en: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 publicou un novo tema: %2",
     "user_started_following_you": "%1 comezou a seguirte.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 enviou unha petición de rexistro.",
     "email-confirmed": "Correo confirmado",
     "email-confirmed-message": "Grazas por validar o teu correo. A túa conta agora está activada.",
diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json
index 6d93c08512..49d1b54c31 100644
--- a/public/language/he/notifications.json
+++ b/public/language/he/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "יש לך התראות שלא נקראו.",
     "new_message_from": "הודעה חדשה מ %1",
     "upvoted_your_post_in": "%1 הצביע בעד הפוסט שלך ב %2",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 הוסיף את הפוסט שלך ב %2 למועדפים שלו.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 דיווח על פוסט ב %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 פרסם תגובה ל: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 העלה נושא חדש: %2",
     "user_started_following_you": "%1 התחיל לעקוב אחריך.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "כתובת המייל אושרה",
     "email-confirmed-message": "תודה שאישרת את כתובת המייל שלך. החשבון שלך פעיל כעת.",
diff --git a/public/language/hu/notifications.json b/public/language/hu/notifications.json
index 643037bd28..f255352a1a 100644
--- a/public/language/hu/notifications.json
+++ b/public/language/hu/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "You have unread notifications.",
     "new_message_from": "New message from %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 has posted a reply to: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email Confirmed",
     "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
diff --git a/public/language/id/notifications.json b/public/language/id/notifications.json
index 296bfd9c2a..7333364bd9 100644
--- a/public/language/id/notifications.json
+++ b/public/language/id/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Kamu memiliki pemberitahuan yang belum dibaca.",
     "new_message_from": "Pesan baru dari %1",
     "upvoted_your_post_in": "%1 telah melakukan upvote untuk posting kamu di %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 telah memfavoritkan posting mu di %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 menandai sebuah posting di %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 telah mengirim sebuah balasan kepada: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 telah membuat topik baru: %2",
     "user_started_following_you": "%1 mulai mengikutimu.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 mengirim permintaan registrasi.",
     "email-confirmed": "Email telah Dikonfirmasi",
     "email-confirmed-message": "Terimakasih telah melakukan validasi email. Akunmu saat ini telah aktif sepenuhnya.",
diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json
index 15ca49f2ec..e5d6625d0e 100644
--- a/public/language/it/notifications.json
+++ b/public/language/it/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Hai notifiche non lette.",
     "new_message_from": "Nuovo messaggio da %1",
     "upvoted_your_post_in": "%1 ha votato positivamente il tuo post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 ha messo nei favoriti il tuo post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 ha segnalato un post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 ha postato una risposta a: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 ha postato un nuovo Topic: %2",
     "user_started_following_you": "%1 ha iniziato a seguirti.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 ha inviato una richiesta di registrazione.",
     "email-confirmed": "Email Confermata",
     "email-confirmed-message": "Grazie per aver validato la tua email. Il tuo account è ora completamente attivato.",
diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json
index e5f9facc16..963dbc3e6e 100644
--- a/public/language/ja/notifications.json
+++ b/public/language/ja/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "未読の通知があります。",
     "new_message_from": "%1からの新しいメッセージ",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1%2 への返事を作成しました。",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email Confirmed",
     "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
diff --git a/public/language/ko/notifications.json b/public/language/ko/notifications.json
index e7d56db47b..97dcfc3b64 100644
--- a/public/language/ko/notifications.json
+++ b/public/language/ko/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "읽지 않은 알림이 있습니다.",
     "new_message_from": "%1님이 메시지를 보냈습니다.",
     "upvoted_your_post_in": "%1님이 %2의 내 게시물을 추천했습니다.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1님이 %2의 내 게시물을 좋아합니다.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1님이 %2의 게시물을 신고했습니다.",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1님이 %2에 답글을 작성했습니다.",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1님이 새 주제를 작성했습니다: %2",
     "user_started_following_you": "%1님이 나를 팔로우합니다.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "확인된 이메일",
     "email-confirmed-message": "이메일을 확인해주셔서 감사합니다. 계정이 완전히 활성화되었습니다.",
diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json
index 596993bb92..4bbd1e6fae 100644
--- a/public/language/lt/notifications.json
+++ b/public/language/lt/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Jūs turite neperskaitytų pranešimų.",
     "new_message_from": "Nauja žinutė nuo %1",
     "upvoted_your_post_in": "%1  užbalsavo už jūsų pranešima čia  %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 patinka jūsų pranešimas čia %2",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1pagrįso nuomone čia %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 parašė atsaką %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 paskelbė naują temą: %2",
     "user_started_following_you": "%1 pradėjo sekti tave",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 atsiuntė registracijos prašymą",
     "email-confirmed": "El. paštas patvirtintas",
     "email-confirmed-message": "Dėkojame už el. pašto patvirtinimą. Jūsų paskyra pilnai aktyvuota.",
diff --git a/public/language/ms/notifications.json b/public/language/ms/notifications.json
index 34c1f104a0..196e3971ca 100644
--- a/public/language/ms/notifications.json
+++ b/public/language/ms/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Ada pemberitahuan yang belum dibaca",
     "new_message_from": "Pesanan baru daripada  %1",
     "upvoted_your_post_in": "%1 telah mengundi naik kiriman and di %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 telah memindahkan kiriman anda ke %2",
     "moved_your_topic": "%1 telah memindahkan %2",
     "favourited_your_post_in": "%1 menggemari kiriman and di %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 menanda kiriman anda di %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 telah membalas kiriman kepada: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 membuka topik baru : %2",
     "user_started_following_you": "%1 mula mengikut anda.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 menghantar jemputan pendaftaran.",
     "email-confirmed": "Emel Disahkan",
     "email-confirmed-message": "Terima kasih kerana mengesahkan emel anda. Akaun anda telah diaktifkan sepenuhnya.",
diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json
index 425997b22f..568357137a 100644
--- a/public/language/nb/notifications.json
+++ b/public/language/nb/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Du har uleste varsler.",
     "new_message_from": "Ny melding fra %1",
     "upvoted_your_post_in": "%1 har stemt opp innlegget ditt i %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 har favorittmerket innlegget ditt i %2",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 har flagget et innlegg i %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 har skrevet et svar til: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 har skrevet et nytt emne: %2",
     "user_started_following_you": "%1 begynte å følge deg.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sendte en forespørsel om registrering",
     "email-confirmed": "E-post bekreftet",
     "email-confirmed-message": "Takk for at du har validert din e-post. Kontoen din er nå fullstendig aktivert.",
diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json
index f049f78b92..d2c8ec0058 100644
--- a/public/language/nl/notifications.json
+++ b/public/language/nl/notifications.json
@@ -9,19 +9,29 @@
     "continue_to": "Door naar %1",
     "return_to": "Terug naar %1",
     "new_notification": "Nieuwe melding",
-    "you_have_unread_notifications": "Ongelezen berichten",
+    "you_have_unread_notifications": "Je hebt nieuwe notificaties.",
     "new_message_from": "Nieuw bericht van %1",
     "upvoted_your_post_in": "%1 heeft voor een bericht gestemd in %2.",
+    "upvoted_your_post_in_dual": "%1 en %2 hebben voor een bericht in gestemd in %3.",
+    "upvoted_your_post_in_multiple": "%1 en %2 andere hebben in gestemd in %3.",
     "moved_your_post": "%1 heeft je bericht verplaatst naar %2",
     "moved_your_topic": "%1 heeft %2 verplaatst",
     "favourited_your_post_in": "%1 heeft een van je berichten in %2 aan zijn of haar favorieten toegevoegd.",
+    "favourited_your_post_in_dual": "%1 en %2 hebben een van je berichten in %3 aan zijn of haar favorieten toegevoegd.",
+    "favourited_your_post_in_multiple": "%1 en %2 hebben een van je berichten in 3 aan hun favorieten toegevoegd.",
     "user_flagged_post_in": "%1 rapporteerde een bericht in %2",
+    "user_flagged_post_in_dual": "%1 en %2 rapporteerde een bericht in %3",
+    "user_flagged_post_in_multiple": "%1 en %2 andere rapporteede een bericht in %3",
     "user_posted_to": "%1 heeft een reactie geplaatst in %2",
+    "user_posted_to_dual": "%1 en %2 hebben een reactie geplaatst in: %3",
+    "user_posted_to_multiple": "%1 en %2 hebben een reactie geplaatst in: %3",
     "user_posted_topic": "%1 heeft een nieuw onderwerp geplaatst: %2",
     "user_started_following_you": "%1 volgt jou nu.",
+    "user_started_following_you_dual": "%1 en %2 volgen jou nu.",
+    "user_started_following_you_multiple": "%1 en %2 andere volgen jou nu.",
     "new_register": "%1 heeft een registratie verzoek aangevraagd.",
     "email-confirmed": "E-mailadres bevestigd",
     "email-confirmed-message": "Bedankt voor het bevestigen van je e-mailadres. Dit account is nu volledig geactiveerd.",
     "email-confirm-error-message": "Er was een probleem met het bevestigen van dit e-mailadres. Misschien is de code niet goed ingevoerd of was de beschikbare tijd inmiddels verstreken.",
-    "email-confirm-sent": "Bevestigingsmail verstuurd"
+    "email-confirm-sent": "Bevestigingsmail verstuurd."
 }
\ No newline at end of file
diff --git a/public/language/pl/notifications.json b/public/language/pl/notifications.json
index e655a6253a..e34cb43dc6 100644
--- a/public/language/pl/notifications.json
+++ b/public/language/pl/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Masz nieprzeczytane powiadomienia.",
     "new_message_from": "Nowa wiadomość od %1",
     "upvoted_your_post_in": "%1 zagłosował na Twój post w %2",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 polubił Twój post w %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 oflagował Twój post w %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 dodał odpowiedź do %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 wysłał nowy temat: %2",
     "user_started_following_you": "%1 zaczął Cię śledzić.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 wysłał żądanie rejestracji.",
     "email-confirmed": "E-mail potwierdzony",
     "email-confirmed-message": "Dziękujemy za potwierdzenie maila. Twoje konto zostało aktywowane.",
diff --git a/public/language/pt_BR/notifications.json b/public/language/pt_BR/notifications.json
index 7a3b36d8d6..58d959e039 100644
--- a/public/language/pt_BR/notifications.json
+++ b/public/language/pt_BR/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Você possui notificações não lidas.",
     "new_message_from": "Nova mensagem de %1",
     "upvoted_your_post_in": "%1 deu voto positivo para seu post em %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 moveu seu post para %2",
     "moved_your_topic": "%1 movido %2",
     "favourited_your_post_in": "%1 adicionou seu tópico aos favoritos em %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 sinalizou um post em %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 postou uma resposta para: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 postou um novo tópico: %2",
     "user_started_following_you": "%1 começou a seguir você.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 lhe enviou um pedido de cadastro.",
     "email-confirmed": "Email Confirmado",
     "email-confirmed-message": "Obrigado por validar o seu email. Agora sua conta está plenamente ativada.",
diff --git a/public/language/ro/notifications.json b/public/language/ro/notifications.json
index a7cc002529..a37dac936b 100644
--- a/public/language/ro/notifications.json
+++ b/public/language/ro/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Ai notificări necitite.",
     "new_message_from": "Un mesaj nou de la %1",
     "upvoted_your_post_in": "%1 a votat pozitiv mesajul tău în %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 a adăugat mesajul tău la favorite în %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 a semnalizat un mesaj în %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 a postat un răspuns la: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 a început să te urmărească.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email confirmat",
     "email-confirmed-message": "Îți mulțumim pentru validarea emailului. Contul tău este acuma activat.",
diff --git a/public/language/ru/notifications.json b/public/language/ru/notifications.json
index 24be55d9ea..197bfa2c09 100644
--- a/public/language/ru/notifications.json
+++ b/public/language/ru/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "У вас есть непрочитанные уведомления.",
     "new_message_from": "Новое сообщение от %1",
     "upvoted_your_post_in": "%1 проголосовал за Ваше сообщение в %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 добавил в избранное Ваше сообщение в %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 пометил сообщение в %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 ответил на запись: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 открыл новую тему: %2",
     "user_started_following_you": "%1 подписался на Вас.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 отправлен запрос на регистрацию.",
     "email-confirmed": "Email подтвержден",
     "email-confirmed-message": "Спасибо за подтверждение Вашего Email-адреса. Ваш аккаунт активирован.",
diff --git a/public/language/rw/notifications.json b/public/language/rw/notifications.json
index a9d10be6e2..64f4c98753 100644
--- a/public/language/rw/notifications.json
+++ b/public/language/rw/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Ufite amatangazo utarasoma. ",
     "new_message_from": " %1 yakwandikiye",
     "upvoted_your_post_in": "%1 yagushimye aguha inota kuri %2 washyizeho.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 yatonesheje %2 washyizeho.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 yatambikanye ikintu muri %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 yanditse kuri: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 yatangije ikiganiro gishya: %2",
     "user_started_following_you": "%1 yatangiye kugukurikira.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 yasabye kwandikwa.",
     "email-confirmed": "Email Yemejwe",
     "email-confirmed-message": "Urakoze kugaragaza ko email yawe ikora. Ubu ngubu konte yawe irakora nta kabuza. ",
diff --git a/public/language/sc/notifications.json b/public/language/sc/notifications.json
index 929f5a55c6..b9d09d0159 100644
--- a/public/language/sc/notifications.json
+++ b/public/language/sc/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "You have unread notifications.",
     "new_message_from": "New message from %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 has posted a reply to: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email Confirmed",
     "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",
diff --git a/public/language/sk/notifications.json b/public/language/sk/notifications.json
index a8e6619d33..5b62d0317e 100644
--- a/public/language/sk/notifications.json
+++ b/public/language/sk/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Máte neprečítané notifikácie",
     "new_message_from": "Nova spáva od %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 odpovedal: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email bol potvrdený",
     "email-confirmed-message": "Ďakujeme za potvrdenie tvojho emailu. Účet je plne aktivovaný.",
diff --git a/public/language/sl/notifications.json b/public/language/sl/notifications.json
index b0164f086e..6554627f8f 100644
--- a/public/language/sl/notifications.json
+++ b/public/language/sl/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Imate neprebrana obvestila.",
     "new_message_from": "Novo obvestilo od %1",
     "upvoted_your_post_in": "%1 je glasoval za vašo objavo v %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 je dodal med priljubljene vašo objavo v %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1je prijavil vašo objavo v %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 je odgovoril na: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 je odprl novo temo: %2",
     "user_started_following_you": "%1 te sledi.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 je poslal prošnjo za registracijo.",
     "email-confirmed": "E-mail naslov potrjen",
     "email-confirmed-message": "Hvala ker ste potrdili svoj naslov. Račun je sedaj aktiviran.",
diff --git a/public/language/sr/notifications.json b/public/language/sr/notifications.json
index e65b13f46d..79d715bae4 100644
--- a/public/language/sr/notifications.json
+++ b/public/language/sr/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Имате непрочитаних обавештења.",
     "new_message_from": "Нова порука од %1",
     "upvoted_your_post_in": "%1 дода глас вашој поруци у %2",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 доду вашу поруку из %2 у омиљене.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 означи поруку у %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 посла нови одговор за: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 постави нову тему:",
     "user_started_following_you": "%1 поче да вас прати.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Е-пошта је је отврђена.",
     "email-confirmed-message": "Хвала на овери ваше е-поште. Ваш налог је сада у потпуности активан.",
diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json
index dbf4d290c6..dcb54b72ab 100644
--- a/public/language/sv/notifications.json
+++ b/public/language/sv/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Du har olästa notiser.",
     "new_message_from": "Nytt medelande från %1",
     "upvoted_your_post_in": "%1 har röstat upp ditt inlägg i %2",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 har favoriserat ditt inlägg i %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flaggade ett inlägg i %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 har skrivit ett svar på: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 har skapat ett nytt ämne: %2",
     "user_started_following_you": "%1 började följa dig.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 skickade en registreringsförfrågan.",
     "email-confirmed": "Epost bekräftad",
     "email-confirmed-message": "Tack för att du bekräftat din epostadress. Ditt konto är nu fullt ut aktiverat.",
diff --git a/public/language/th/notifications.json b/public/language/th/notifications.json
index 34fc870629..14fd6afc25 100644
--- a/public/language/th/notifications.json
+++ b/public/language/th/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "คุณมีคำเตือนที่ยังไม่ได้อ่าน",
     "new_message_from": "New message from %1",
     "upvoted_your_post_in": "%1 has upvoted your post in %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 has favourited your post in %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 flagged a post in %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 has posted a reply to: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 has posted a new topic: %2",
     "user_started_following_you": "%1 started following you.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Email ได้รับการยืนยันแล้ว",
     "email-confirmed-message": "ขอบคุณที่ยืนยัน Email ของคุณ บัญชีของคุณสามารถใช้งานได้แล้ว",
diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json
index b0eb25ec97..b69d4c980f 100644
--- a/public/language/tr/notifications.json
+++ b/public/language/tr/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Okunmamış bildirimleriniz var.",
     "new_message_from": "%1 size bir mesaj gönderdi",
     "upvoted_your_post_in": "%1 iletinizi beğendi. %2",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 senin iletin %2 taşındı",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 iletinizi favorilerine ekledi. %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 bir iletiyi bayrakladı. %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 %2 başlığına bir ileti gönderdi.",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 yeni bir konu yarattı: %2",
     "user_started_following_you": "%1 sizi takip etmeye başladı.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 kayıt olma isteği gönderdi.",
     "email-confirmed": "E-posta onaylandı",
     "email-confirmed-message": "E-postanızı onaylandığınız için teşekkürler. Hesabınız tamamen aktive edildi.",
diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json
index 533e5d2a53..3d3ca64228 100644
--- a/public/language/vi/notifications.json
+++ b/public/language/vi/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "Bạn có thông báo chưa đọc",
     "new_message_from": "Tin nhắn mới từ %1",
     "upvoted_your_post_in": "%1 đã bình chọn bài của bạn trong %2.",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 đã thích bài của bạn trong %2.",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 gắn cờ 1 bài trong %2",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 đã trả lời %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 đã gởi chủ đề mới ở %2",
     "user_started_following_you": "%1 đã theo dõi bạn.",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "Đã xác nhận email",
     "email-confirmed-message": "Cảm ơn bạn đã xác nhận địa chỉ email của bạn. Tài khoản của bạn đã được kích hoạt đầy đủ.",
diff --git a/public/language/zh_CN/notifications.json b/public/language/zh_CN/notifications.json
index 9589fe7507..5fba6a56e0 100644
--- a/public/language/zh_CN/notifications.json
+++ b/public/language/zh_CN/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "您有未读的通知。",
     "new_message_from": "来自 %1 的新消息",
     "upvoted_your_post_in": "%1%2 点赞了您的帖子。",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "您的帖子已被 %1 移动到了 %2",
     "moved_your_topic": "%1 移动到了 %2",
     "favourited_your_post_in": "%1%2 收藏了您的帖子。",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1%2 标记了一个帖子",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 回复了:%2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 发表了新主题:%2",
     "user_started_following_you": "%1关注了您。",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 发出了注册请求",
     "email-confirmed": "电子邮箱已确认",
     "email-confirmed-message": "感谢您验证您的电子邮箱。您的帐户现已全面激活。",
diff --git a/public/language/zh_TW/notifications.json b/public/language/zh_TW/notifications.json
index 993d2cd3d8..fb2f3baa39 100644
--- a/public/language/zh_TW/notifications.json
+++ b/public/language/zh_TW/notifications.json
@@ -12,13 +12,23 @@
     "you_have_unread_notifications": "您有未讀的訊息!",
     "new_message_from": "來自 %1 的新訊息",
     "upvoted_your_post_in": "%1 upvote了您在 %2的post。",
+    "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.",
+    "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.",
     "moved_your_post": "%1 has moved your post to %2",
     "moved_your_topic": "%1 has moved %2",
     "favourited_your_post_in": "%1 收藏了你在 %2的post。",
+    "favourited_your_post_in_dual": "%1 and %2 have favourited your post in %3.",
+    "favourited_your_post_in_multiple": "%1 and %2 others have favourited your post in %3.",
     "user_flagged_post_in": "%1 舉報了 %2裡的一個post。",
+    "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3",
+    "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3",
     "user_posted_to": "%1 發布一個回覆給: %2",
+    "user_posted_to_dual": "%1 and %2 have posted replies to: %3",
+    "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3",
     "user_posted_topic": "%1 發布了一個新的主題: %2",
     "user_started_following_you": "%1 開始關注你。",
+    "user_started_following_you_dual": "%1 and %2 started following you.",
+    "user_started_following_you_multiple": "%1 and %2 others started following you.",
     "new_register": "%1 sent a registration request.",
     "email-confirmed": "已確認電郵",
     "email-confirmed-message": "感謝您驗證您的電郵。您的帳戶現已全面啟用。",

From ba719148c1ca0b8aa50e28eca843551c67dd94e3 Mon Sep 17 00:00:00 2001
From: psychobunny 
Date: Thu, 17 Dec 2015 16:44:22 -0500
Subject: [PATCH 14/19] generic "related topics" functionality

---
 src/topics.js      |  7 +++++++
 src/topics/tags.js | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/src/topics.js b/src/topics.js
index 560e434fb5..423dafe197 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -192,12 +192,19 @@ var async = require('async'),
 				}, next);
 			},
 			function(results, next) {
+				if (plugins.hasListeners('filter:topic.getRelatedTopics')) {
+					plugins.fireHook('filter:topic.getRelatedTopics', results, next);
+				} else {
+					Topics.getRelatedTopics(results, next);
+				}
+			}, function(results, next) {
 				topicData.posts = results.posts;
 				topicData.category = results.category;
 				topicData.thread_tools = results.threadTools.tools;
 				topicData.tags = results.tags;
 				topicData.isFollowing = results.isFollowing[0];
 				topicData.bookmark = results.bookmark;
+				topicData.related = results.related || [];
 
 				topicData.unreplied = parseInt(topicData.postcount, 10) === 1;
 				topicData.deleted = parseInt(topicData.deleted, 10) === 1;
diff --git a/src/topics/tags.js b/src/topics/tags.js
index bde9beff8f..8d29f947cf 100644
--- a/src/topics/tags.js
+++ b/src/topics/tags.js
@@ -5,6 +5,7 @@ var async = require('async'),
 
 	db = require('../database'),
 	meta = require('../meta'),
+	user = require('../user'),
 	_ = require('underscore'),
 	plugins = require('../plugins');
 
@@ -322,4 +323,41 @@ module.exports = function(Topics) {
 		});
 	};
 
+	Topics.getRelatedTopics = function(topicData, callback) {
+		if (!topicData.tags.length) {
+			return callback(null, topicData);
+		}
+
+		var related = [];
+
+		user.isAdministrator(topicData.threadTools.uid, function(err, isAdministrator) {
+			async.each(topicData.tags, function(tag, next) {
+				tag = tag.value;
+
+				Topics.getTagTids(tag, 0, 5, function(err, tids) {
+					Topics.getTopics(tids, topicData.threadTools.uid, function(err, topics) {
+						related = related.concat(topics.filter(function(topic) {
+							var doesntOwnTopic = parseInt(topic.uid, 10) !== parseInt(topicData.threadTools.uid, 10);
+							var isntSameTopic = parseInt(topic.tid, 10) !== parseInt(topicData.threadTools.topic.tid, 10);
+
+							return doesntOwnTopic && isntSameTopic;
+						}));
+
+						next(err);
+					});
+				});
+			}, function(err) {
+				if (!isAdministrator) {
+					related = related.filter(function(topic) {
+						return topic && !topic.deleted;
+					});
+				}
+
+				related = _.shuffle(related).slice(0, 5);
+
+				topicData.related = related;
+				callback(err, topicData);
+			});
+		});
+	};
 };
\ No newline at end of file

From 339b4c30fcc666843b7cca7d1fa3efa8b50e3379 Mon Sep 17 00:00:00 2001
From: psychobunny 
Date: Thu, 17 Dec 2015 16:52:02 -0500
Subject: [PATCH 15/19] ability to set maximum related topics rendered in ACP

---
 src/topics/tags.js                |  6 ++++--
 src/views/admin/settings/tags.tpl | 11 +++++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/topics/tags.js b/src/topics/tags.js
index 8d29f947cf..183dbe903c 100644
--- a/src/topics/tags.js
+++ b/src/topics/tags.js
@@ -324,7 +324,9 @@ module.exports = function(Topics) {
 	};
 
 	Topics.getRelatedTopics = function(topicData, callback) {
-		if (!topicData.tags.length) {
+		var maximumTopics = typeof meta.config.maximumRelatedTopics !== 'undefined' ? parseInt(meta.config.maximumRelatedTopics, 10) : 5;
+
+		if (!topicData.tags.length || maximumTopics === 0) {
 			return callback(null, topicData);
 		}
 
@@ -353,7 +355,7 @@ module.exports = function(Topics) {
 					});
 				}
 
-				related = _.shuffle(related).slice(0, 5);
+				related = _.shuffle(related).slice(0, maximumTopics);
 
 				topicData.related = related;
 				callback(err, topicData);
diff --git a/src/views/admin/settings/tags.tpl b/src/views/admin/settings/tags.tpl
index 6c09dab80e..90aa5ed0bc 100644
--- a/src/views/admin/settings/tags.tpl
+++ b/src/views/admin/settings/tags.tpl
@@ -31,4 +31,15 @@
 	
 
 
+
+
Related Topics
+
+
+
+ + +
+
+
+ \ No newline at end of file From 89901b2caa57efe303b928007b45d1d916f6c3f7 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 17 Dec 2015 16:53:42 -0500 Subject: [PATCH 16/19] reorganized settings/tags acp --- src/views/admin/settings/tags.tpl | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/views/admin/settings/tags.tpl b/src/views/admin/settings/tags.tpl index 90aa5ed0bc..e1e8f01f1c 100644 --- a/src/views/admin/settings/tags.tpl +++ b/src/views/admin/settings/tags.tpl @@ -4,12 +4,6 @@
Tag Settings
-
- -
@@ -31,6 +25,21 @@
+ +
+
Privacy
+
+ +
+ +
+ +
+
+
Related Topics
@@ -39,6 +48,7 @@
+
From a0910671754b297484adb589e2ff1d8759e304b8 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 17 Dec 2015 18:22:03 -0500 Subject: [PATCH 17/19] closes #3963 --- public/src/modules/translator.js | 36 ++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js index 35429af587..ca9cbb9f29 100644 --- a/public/src/modules/translator.js +++ b/public/src/modules/translator.js @@ -265,6 +265,7 @@ path = require('path'), winston = require('winston'), file = require('../../../src/file'), + plugins = require('../../../src/plugins'), meta = require('../../../src/meta'); language = language || meta.config.defaultLang || 'en_GB'; @@ -275,18 +276,35 @@ } fs.readFile(path.join(__dirname, '../../language', language, filename + '.json'), function(err, data) { - if (err) { - winston.error('Could not load `' + filename + '`: ' + err.message + '. Skipping...'); - return callback({}); + var onData = function(data) { + try { + data = JSON.parse(data.toString()); + } catch (e) { + winston.error('Could not parse `' + filename + '.json`, syntax error? Skipping...'); + data = {}; + } + callback(data); } - try { - data = JSON.parse(data.toString()); - } catch (e) { - winston.error('Could not parse `' + filename + '.json`, syntax error? Skipping...'); - data = {}; + if (err) { + if (err.code === 'ENOENT' && plugins.customLanguageFallbacks.hasOwnProperty(filename)) { + // Resource non-existant but fallback exists + return fs.readFile(plugins.customLanguageFallbacks[filename], { + encoding: 'utf-8' + }, function(err, data) { + if (err) { + return winston.error('[translator] Could not load fallback language file for resource ' + filename); + } + + onData(data); + }) + } else { + winston.error('[translator] Could not load `' + filename + '`: ' + err.message + '. Skipping...'); + return callback({}); + } } - callback(data); + + onData(data); }); } From e067d26ca36508cb724fde59c0a5e91c32dc0a4c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 18 Dec 2015 13:09:47 +0200 Subject: [PATCH 18/19] closes #3961 --- src/groups/update.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/groups/update.js b/src/groups/update.js index b239df39de..0ac688aca0 100644 --- a/src/groups/update.js +++ b/src/groups/update.js @@ -45,6 +45,7 @@ module.exports = function(Groups) { } async.series([ + async.apply(checkNameChange, groupName, values.name), async.apply(updatePrivacy, groupName, values.private), function(next) { if (values.hasOwnProperty('hidden')) { @@ -217,6 +218,23 @@ module.exports = function(Groups) { }); } + function checkNameChange(oldName, newName, callback) { + if (oldName === newName) { + return callback(); + } + var oldSlug = utils.slugify(oldName); + var newSlug = utils.slugify(newName); + if (oldSlug === newSlug) { + return callback(); + } + Groups.existsBySlug(newSlug, function(err, exists) { + if (err || exists) { + return callback(err || new Error('[[error:group-already-exists]]')); + } + callback(); + }); + } + function renameGroup(oldName, newName, callback) { if (oldName === newName || !newName || newName.length === 0) { return callback(); From 99815550423d0886498cc07c77d9a5e2e5e002fe Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 18 Dec 2015 13:14:44 +0200 Subject: [PATCH 19/19] rename --- src/groups/update.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/groups/update.js b/src/groups/update.js index 0ac688aca0..26d2b258be 100644 --- a/src/groups/update.js +++ b/src/groups/update.js @@ -218,13 +218,13 @@ module.exports = function(Groups) { }); } - function checkNameChange(oldName, newName, callback) { - if (oldName === newName) { + function checkNameChange(currentName, newName, callback) { + if (currentName === newName) { return callback(); } - var oldSlug = utils.slugify(oldName); + var currentSlug = utils.slugify(currentName); var newSlug = utils.slugify(newName); - if (oldSlug === newSlug) { + if (currentSlug === newSlug) { return callback(); } Groups.existsBySlug(newSlug, function(err, exists) {