I found that out of the box, the Astro 4.5 blog example and internationalization/localization (i18n) features require quite a bit of work to become a fully working, SEO-optimized and screen reader-friendly blog. This project attempts to make getting started a bit easier.
Caution
I've stopped maintenance of this starter, because:
- Keeping this repo updated with Astro's changes takes quit a bit of time, whereas pulling in changes to sites that are based can likely result in merge conflicts.
- The way it redefines collection pages' 'slugs' (paths) using
getPagePath()
andgetPostPath()
works fine, but I've found that it's convoluted and that it's easier to use file path-based routing instead—even if that involves a slightly complicated glob pattern with the default language not having a path prefix.
Important
There's one feature you may still find interesting to see in this project: finding translations of pages. Other starters often rely on file names to find translations, making it impossible to make locale-specific URLs. In this repo you find that pages can have a reference
frontmatter value. MainI18n.astro
creates an array of all translations of the current page, based on that value.
Tip
To create the what I called a 'slighly complicated glob pattern' above, you can define the loader (that's an Astro 5 thing) for the blog collection like this:
const bblogCollection = defineCollection({
loader: glob({
pattern: "{blog,nl/blog,de/blog}/**/*.{md,mdx}",
base: "./src/content/",
}),
// ...
})
- Use built-in features and reduce additional dependencies where possible. The assumption is that the Astro team will expand i18n features and that parts of this setup can be replaced with built-in functions in the future.
- Add a minimum of styling and hard-coded settings, so you can quickly get to styling and configuring your own site.
- Allow for multiple collections (don't abuse collections for localization)
- Separate layouts, components and content; make sure all content is saved in markdown and data files.
- Support the features below!
- ⛓️ Linked translations via a reference property: no need for matching slugs between locales.
- 🏖️ Allow adding pages for a new locale with minimal effort; use the default locale* as a fallback for missing settings and strings.
- 🏷️ Content tags á la WordPress
- 🗺️ Sitemap support with translation links
- 📡 Localized RSS Feeds
- 🌍 Customizable URL structure, like
domain.tld/locale/directory/slug
- 🪽 Skip to content link for screen reader and keyboard users
- 👩💼 Localized author profiles from a single data file
- 🔏 Secret/draft state to exclude posts from rendering
- 🔚 404 Page not found page
- 🐭 Ultra minimal styling without CSS classes with new.css (remove only two lines of code to remove it!)
- 🔗
target="_blank"
for external links with Rehype plugin - 😉 Separate favicon for dev server to not get confused between dev and production
*) This is why the Dutch demo pages have an English header menu; no Dutch menu items were defined.
Based on the official blog example, this setup still has:
- ✅ 100/100 Lighthouse performance
- ✅ SEO-friendly with canonical URLs and OpenGraph data
- ✅ Markdown & MDX support
You'll see the following folders and files:
├── public/
├── src/
│ ├── components/
│ ├── content/
│ ├── i18n/
│ │ ├── i18n.ts ← Set up locales here
│ │ ├── uiStrings.js ← Localized headings, labels, etc.
│ │ └── utilities ← i18n-specific functions
│ ├── layouts/
│ ├── styles/
│ ├── utilities/
│ ├── consts.ts ← Settings loaded by astro.config.mjs
│ ├── env.d.ts
│ ├── header.ts ← Settings for header menus, optionally per locale
│ └── people.ts ← Bylines and author profile pages
├── astro.config.mjs
├── README.md
├── package.json
└── tsconfig.json
Astro looks for .astro
or .md
files in the src/pages/
directory. Each page is exposed as a route based on its file name.
There's nothing special about src/components/
, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
The src/content/
directory contains collections of related markdown and MDX documents. A 'blog' collection has been defined already.
Any static assets, like images, can be placed in the public/
directory.
All default commands can be run from the root of the project, from a terminal:
Command | Action |
---|---|
pnpm install |
Installs dependencies |
pnpm run dev |
Starts local dev server at localhost:4321 |
pnpm run build |
Build your production site to ./dist/ |
pnpm run preview |
Preview your build locally, before deploying |
pnpm run astro ... |
Run CLI commands like astro add , astro check |
pnpm run astro -- --help |
Get help using the Astro CLI |
- Get feedback. This is my third Astro project, but it's I noticed while making this, that I'm very much a novice Astro user. Feel free to contact me and make pull requests.
- Although there are no errors or known issues, your editor may show a few squiggly lines caused missing/faulty TypeScript settings.