Hugo HowTo: get localized comment counters with Disqus
(playing with numbers, many languages and JavaScript)
This blog is built into two languages (Italian, primary, and English, secondary), each one with its home and some other sections/pages, generally without a translated counterpart.
The primary home lists posts from all languages, the secondary only from its one. In any case, a post must consistently show its information in the same language.
So, for example:
Hugo HowTo: get localized comment counters with Disqus (playing with numbers, many languages and JavaScript)
(from "Tech stuff")
that includes title, description, date, summary, link to read more and, finally, our comment counter.
Hugo documentation about the multilingual mode is quite accurate, but says nothing about comment counters. And nothing also in Disqus help here. Here, instead, you discover how to embed Disqus according to page language (and this is ok, even you have to override the default Disqus template), and that you can translate/customize counters, true, but not for all languages in your static site (and this is not ok, right?).
Thus, let me illustrate my solution.
A first, trivial intermediate attempt
The obvious (and substantially unique) prerequisite is that you are already using Disqus for comments (have got disqusShortname, set it in config, etc).
Now, go to:
https://[your_disqusShortname].disqus.com/admin/settings/community/
or, alternatively, find the section of settings where you can customize the comment counter labels.
As you see, there are three options, for 0, 1 and {num} (>1) comments respectively. Simply edit each label keeping only the associated number, that is, “0”, “1”, and “{num}”, without quotes and other text. Save and close that page.
At this point, follow instructions on this page to include Disqus count.js in your Hugo site, according to the theme you use.
As you read, there are practically two ways to include comment counters:
- by an
<a>
element, with attributes href and (optional) data-disqus-identifier; - by a
<div>
or<span>
element, with attributes class and (optional) data-disqus-identifier or data-disqus-url.
Attributes are explained in more detail on the page above. In any case, Disqus script will find these elements and replace their innerHTML (readable text) with labels you edited previously.
In my opinion, the second choice offers more possibilities for a better result, especially <span>
. Consider also that you could be in the situation to want the comment counter from a disqus_url (specified in post front matter) and a link pointing to post comment section at real URL; getting this with a simple <a>
tag is quite difficult, I think.
Another consideration to do: apparently, in Hugo i18n seems to refer always to current page language (home/section that is listing posts), and I have not been able to find a way to force it differently. So, to get the correct localization, you have to use the .Site.Params.param mechanism, that relies on [languages] section described in Hugo multilingual mode.
So, here is a first, combined solution.
Find the correct template to override in your theme (in Ananke it is “layouts/partials/summary.html”), and add:
<a href="{{ .Permalink }}#disqus_thread">
<span class="disqus-comment-count" data-disqus-url="{{ with .Params.disqus_url }}{{ . }}{{ else }}{{ .Permalink }}{{ end }}"></span>
{{ .Site.Params.commentCounter }}
</a>
Once filled commentCounter param for all languages in your config (i.e.: with “comments” for English), you finally put online all changes (verifying locally requires another workaround, see below), and get link with text “0 comments”, “1 comments”, “42 comments” and so on, correctly localized and pointing to post comment section. Very basic, but working.
But you want more, much more than this, right? π
My JavaScript solution
If you have read me up to here (if not, do it), you have already the basic code to proceed.
At this point, my idea has been to hide Disqus <span>
, but taking advantage of it via JavaScript, to dynamically change the link text according to the (internal) counter value.
Besides, I removed whitespace between <a>
and </a>
, which seems to create problems to childNodes method, and replaced commentCounter with a noCounter param message (i.e.: “Comment counter not available”) displayed when Disqus temporarily fails or JavaScript is disabled.
So, previous code becomes:
<a id="disqus_comments" href="{{ .Permalink }}#disqus_thread"><span style="display:none!important;" class="disqus-comment-count" data-disqus-url="{{ with .Params.disqus_url }}{{ . }}{{ else }}{{ .Permalink }}{{ end }}"></span>{{ .Site.Params.noCounter }}</a>
Note the id for <a>
, needed for JavaScript below, and the style for hiding <span>
.
Now, you have to add a reference to your .js in theme template, probably under the Disqus script added previously. So, insert:
<script src="/js/yourJavaScript.js"></script>
Create (if you have not it yet) the file yourJavaScript.js under static/js/, and adapt the following code to your language needs:
// get <body> of page
var body = document.getElementsByTagName("body")[0];
// define the function to run after loading
body.onload = (function() {
// get all <a> tags with id="disqus_comments"
aComments = document.querySelectorAll("a#disqus_comments");
// and pass them to function for setting their text
for (i=0; i<aComments.length; i++) {
setCommentCounterText(aComments[i]);
}
});
function setCommentCounterText(a) {
// get hidden Disqus <span>
disqusSpan = a.childNodes[0];
// get its text, hopefully set by Disqus in the meantime
count = disqusSpan.textContent;
// if something went wrong, return (keeping the <a> default label)
if (count == "") {return;}
// get real URL of comment counter link
href = a.getAttribute("href");
// check for specific non-default language(s)
if (href.indexOf("/en/") != -1) {
// and set the new label accordingly
switch(count) {
case "0":
text = "No comment yet, sigh"; break;
case "1":
text = "Wow, there is a comment here!"; break;
default:
text = `Even ${count} comments!`;
}
} else { // default language (Italian, for me)
switch(count) {
case "0":
text = "Ancora nessun commento, sigh"; break;
case "1":
text = "Wow, qualcuno ha commentato!"; break;
default:
text = `Addirittura ${count} commenti!`;
}
}
// set new <a> label
a.textContent = text;
}
And voila! Your comment counters are translated and customized π
Ok, code is not so beautiful, I know, I never wrote JavaScript before this blog… but it works. And, if you have suggestions for improving it, you are welcome π
Counters on localhost
I don’t know exactly if it’s a good idea, but if you want to see counters locally (running “hugo server”), you can do it easily.
To avoid rendering of baseURL to localhost (even by absURL and so on), create a param (i.e.: “remoteBaseURL”) under site non-localized params in your config, setting it to baseURL value without trailing slash. In my case:
[params]
remoteBaseURL = "https://albumblog.github.io"
Now, modify the last HTML code like:
<a id="disqus_comments" href="{{ .Permalink }}#disqus_thread"><span style="display:none!important;" class="disqus-comment-count" data-disqus-url="{{ with .Params.disqus_url }}{{ . }}{{ else }}{{ .Site.Params.remoteBaseURL }}{{ .RelPermalink }}{{ end }}"></span>{{ .Site.Params.noCounter }}</a>
…and finally enjoy the magic. π
Conclusion
Cons:
- time: our JavaScript must wait the document loading has finished;
- scattering: the majority of strings are hard-coded into JavaScript or config, instead of i18n files;
- management: with more languages, code should be broken in smaller functions, to better readability and maintenance.
Advantages:
- goal: multilanguage support (β);
- fault-tolerance: backup text if Disqus fails or JavaScript is disabled;
- flexibility/customization: you easily catch many other numbers, for example adding “For zark, this post has many comments to answer to the Ultimate Question of Life, The Universe and Everything!” when the counter reaches 42 π
Well… the evaluation is acceptable, I think π
And now, let me know your thoughts increasing the comment counter of this post! π
Output by Album at 16:07:42 | 16:03:54