Astro Starter Template : Blog enhanced with I18n
Tags: astro, webdev, node, tutorial
Published: 2023-11-12 07:25:17


## Intro

Welcome to this hands-on tutorial where we'll delve into the Astro Blog Starter i18n template, featuring i18n capabilities with translations in multiple languages. Just to clarify, we're working with a template project here, meaning you can spawn your own repository right from it. Our template of choice is derived from Astro's official Starter Kit, thus carrying its robust DNA. 
Before we get started, I recommend a **basic understanding of Node.js and Astro** to make the most of this journey. Let's dive in!

## Create a new Github repository from template

To start, let's create a new repository from the [Astro Blog Starter i18n template](https://github.com/rebecamurillo/astro-blog-i18n-starter). You new repository will have the core features of the [Astro Starter Blog template](https://github.com/withastro/astro/tree/latest/examples/blog) with the added features of i18n with translations in multiple languages.

## Define your languages
To configure your languages, you will need to configure the available languages, and start a translations object with languages properties.
- Setup available languages and default language in the file `src/i18n/utils.ts`. This is important for the header configuration and canonical URL for SEO.
*File `src/i18n/utils.ts`*
```js
export const LANGUAGES = {
  en: "English",
  fr: "Français",
  es: "Español",
};

export const DEFAULT_LANG = "en";

...

```

- Initiate your translations keys in `src/i18n/ui.ts`
*File `src/i18n/ui.ts`*
```js
export const ui = {
    en: {
        "site.title": "Astro Blog"
    },
    fr: {
        "site.title": "Astro Blog"
    },
    es: {
        "site.title": "Astro Blog"
    }
}
```

## Create a new blog post in English, Spanish and French languages

Let's now add a new blog post, with translations. 
- In the `src/content/blog` folder, create a new folder and call it "new-blog", this will be the slug for the blog pages. 
- Then, inside folder `src/content/blog/new-blog`, create a new file for each language, in my case English `en.md`, Spanish `es.md`, and French `fr.md`. 
- In each file copy the data required in the collection.  Refer to the `src/content/config` file for collection setup, if you would like to add any more data usefull to your blog posts. 

*Example of file `src/content/blog/new-blog/es.md` content.*
```md
---
title: 'Mi primer blog'
description: 'Lorem ipsum dolor sit amet'
pubDate: 'Jul 08 2022'
heroImage: '/blog-placeholder-3.jpg'
author: 'Me'
lang: 'es'
---
# Mi primer Blog ! 
Lorem ipsum dolor sit amet, consectetur adipiscing elit...
```

After adding the content for each language, we can navigate to the blog section on the site to see our new blog post in each language. If the translations are appearing correctly, we have successfully added a new blog post.

## Create a new static page in English, Spanish and French languages

Now, let's add a new static page with translations. 
- In `src/pages/[lang]` create a new file new-page.astro. 
- In `src/i18n/ui.ts` add a translation key for each language in the corresponding property for en, es, fr.

*File `src/i18n/ui.ts`*
```js
export const ui = {
    en: {
        "site.title": "Astro Blog",
        "newpage.title": "New page title",
        "newpage.description": "New page description"
    },
    fr: {
        "site.title": "Astro Blog",
        "newpage.title": "Nouvelle page",
        "newpage.title": "Nouvelle page description"
    },
    es: {
        "site.title": "Astro Blog",
        "newpage.title": "Nueva pagina",
        "newpage.title": "Nueva pagina description"
    }
}
```

- Copy the Layout configuration from the index.astro for example. And set your translations keys using the function 

*File `src/pages/[lang]/new-page.astro`*
```js
---
import Layout from "../../layouts/Layout.astro";

import { getLangFromUrl, useTranslations } from "../../i18n/utils";

const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);

export async function getStaticPaths() {
  return ["en", "fr", "es"].map((lang) => {
    return { params: { lang } };
  });
}
---

<Layout title={t("newpage.title")} description={t("newpage.description")} lang={lang}>
  <h1>{t("newpage.title")}</h1>
</Layout>
```

- Check your new page in your browser [http://localhost:4321/en/new-page](http://localhost:4321/en/new-page), [http://localhost:4321/fr/new-page](http://localhost:4321/fr/new-page),  and [http://localhost:4321/es/new-page](http://localhost:4321/es/new-page)

And that's it! You have now added a new blog post and a new static page to your Astro blog project in multiple languages.

## Optimization for SEO

This Astro Starter Blog I18n Template is pre-optimized for SEO. This is a critical aspect of any online project as it enhances visibility and discoverability on search engines.

One of the ways this optimization is achieved is through the use of canonical URLs. In the template, the default language is set to English. This means all canonical URLs will default to the English language versions. 

On the other hand, alternate URLs are defined accordingly to each language. For instance, in the Spanish version, the alternate languages (which are English and French in this case) will appear in the head block. This setup ensures that search engines accurately index all versions of the site, preventing duplication and enhancing SEO performance.


![SEO canonical and alternate URLs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2d2unzii50pm6zlhsdda.png)

In addition, the Astro sitemaps plugin, already installed in this project, automatically generates sitemaps. These sitemaps include all versions of the website in all languages, providing further assistance to search engines for indexing the website.

## Conclusion
The Astro Starter Blog I18n template comes with the base features for a static website, blog pages in Markdown, translations in multiple languages with i18n feature, SEO optimization, ensuring that your content is ready to reach an international audience right from the get-go.