使用 SvelteKit 和 Directus 实现国际化
开始之前
你需要:
- Node.js v20.11.1 或更高版本。
- 电脑上的代码编辑器。
- 一个 Directus 项目 - 如果你还没有,请按照我们的快速入门指南进行操作。 对 React 和 Svelte 有一定了解。
本教程的代码可在该 GitHub 仓库中获取。
安装 SvelteKit 并设置新项目
首先设置一个新的 Svelte 项目,并安装包括 Directus SDK 在内的所需依赖项:
npm create svelte@latest frontend # Select the Skeleton project
cd directus-i18n-app
npm install
npm install @directus/sdk
在 src/libs 目录中,创建一个 directus.js 文件以创建并导出 Directus SDK 实例:
import { createDirectus, rest } from '@directus/sdk';
import { PUBLIC_DIRECTUS_API_URL } from '$env/static/public';
function getDirectusInstance(fetch) {
const options = fetch ? { globals: { fetch } } : {};
const directus = createDirectus(PUBLIC_DIRECTUS_API_URL).with(rest());
return directus;
}
export default getDirectusInstance;
然后在项目的根目录中创建一个 .env
文件,并添加您的 Directus API URL:
PUBLIC_DIRECTUS_API_URL='https://directus.example.com';
设计数据模型
在 Directus 数据工作室中,导航到设置 -> 数据模型,并创建一个名为 news
的新集合:
slug
(主键字段,类型:手动输入字符串)author
(类型: 字符串, 接口: 输入)cover
(类型:图像)
创建一个名为 languages
的集合:
code
(主键字段,类型:手动输入字符串)name
(类型: 字符串, 接口: 输入)direction
(类型:字符串,界面:下拉菜单,选项: ltr 和 rtl 。默认值: ltr )
direction
字段启用对从右到左阅读的语言的支持。
要在您的 news
集合中启用内容翻译,请使用翻译界面创建一个 translations
字段。选择 name
作为语言指示字段, direction
作为语言方向字段,并将 en-US
设置为默认语言。
保存后,将为您创建一个名为 news_translations
的新集合。在 news_translations
集合中,您将添加需要翻译的字段。
将以下字段添加到 news_translations
集合中:
title
(类型: 字符串, 接口: 输入)body
(类型: 文本, 界面: 所见即所得)
将您希望支持的每种语言作为项目添加到 languages
集合中。
news
系列的项目页面现在包含一个翻译界面。
允许公共角色在访问控制设置中读取 news
、 languages
和 news_translations
集合,以确保前端可以访问这些集合。
使用 SvelteKit 构建新闻应用前端
在您的 Svelte 项目中,更新您的 +page.js
文件以使用 SDK 获取内容:
import getDirectusInstance from "$lib/directus";
import { readItems } from "@directus/sdk";
export async function load({ fetch }) {
const directus = getDirectusInstance(fetch);
return {
global: await directus.request(readItems("global")),
news: await directus.request(readItems("news", {
deep: {
translations: {
_filter: {
_and: [
{
languages_code: { _eq: "en-US" },
},
],
},
},
},
fields: ["*", { translations: ["*"] }],
})
),
};
}
上述代码片段将使用:
readItems
函数用于获取新闻集合中的所有内容。deep
参数用于过滤相关集合,仅显示 en-US(美国英语)的翻译。
更新 src
目录中 +page.svelte
文件的代码以渲染新闻:
<script>
export let data;
</script>
<h1>Trending Today!</h1>
<ul>
{#each data.news as article}
<li>
<div>
<h2>
<a href={`/${article.id}`}>
{article.translations[0].title}
</a>
</h2>
<p>By {article.author}</p>
</div>
</li>
{/each}
</ul>
上述代码将:
- 遍历
+page.js
文件中返回的新闻数组以显示内容。 - 为每个新闻列表附加一个指向新闻详情页的链接。
在 routes 目录中创建一个 news/+page.js
文件,用于渲染单个新闻内容的路线:
import { readItem } from "@directus/sdk";
import getDirectusInstance from "$lib/directus";
import { error } from "@sveltejs/kit";
/** @type {import('./$types').PageLoad} */
export async function load({ fetch, params, url }) {
const directus = getDirectusInstance(fetch);
const slug = params.slug;
try {
const [newsData, languagesData] = await Promise.all([
directus.request(
readItem("news", slug, {
fields: ["*", { "*": ["*"] }],
})
),
directus.request(readItems("languages")),
]);
return {
article: newsData ? newsData : null,
languages: languagesData,
};
} catch (err) {
error(404, "Post not found");
}
}
上述代码将:
- 使用
readItem
函数查找并获取新闻集合中与主键字段(slug)匹配的新闻。 - 从
languages
集合中获取所有可用语言。
在 routes/news
目录中创建一个 +page.svelte
文件,并添加以下代码:
<script>
export let data;
$: ({ article, languages } = data);
</script>
{#if article}
<h1>{article.translations[0].title}</h1>
{@html article.translations[0].body}
<select>
{#each languages as language}
<option value={language.code}>{language.name}</option>
{/each}
</select>
{:else}
<p>News not found.</p>
{/if}
上述代码将:
- 获取从
news/+page.js
文件返回的语言和选定的新闻文章数据并进行渲染。 - 在选择字段中渲染语言,以便用户可以选择他们需要将内容翻译成的语言。
- 使用
@html
装饰器以正确渲染 WYSIWYGbody
字段内容。
添加多语言导航和搜索
更新您的项目以添加多语言导航和搜索功能。更新 routes/news/+page.svelte
文件中的代码,以添加处理程序,根据所选语言动态渲染文章翻译。
<script>
import { goto } from '$app/navigation';
export let data;
$: ({ article, languages, languageCode } = data);
let selectedLanguageCode = languageCode;
function handleLanguageChange(event) {
const newLanguageCode = event.target.value;
selectedLanguageCode = newLanguageCode; // Update the selectedLanguageCode
goto(`?lang=${newLanguageCode}`, { replaceState: true });
}
</script>
{#if article}
<h1>{article.translations[0].title}</h1>
{@html article.translations[0].body}
<select value={selectedLanguageCode} on:change={handleLanguageChange}>
{#each languages as language}
{console.log(language)}
<option value={language.code}>{language.name}</option>
{/each}
</select>
{:else}
<p>News not found.</p>
{/if}
然后,更新您的 routes/news/+page.js
文件中的代码,通过添加一个新的 URL 参数来允许用户动态选择所需的新闻翻译语言,并使用该参数来过滤新闻翻译。
import { readItem } from "@directus/sdk";
import getDirectusInstance from "$lib/directus";
import { error } from "@sveltejs/kit";
/** @type {import('./$types').PageLoad} */
export async function load({ fetch, params, url }) {
const directus = getDirectusInstance(fetch);
const slug = params.slug;
const languageCode = url.searchParams.get("lang") || "en-US";
try {
const [newsData, languagesData] = await Promise.all([
directus.request(
readItem("news", slug, {
deep: {
translations: {
_filter: {
_and: [
{ languages_code: { _eq: languageCode } },
],
},
},
},
fields: ["*", { "*": ["*"] }],
})
),
directus.request(readItems("languages")),
]);
return {
article: newsData ? newsData : null,
languages: languagesData,
languageCode,
};
} catch (err) {
error(404, "Post not found");
}
}
现在您可以将新闻翻译成英语、德语和法语。
将以下代码片段替换您 routes/+page.svelte
文件中的代码,以添加搜索功能:
<script>
import { goto } from "$app/navigation";
import { page } from "$app/stores";
export let data;
let searchQuery = $page.url.searchParams.get("q") || "";
function handleSearchChange() {
goto(`/?q=${searchQuery}`, { replaceState: true });
}
</script>
<h1>Trending Today!</h1>
<div>
<input type="text" bind:value={searchQuery} placeholder="Search News..." />
<button on:click={handleSearchChange}>Search</button>
</div>
<ul>
{#each data.news as article}
<li>
<div>
<h2>
<a href={`/${article.id}`}>
{article.translations[0].title}
</a>
</h2>
<p>By {article.author}</p>
</div>
</li>
{/each}
</ul>
上述代码将:
- 定义变量
searchQuery
以存储用户的搜索输入。 - 使用当前 URL
($page.url.searchParams.get("q"))
中 q 查询参数的值初始化searchQuery
变量。如果q
参数不存在,则默认为空字符串。 - 使用
handleSearchChange
通过$app/navigation
中的goto
函数,用当前的searchQuery
值更新 URL。replaceState: true
选项将替换当前的历史记录条目,而不是创建新的条目。 - 渲染一个输入框和一个按钮,允许用户输入搜索查询并触发搜索。
- 显示搜索到的新闻,若未进行搜索则显示所有新闻。
摘要
在本教程中,您学习了如何使用 SvelteKit 和 Directus 构建一个多语言新闻应用程序。您已经设置了一个 SvelteKit 项目,创建了一个 Directus 包装器,并使用它来查询数据。我们通过 Directus 灵活的 CMS 创建了翻译集合,并使用翻译界面将新闻文章内容翻译成不同的语言。