Відмінювання слова «коментар» у Disqus

Як і майже у всіх платформах коментування, в Disqus є проблема з відмінюванням кількості коментарів. В англійській мові з одниною і множиною все просто, є comment, і є comments. Розробники переважно не вникають в особливості інших мов, і дозволяють тільки три опції для відображення кількості коментарів — опція для однини, опція для множини, і ше одна опція, коли коментарів зовсім нема. Англійською все добре:

None comments
One comment
%num% comments

Але в багатих слов’янських мовах з’являються проблеми, трьох опцій не досить, може бути і коментар, і коментарі, і коментарів. Це вже три опції + треба ше одну для нуля коментарів. Тому

%num% коментарів
перетворюється на:
2 коментарів

Шо невимовно бісить, доводиться викручуватись якось так:

%num% коментарі(в)

або

Коментарів: %num%

А це теж чіпляє чутливу душу граматичного нациста, хочеться нормальних людських відмінювань.

Тепер по суті. Виправити це в Disqus можна, якщо трошки підправити деякі скрипти.

На сторінці налаштувань Disqus є доступ до цих самих трьох опцій, але нам їх мало, тому треба знайти спосіб виводити кількість коментарів правильно.Який взагалі у Disqus механізм відображення кількості коментарів до запису. Нехай запис знаходиться на сторінці http://example.com/post.html. Тоді в тому місці, де треба вивести к-сть коментарів, треба додати щось таке:

<a href="http://example.com/post.html#disqus_thread">Коментарі</a>

І в футері сторінки вставити такий скрипт:

<script type="text/javascript">
  /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
  var disqus_shortname = 'poohitan'; // required: replace example with your forum shortname
  /* * * DON'T EDIT BELOW THIS LINE * * */
  (function() {
    var s = document.createElement('script');
    s.async = true;
    s.type = 'text/javascript';
    s.src = '//' + disqus_shortname + '.disqus.com/count.js';
    (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
  }());
</script>

Цей скрипт проходиться по сторінці, шукає всі посилання, href яких містить #disqus_thread, йде на сервер Disqus'у, десь там дивиться, скільки є коментарів до запису з такою адресою, а тоді заміняє вміст тих посилань на власне кількість коментарів.

Бачимо, що у цьому скрипті нічого схожого на виведення кількості комнтарів нема, але він звертається до іншого скрипта count.js, вочевидь, там все і відбувається. Йдемо за адресою, там такий скрипт без whitespace'ів.

var DISQUSWIDGETS,disqus_domain,disqus_shortname;
typeof DISQUSWIDGETS=="undefined"&&(DISQUSWIDGETS=function(){var c={},n=document.getElementsByTagName("HEAD")[0]||document.body,i={},m={identifier:1,url:2};c.domain="disqus.com";c.forum="";c.getCount=function(){var a,b;a=encodeURIComponent;var o=document.location.protocol+"//"+c.forum+"."+c.domain+"/count-data.js?",d=[],g=0,j=10;b=document.getElementsByTagName("A");for(var h,e,f,k=0;k<b.length;k++){h=b[k];e=h.getAttribute("data-disqus-identifier");f=h.hash==="#disqus_thread"&&h.href.replace("#disqus_thread",
"");if(e)f=m.identifier;else if(f)e=f,f=m.url;else continue;var l;i.hasOwnProperty(e)?l=i[e]:(l=i[e]={elements:[],type:f},d.push(a(f)+"="+a(e)));l.elements.push(h)}d.sort();for(a=d.slice(g,j);a.length;)b=document.createElement("script"),b.async=!0,b.src=o+a.join("&"),n.appendChild(b),g+=10,j+=10,a=d.slice(g,j)};c.displayCount=function(a){for(var b,c,d,g=a.counts,a=a.text.comments;b=g.shift();)if(c=i[b.id]){switch(b.comments){case 0:d=a.zero;break;case 1:d=a.one;break;default:d=a.multiple}b=d.replace("{num}",
b.comments);c=c.elements;for(d=c.length-1;d>=0;d--)c[d].innerHTML=b}};return c}());(function(){if(typeof disqus_domain!="undefined")DISQUSWIDGETS.domain=disqus_domain;DISQUSWIDGETS.forum=disqus_shortname;DISQUSWIDGETS.getCount()})();

Пропускаємо його через jsbeautifier.org, отримуємо таке:

var DISQUSWIDGETS, disqus_domain, disqus_shortname;
typeof DISQUSWIDGETS == & quot;
undefined & quot; & amp; & amp;
(DISQUSWIDGETS = function() {
    var c = {},
      n = document.getElementsByTagName( & quot; HEAD & quot;)[0] || document.body,
      i = {},
      m = {
        identifier: 1,
        url: 2
      };
    c.domain = & quot;
    disqus.com & quot;;
    c.forum = & quot; & quot;;
    c.getCount = function() {
      var a, b;
      a = encodeURIComponent;
      var o = document.location.protocol + & quot; //&quot;+c.forum+&quot;.&quot;+c.domain+&quot;/count-data.js?&quot;,d=[],g=0,j=10;b=document.getElementsByTagName(&quot;A&quot;);for(var h,e,f,k=0;k&lt;b.length;k++){h=b[k];e=h.getAttribute(&quot;data-disqus-identifier&quot;);f=h.hash===&quot;#disqus_thread&quot;&amp;&amp;h.href.replace(&quot;#disqus_thread&quot;,
      &
      quot; & quot;);
    if (e) f = m.identifier;
    else if (f) e = f, f = m.url;
    else continue;
    var l;
    i.hasOwnProperty(e) ? l = i[e] : (l = i[e] = {
      elements: [],
      type: f
    }, d.push(a(f) + & quot; = & quot; + a(e)));
    l.elements.push(h)
  }
  d.sort();
  for (a = d.slice(g, j); a.length;) b = document.createElement( & quot; script & quot;), b.async = !0, b.src = o + a.join( & quot; & amp; & quot;), n.appendChild(b), g += 10, j += 10, a = d.slice(g, j)
};
c.displayCount = function(a) {
  for (var b, c, d, g = a.counts, a = a.text.comments; b = g.shift();)
    if (c = i[b.id]) {
      switch (b.comments) {
        case 0:
          d = a.zero;
          break;
        case 1:
          d = a.one;
          break;
        default:
          d = a.multiple
      }
      b = d.replace( & quot; {
          num
        } & quot;,
        b.comments);
      c = c.elements;
      for (d = c.length - 1; d & gt; = 0; d--) c[d].innerHTML = b
    }
};
return c
}());
(function() {
  if (typeof disqus_domain != & quot; undefined & quot;) DISQUSWIDGETS.domain = disqus_domain;
  DISQUSWIDGETS.forum = disqus_shortname;
  DISQUSWIDGETS.getCount()
})();

В це теж не хочеться вникати, незрозумілі назви змінних і всяке таке. Якщо поверхнево, то є дві функції, getCount() i displayCount(). Логічно припустити, шо нам треба displayCount(). Бачимо там такий шматок коду:

switch (b.comments) {
  case 0:
    d = a.zero;
    break;
  case 1:
    d = a.one;
    break;
  default:
    d = a.multiple
}
b = d.replace("{num}", b.comments);
c = c.elements;
for (d = c.length - 1; d >= 0; d--) c[d].innerHTML = b

Здається, тут якраз і відбувається те, шо нам треба. Є якесь b.comments, очевидно, шо це і є кількість коментарів до запису, бо далі в switch там перебираються випадки 0, 1 і решта. Після switch відбувається ше якась фігня, а потім в циклі ше шось. Можу тільки здогадуватись, шо там у змінних a, b, c i d, але це не суттєво, ніколи не треба без потреби розбиратись в чужому коді :). Достатньо бачити, що десь звідкись береться кількість коментарів, потім в циклі в якихось об’єктів заміняється innerHTML. Ясно, що ті об’єкти — це і є посилання з #disqus_thread, і їх вміст міняється на кількість коментарів. Отже в тому for нам треба міняти c[d].innerHTML на правильну кількість коментарів замість тої, яку видає Disqus. Переписуємо функцію displayCount() по-своєму:

c.displayCount = function(a) {
  var result;
  for (var b, c, d, g = a.counts, a = a.text.comments; b = g.shift();)
    if (c = i[b.id]) {
      if (b.comments == 0) {
        result = "Немає коментарів";
      } else if (b.comments == 1) {
        result = "1 коментар";
      } else {
        var numStr = b.comments.toString();
        var lastDigit = numStr.charAt(numStr.length - 1);
        if (lastDigit >= 2 && lastDigit <= 4) {
          result = b.comments + " коментарі";
        } else {
          result = b.comments + " коментарів";
        }
      }
      c = c.elements;
      for (d = c.length - 1; d >= 0; d--) c[d].innerHTML = result
    }
};

Круто, тепер треба, щоб Disqus звертався до нашого скрипта, а не до свого. Повертаємось до того скрипта, що у футері сайту, міняємо там рядок з адресою потрібного скрипта. Хоч він знаходиться нижче коментаря «/* * * DON'T EDIT BELOW THIS LINE * * */». Правила деколи треба порушувати :)

<script type="text/javascript">
  /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
  var disqus_shortname = 'poohitan'; // required: replace example with your forum shortname
  /* * * DON'T EDIT BELOW THIS LINE * * */
  (function() {
    var s = document.createElement('script');
    s.async = true;
    s.type = 'text/javascript';
    s.src = 'http://example.com/comments-count.js';
    (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
  }());
</script>

І ура, все працює, можна насолоджуватись правильним відмінюванням. Отже, наш перероблений скрипт comments-count.js:

var DISQUSWIDGETS, disqus_domain, disqus_shortname;
typeof DISQUSWIDGETS == "undefined" && (DISQUSWIDGETS = function() {
  var c = {},
    n = document.getElementsByTagName("HEAD")[0] || document.body,
    i = {},
    m = {
      identifier: 1,
      url: 2
    };
  c.domain = "disqus.com";
  c.forum = "";
  c.getCount = function() {
    var a, b;
    a = encodeURIComponent;
    var o = document.location.protocol + "//" + c.forum + "." + c.domain + "/count-data.js?",
      d = [],
      g = 0,
      j = 10;
    b = document.getElementsByTagName("A");
    for (var h, e, f, k = 0; k < b.length; k++) {
      h = b[k];
      e = h.getAttribute("data-disqus-identifier");
      f = h.hash === "#disqus_thread" && h.href.replace("#disqus_thread",
        "");
      if (e) f = m.identifier;
      else if (f) e = f, f = m.url;
      else continue;
      var l;
      i.hasOwnProperty(e) ? l = i[e] : (l = i[e] = {
        elements: [],
        type: f
      }, d.push(a(f) + "=" + a(e)));
      l.elements.push(h)
    }
    d.sort();
    for (a = d.slice(g, j); a.length;) b = document.createElement("script"), b.async = !0, b.src = o + a.join("&"), n.appendChild(b), g += 10, j += 10, a = d.slice(g, j)
  };
  c.displayCount = function(a) {
    var result;
    for (var b, c, d, g = a.counts, a = a.text.comments; b = g.shift();)
      if (c = i[b.id]) {
        if (b.comments == 0) {
          result = "Немає коментарів";
        } else if (b.comments == 1) {
          result = "1 коментар";
        } else {
          var numStr = b.comments.toString();
          var lastDigit = numStr.charAt(numStr.length - 1);
          if (lastDigit >= 2 && lastDigit <= 4) {
            result = b.comments + " коментарі";
          } else {
            result = b.comments + " коментарів";
          }
        }
        c = c.elements;
        for (d = c.length - 1; d >= 0; d--) c[d].innerHTML = result
      }
  };
  return c
}());
(function() {
  if (typeof disqus_domain != "undefined") DISQUSWIDGETS.domain = disqus_domain;
  DISQUSWIDGETS.forum = disqus_shortname;
  DISQUSWIDGETS.getCount()
})();

І перероблений скрипт у футері сайту, який буде звертатись до нашого скрипта:

<script type="text/javascript">
  /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
  var disqus_shortname = 'poohitan'; // required: replace example with your forum shortname
  /* * * DON'T EDIT BELOW THIS LINE * * */
  (function() {
    var s = document.createElement('script');
    s.async = true;
    s.type = 'text/javascript';
    s.src = 'http://example.com/comments-count.js';
    (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
  }());
</script>

Все. Хай живе граматика.