1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SvelteKitでi18nを頑張っていたら言語切り替えにつまづいてどうにか解消した話

Last updated at Posted at 2025-01-21

この記事の概要

練習がてら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関数を定義していました。

+page.ts
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],
  };
}

それを、各ページにてこのようなイメージで使っていました。

+page.svelte
<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.svelte
<header>
  <div>
    <a href="/">TOP</a>
    <a href="/en">English</a>
    <a href="/ja">日本語</a>
  </div>
</header>

/en/ja自体は固定なのだから、それぞれのリンクをクリックすれば英語版トップ、日本語版トップへ飛ぶだろうと踏んでいましたが、上手くいきませんでした。

URLは目的のものに変わるのですが、画面に描画されている内容が変わらない、という状態でした。

解消した方法

data$derivedで囲うのみでした。

+page.svelte
 <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.svelte
 <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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?