Color mode

Localization

Riebeckite では、@riebeckite/plugin-l10n を使って多言語 Site を構築できます。

l10n Plugin は、Content ごとの言語を判定し、

  • 言語ごとの URL
  • 同じ Content の翻訳版
  • Site 内リンク
  • 言語切り替え
  • SEO と組み合わせた hreflang

などを扱います。

Diagram source
text
flowchart LR
    Content["Markdown"]
    L10n["l10n Plugin"]
    EN["English"]
    JA["日本語"]
 
    Content --> L10n
    L10n --> EN
    L10n --> JA

starter 以上の Preset では、次の7言語が設定されます。

text
en
ja
zh-CN
es
de
fr
ko

すべての言語の記事を用意する必要はありません。実際に利用する言語に合わせて設定できます。

基本設定

riebeckite.config.ts に l10n Plugin を追加します。

ts
import { l10n } from "@riebeckite/plugin-l10n";
 
export default defineConfig({
  plugins: [
    l10n({
      defaultLang: "en",
      languages: ["en", "ja"],
    }),
  ],
});

この例では、

text
defaultLang
  → en
 
利用する言語
  → en / ja

となります。

defaultLang は、Content の言語を他の方法で判定できなかった場合にも使われます。

Content の言語を決める

l10n Plugin は、それぞれの Content が何語なのかを判定します。

判定には優先順位があります。

Diagram source
text
flowchart TD
    Start["Content"]
 
    Start --> FM{"frontmatterに<br/>言語がある?"}
    FM -->|Yes| Result["言語を決定"]
    FM -->|No| Detector{"custom detectorで<br/>判定できる?"}
 
    Detector -->|Yes| Result
    Detector -->|No| File{"ファイル名で<br/>判定できる?"}
 
    File -->|Yes| Result
    File -->|No| Default["defaultLang"]

優先順位は次のとおりです。

  1. Frontmatter
  2. Custom Detector
  3. ファイル名
  4. defaultLang

上の方法で判定できた時点で、その Content の言語が決まります。

Frontmatter で指定する

最も明示的なのは Frontmatter の lang です。

md
---
title: こんにちは
lang: ja
publish: true
---
 
日本語の記事です。

この Content は日本語として扱われます。

ファイルの場所や名前とは別に言語を明示したい場合に利用できます。

ファイル名で分ける

同じ Directory に複数言語の記事を置く場合は、ファイル名の末尾で分けます。

たとえば、

text
README.md
README.ja.md

のように配置します。

README.ja.md の .ja から、その Content が日本語だと判定できます。defaultLang の言語には接尾辞を付けません。

推奨は .言語 ですが、-言語 と _言語 も同じ意味で扱われます。

この方式なら、

text
docs/
├─ README.md
├─ README.ja.md
├─ installation.md
└─ installation.ja.md

のように、元の記事と翻訳版を近くに置いて管理できます。

Directory では分けない

言語ごとに Directory を分ける構成(en/note.md、ja/note.md)は、言語判定には使われません。

言語判定の暗黙ルールをファイル名の接尾辞だけに絞ることで、同じ名前の記事が複数言語で存在しても WikiLink が一意に解決されます。言語はファイル名の接尾辞か、Frontmatter の lang で指定してください。

翻訳同士を対応付ける

「この日本語記事と、この英語記事は同じ Content の翻訳版」という関係は、Frontmatter の translation で表します。

たとえば日本語版を、

md
---
title: こんにちは
publish: true
lang: ja
translation: hello
---
 
日本語の記事です。

とします。

対応する英語版にも同じ translation を指定します。

md
---
title: Hello
publish: true
lang: en
translation: hello
---
 
This is the English version.

両方に、

yaml
translation: hello

があるため、同じ Content の翻訳として扱われます。

Diagram source
text
flowchart LR
    EN["Hello<br/>lang: en"]
    Group["translation: hello"]
    JA["こんにちは<br/>lang: ja"]
 
    EN --> Group
    JA --> Group

lang と translation の違い

この2つは役割が異なります。

Field 意味
lang このページが何語なのか
translation どのページ同士が翻訳関係なのか

たとえば、

yaml
lang: ja
translation: getting-started

なら、

text
このページの言語
  → 日本語
 
翻訳グループ
  → getting-started

という意味になります。

translation 自体は言語名ではありません。

同じ内容を表すページ同士で共通の値を使います。

翻訳が存在しない場合

すべての Content にすべての言語版を用意する必要はありません。

たとえば、

text
article-a.md       日本語
article-a.en.md    English
article-b.md       日本語

のように、一部の言語版だけが存在しても構いません。

article-b の英語版が存在しない場合、Riebeckite が英語ページを自動生成することはありません。

Diagram source
text
flowchart LR
    JA["日本語ページ"]
    Check{"英語版が存在?"}
 
    JA --> Check
    Check -->|Yes| EN["英語ページ"]
    Check -->|No| None["何も生成しない"]

l10n Plugin は既存の翻訳関係を扱いますが、Content 自体を翻訳する機能ではありません。

URL

l10n Plugin は Content の言語情報を使って Public URL を扱います。

つまり、多言語化は単に画面へ言語名を表示するだけではなく、

text
Content
  ↓
言語判定
  ↓
Public Location
  ↓
URL

まで含めて処理されます。

Site 側でファイル名から独自に URL を組み立てるのではなく、Riebeckite が解決した Public Location を利用してください。

Public Location の仕組みについては Content System を参照してください。

Site 内リンク

多言語 Site では、本文中のリンクも言語を考慮して扱われます。

たとえば日本語の記事から別の記事へ移動するとき、対応する日本語版が存在する場合は、その言語に対応したリンクとして扱えます。

Diagram source
text
flowchart LR
    JA1["日本語 Article A"]
    EN2["Article B / English"]
    JA2["Article B / 日本語"]
 
    JA1 -.-> EN2
    JA1 -->|"対応する言語"| JA2

これによって、記事本文のリンクだけ別言語のページへ戻ってしまう、といった問題を避けられます。

言語切り替え

同じ translation を持つ Content は、言語切り替えの候補になります。

たとえば、

text
translation: hello
 
├─ lang: en
├─ lang: ja
└─ lang: de

という Content が存在すれば、それぞれを同じ Content の別言語版として扱えます。

実際に存在する翻訳だけが候補になります。

存在しない言語版への Fallback Page は自動生成されません。

SEO

SEO Plugin と組み合わせることで、翻訳関係を hreflang として出力できます。

概念的には、

text
English page
   ↕
translation relationship
   ↕
日本語 page
   ↓
SEO
   ↓
hreflang

という関係です。

これによって Search Engine に同じ Content の別言語版であることを伝えられます。

おすすめの構成

英語と日本語の2言語で運用する場合は、たとえば次のようにできます。

text
content/
├─ getting-started.md
├─ getting-started.ja.md
├─ installation.md
├─ installation.ja.md
└─ faq.ja.md

そして翻訳関係を Frontmatter で明示します。

英語版は次のとおりです。

md
---
title: Getting Started
lang: en
translation: getting-started
publish: true
---

日本語版は次のとおりです。

md
---
title: はじめに
lang: ja
translation: getting-started
publish: true
---

翻訳がまだ存在しない faq.ja.md は、日本語だけで公開しても構いません。

導入の流れ

多言語 Site を作る場合は、次の順番で考えると分かりやすくなります。

Diagram source
text
flowchart TD
    Lang["1. 使用する言語を決める"]
    Config["2. l10nを設定"]
    Detection["3. 言語の判定方法を決める"]
    Content["4. 各言語の記事を書く"]
    Translation["5. translationで対応付ける"]
    Link["6. URL・リンクを確認"]
    SEO["7. 必要ならSEOと組み合わせる"]
 
    Lang --> Config
    Config --> Detection
    Detection --> Content
    Content --> Translation
    Translation --> Link
    Link --> SEO

まとめ

Riebeckite の多言語対応では、次の3つを分けて考えると分かりやすくなります。

text
lang
  → このContentは何語か
 
translation
  → どのContentと翻訳関係にあるか
 
Public Location
  → その言語のContentをどのURLで公開するか

言語は、

text
frontmatter
    ↓
custom detector
    ↓
ファイル名
    ↓
defaultLang

の優先順位で判定されます。

翻訳関係は translation で明示し、実際に存在する翻訳だけを利用します。存在しない翻訳を Riebeckite が自動生成することはありません。

詳しい Option や Public API は、@riebeckite/plugin-l10n の Package README と Plugin API を参照してください。

History

1 changesCollapseExpand
1 + # Localization
2 +
3 + Riebeckite では、`@riebeckite/plugin-l10n` を使って多言語 Site を構築できます。
4 +
5 + l10n Plugin は、Content ごとの言語を判定し、
6 +
7 + - 言語ごとの URL
8 + - 同じ Content の翻訳版
9 + - Site 内リンク
10 + - 言語切り替え
11 + - SEO と組み合わせた `hreflang`
12 +
13 + などを扱います。
14 +
15 + ```mermaid
16 + flowchart LR
17 + Content["Markdown"]
18 + L10n["l10n Plugin"]
19 + EN["English"]
20 + JA["日本語"]
21 +
22 + Content --> L10n
23 + L10n --> EN
24 + L10n --> JA
25 + ```
26 +
27 + `starter` 以上の Preset では、次の7言語が設定されます。
28 +
29 + ```text
30 + en
31 + ja
32 + zh-CN
33 + es
34 + de
35 + fr
36 + ko
37 + ```
38 +
39 + すべての言語の記事を用意する必要はありません。実際に利用する言語に合わせて設定できます。
40 +
41 + ## 基本設定
42 +
43 + `riebeckite.config.ts` に `l10n` Plugin を追加します。
44 +
45 + ```ts
46 + import { l10n } from "@riebeckite/plugin-l10n";
47 +
48 + export default defineConfig({
49 + plugins: [
50 + l10n({
51 + defaultLang: "en",
52 + languages: ["en", "ja"],
53 + }),
54 + ],
55 + });
56 + ```
57 +
58 + この例では、
59 +
60 + ```text
61 + defaultLang
62 + → en
63 +
64 + 利用する言語
65 + → en / ja
66 + ```
67 +
68 + となります。
69 +
70 + `defaultLang` は、Content の言語を他の方法で判定できなかった場合にも使われます。
71 +
72 + ## Content の言語を決める
73 +
74 + l10n Plugin は、それぞれの Content が何語なのかを判定します。
75 +
76 + 判定には優先順位があります。
77 +
78 + ```mermaid
79 + flowchart TD
80 + Start["Content"]
81 +
82 + Start --> FM{"frontmatterに<br/>言語がある?"}
83 + FM -->|Yes| Result["言語を決定"]
84 + FM -->|No| Detector{"custom detectorで<br/>判定できる?"}
85 +
86 + Detector -->|Yes| Result
87 + Detector -->|No| File{"ファイル名で<br/>判定できる?"}
88 +
89 + File -->|Yes| Result
90 + File -->|No| Default["defaultLang"]
91 + ```
92 +
93 + 優先順位は次のとおりです。
94 +
95 + 1. Frontmatter
96 + 2. Custom Detector
97 + 3. ファイル名
98 + 4. `defaultLang`
99 +
100 + 上の方法で判定できた時点で、その Content の言語が決まります。
101 +
102 + ## Frontmatter で指定する
103 +
104 + 最も明示的なのは Frontmatter の `lang` です。
105 +
106 + ```md
107 + ---
108 + title: こんにちは
109 + lang: ja
110 + publish: true
111 + ---
112 +
113 + 日本語の記事です。
114 + ```
115 +
116 + この Content は日本語として扱われます。
117 +
118 + ファイルの場所や名前とは別に言語を明示したい場合に利用できます。
119 +
120 + ## ファイル名で分ける
121 +
122 + 同じ Directory に複数言語の記事を置く場合は、ファイル名の末尾で分けます。
123 +
124 + たとえば、
125 +
126 + ```text
127 + README.md
128 + README.ja.md
129 + ```
130 +
131 + のように配置します。
132 +
133 + `README.ja.md` の `.ja` から、その Content が日本語だと判定できます。`defaultLang` の言語には接尾辞を付けません。
134 +
135 + 推奨は `.言語` ですが、`-言語` と `_言語` も同じ意味で扱われます。
136 +
137 + この方式なら、
138 +
139 + ```text
140 + docs/
141 + ├─ README.md
142 + ├─ README.ja.md
143 + ├─ installation.md
144 + └─ installation.ja.md
145 + ```
146 +
147 + のように、元の記事と翻訳版を近くに置いて管理できます。
148 +
149 + ## Directory では分けない
150 +
151 + 言語ごとに Directory を分ける構成(`en/note.md`、`ja/note.md`)は、言語判定には使われません。
152 +
153 + 言語判定の暗黙ルールをファイル名の接尾辞だけに絞ることで、同じ名前の記事が複数言語で存在しても WikiLink が一意に解決されます。言語はファイル名の接尾辞か、Frontmatter の `lang` で指定してください。
154 +
155 + ## 翻訳同士を対応付ける
156 +
157 + 「この日本語記事と、この英語記事は同じ Content の翻訳版」という関係は、Frontmatter の `translation` で表します。
158 +
159 + たとえば日本語版を、
160 +
161 + ```md
162 + ---
163 + title: こんにちは
164 + publish: true
165 + lang: ja
166 + translation: hello
167 + ---
168 +
169 + 日本語の記事です。
170 + ```
171 +
172 + とします。
173 +
174 + 対応する英語版にも同じ `translation` を指定します。
175 +
176 + ```md
177 + ---
178 + title: Hello
179 + publish: true
180 + lang: en
181 + translation: hello
182 + ---
183 +
184 + This is the English version.
185 + ```
186 +
187 + 両方に、
188 +
189 + ```yaml
190 + translation: hello
191 + ```
192 +
193 + があるため、同じ Content の翻訳として扱われます。
194 +
195 + ```mermaid
196 + flowchart LR
197 + EN["Hello<br/>lang: en"]
198 + Group["translation: hello"]
199 + JA["こんにちは<br/>lang: ja"]
200 +
201 + EN --> Group
202 + JA --> Group
203 + ```
204 +
205 + ## `lang` と `translation` の違い
206 +
207 + この2つは役割が異なります。
208 +
209 + | Field | 意味 |
210 + | --- | --- |
211 + | `lang` | このページが何語なのか |
212 + | `translation` | どのページ同士が翻訳関係なのか |
213 +
214 + たとえば、
215 +
216 + ```yaml
217 + lang: ja
218 + translation: getting-started
219 + ```
220 +
221 + なら、
222 +
223 + ```text
224 + このページの言語
225 + → 日本語
226 +
227 + 翻訳グループ
228 + → getting-started
229 + ```
230 +
231 + という意味になります。
232 +
233 + `translation` 自体は言語名ではありません。
234 +
235 + 同じ内容を表すページ同士で共通の値を使います。
236 +
237 + ## 翻訳が存在しない場合
238 +
239 + すべての Content にすべての言語版を用意する必要はありません。
240 +
241 + たとえば、
242 +
243 + ```text
244 + article-a.md 日本語
245 + article-a.en.md English
246 + article-b.md 日本語
247 + ```
248 +
249 + のように、一部の言語版だけが存在しても構いません。
250 +
251 + `article-b` の英語版が存在しない場合、Riebeckite が英語ページを自動生成することはありません。
252 +
253 + ```mermaid
254 + flowchart LR
255 + JA["日本語ページ"]
256 + Check{"英語版が存在?"}
257 +
258 + JA --> Check
259 + Check -->|Yes| EN["英語ページ"]
260 + Check -->|No| None["何も生成しない"]
261 + ```
262 +
263 + l10n Plugin は既存の翻訳関係を扱いますが、Content 自体を翻訳する機能ではありません。
264 +
265 + ## URL
266 +
267 + l10n Plugin は Content の言語情報を使って Public URL を扱います。
268 +
269 + つまり、多言語化は単に画面へ言語名を表示するだけではなく、
270 +
271 + ```text
272 + Content
273 + ↓
274 + 言語判定
275 + ↓
276 + Public Location
277 + ↓
278 + URL
279 + ```
280 +
281 + まで含めて処理されます。
282 +
283 + Site 側でファイル名から独自に URL を組み立てるのではなく、Riebeckite が解決した Public Location を利用してください。
284 +
285 + Public Location の仕組みについては [Content System](../framework/content-system.ja.md) を参照してください。
286 +
287 + ## Site 内リンク
288 +
289 + 多言語 Site では、本文中のリンクも言語を考慮して扱われます。
290 +
291 + たとえば日本語の記事から別の記事へ移動するとき、対応する日本語版が存在する場合は、その言語に対応したリンクとして扱えます。
292 +
293 + ```mermaid
294 + flowchart LR
295 + JA1["日本語 Article A"]
296 + EN2["Article B / English"]
297 + JA2["Article B / 日本語"]
298 +
299 + JA1 -.-> EN2
300 + JA1 -->|"対応する言語"| JA2
301 + ```
302 +
303 + これによって、記事本文のリンクだけ別言語のページへ戻ってしまう、といった問題を避けられます。
304 +
305 + ## 言語切り替え
306 +
307 + 同じ `translation` を持つ Content は、言語切り替えの候補になります。
308 +
309 + たとえば、
310 +
311 + ```text
312 + translation: hello
313 +
314 + ├─ lang: en
315 + ├─ lang: ja
316 + └─ lang: de
317 + ```
318 +
319 + という Content が存在すれば、それぞれを同じ Content の別言語版として扱えます。
320 +
321 + **実際に存在する翻訳だけが候補になります**。
322 +
323 + 存在しない言語版への Fallback Page は自動生成されません。
324 +
325 + ## SEO
326 +
327 + SEO Plugin と組み合わせることで、翻訳関係を `hreflang` として出力できます。
328 +
329 + 概念的には、
330 +
331 + ```text
332 + English page
333 + ↕
334 + translation relationship
335 + ↕
336 + 日本語 page
337 + ↓
338 + SEO
339 + ↓
340 + hreflang
341 + ```
342 +
343 + という関係です。
344 +
345 + これによって Search Engine に同じ Content の別言語版であることを伝えられます。
346 +
347 + ## おすすめの構成
348 +
349 + 英語と日本語の2言語で運用する場合は、たとえば次のようにできます。
350 +
351 + ```text
352 + content/
353 + ├─ getting-started.md
354 + ├─ getting-started.ja.md
355 + ├─ installation.md
356 + ├─ installation.ja.md
357 + └─ faq.ja.md
358 + ```
359 +
360 + そして翻訳関係を Frontmatter で明示します。
361 +
362 + 英語版は次のとおりです。
363 +
364 + ```md
365 + ---
366 + title: Getting Started
367 + lang: en
368 + translation: getting-started
369 + publish: true
370 + ---
371 + ```
372 +
373 + 日本語版は次のとおりです。
374 +
375 + ```md
376 + ---
377 + title: はじめに
378 + lang: ja
379 + translation: getting-started
380 + publish: true
381 + ---
382 + ```
383 +
384 + 翻訳がまだ存在しない `faq.ja.md` は、日本語だけで公開しても構いません。
385 +
386 + ## 導入の流れ
387 +
388 + 多言語 Site を作る場合は、次の順番で考えると分かりやすくなります。
389 +
390 + ```mermaid
391 + flowchart TD
392 + Lang["1. 使用する言語を決める"]
393 + Config["2. l10nを設定"]
394 + Detection["3. 言語の判定方法を決める"]
395 + Content["4. 各言語の記事を書く"]
396 + Translation["5. translationで対応付ける"]
397 + Link["6. URL・リンクを確認"]
398 + SEO["7. 必要ならSEOと組み合わせる"]
399 +
400 + Lang --> Config
401 + Config --> Detection
402 + Detection --> Content
403 + Content --> Translation
404 + Translation --> Link
405 + Link --> SEO
406 + ```
407 +
408 + ## まとめ
409 +
410 + Riebeckite の多言語対応では、次の3つを分けて考えると分かりやすくなります。
411 +
412 + ```text
413 + lang
414 + → このContentは何語か
415 +
416 + translation
417 + → どのContentと翻訳関係にあるか
418 +
419 + Public Location
420 + → その言語のContentをどのURLで公開するか
421 + ```
422 +
423 + 言語は、
424 +
425 + ```text
426 + frontmatter
427 + ↓
428 + custom detector
429 + ↓
430 + ファイル名
431 + ↓
432 + defaultLang
433 + ```
434 +
435 + の優先順位で判定されます。
436 +
437 + 翻訳関係は `translation` で明示し、実際に存在する翻訳だけを利用します。存在しない翻訳を Riebeckite が自動生成することはありません。
438 +
439 + 詳しい Option や Public API は、`@riebeckite/plugin-l10n` の Package README と [Plugin API](../reference/plugin-api.ja.md) を参照してください。
440 +