CSSの::before疑似要素を用いて、要素の前に何かを表示する方法があります。contentプロパティに文字を入れてテキストを出すこともできますが、ふと、「このテキストを多言語化対応するにはどうすればいいのだろう」と思い浮かんだので、どんなやり方があるか考えてみることにしました。
先に今回書いたコードを載せておきます。
ここではcodepenを使用する都合上、main要素にlang属性を指定していますが、もちろんhtml要素のlang属性を指定しても大丈夫です。また、ボタン押下によってlang属性を切り替えていますが、ここもページ読み込み時にphpなどでhtml要素のlang属性を切り替えるのでも行けます。
まずはhtmlの属性でテキストを指定し、CSSでそれを読ませてみることにしました。
<main class="lang-setting" lang="ja">
<h1 class="ttl"
data-ja="主題"
data-ko="주제"
data-ru="предмет"
data-en="subject">
タイトル
</h1>
</main>
main[lang="ja"] {
.ttl {
&::before{
content: attr(data-ja)':';
}
}
}
main[lang="ko"] {
.ttl {
&::before{
content: attr(data-ko)':';
}
}
}
// ......
やっていることは単純で、main要素のlang属性に合わせてdata-jaやdata-koをattr()で読んであげているだけです。attr()はCSSの関数で、任意の属性を読み取ることができます。あとはJSでmain要素のlang属性を書き換えれば、lang="ko"ならdata-koの中身が、lang="ru"ならdata-ruの中身が画面に表示されます。
これでも一応言語に合わせて文言を変えることはできるのですが、::beforeで指定している箇所が多い場合、そのすべてにdata属性を振るのは流石に面倒です。他にも方法はないでしょうか。
次に、CSSのcontentに直接文言を指定してみることにしました。
<main class="lang-setting" lang="ja">
<section class="sec">
<h2 class="ttl">タイトル</h2>
<p>本文本文本文本文</p>
</section>
</main>
main[lang="ja"] {
.sec {
> .ttl{
&::before{
content: '副題:';
}
}
}
}
main[lang="ko"] {
.sec {
> .ttl{
&::before{
content: '부제:';
}
}
}
}
同じ内容の::beforeを出す箇所が沢山ある場合、この方が一括指定できて楽そうに見えます。
しかしです。そもそも多言語化対応をするようなケースにおいて、htmlやCSSに直接文言を書くのは、見通しも悪くなるし、管理も煩雑になりそうです。もっと他の方法もないでしょうか。
多言語化対応をするときは、大抵JSONでデータを持っているはずです。そこで、JSでオブジェクトとしてデータを取得したテイで、見出しにdata属性を付与してみることにします。
<main class="lang-setting" lang="ja">
<section class="sec-2nd">
<h3 class="ttl js-subhead">タイトル</h3>
<p>本文本文本文本文本文本文本文本文</p>
</section>
</main>
main {
.sec-2nd {
> .ttl {
&::before{
content: attr(data-lang);
}
}
}
}
const subhead = {
ja: '小見出し:',
ko: '작은 표제:',
ru: 'подзаголовок: ',
en: 'subhead: '
}
let langSetting = document.querySelector('.lang-setting');
const items = document.querySelectorAll('.js-subhead');
items.forEach(item => {
switch(langSetting.getAttribute('lang')) {
case 'ja':
item.dataset.before = subhead.ja;
break;
case 'ko':
item.dataset.before = subhead.ko;
break;
case 'ru':
item.dataset.before = subhead.ru;
break;
case 'en':
item.dataset.before = subhead.en;
break;
}
})
上のコードでは、lang属性を読んでdata-before属性を変更する部分だけ抜き出しています。実際は利用方法に応じて、DOMContentLoadedやclickイベントなどに紐づけてください。codepenの方ではclickで実行しています。
この方法ならテキストを一か所で管理できるため、対応箇所が多い場合は便利そうです。
実際に::beforeに多言語化対応が必要になるようなテキストを入れるか? と言われるとまあ滅多にないとは思うのですが、やりようはあるという実験でした。
実は最初にやり方を考え始めたとき、JSから::beforeを操作することはできないので(スタイルの取得などは可能ですが)、JSで多言語化するのは無理ではないかと思っていました。ですがdata属性を操作することは可能なので、こちらを使って::beforeの中身を変更することができました。
他にも、できない思っていたことにも別の道があったりするので、色々試していきたいですね。