如何使用 Astro Js 与 Decap CMS 和 astro-i18next 为集合创建多语言路由?

问题描述 投票:0回答:1

我正在制作一个多语言(EN、ES)网站,其中包含一个 Astro js 博客,使用 Decap CMS 来发布博客文章,使用 astro-i18next 来实现其国际化功能。

我在找出如何使其正常工作时遇到问题。

此 astro 网站设置为 EN 作为默认语言,ES 作为辅助语言。这是页面结构:

pages/ ─── index 
             ├── about-us 
             └── es/ ─── index 
                      └─ about-us 

感谢 astro-i18next 配置,例如,我可以将西班牙语路由到 website.com/es/quien-somos。

现在,我已经设置了 Decap CMS 来创建多语言博客文章。但是当我通过管理面板创建新帖子时,它会在每种语言以及默认语言的文件夹中创建 md 文件:

content/blog/─── en/ ─── first-post.md 
              └─ es/ ─── first-post.md 

这是我的第一个问题,因为英文博客页面的网址是website.com/blog,但英文博客文章的网址是website/blog/en/first-post。 西班牙语版本也是如此:博客页面的网址是 website.com/es/blog,但西班牙语博客文章的网址是 website/blog/es/first-post。最重要的是,蛞蝓是英语而不是西班牙语。

有人可以给我一些关于如何以正确的方式路由的提示吗?我的意思是,不是通过一些动态路由魔法硬编码在 i18next 配置文件中。就是这样:

  • 英文博客文章的网址是website/blog/first-post
  • 西班牙语博客文章的网址是 website/es/blog/primera-entrada

谢谢!

javascript routes astrojs decap-cms
1个回答
0
投票

最后我可以通过路由来解决。主要思想是根据帖子标题(每种语言)设置帖子路线。

实用程序片段

首先,在 utils.ts 中,我从 https://www.30secondsofcode.org/js/s/string-to-slug/

复制了一个小片段
export const slugify = (str: string) =>
    str
        .toLowerCase()
        .trim()
        .replace(/[^\w\s-]/g, '')
        .replace(/[\s_-]+/g, '-')
        .replace(/^-+|-+$/g, '');

我将长期使用这个。

发布索引页

接下来,对于

pages/blog/index.astro
,我会过滤所需语言的所有帖子,并根据 slugified 帖子标题创建帖子 url。因为 Decap CMS 使用相同的文件名保存每个帖子,但按语言保存在文件夹中,所以它为我提供了一种轻松过滤它们的方法。

---
// get posts and filter them for targeted language and sort them
const lang = i18next.language;
const posts = (
    await getCollection('blog', ({ id }) => {
        return id.startsWith(lang);
    })
).sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---
<h1>Blog Index</h1>
{
   posts.map(post => (
      <a href={localizePath(`/blog/${slugify(post.data.title)}/`)}>{post.data.title}</a>
   ))
}

单个帖子页面(带有动态路由)

然后,我为单个帖子创建文件

pages/blog/[...title].astro
。该文件还控制这些单个帖子的动态路由。

export async function getStaticPaths() {
    const posts = await getCollection('blog');
    return posts.map((post) => ({
        params: { title: slugify(post.data.title) },
        props: post
    }));
}

导航栏

因为我无法将 i18next 配置文件用于我的帖子路由,所以我必须创建一个额外的函数来根据标题和slugs 获取翻译的路径。

async function getTranslatedPostUrl() {
    // Split pathname
    // While filtereing out the empty entries
    // https://stackoverflow.com/a/39184134/2812386
    const pathParts = pathname.split('/').filter(i => i);

    // Find the index of 'blog' in the pathParts array
    const blogIndex = pathParts.indexOf('blog');

    // Determine the target language
    const targetLang = lang === 'es' ? 'en' : 'es';

    // Check if 'blog' exists in the URL and if there's something after it
    if (blogIndex !== -1 && pathParts.length > blogIndex + 1) {
        // Get all blog posts
        const allPosts = await getCollection('blog');

        // Extract the slugified title form the pathname
        const currentSlugifiedTitle = pathParts[blogIndex + 1];

        // Find the current post to get its title in the original language
        const currentPost = allPosts.find((post) => {
            return slugify(post.data.title) === currentSlugifiedTitle;
        });

        if (currentPost) {
            // Extract the slug without the language prefix from the current post
            const baseSlug = currentPost.slug.split('/').slice(1).join('/'); // Removes 'en/' or 'es/'

            // Find the translated post based on the base slug
            const translatedPost = allPosts.find((post) => {
                return post.slug === `${targetLang}/${baseSlug}`;
            });

            if (translatedPost) {
                // Generate the URL for the translated post
                const slugifiedTranslatedTitle = slugify(translatedPost.data.title);
                return targetLang === 'es' ? `/es/blog/${slugifiedTranslatedTitle}/` : `/blog/${slugifiedTranslatedTitle}/`;
            }
        }
    } else {
        // Handle other pages with i18next
        return localizePath(pathname, targetLang);
    }
}
const translatedPostUrl = await getTranslatedPostUrl();

现在我可以使用

translatedPostUrl
的值来链接到翻译的内容。

^_^

编辑:在 Netlify 上部署此解决方案后,我注意到导航栏逻辑并未 100% 工作。那是因为

pathname.split('/')
创建了一些空条目。所以我必须过滤它。有关更多信息,请访问 https://stackoverflow.com/a/39184134/2812386

© www.soinside.com 2019 - 2024. All rights reserved.