Takový pěkný CSS hack na páteční odpoledne, aneb Jak vyřešit plurály, když máte v ruce jen CSS a HTML?

Představte si redakční systém, kde máte přístup jen k HTML šablonám a k CSS. Obsah do nich vkládáte pomocí nějakých speciálních značek. A teď chcete vypsat počet komentářů.

S počtem komentářů je ten problém, že v češtině máme dvě množná čísla. Podívejte se sami:

  • 1 komentář
  • 2 komentáře
  • 3 komentáře
  • 4 komentáře
  • 5 komentářů
  • 6 komentářů

…atakdál. Podle starých pravidel se řídil tvar podle poslední číslice i v případech jako je 21, 22, 23… (21 komentář, 22 komentáře), ale nová pravidla kodifikují jako přijatelný i tvar „21 komentářů“. (Důvod je prostý – představte si větu „4721 divák nadšeně aplaudoval“ – viz Šílený korektor).

Takže tedy řešíme stavy 0, 1, 2-4 a 5+ a patřičný tvar.

A teď si představte, že redakční systém umí odlišit situaci, kdy nejsou žádné komentáře (a tu ošetří), no a pro všechno ostatní tu je jedna HTML šablona a v ní je:

<p>Diskuse obsahuje $CommentNum$ příspěvků</p>

Ne, žádné podmínky šablona nenabízí. Takže výsledkem jsou hlášky „Diskuse obsahuje 3 příspěvků“, nemluvě o „Diskuse obsahuje 1 příspěvků“.

Jak to pořešit? Jedna z možností je využít JavaScript, no a druhá možnost, kterou mi dneska ukázal kolega Honza Drda, využívá CSS. Já takové řešení nenašel, tak ho zveřejňuju s nadějí, že se může někomu hodit (a s Honzovým souhlasem, samozřejmě).

HTML kód je:

<p>Diskuse obsahuje $CommentNum$ <span class="none ek$CommentNum$">příspěvek</span><span class="none ky$CommentNum$">příspěvky</span><span class="ku$CommentNum$">příspěvků</span></p>

a k tomu patří jednoduchá CSS pravidla:

.none,.ku1,.ku2,.ku3,.ku4 { display: none; } 
.ek1,.ky2,.ky3,.ky4 { display: inline;}

A to je celé… Vyzkoušel jsem v Chrome, funguje, ale je možné, že někde to nepoběží.

Samozřejmě ideální řešení je využít nástroj na straně serveru, který tohle umí ošetřit (gettext např.) Ale někdy holt není…

Update: Krásné řešení navrhl v komentářích David Matějka (s použitím datových atributů a CSS3)

HTML:

<div>Diskuze obsahuje <span data-count="$CommentNum$" data-plural-1="komentář" data-plural-2="komentáře" data-plural-3="komentářů"></span></div>

CSS:

span[data-count]:before{
 content: attr(data-count) ' ';
}
span:after {
 content: attr(data-plural-3);
}
span[data-count='1']:after {
 content: attr(data-plural-1);
}
span[data-count='2']:after, span[data-count='3']:after, span[data-count='4']:after {
 content: attr(data-plural-2);
}

Update 2: vylepšení předchozího tak, že i v případě vypnutých CSS zůstane sémanticky správné sdělení, napsal Martin Keder

HTML:

<div>Diskuze obsahuje $CommentNum$ <span data-count="$CommentNum$" data-plural-1="komentář" data-plural-2="komentáře"><span>komentářů</span></span></div>

CSS:

span[data-count='1']:after
{
 content: attr(data-plural-1);
}
span[data-count='2']:after, 
span[data-count='3']:after, 
span[data-count='4']:after 
{
 content: attr(data-plural-2);
}
span[data-count='1'] span, 
span[data-count='2'] span, 
span[data-count='3'] span, 
span[data-count='4'] span
{
 display: none;
}