国際化 (i18n)
EmDashはAstroの組み込みi18nルーティングと統合し、多言語コンテンツ管理を提供します。AstroがURLルーティングと言語検出を処理し、EmDashが翻訳コンテンツの保存と取得を処理します。
各翻訳は完全で独立したコンテンツエントリであり、独自のスラッグ、ステータス、改訂履歴を持ちます。投稿のフランス語版は下書きのままにし、英語版を公開することができます。
Astro設定にi18nブロックを追加してi18nを有効にします。EmDashはこの設定を自動的に読み取ります — EmDash内で別途ロケール設定を行う必要はありません。
import { defineConfig } from "astro/config";import emdash, { local } from "emdash/astro";import { sqlite } from "emdash/db";
export default defineConfig({ i18n: { defaultLocale: "en", locales: ["en", "fr", "es"], fallback: { fr: "en", es: "en" }, }, integrations: [ emdash({ database: sqlite({ url: "file:./data.db" }), storage: local({ directory: "./uploads", baseUrl: "/_emdash/api/media/file", }), }), ],});Astro設定にi18nが存在しない場合、すべてのi18n機能は無効になり、EmDashは単一言語CMSとして動作します。
翻訳の仕組み
Section titled “翻訳の仕組み”EmDashはロケールごとの行モデルを使用します。各翻訳はデータベース内で独自のID、スラッグ、ステータスを持つ行であり、共有のtranslation_group識別子を介して他の翻訳とリンクされます。
ec_posts:id | slug | locale | translation_group | status---------|-------------|--------|-------------------|----------01ABC... | my-post | en | 01ABC... | published01DEF... | mon-article | fr | 01ABC... | draft01GHI... | mi-entrada | es | 01ABC... | publishedこの設計は以下を意味します:
- ロケールごとのスラッグ —
/blog/my-postと/fr/blog/mon-articleが自然に機能 - ロケールごとの公開 — 英語版を公開しながらフランス語版を下書きのまま保持
- ロケールごとの改訂 — 各翻訳が独自の改訂履歴を持つ
- クロスロケールクエリの複雑さなし — リストクエリは単一ロケールのエントリのみを返す
翻訳コンテンツのクエリ
Section titled “翻訳コンテンツのクエリ”単一エントリ
Section titled “単一エントリ”特定の翻訳を取得するには、getEmDashEntryにlocaleを渡します。省略された場合、リクエストの現在のロケール(Astroのi18nミドルウェアによって設定)がデフォルトになります。
astro title="src/pages/[...slug].astro"---import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;const { entry: post, error } = await getEmDashEntry("posts", slug, { locale: Astro.currentLocale,});
if (!post) return Astro.redirect("/404");---
<article> <h1>{post.data.title}</h1></article>フォールバックチェーン
Section titled “フォールバックチェーン”リクエストされたロケールのコンテンツが存在しない場合、EmDashはAstro設定で定義されたフォールバックチェーンに従います。fallback: { fr: "en" }が与えられた場合:
- リクエストされたロケールを試す(
fr) - フォールバックロケールを試す(
en) - デフォルトロケールを試す
フォールバックは単一エントリクエリにのみ適用されます。リストクエリはリクエストされたロケールのエントリのみを返します — クロスロケールの混合はありません。
コレクションリスト
Section titled “コレクションリスト”ロケールでコレクションをフィルタリング:
astro title="src/pages/posts.astro"---import { getEmDashCollection } from "emdash";
const { entries: posts } = await getEmDashCollection("posts", { locale: Astro.currentLocale, status: "published",});---
<ul> {posts.map((post) => ( <li><a href={`/${post.data.slug}`}>{post.data.title}</a></li> ))}</ul>言語切り替え
Section titled “言語切り替え”getTranslationsを使用して、現在のエントリの既存の翻訳にリンクする言語切り替えを構築:
astro title="src/components/LanguageSwitcher.astro"---import { getTranslations } from "emdash";import { getRelativeLocaleUrl } from "astro:i18n";
interface Props { collection: string; entryId: string;}
const { collection, entryId } = Astro.props;const { translations } = await getTranslations(collection, entryId);---
<nav aria-label="Language"> <ul> {translations.map((t) => ( <li> <a href={getRelativeLocaleUrl(t.locale, `/blog/${t.slug}`)} aria-current={t.locale === Astro.currentLocale ? "page" : undefined} > {t.locale.toUpperCase()} </a> </li> ))} </ul></nav>getTranslations関数は同じ翻訳グループ内のすべてのロケールバリアントを返します:
const { translationGroup, translations } = await getTranslations("posts", post.entry.id);// translations: [// { locale: "en", id: "01ABC...", slug: "my-post", status: "published" },// { locale: "fr", id: "01DEF...", slug: "mon-article", status: "draft" },// ]管理パネルでの翻訳管理
Section titled “管理パネルでの翻訳管理”コンテンツリスト
Section titled “コンテンツリスト”i18nが有効な場合、コンテンツリストは以下を表示します:
- 各エントリのロケールを表示するロケール列
- ロケール間を切り替えるツールバーのロケールフィルター
エディタで任意のコンテンツエントリを開きます。サイドバーには、設定されたすべてのロケールをリストする翻訳パネルが表示されます。各ロケールについて:
- 翻訳がないロケールには**「翻訳」**が表示 — クリックして作成
- 既存の翻訳があるロケールには**「編集」**が表示 — クリックして移動
- 現在のロケールはチェックマークでマーク
翻訳を作成する際、新しいエントリはソースロケールのデータで事前入力され、デフォルトスラッグ{source-slug}-{locale}が割り当てられます。必要に応じてスラッグとコンテンツを調整し、保存します。
ロケールごとの公開
Section titled “ロケールごとの公開”各翻訳は独自のステータスを持ちます。翻訳を独立して公開、非公開、またはスケジュールできます。フランス語版は下書きのままにし、英語版をライブにすることができます。
コンテンツAPI
Section titled “コンテンツAPI”ロケールパラメータ
Section titled “ロケールパラメータ”すべてのコンテンツAPIルートはオプションのlocaleクエリパラメータを受け入れます:
GET /_emdash/api/content/posts?locale=frGET /_emdash/api/content/posts/my-post?locale=fr省略された場合、設定されたデフォルトロケールがデフォルトになります。
API経由での翻訳作成
Section titled “API経由での翻訳作成”コンテンツ作成エンドポイントにlocaleとtranslationOfを渡して翻訳を作成:
POST /_emdash/api/content/postsContent-Type: application/json
{ "locale": "fr", "translationOf": "01ABC...", "data": { "title": "Mon Article", "slug": "mon-article" }}新しいエントリはソースエントリのtranslation_groupを共有し、下書きとして開始します。
翻訳のリスト
Section titled “翻訳のリスト”特定のエントリのすべての翻訳を取得:
GET /_emdash/api/content/posts/01ABC.../translations翻訳グループIDと、ID、スラッグ、ステータスを含むロケールバリアントの配列を返します。
CLIはコンテンツコマンドで--localeフラグをサポート:
# List French postsemdash content list posts --locale fr
# フランス語の特定のエントリを取得emdash content get posts my-post --locale fr
# 既存エントリのフランス語翻訳を作成emdash content create posts --locale fr --translation-of 01ABC...多言語コンテンツのシーディング
Section titled “多言語コンテンツのシーディング”シードファイルはlocaleとtranslationOfを使用して翻訳を表現:
json title=".emdash/seed.json"{ "content": { "posts": [ { "id": "welcome", "slug": "welcome", "locale": "en", "status": "published", "data": { "title": "ようこそ" } }, { "id": "welcome-fr", "slug": "bienvenue", "locale": "fr", "translationOf": "welcome", "status": "draft", "data": { "title": "Bienvenue" } } ] }}ソースロケールエントリは、translationOf参照が正しく解決されるように、シードファイル内でその翻訳よりも前に表示される必要があります。
フィールドの翻訳可能性
Section titled “フィールドの翻訳可能性”各フィールドにはtranslatable設定(デフォルト:true)があります。翻訳を作成する際:
- 翻訳可能フィールドは編集のためにソースロケールから事前入力
- 翻訳不可能フィールドはコピーされ、グループ内のすべての翻訳間で同期保持
status、published_at、author_idなどのシステムフィールドは常にロケールごとであり、同期されることはありません。
EmDashはロケールURLを管理しません — ルーティングはAstroが処理します。一般的なパターン:
# prefix-other-locales (Astro default)/blog/my-post → en (default locale, no prefix)/fr/blog/mon-article → fr
# prefix-always/en/blog/my-post → en/fr/blog/mon-article → frルーティングモードに関わらず正しいURLを構築するには、astro:i18nのgetRelativeLocaleUrlを使用してください。
多言語コンテンツのインポート
Section titled “多言語コンテンツのインポート”WPMLまたはPolylangを使用したWordPress
Section titled “WPMLまたはPolylangを使用したWordPress”WordPressプラグインのインポートソースは、WPMLとPolylangを自動的に検出します。検出されると、インポートされたコンテンツにはロケールと翻訳グループのメタデータが含まれ、多言語構造が保持されます。
WXRファイル
Section titled “WXRファイル”WXRエクスポートにはWPML/Polylangメタデータは含まれません。単一ロケールとしてインポートし手動で翻訳を作成するか、--localeフラグを使用してすべてのインポート項目にロケールを割り当てます:
# Import a French WXR exportemdash import wordpress export-fr.xml --execute --locale fr
# 既存の英語コンテンツをスラッグで照合emdash import wordpress export-fr.xml --execute --locale fr --translation-of-locale en次のステップ
Section titled “次のステップ”- コンテンツのクエリ — 完全なクエリAPIリファレンス
- コンテンツの操作 — 管理者用コンテンツ管理
- Astro i18nルーティング — Astroのルーティング設定