Adding New Pages

This guide shows you how to add a new page to a multilingual Astro project.

Two Approaches for Localization

Choose the approach based on your needs:

🗂️ Pattern A: [...pages].astro (Single File Pattern)

When to use: Simple pages without subpages
Examples: [...index].astro, [...blog].astro, [...contact].astro

import { buildLocalizedStaticPaths } from "@i18n/utils";

// Single-file catch‑all: [...pages].astro
export function getStaticPaths() {
    return buildLocalizedStaticPaths("/pages", ["...pages"]);
}

📁 Pattern B: [pages]/[...index].astro (Folder Pattern)

When to use: Pages with additional files (MDX, images, components) Examples: [about]/[...index].astro, [services]/[...index].astro Advantages: Organized structure, easier maintenance

import { buildLocalizedStaticPaths } from "@i18n/utils";

// Folder pattern: [pages]/[...index].astro
export function getStaticPaths() {
    return buildLocalizedStaticPaths("/pages", ["pages", "...index"]);
}

⚠️ CRITICAL - Synchronization

Ensure any localized segments (e.g., pages → strani) exist in routes.ts. useTranslatedPath() relies on these mappings.


🔄 Flipping default language

You can switch the root language without touching your page files:

  1. In src/i18n/ui.ts, set:
    • defaultLang = "sl" (or your target)
    • showDefaultLang = true | false (include prefix for the default language)
  2. Root becomes / (when showDefaultLang = false) or /{defaultLang}/ (when true).
  3. All page URLs adapt automatically because getStaticPaths() uses useTranslatedPath().
  4. Verify home, about, pages, and navigation paths.

Tip: Use useTranslatedPath(lang)("/pages") in examples to avoid hard-coded localized segments.


🛠️ Practical Example: Adding “Services” Page

Let’s add a new page /services/sl/storitve:

Step 1: Create File

src/pages/[services]/[...index].astro

Step 2: Configure getStaticPaths

import { useTranslations, buildLocalizedStaticPaths } from "@i18n/utils";
import Base from "@layouts/Base.astro";
import "@styles/markdown.css";

export function getStaticPaths() {
    return buildLocalizedStaticPaths("/services", ["services", "...index"]);
}

const { lang } = Astro.props;
const t = useTranslations(lang);
const { Content, frontmatter } = await import(`./_services-${lang}.mdx`);
---

<Base
    title={frontmatter?.title}
    meta={{
        description: frontmatter?.description,
        keywords: frontmatter?.keywords,
    }}
    >
    <section id="md-content">
        <Content />
    </section>
</Base>

Step 3: Add to routes.ts

export const routes: Record<string, Record<string, string>> = {
    sl: {
        about: "o-projektu",
        blog: "spletni-dnevnik",
        pages: "strani",
        services: "storitve", // ← Matches "storitve" above
    },
};

Step 4: Add to Navigation

const navigationData = [
    {
        label: "menu.list.services",
        href: "/services", // ← English path
        children: [],
    },
];

Step 5: Create Content Files

Step 6: Add Translations (optional, if not reading from MDX)

In locales/en/services.json:

{
    "head": {
        "title": "Our Services",
        "description": "Professional services we offer"
    },
    // If needed, add more translations here
    "title": "Our Services",
    "description": "We provide comprehensive solutions for your business needs."
}

In locales/sl/services.json:

{
    "head": {
        "title": "Naše storitve",
        "description": "Strokovne storitve, ki jih ponujamo"
    },
    // If needed, add more translations here
    "title": "Naše storitve",
    "description": "Zagotavljamo celovite rešitve za vaše poslovne potrebe."
}

Add to locales/en/menu.json:

{
    "list": {
        "services": "Services"
    }
}

Add to locales/sl/menu.json:

{
    "list": {
        "services": "Storitve"
    }
}

🎯 Final Result

Assuming defaultLang = "en" and showDefaultLang = false:

LanguageURLWorks
🇬🇧 English/services
🇸🇮 Slovenian/sl/storitve
🧭 NavigationAutomatic
🔄 Language switcherSwitches language
🍞 BreadcrumbsShows path

Congratulations! New page successfully added! 🎉