#Need Help Implementing Collections with i18n in My Astro Project

4 messages · Page 1 of 1 (latest)

astral seal
#

I've been working on adding the i18n feature to my Astro project following the guidance provided in the official documentation here: https://docs.astro.build/en/recipes/i18n/.

I've successfully implemented translation for my site, but I'm facing challenges when it comes to using collections for translated content. Specifically, my blog posts aren't loading as expected. It is showing all posts from all languages.

In the docs have only instructions for a regular collection without pagination. But in my case I use pagination.

I understand I have to filter the languages in the getStaticPaths method but Im not sure how. Here is what I have:

pages/blog/[page].astro (en)

...
export const getStaticPaths = (async ({ paginate }) => {
  const posts = (await getCollection("blog")).sort(
    (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
  );

  return paginate(posts, { pageSize: LIST_CONTENT_PAGE_SIZE });
}) satisfies GetStaticPaths;
...
Docs

Use dynamic routing and content collections to add internationalization support to your Astro site.

indigo crescentBOT
#

Hi @astral seal. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

You need to filter your collection entries by language before passing them to paginate(). Since your blog content is organized in subdirectories by language (e.g., src/content/blog/en/ and src/content/blog/fr/), you can filter by the id property which includes the full path.

For your English blog page at pages/blog/[page].astro, filter entries where the id starts with en/:

---
import { getCollection } from 'astro:content';

export const getStaticPaths = (async ({ paginate }) => {
  const posts = (await getCollection("blog", ({ id }) => {
    return id.startsWith('en/');
  })).sort(
    (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
  );

  return paginate(posts, { pageSize: LIST_CONTENT_PAGE_SIZE });
}) satisfies GetStaticPaths;
---

[filtering collections]

If you want a more scalable approach that handles all languages in a single dynamic route (e.g., pages/[lang]/blog/[page].astro), you can split the id to extract the language and slug, then use paginate() with additional params:

---
import { getCollection } from 'astro:content';

export async function getStaticPaths({ paginate }) {
  const allPosts = await getCollection("blog");

  // Group posts by language
  const languages = ['en', 'fr']; // your supported languages

  return languages.flatMap((lang) => {
    const filteredPosts = allPosts
      .filter(({ id }) => id.startsWith(`${lang}/`))
      .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());

    return paginate(filteredPosts, {
      params: { lang },
      pageSize: LIST_CONTENT_PAGE_SIZE,
    });
  });
}

const { lang } = Astro.params;
const { page } = Astro.props;
---
#

[i18n collections; paginate reference]

The key points are:

  • Use getCollection()'s optional filter callback to narrow entries by id prefix (e.g., id.startsWith('en/'))
  • When using paginate() with multiple languages in one route, pass params: { lang } in the paginate() options so each language gets its own set of paginated URLs

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: