この記事の読者
- WebでPHPをあまり使ったことがない方
- 多言語対応させたいけど、SQLなどは使いたくない方
- この記事を楽しく読める人
きっかけ
自分の運営している団体でWebを多言語対応させよう思った時に、WordPressなどは使わず、一からWebを構築しているため、自ら多言語対応をする必要があった。
前提条件
- 使えるのはHTML、CSS、JavaScriptの3つだけ。
- 外部ライブラリを使うのは問題ない
- 翻訳を担当するのは別の人
結論
JSONファイルを作成→配列から読み込み
追記(2022/12/24)
@think49 様より、コード改善のアドバイスをいただきました。
誠に感謝しかございません。
のちにその修正コードを追記させていただきます。
詳細
例として以下のHTMLファイルを用意。
index.html
<!DOCTYPE html>
<html>
<head>
<title>test<title>
</head>
<body>
<h1 name="enterd"> 果物</p>
<p name="enterd">りんご</p>
</body>
</html>
data.json
[
{
"lang":"ja",
"value":{
"title":"果物",
"text":"りんご"
}
},
{
"lang":"en",
"value":{
"title":"Fruits",
"text":"Apple"
}
}
]
main.js
//初期値の設定
let langNum = 3;
//パラメータの取得
function getParam(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
};
//言語のパラメータがある場合は取得、ない場合はブラウザの言語を取得
if (getParam("lang") == null) {
const browserLangugage = window.navigator.language;
setLanguage(browserLangugage);
console.log("No language")
} else {
setLanguage(getParam("lang"));
console.log("Para")
}
//JSONから言語の取得をするための変換
function setLanguage(lang) {
if (lang == "ja") {
langNum = 0;
console.log(langNum);
} else if (lang == "en") {
langNum = 1;
console.log(langNum);
} else if (lang == "es") {
langNum = 2;
console.log(langNum);
} else {
langNum = 1;
console.log(langNum);
};
};
//JSONファイルから言語データを取得
fetch('./data.json')
.then(function (response) {
console.log(response);
return response.json();
})
.then(function (data) {
console.log(langNum);
let valueArray = Object.values(data[langNum].value);
console.log(valueArray);
return valueArray;
})
.then(function (valuesOfInfo) {
const length = valuesOfInfo.length;
for (let i = 0; i < length; i++) {
document.getElementsByName("enterd")[i].innerHTML = valuesOfInfo[i];
}
})
JSONファイルの中が配列なので、パラメータで指定されている言語と対応する番号(配列インデックス)に変換する必要がある。
たとえば、URLは表記は以下の通りになる。
https://example.com/?lang=ja
だが、JSONのファイルの中では一つ目の配列にデータが入っているので、パラメータがja
ならlangNum
変数に0を入れる、のように対応させている。
利点
- 他の言語の追加が容易である
- 編集が簡単
改善すべきポイント
- JSONを配列に変換しているので、一つでも忘れたら修正作業が大変
筆者の戯言
結局、Webページの多言語対応ってどのようにやるのが正解なんですかね?
修正1 (2022/12/24)
@think49 の修正版コードを追記します。
詳しくは、コメント欄を参照いただけると幸いです。
再度、 @think49 様に感謝申し上げます。
sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>sample</title>
</head>
<body>
<template id="sample">
<h1>${title}</h1>
<p>${text}</p>
</template>
<script>
'use strict';
function replaceTextNode (entries, ...contextNodeList) {
for (let contextNode of contextNodeList) {
const xpathResult = document.evaluate('descendant::text()', contextNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
let i = xpathResult.snapshotLength;
while (i--) {
const textNode = xpathResult.snapshotItem(i);
for (let [key, value] of entries){
textNode.data = textNode.data.replace(new RegExp('\\${' + key + '}', 'g'), value);
}
}
}
}
fetch('lang.json')
.then(response => response.json())
.then(contentEntries => {
const lang = new URLSearchParams(location.search).get('lang');
const contents = contentEntries[lang];
if (!contents) return;
document.documentElement.lang = lang;
const df = document.getElementById('sample').content.cloneNode(true);
replaceTextNode(Object.entries(contents), ...df.childNodes);
document.body.appendChild(df);
});
</script>
</body>
</html>
lang.json
{
"ja":{
"title": "果物",
"text": "りんご"
},
"en":{
"title": "Fruits",
"text": "Apple"
}
}