Site search / サイト内検索

必要な情報を探す

ページ内の言葉を探す検索と、意味が近い内容を探す検索を使い分けられます。

「検索する」を実行すると、入力した検索語をOpenAI APIへ送り数値表現に変換し、その数値表現をCloudflare Vectorizeで当サイトの公開情報と照合します。あわせて、Acecore共通検索API(acecore.net)へ送信し、 Acecore関連サイトの公開情報を下部に表示することがあります。個人情報や機密情報は入力しないでください。個人情報の取り扱い

Insights / 技術解説

Sveltia CMSで多言語ブログを運用する方法

Sveltia CMSで日本語記事を更新し、GitHub ActionsとGitHub Copilotで翻訳PRを作る運用を、UI翻訳との違い、検索エンジン上のメリット、hreflang、RSS、sitemap、レビュー観点まで含めて整理します。

  • 技術
  • GitHub Copilot
  • i18n
  • CMS
  • SEO
Sveltia CMSで多言語ブログを運用する方法
この記事の目次
  1. 結論
  2. UI翻訳で十分な場面
  3. UI翻訳だけでは弱い場面
  4. 検索エンジン上のメリット
  5. 1. 言語別URLを直接クロールできる
  6. 2. titleとdescriptionを各言語で最適化できる
  7. 3. hreflangで言語版の対応関係を伝えられる
  8. 4. sitemapとRSSに言語別ページを載せられる
  9. 5. 内部リンクを言語別に保てる
  10. Sveltia CMSはどこを担当するか
  11. 翻訳はGitHubのPRに分離する
  12. commit subjectをワークフロー契約にする
  13. 翻訳PRに渡すルール
  14. PR body markerで重複を防ぐ
  15. AI翻訳で気をつけること
  16. 実装で踏みやすい落とし穴
  17. 1. CMS名の古い表記が記事に残る
  18. 2. 公開日を更新しないとブログトップに出ない
  19. 3. 翻訳記事のslugを変えない
  20. 4. 言語別URLに戻さない内部リンク
  21. 5. sitemapとRSSだけを見て安心しない
  22. 最小構成
  23. 参考リンク
  24. まとめ

問い合わせAI、Sveltia CMS、サービスCTAの導線まで整えてくると、次に効いてくるのが 多言語ブログの運用 です。

このサイトは日本語を中心に運用していますが、ブログや固定ページは9言語で公開しています。ここで大事なのは、「画面上で翻訳できること」と「検索エンジンに各言語ページとして渡せること」は別物だという点です。

Chromeの翻訳、ブラウザ拡張、翻訳ウィジェットは、読者が目の前のページを読むには便利です。しかし、それだけでは en, zh-cn, es, pt, fr, ko, de, ru のURL、メタ情報、RSS、sitemap、内部リンクが生まれるわけではありません。

この記事では、Sveltia CMSで日本語記事だけを更新し、GitHub ActionsとGitHub Copilotで翻訳PRを作る運用を、検索エンジン上のメリットも含めて整理します。

結論

多言語ブログを検索流入まで見据えて運用するなら、翻訳を「UIの表示処理」ではなく、公開前のコンテンツ生成処理 として扱うほうが強いです。

このサイトでは次の構成にしています。

  • 日本語記事: src/content/blog/{slug}.md
  • 翻訳記事: src/content/blog/{locale}/{slug}.md
  • 表示URL: /blog/{slug}/, /en/blog/{slug}/, /zh-cn/blog/{slug}/ など
  • 翻訳元: 日本語Markdown
  • 翻訳作業: GitHub CopilotのPR
  • 公開判断: buildとレビューを通ったPRだけmainへ入れる

Sveltia CMSは、ここで 日本語sourceを編集する入口 として使います。翻訳そのものはCMS画面で各言語を直接触るのではなく、GitHub側のPR運用に分離します。

UI翻訳で十分な場面

まず、UI翻訳が悪いわけではありません。

次のような用途なら、ブラウザ翻訳や翻訳ウィジェットで十分なこともあります。

  • 社内向けの一時的な閲覧
  • 既存ページを海外ユーザーがざっと読む
  • 管理画面やヘルプを読むための補助
  • SEO流入を狙わないページ
  • 翻訳品質を運用対象にしないページ

この場合、翻訳は「読者の環境で起きる表示上の変換」です。サイト運営側は翻訳結果をファイルとして持ちません。

だから管理は軽いです。一方で、公開物としての言語別ページは残りません。

UI翻訳だけでは弱い場面

ブログやサービス紹介のように検索流入を狙うページでは、UI翻訳だけでは足りないことがあります。

理由は単純で、検索エンジンやSNSが見る単位は基本的に URLとHTML だからです。

たとえば日本語ページ /blog/copilot-translation-pipeline/ だけが存在していて、英語はブラウザ側で翻訳される構成だとします。この場合、検索結果に出るURL、title、description、構造化データ、RSS、sitemapは日本語ページのものになります。

読者は英語で読めるかもしれません。しかし、検索エンジンに対して「これは英語版の記事です」と安定して渡せる状態ではありません。

静的な多言語ページを生成すると、ここが変わります。

/blog/copilot-translation-pipeline/
/en/blog/copilot-translation-pipeline/
/zh-cn/blog/copilot-translation-pipeline/
/es/blog/copilot-translation-pipeline/
/pt/blog/copilot-translation-pipeline/
/fr/blog/copilot-translation-pipeline/
/ko/blog/copilot-translation-pipeline/
/de/blog/copilot-translation-pipeline/
/ru/blog/copilot-translation-pipeline/

このようにURLが分かれていると、各ページに言語別の title, description, og:title, og:description, JSON-LD, 内部リンクを持たせられます。

検索エンジン上のメリット

多言語ページを静的に生成する一番のメリットは、検索エンジンに渡す情報が明確になることです。

1. 言語別URLを直接クロールできる

GoogleはJavaScriptも処理しますが、Google Search CentralではJavaScriptには制約があり、静的レンダリングやサーバーサイドレンダリングが安定した選択肢として示されています。

また、Google以外のクローラーやSNSのプレビュー、RSSリーダー、サイト内検索まで考えると、最初からHTMLに翻訳済み本文が入っているほうが扱いやすいです。

UI翻訳ではなく、/en/blog/.../ のようなURLに英語HTMLを置くと、そのURL自体がクロール対象になります。

2. titleとdescriptionを各言語で最適化できる

検索結果で見えるのは本文だけではありません。titledescription も重要です。

UI翻訳だけの場合、元HTMLのメタ情報は日本語のままになりがちです。英語ユーザーに見せたい検索結果なのに、検索結果のタイトルや説明が日本語に寄る可能性があります。

翻訳ファイルを持つ構成なら、frontmatter自体を翻訳できます。

title: "How to Run a Multilingual Blog with Sveltia CMS"
description: "A practical workflow for publishing Japanese source articles through Sveltia CMS and generating localized static pages with GitHub Copilot."

この差は、検索結果だけでなく、SNS共有、OGP画像、サイト内関連記事にも効きます。

3. hreflangで言語版の対応関係を伝えられる

Googleは、言語や地域ごとにURLが分かれている場合、hreflang で各ページの対応関係を伝えることを推奨しています。

このサイトでは、BaseLayout.astro と sitemap で各ロケールのURLを出力しています。

<link
  rel="alternate"
  hreflang="en"
  href="https://acecore.net/en/blog/copilot-translation-pipeline/"
/>
<link
  rel="alternate"
  hreflang="ja"
  href="https://acecore.net/blog/copilot-translation-pipeline/"
/>

UI翻訳だけでは、対応する英語URLそのものがありません。つまり、hreflangの対象にしにくいです。

4. sitemapとRSSに言語別ページを載せられる

多言語記事を静的ファイルとして持つと、sitemapやRSSにも言語別のURLを出せます。

  • /rss.xml
  • /en/rss.xml
  • /zh-cn/rss.xml
  • /es/rss.xml
  • /pt/rss.xml
  • /fr/rss.xml
  • /ko/rss.xml
  • /de/rss.xml
  • /ru/rss.xml

RSSリーダーや外部サービスに対しても、各言語のフィードを出せるようになります。

UI翻訳だけでは、RSSのitemは元言語のままです。フィード経由の読者や検索エンジンに渡る情報も元言語に寄ります。

5. 内部リンクを言語別に保てる

多言語サイトで壊れやすいのが内部リンクです。

英語記事を読んでいるのに関連記事リンクだけ日本語URLへ戻ると、ユーザー体験もクローラーの理解もぶれます。

翻訳ファイルを持つ構成なら、リンク生成を getLocalizedUrl() に寄せたり、Markdown内の内部リンクをlocale別に調整したりできます。

今回のようなブログ運用では、翻訳時に次のルールを固定します。

  • /blog/foo/ は必要に応じて /{locale}/blog/foo/ にする
  • 外部URLは翻訳しない
  • 画像pathは翻訳しない
  • コードブロック内のpathは不用意に変えない
  • tag IDは翻訳せず、表示名だけ翻訳する

Sveltia CMSはどこを担当するか

Sveltia CMSは、翻訳エンジンではありません。この運用では、CMSは日本語sourceを編集するための入口です。

CMS側で扱うのは主に次です。

  • 日本語ブログ記事
  • 著者情報
  • タグ定義
  • 日本語source JSON
  • 画像アップロード
  • 公開日、更新日、関連記事、FAQなどのfrontmatter

CMS導入自体の設計は Sveltia CMS導入ガイド に分けています。この記事では、その後ろにある翻訳PR運用に絞ります。

翻訳はGitHubのPRに分離する

多言語CMSでありがちな失敗は、すべての言語をCMS画面に出してしまうことです。

もちろん、編集者が各言語を直接直す運用ならそれでも構いません。ただ、少人数で日本語を中心に運用するサイトでは、全言語をCMSに出すと入力項目が増えすぎます。

Acecoreでは次の分担にしました。

  • Sveltia CMS: 日本語sourceを安全に更新する
  • GitHub Actions: CMS commitや変更pathを検出する
  • GitHub Copilot: 翻訳PRを作る
  • Pull Request: 翻訳差分をレビューする
  • Astro build: ルート、frontmatter、リンク、構造化データの破綻を検出する

翻訳をPRにすると、レビュー、差分確認、build、rollbackができます。CMS画面で直接8言語を書き換えるより、変更履歴も追いやすくなります。

commit subjectをワークフロー契約にする

翻訳ワークフローは、すべてのMarkdown更新で走らせると扱いづらくなります。

たとえば日付だけを直した、タグだけを直した、内部リンクだけを直した、という変更で毎回8言語分の翻訳PRが出るとノイズになります。

そこで、CMS更新であることをcommit subjectで識別します。

cms: create blog "new-article-slug"
cms: update blog "copilot-translation-pipeline"

このprefixをGitHub Actions側の契約にすると、意図したときだけ翻訳タスクを起こせます。

前回の反省として、commit subjectやpath条件を曖昧にすると「本来走らないはずのワークフローが走ったのでは」と判断しづらくなります。ワークフローの起動条件は記事運用の仕様として明文化したほうが安全です。

翻訳PRに渡すルール

Copilotに翻訳を任せるときは、単に「翻訳して」では足りません。

最低限、次のようなルールを固定します。

Translate the Japanese source article into the target locale.

Keep:

- slug
- image path
- author id
- tag ids
- internal code tokens
- external URLs
- code blocks unless comments are natural language

Localize:

- title
- description
- callout
- FAQ
- link card title and description
- body text
- internal blog URLs when locale-specific URLs exist

重要なのは、翻訳対象と翻訳してはいけない対象を分けることです。

Markdownでは、本文、frontmatter、コードブロック、URL、画像、タグIDが同じファイルに混ざります。ここを曖昧にすると、ビルドは通ってもリンクや分類が壊れます。

PR body markerで重複を防ぐ

翻訳PRは非同期です。GitHub Actions、Copilot task、build、auto-mergeが別々に動きます。

そのため、PR本文にsource pathと対象localeを入れておくと運用しやすくなります。

<!-- translation-source: src/content/blog/copilot-translation-pipeline.md -->
<!-- translation-locales: en,zh-cn,es,pt,fr,ko,de,ru -->

open PRを検索すれば、同じsource pathの翻訳PRが既にあるか確認できます。

AI翻訳で気をつけること

AI翻訳は便利ですが、検索流入を狙うなら「量産できる」だけでは足りません。

Googleのスパムポリシーでも、ユーザー価値を追加しない大量生成は問題になり得ます。AIを使うこと自体より、各言語ページとして読む価値があるか、事実関係やリンクが正しいかが大事です。

レビューでは、次を見ます。

  • タイトルがその言語の検索語として自然か
  • descriptionが日本語直訳で不自然になっていないか
  • サービス名、製品名、固有名詞が崩れていないか
  • 内部リンクが読者のlocaleへ向いているか
  • 画像altが翻訳されているか
  • FAQがその言語の読者にも意味を持つか
  • コードブロックやURLが壊れていないか

AI翻訳は下書きとして優秀です。ただし、公開物にするなら、最後はサイト運用側の責任でレビューします。

実装で踏みやすい落とし穴

今回の一連のPRでも、記事化しておくべき反省点がいくつかありました。

1. CMS名の古い表記が記事に残る

実装はSveltia CMSへ移行しているのに、過去記事には Pages CMS の説明やスクリーンショットが残っていました。

CMSは運用画面なので、記事本文に古い名前が残ると読者が迷います。実装を変えたら、関連する解説記事、内部リンク、画像altも一緒に棚卸しするべきです。

2. 公開日を更新しないとブログトップに出ない

記事を全面更新しても、frontmatterの date が古いままだとブログトップには上がりません。

lastUpdated だけでは「更新日」は伝わりますが、このサイトのブログ一覧は date 降順です。大きく記事を作り直したときは、公開日として扱うのか、既存記事の更新として扱うのかを決める必要があります。

3. 翻訳記事のslugを変えない

翻訳タイトルは変えても、slugは元記事と揃えます。

src/content/blog/copilot-translation-pipeline.md
src/content/blog/en/copilot-translation-pipeline.md
src/content/blog/fr/copilot-translation-pipeline.md

slugが揃っていると、localizePost()getBaseSlug() のような解決処理がシンプルになります。

4. 言語別URLに戻さない内部リンク

翻訳記事の本文で /blog/foo/ のままリンクすると、英語ページから日本語ページへ戻ってしまいます。

このサイトのコンポーネント内リンクは getLocalizedUrl() に寄せていますが、Markdown本文のリンクは翻訳PRで注意が必要です。

5. sitemapとRSSだけを見て安心しない

サイトマップにURLが出ていても、記事本文、canonical、hreflang、JSON-LD、内部リンク、RSSがすべて揃っているとは限りません。

生成HTMLを確認し、最低限 dist/blog/index.html, dist/rss.xml, dist/sitemap-0.xml, dist/{locale}/blog/{slug}/index.html を見ると事故を減らせます。

最小構成

他のAstroサイトで同じ運用を始めるなら、最小構成はこれです。

src/content/blog/
  my-article.md
  en/
    my-article.md
  zh-cn/
    my-article.md
const posts = await getCollection("blog");
const basePosts = posts.filter(isBasePost);
const displayPosts = basePosts.map((post) => localizePost(post, posts, locale));
title: "Sveltia CMSで多言語ブログを運用する方法"
description: "Sveltia CMSとGitHub Copilotで翻訳PRを作る運用メモ"
date: 2026-06-07T17:00
lastUpdated: 2026-06-07T00:00
author: gui
tags: ["技術", "GitHub Copilot", "i18n", "CMS", "SEO"]

この状態に、Sveltia CMS、GitHub Actions、Copilot task作成、build確認を順に足していけばよいです。

最初から全部を自動化しなくても構いません。重要なのは、日本語sourceと翻訳ファイルの関係を壊さないことです。

参考リンク

まとめ

UI上の翻訳は、読者がその場で読むための便利な補助です。

一方で、多言語ブログを検索流入や継続運用まで含めて考えるなら、翻訳を静的コンテンツとして生成し、言語別URL、メタ情報、内部リンク、RSS、sitemap、hreflangまで揃えるほうが強いです。

Sveltia CMSは日本語sourceを安全に更新する入口として使い、翻訳はGitHub CopilotのPRに分離する。

この分担にすると、編集画面は軽く保てます。翻訳差分はレビューできます。検索エンジンには各言語のHTMLを渡せます。

多言語運用で大事なのは、翻訳そのものよりも、翻訳をサイト構造の中でどう扱うか です。

Translation Workflow

Sveltia CMSから翻訳PRまでの流れ

日本語をsource of truthにして、翻訳はGitHub側のPR運用に分離します。

  1. 日本語だけ編集

    Sveltia CMSまたはMarkdownで `src/content/blog/{slug}.md` を更新する。

  2. CMS commitを検出

    `cms:` prefixや変更pathをGitHub Actions側の契約にする。

  3. 翻訳PRを作成

    Copilotにsource path、locale、翻訳ルールを渡して翻訳ファイルを生成させる。

  4. build後に反映

    Astro build、Pagefind、リンク確認を通したPRだけをmainへ入れる。

UI上の翻訳と、言語別ページを生成する翻訳運用の違い

UI翻訳

  • ユーザーのブラウザや翻訳ウィジェットが表示時に訳す
  • URL、title、description、OGPは元言語のままになりやすい
  • sitemap、RSS、hreflangに言語別ページとして出しにくい
  • 共有URLや検索結果の表示文言が元言語に寄る

静的な多言語ページ

  • `/{locale}/blog/{slug}/` のように言語別URLを公開できる
  • title、description、本文、FAQ、構造化データを言語別に持てる
  • hreflangで各言語版の対応関係を検索エンジンへ伝えられる
  • RSS、sitemap、内部リンク、Search Console確認を言語別に扱える

導入時に決めること

  • 日本語記事を翻訳元として扱う
  • 翻訳ファイルのslugを日本語記事と一致させる
  • `cms:` commitなど、翻訳ワークフローの起動条件を固定する
  • URL、画像path、コードブロック、タグIDを翻訳で壊さない
  • hreflang、canonical、RSS、sitemapの出力をbuildで確認する

よくある質問

UI上の翻訳だけではだめですか?

ユーザーが読むだけなら役に立ちます。ただし検索エンジンやSNS共有に対して、言語別URL、title、description、構造化データ、内部リンクを安定して渡したい場合は、翻訳済みページを静的HTMLとして持つほうが扱いやすいです。

AI翻訳した記事は検索上不利ですか?

AIを使うこと自体より、ユーザー価値のない大量生成になっていないかが重要です。用語、リンク、事実関係、現地語としての自然さをレビューし、各言語ページとして読む価値を持たせる運用にします。

翻訳ページは重複コンテンツになりませんか?

Googleは、主本文が翻訳されているローカライズページを単なる重複とは扱いません。各言語版を同じslugで対応させ、hreflangやsitemapで関係を示すのが基本です。