この記事の概要
練習がてらSvelteKitでサイトを作っていて、練習なので外部ライブラリに頼らずi18n対応をしてみていました。
その際、ヘッダーのリンクから日本語のパス、英語のパスへそれぞれ飛べるようにしようとしたらつまづきました。
正しいアプローチなのか分からないのですが、ひとまず解消できた方法を記事にします。
そもそものSvelteKitの扱い、i18nの実装方法、回避した方法、どれもあまり正しさに自信がありません。備忘録の側面が強いので、鵜呑みにはしないでください。間違いがあれば指摘いただけると助かります。
追記:ちゃんとした方法を教えていただきましたので、そちらの内容で記事を更新しました。
環境
依存関係 | バージョン |
---|---|
svelte | 5.1.13 |
@sveltejs/kit | 2.8.0 |
やっていたこと
今回の話に関係のある部分でいうと、このようなディレクトリ構造のプロジェクトです。
.
├── src
│ ├── lib
│ │ └── components
│ │ └── Header.svelte
│ └── routes
│ ├── +page.server.ts
│ └── [lang]
│ ├── +layout.svelte
│ ├── +layout.ts
│ ├── +page.svelte
│ ├── +page.ts
│ ├── foo
│ │ ├── +page.svelte
│ │ └── +page.ts
. .
. .
. .
+page.ts
では以下のようなイメージで、それぞれの言語とload
関数を定義していました。
const i18nText = {
en: {
title: "English title"
description: "English description",
},
ja: {
title: "日本語のタイトル"
description: "日本語の説明文",
},
};
export function load({ params }: { params: { lang: "en" | "ja" } }) {
return {
lang: params.lang,
i18nText: i18nText[params.lang],
};
}
それを、各ページにてこのようなイメージで使っていました。
<script lang="ts">
let { data } = $props();
const { i18nText } = data;
</script>
<h1>{i18nText.title}</h1>
<p>{i18nText.description}</p>
というわけで、このサイトでは次のようなURLでアクセスできるわけです。
ページ種別 | 英語版URL | 日本語版URL |
---|---|---|
トップページ | example.com/en |
example.com/ja |
/foo のページ |
example.com/en/foo |
example.com/ja/foo |
ここで、全ページ共通で使うコンポーネントに以下のようにリンクを設定していました。
(全体的なコードは簡略化してあります)
<header>
<div>
<a href="/">TOP</a>
<a href="/en">English</a>
<a href="/ja">日本語</a>
</div>
</header>
/en
と/ja
自体は固定なのだから、それぞれのリンクをクリックすれば英語版トップ、日本語版トップへ飛ぶだろうと踏んでいましたが、上手くいきませんでした。
URLは目的のものに変わるのですが、画面に描画されている内容が変わらない、という状態でした。
解消した方法
data
を$derived
で囲うのみでした。
<script lang="ts">
let { data } = $props();
- const { i18nText } = data;
+ const { i18nText } = $derived(data);
</script>
<h1>{i18nText.title}</h1>
<p>{i18nText.description}</p>
当初、$derived
関連は以下のようにだけ理解していました。
- リアクティブな変数を
$state
で宣言する -
$state
で宣言した変数から派生するものは$derived
で宣言する
しかし今回の多言語用テキストも$derived
での派生の対象だったようで、囲ってあげれば無事に動きました。
↓ちゃんとしたやり方教えていただいた様子
旧:解消した方法
当初はこちらの方法で対応していましたが、いいやり方ではないです。一応ログとしてだけ残してありますが、上の方法を参考にしてください。
詳細
リンクのそれぞれにdata-sveltekit-reload
をつけました。
<header>
<div>
<a href="/">TOP</a>
<div>
- <a href="/en">English</a>
- <a href="/ja">日本語</a>
+ <a href="/en" data-sveltekit-reload>English</a>
+ <a href="/ja" data-sveltekit-reload>日本語</a>
</div>
</div>
</header>
ブラウザのdevtoolsのnetworkを見ると分かるように、通常SvelteKitのアプリケーション内で移動しても、ページ自体の読み込みはなされません。
しかしdata-sveltekit-reload
をつけると、完全な読み込み(?)が発生します。
https://svelte.dev/docs/kit/link-options#data-sveltekit-reload