refactor: centralize locale constants to prevent breaking changes

Created src/lib/i18n/locales.ts as single source of truth for:
- SUPPORTED_LOCALES array
- LOCALE_COOKIE name
- DEFAULT_LOCALE
- LOCALE_CONFIG (labels, flags, Saleor locale mapping)
- Helper functions (isValidLocale, getSaleorLocale, getLocaleFromPath)

Updated all files to use centralized constants:
- middleware.ts
- Header.tsx
- ProductCard.tsx
- sitemap.ts
- root layout and locale layout
- routing.ts

Benefits:
- Adding new locale only requires updating ONE file (locales.ts)
- No more hardcoded locale lists scattered across codebase
- Cookie name defined in one place
- Type-safe locale validation
This commit is contained in:
Unchained
2026-03-24 11:27:55 +02:00
parent a4e7a07adb
commit a5cd048a6e
8 changed files with 92 additions and 81 deletions

View File

@@ -1,7 +1,7 @@
import { MetadataRoute } from "next";
import { getProducts } from "@/lib/saleor";
import { SUPPORTED_LOCALES, type Locale } from "@/lib/i18n/locales";
const LOCALES = ["sr", "en", "de", "fr"] as const;
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com";
interface SitemapEntry {
@@ -29,12 +29,9 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
changeFrequency: "daily",
priority: 1,
alternates: {
languages: {
sr: `${baseUrl}`,
en: `${baseUrl}/en`,
de: `${baseUrl}/de`,
fr: `${baseUrl}/fr`,
},
languages: Object.fromEntries(
SUPPORTED_LOCALES.map((locale) => [locale, locale === "sr" ? baseUrl : `${baseUrl}/${locale}`])
),
},
},
{
@@ -43,12 +40,9 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
changeFrequency: "daily",
priority: 0.9,
alternates: {
languages: {
sr: `${baseUrl}/products`,
en: `${baseUrl}/en/products`,
de: `${baseUrl}/de/products`,
fr: `${baseUrl}/fr/products`,
},
languages: Object.fromEntries(
SUPPORTED_LOCALES.map((locale) => [locale, locale === "sr" ? `${baseUrl}/products` : `${baseUrl}/${locale}/products`])
),
},
},
{
@@ -57,12 +51,9 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
changeFrequency: "monthly",
priority: 0.6,
alternates: {
languages: {
sr: `${baseUrl}/about`,
en: `${baseUrl}/en/about`,
de: `${baseUrl}/de/about`,
fr: `${baseUrl}/fr/about`,
},
languages: Object.fromEntries(
SUPPORTED_LOCALES.map((locale) => [locale, locale === "sr" ? `${baseUrl}/about` : `${baseUrl}/${locale}/about`])
),
},
},
{
@@ -71,12 +62,9 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
changeFrequency: "monthly",
priority: 0.6,
alternates: {
languages: {
sr: `${baseUrl}/contact`,
en: `${baseUrl}/en/contact`,
de: `${baseUrl}/de/contact`,
fr: `${baseUrl}/fr/contact`,
},
languages: Object.fromEntries(
SUPPORTED_LOCALES.map((locale) => [locale, locale === "sr" ? `${baseUrl}/contact` : `${baseUrl}/${locale}/contact`])
),
},
},
{
@@ -85,12 +73,9 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
changeFrequency: "monthly",
priority: 0.5,
alternates: {
languages: {
sr: `${baseUrl}/checkout`,
en: `${baseUrl}/en/checkout`,
de: `${baseUrl}/de/checkout`,
fr: `${baseUrl}/fr/checkout`,
},
languages: Object.fromEntries(
SUPPORTED_LOCALES.map((locale) => [locale, locale === "sr" ? `${baseUrl}/checkout` : `${baseUrl}/${locale}/checkout`])
),
},
},
];
@@ -98,7 +83,13 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
const productUrls: SitemapEntry[] = [];
for (const product of products) {
for (const locale of LOCALES) {
const hreflangs: Record<string, string> = {};
for (const locale of SUPPORTED_LOCALES) {
const path = locale === "sr" ? `/products/${product.slug}` : `/${locale}/products/${product.slug}`;
hreflangs[locale] = `${baseUrl}${path}`;
}
for (const locale of SUPPORTED_LOCALES) {
const localePrefix = locale === "sr" ? "" : `/${locale}`;
productUrls.push({
url: `${baseUrl}${localePrefix}/products/${product.slug}`,
@@ -106,12 +97,7 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
changeFrequency: "weekly",
priority: 0.8,
alternates: {
languages: {
sr: `${baseUrl}/products/${product.slug}`,
en: `${baseUrl}/en/products/${product.slug}`,
de: `${baseUrl}/de/products/${product.slug}`,
fr: `${baseUrl}/fr/products/${product.slug}`,
},
languages: hreflangs,
},
});
}