refactor: eliminate hardcoded locale comparisons for antifragility
Created centralized helpers: - src/lib/i18n/pageMetadata.ts: All page metadata (titles, descriptions, alt text) - src/lib/i18n/productText.ts: Product-specific translated text (shortDescription, benefits) - src/lib/i18n/metadata.ts: Helper functions for locale handling Updated all pages to use centralized metadata: - Homepage: Uses getPageMetadata for title, description, productionAlt - Products page: Uses getPageMetadata - Product detail: Uses getPageMetadata + getTranslatedShortDescription/getTranslatedBenefits - About page: Uses getPageMetadata ProductDetail component now uses: - getTranslatedShortDescription() instead of locale comparison - getTranslatedBenefits() instead of locale comparison All user-facing text now goes through translation files or centralized helpers. Adding a new language now requires only: 1. Add to SUPPORTED_LOCALES in locales.ts 2. Add LOCALE_CONFIG entry 3. Add entries to pageMetadata.ts and productText.ts 4. Add translation keys to message files
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||||
import Header from "@/components/layout/Header";
|
import Header from "@/components/layout/Header";
|
||||||
import Footer from "@/components/layout/Footer";
|
import Footer from "@/components/layout/Footer";
|
||||||
|
import { getPageMetadata } from "@/lib/i18n/pageMetadata";
|
||||||
|
import { isValidLocale, DEFAULT_LOCALE, type Locale } from "@/lib/i18n/locales";
|
||||||
|
|
||||||
interface AboutPageProps {
|
interface AboutPageProps {
|
||||||
params: Promise<{ locale: string }>;
|
params: Promise<{ locale: string }>;
|
||||||
@@ -8,19 +10,19 @@ interface AboutPageProps {
|
|||||||
|
|
||||||
export async function generateMetadata({ params }: AboutPageProps) {
|
export async function generateMetadata({ params }: AboutPageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
const metadata = getPageMetadata(validLocale as Locale);
|
||||||
return {
|
return {
|
||||||
title: locale === "sr"
|
title: metadata.about.title,
|
||||||
? "O nama - ManoonOils"
|
description: metadata.about.description,
|
||||||
: "About - ManoonOils",
|
|
||||||
description: locale === "sr"
|
|
||||||
? "Saznajte više o ManoonOils - naša priča, misija i posvećenost prirodnoj lepoti."
|
|
||||||
: "Learn more about ManoonOils - our story, mission, and commitment to natural beauty.",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function AboutPage({ params }: AboutPageProps) {
|
export default async function AboutPage({ params }: AboutPageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
setRequestLocale(locale);
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
const metadata = getPageMetadata(validLocale as Locale);
|
||||||
|
setRequestLocale(validLocale);
|
||||||
const t = await getTranslations("About");
|
const t = await getTranslations("About");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -43,7 +45,7 @@ export default async function AboutPage({ params }: AboutPageProps) {
|
|||||||
<div className="relative h-[400px] md:h-[500px] overflow-hidden">
|
<div className="relative h-[400px] md:h-[500px] overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=2000&auto=format&fit=crop"
|
src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=2000&auto=format&fit=crop"
|
||||||
alt={locale === "sr" ? "Proizvodnja prirodnih ulja" : "Natural oils production"}
|
alt={metadata.productionAlt}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-black/20" />
|
<div className="absolute inset-0 bg-black/20" />
|
||||||
|
|||||||
@@ -10,30 +10,32 @@ import ProductReviews from "@/components/product/ProductReviews";
|
|||||||
import BeforeAfterGallery from "@/components/home/BeforeAfterGallery";
|
import BeforeAfterGallery from "@/components/home/BeforeAfterGallery";
|
||||||
import ProblemSection from "@/components/home/ProblemSection";
|
import ProblemSection from "@/components/home/ProblemSection";
|
||||||
import HowItWorks from "@/components/home/HowItWorks";
|
import HowItWorks from "@/components/home/HowItWorks";
|
||||||
|
import { getPageMetadata } from "@/lib/i18n/pageMetadata";
|
||||||
|
import { isValidLocale, DEFAULT_LOCALE, getSaleorLocale, type Locale } from "@/lib/i18n/locales";
|
||||||
|
|
||||||
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
|
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
setRequestLocale(locale);
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
const metadata = getPageMetadata(validLocale as Locale);
|
||||||
|
setRequestLocale(validLocale);
|
||||||
return {
|
return {
|
||||||
title: locale === "sr"
|
title: metadata.home.title,
|
||||||
? "ManoonOils - Premium prirodna ulja za negu kose i kože"
|
description: metadata.home.description,
|
||||||
: "ManoonOils - Premium Natural Oils for Hair & Skin",
|
|
||||||
description: locale === "sr"
|
|
||||||
? "Otkrijte našu premium kolekciju prirodnih ulja za negu kose i kože."
|
|
||||||
: "Discover our premium collection of natural oils for hair and skin care.",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Homepage({ params }: { params: Promise<{ locale: string }> }) {
|
export default async function Homepage({ params }: { params: Promise<{ locale: string }> }) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
setRequestLocale(locale);
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
setRequestLocale(validLocale);
|
||||||
const t = await getTranslations("Home");
|
const t = await getTranslations("Home");
|
||||||
const tBenefits = await getTranslations("Benefits");
|
const tBenefits = await getTranslations("Benefits");
|
||||||
|
const metadata = getPageMetadata(validLocale as Locale);
|
||||||
|
|
||||||
const productLocale = locale === "sr" ? "SR" : "EN";
|
const saleorLocale = getSaleorLocale(validLocale as Locale);
|
||||||
let products: any[] = [];
|
let products: any[] = [];
|
||||||
try {
|
try {
|
||||||
products = await getProducts(productLocale);
|
products = await getProducts(saleorLocale);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Failed to fetch products during build");
|
console.log("Failed to fetch products during build");
|
||||||
}
|
}
|
||||||
@@ -41,7 +43,7 @@ export default async function Homepage({ params }: { params: Promise<{ locale: s
|
|||||||
const featuredProducts = products?.slice(0, 4) || [];
|
const featuredProducts = products?.slice(0, 4) || [];
|
||||||
const hasProducts = featuredProducts.length > 0;
|
const hasProducts = featuredProducts.length > 0;
|
||||||
|
|
||||||
const basePath = `/${locale}`;
|
const basePath = `/${validLocale}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -122,7 +124,7 @@ export default async function Homepage({ params }: { params: Promise<{ locale: s
|
|||||||
<div className="relative aspect-[4/3] bg-[#e8f0f5] rounded-lg overflow-hidden">
|
<div className="relative aspect-[4/3] bg-[#e8f0f5] rounded-lg overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=800&auto=format&fit=crop"
|
src="https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?q=80&w=800&auto=format&fit=crop"
|
||||||
alt={locale === "sr" ? "Proizvodnja prirodnih ulja" : "Natural oils production"}
|
alt={metadata.home.productionAlt}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import Footer from "@/components/layout/Footer";
|
|||||||
import ProductDetail from "@/components/product/ProductDetail";
|
import ProductDetail from "@/components/product/ProductDetail";
|
||||||
import type { Product } from "@/types/saleor";
|
import type { Product } from "@/types/saleor";
|
||||||
import { routing } from "@/i18n/routing";
|
import { routing } from "@/i18n/routing";
|
||||||
|
import { getPageMetadata } from "@/lib/i18n/pageMetadata";
|
||||||
|
import { isValidLocale, DEFAULT_LOCALE, getSaleorLocale, type Locale } from "@/lib/i18n/locales";
|
||||||
|
|
||||||
interface ProductPageProps {
|
interface ProductPageProps {
|
||||||
params: Promise<{ locale: string; slug: string }>;
|
params: Promise<{ locale: string; slug: string }>;
|
||||||
@@ -16,8 +18,8 @@ export async function generateStaticParams() {
|
|||||||
|
|
||||||
for (const locale of locales) {
|
for (const locale of locales) {
|
||||||
try {
|
try {
|
||||||
const productLocale = locale === "sr" ? "SR" : "EN";
|
const saleorLocale = locale === "sr" ? "SR" : "EN";
|
||||||
const products = await getProducts(productLocale, 100);
|
const products = await getProducts(saleorLocale, 100);
|
||||||
products.forEach((product: Product) => {
|
products.forEach((product: Product) => {
|
||||||
params.push({ locale, slug: product.slug });
|
params.push({ locale, slug: product.slug });
|
||||||
});
|
});
|
||||||
@@ -29,16 +31,18 @@ export async function generateStaticParams() {
|
|||||||
|
|
||||||
export async function generateMetadata({ params }: ProductPageProps) {
|
export async function generateMetadata({ params }: ProductPageProps) {
|
||||||
const { locale, slug } = await params;
|
const { locale, slug } = await params;
|
||||||
const productLocale = locale === "sr" ? "SR" : "EN";
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
const product = await getProductBySlug(slug, productLocale);
|
const metadata = getPageMetadata(validLocale as Locale);
|
||||||
|
const saleorLocale = validLocale === "sr" ? "SR" : "EN";
|
||||||
|
const product = await getProductBySlug(slug, saleorLocale);
|
||||||
|
|
||||||
if (!product) {
|
if (!product) {
|
||||||
return {
|
return {
|
||||||
title: locale === "sr" ? "Proizvod nije pronađen" : "Product not found",
|
title: metadata.productNotFound,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const localized = getLocalizedProduct(product, productLocale);
|
const localized = getLocalizedProduct(product, saleorLocale);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: localized.name,
|
title: localized.name,
|
||||||
@@ -48,12 +52,13 @@ export async function generateMetadata({ params }: ProductPageProps) {
|
|||||||
|
|
||||||
export default async function ProductPage({ params }: ProductPageProps) {
|
export default async function ProductPage({ params }: ProductPageProps) {
|
||||||
const { locale, slug } = await params;
|
const { locale, slug } = await params;
|
||||||
setRequestLocale(locale);
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
setRequestLocale(validLocale);
|
||||||
const t = await getTranslations("Product");
|
const t = await getTranslations("Product");
|
||||||
const productLocale = locale === "sr" ? "SR" : "EN";
|
const saleorLocale = getSaleorLocale(validLocale as Locale);
|
||||||
const product = await getProductBySlug(slug, productLocale);
|
const product = await getProductBySlug(slug, saleorLocale);
|
||||||
|
|
||||||
const basePath = locale === "sr" ? "" : `/${locale}`;
|
const basePath = `/${validLocale}`;
|
||||||
|
|
||||||
if (!product) {
|
if (!product) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import Header from "@/components/layout/Header";
|
|||||||
import Footer from "@/components/layout/Footer";
|
import Footer from "@/components/layout/Footer";
|
||||||
import ProductCard from "@/components/product/ProductCard";
|
import ProductCard from "@/components/product/ProductCard";
|
||||||
import { ChevronDown } from "lucide-react";
|
import { ChevronDown } from "lucide-react";
|
||||||
|
import { getPageMetadata } from "@/lib/i18n/pageMetadata";
|
||||||
|
import { isValidLocale, DEFAULT_LOCALE, getSaleorLocale, type Locale } from "@/lib/i18n/locales";
|
||||||
|
|
||||||
interface ProductsPageProps {
|
interface ProductsPageProps {
|
||||||
params: Promise<{ locale: string }>;
|
params: Promise<{ locale: string }>;
|
||||||
@@ -11,22 +13,21 @@ interface ProductsPageProps {
|
|||||||
|
|
||||||
export async function generateMetadata({ params }: ProductsPageProps) {
|
export async function generateMetadata({ params }: ProductsPageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
const metadata = getPageMetadata(validLocale as Locale);
|
||||||
return {
|
return {
|
||||||
title: locale === "sr"
|
title: metadata.products.title,
|
||||||
? "Proizvodi - ManoonOils"
|
description: metadata.products.description,
|
||||||
: "Products - ManoonOils",
|
|
||||||
description: locale === "sr"
|
|
||||||
? "Pregledajte našu kolekciju premium prirodnih ulja za negu kose i kože."
|
|
||||||
: "Browse our collection of premium natural oils for hair and skin care.",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ProductsPage({ params }: ProductsPageProps) {
|
export default async function ProductsPage({ params }: ProductsPageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
setRequestLocale(locale);
|
const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
setRequestLocale(validLocale);
|
||||||
const t = await getTranslations("Products");
|
const t = await getTranslations("Products");
|
||||||
const productLocale = locale === "sr" ? "SR" : "EN";
|
const saleorLocale = getSaleorLocale(validLocale as Locale);
|
||||||
const products = await getProducts(productLocale);
|
const products = await getProducts(saleorLocale);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { useTranslations } from "next-intl";
|
|||||||
import type { Product } from "@/types/saleor";
|
import type { Product } from "@/types/saleor";
|
||||||
import { useSaleorCheckoutStore } from "@/stores/saleorCheckoutStore";
|
import { useSaleorCheckoutStore } from "@/stores/saleorCheckoutStore";
|
||||||
import { getProductPrice, getProductPriceAmount, getLocalizedProduct, formatPrice } from "@/lib/saleor";
|
import { getProductPrice, getProductPriceAmount, getLocalizedProduct, formatPrice } from "@/lib/saleor";
|
||||||
|
import { getTranslatedShortDescription, getTranslatedBenefits } from "@/lib/i18n/productText";
|
||||||
|
import { isValidLocale } from "@/lib/i18n/locales";
|
||||||
import ProductCard from "@/components/product/ProductCard";
|
import ProductCard from "@/components/product/ProductCard";
|
||||||
import ProductBenefits from "@/components/product/ProductBenefits";
|
import ProductBenefits from "@/components/product/ProductBenefits";
|
||||||
import ProductReviews from "@/components/product/ProductReviews";
|
import ProductReviews from "@/components/product/ProductReviews";
|
||||||
@@ -94,6 +96,7 @@ export default function ProductDetail({ product, relatedProducts, locale = "sr"
|
|||||||
const [isAdding, setIsAdding] = useState(false);
|
const [isAdding, setIsAdding] = useState(false);
|
||||||
const [urgencyIndex, setUrgencyIndex] = useState(0);
|
const [urgencyIndex, setUrgencyIndex] = useState(0);
|
||||||
const { addLine, openCart } = useSaleorCheckoutStore();
|
const { addLine, openCart } = useSaleorCheckoutStore();
|
||||||
|
const validLocale = isValidLocale(locale) ? locale : "sr";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
@@ -132,15 +135,10 @@ export default function ProductDetail({ product, relatedProducts, locale = "sr"
|
|||||||
const priceAmount = getProductPriceAmount(product);
|
const priceAmount = getProductPriceAmount(product);
|
||||||
const originalPrice = priceAmount > 0 ? formatPrice(Math.round(priceAmount * 1.30)) : null;
|
const originalPrice = priceAmount > 0 ? formatPrice(Math.round(priceAmount * 1.30)) : null;
|
||||||
|
|
||||||
const shortDescription = localized.description
|
const shortDescription = getTranslatedShortDescription(localized.description, validLocale);
|
||||||
? localized.description.split('.')[0] + '.'
|
|
||||||
: locale === "en" ? "Premium natural oil for your beauty routine." : "Premium prirodno ulje za vašu rutinu lepote.";
|
|
||||||
|
|
||||||
const benefits = product.metadata?.find(m => m.key === "benefits")?.value?.split(',') || [
|
const metadataBenefits = product.metadata?.find(m => m.key === "benefits")?.value?.split(',');
|
||||||
locale === "en" ? "Natural" : "Prirodno",
|
const benefits = getTranslatedBenefits(metadataBenefits, validLocale);
|
||||||
locale === "en" ? "Organic" : "Organsko",
|
|
||||||
locale === "en" ? "Cruelty-free" : "Bez okrutnosti",
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -148,7 +146,7 @@ export default function ProductDetail({ product, relatedProducts, locale = "sr"
|
|||||||
<div className="border-b border-[#e5e5e5] pt-[72px] lg:pt-[72px]">
|
<div className="border-b border-[#e5e5e5] pt-[72px] lg:pt-[72px]">
|
||||||
<div className="container py-5">
|
<div className="container py-5">
|
||||||
<nav className="flex items-center gap-2 text-sm">
|
<nav className="flex items-center gap-2 text-sm">
|
||||||
<Link href={`/${locale.toLowerCase()}`} className="text-[#666666] hover:text-black transition-colors">
|
<Link href={`/${validLocale}`} className="text-[#666666] hover:text-black transition-colors">
|
||||||
{t("home")}
|
{t("home")}
|
||||||
</Link>
|
</Link>
|
||||||
<span className="text-[#999999]">/</span>
|
<span className="text-[#999999]">/</span>
|
||||||
|
|||||||
@@ -1,17 +1,37 @@
|
|||||||
import { DEFAULT_LOCALE, LOCALE_CONFIG, type Locale } from "./locales";
|
import { DEFAULT_LOCALE, LOCALE_CONFIG, SUPPORTED_LOCALES, type Locale } from "./locales";
|
||||||
|
|
||||||
export function getMetadataText(locale: Locale, texts: Partial<Record<Locale, string>>): string {
|
|
||||||
return texts[locale] || texts[DEFAULT_LOCALE] || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSaleorLocale(locale: Locale): string {
|
export function getSaleorLocale(locale: Locale): string {
|
||||||
return LOCALE_CONFIG[locale].saleorLocale;
|
return LOCALE_CONFIG[locale].saleorLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLocaleDisplayName(locale: Locale): string {
|
export function getLocaleLabel(locale: Locale): string {
|
||||||
return LOCALE_CONFIG[locale].label;
|
return LOCALE_CONFIG[locale].label;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDefaultLocale(locale: string): boolean {
|
export function isDefaultLocale(locale: string): boolean {
|
||||||
return locale === DEFAULT_LOCALE;
|
return locale === DEFAULT_LOCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getLocaleFromParams(params: { locale: string }): Locale {
|
||||||
|
const { locale } = params;
|
||||||
|
if (SUPPORTED_LOCALES.includes(locale as Locale)) {
|
||||||
|
return locale as Locale;
|
||||||
|
}
|
||||||
|
return DEFAULT_LOCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProductLocale(locale: Locale): string {
|
||||||
|
return getSaleorLocale(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildHreflangAlternates(baseUrl: string): Record<string, string> {
|
||||||
|
const alternates: Record<string, string> = {};
|
||||||
|
for (const loc of SUPPORTED_LOCALES) {
|
||||||
|
if (loc === DEFAULT_LOCALE) {
|
||||||
|
alternates[loc] = baseUrl;
|
||||||
|
} else {
|
||||||
|
alternates[loc] = `${baseUrl}/${loc}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alternates;
|
||||||
|
}
|
||||||
|
|||||||
98
src/lib/i18n/pageMetadata.ts
Normal file
98
src/lib/i18n/pageMetadata.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import type { Locale } from "./locales";
|
||||||
|
|
||||||
|
const PAGE_METADATA: Record<Locale, {
|
||||||
|
home: { title: string; description: string; productionAlt: string };
|
||||||
|
products: { title: string; description: string };
|
||||||
|
productNotFound: string;
|
||||||
|
about: { title: string; description: string; productionAlt: string };
|
||||||
|
contact: { title: string; description: string };
|
||||||
|
}> = {
|
||||||
|
sr: {
|
||||||
|
home: {
|
||||||
|
title: "ManoonOils - Premium prirodna ulja za negu kose i kože",
|
||||||
|
description: "Otkrijte našu premium kolekciju prirodnih ulja za negu kose i kože.",
|
||||||
|
productionAlt: "Proizvodnja prirodnih ulja",
|
||||||
|
},
|
||||||
|
products: {
|
||||||
|
title: "Proizvodi - ManoonOils",
|
||||||
|
description: "Pregledajte našu kolekciju premium prirodnih ulja za negu kose i kože.",
|
||||||
|
},
|
||||||
|
productNotFound: "Proizvod nije pronađen",
|
||||||
|
about: {
|
||||||
|
title: "O nama - ManoonOils",
|
||||||
|
description: "Saznajte više o ManoonOils - naša priča, misija i posvećenost prirodnoj lepoti.",
|
||||||
|
productionAlt: "Proizvodnja prirodnih ulja",
|
||||||
|
},
|
||||||
|
contact: {
|
||||||
|
title: "Kontakt - ManoonOils",
|
||||||
|
description: "Kontaktirajte nas za sva pitanja o proizvodima, narudžbinama ili saradnji.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
home: {
|
||||||
|
title: "ManoonOils - Premium Natural Oils for Hair & Skin",
|
||||||
|
description: "Discover our premium collection of natural oils for hair and skin care.",
|
||||||
|
productionAlt: "Natural oils production",
|
||||||
|
},
|
||||||
|
products: {
|
||||||
|
title: "Products - ManoonOils",
|
||||||
|
description: "Browse our collection of premium natural oils for hair and skin care.",
|
||||||
|
},
|
||||||
|
productNotFound: "Product not found",
|
||||||
|
about: {
|
||||||
|
title: "About - ManoonOils",
|
||||||
|
description: "Learn more about ManoonOils - our story, mission, and commitment to natural beauty.",
|
||||||
|
productionAlt: "Natural oils production",
|
||||||
|
},
|
||||||
|
contact: {
|
||||||
|
title: "Contact - ManoonOils",
|
||||||
|
description: "Contact us for any questions about products, orders, or collaborations.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
home: {
|
||||||
|
title: "ManoonOils - Premium natürliche Öle für Haar & Haut",
|
||||||
|
description: "Entdecken Sie unsere Premium-Kollektion natürlicher Öle für Haar- und Hautpflege.",
|
||||||
|
productionAlt: "Natürliche Ölproduktion",
|
||||||
|
},
|
||||||
|
products: {
|
||||||
|
title: "Produkte - ManoonOils",
|
||||||
|
description: "Durchsuchen Sie unsere Kollektion premium natürlicher Öle für Haar- und Hautpflege.",
|
||||||
|
},
|
||||||
|
productNotFound: "Produkt nicht gefunden",
|
||||||
|
about: {
|
||||||
|
title: "Über uns - ManoonOils",
|
||||||
|
description: "Erfahren Sie mehr über ManoonOils und unsere Mission, premium natürliche Produkte anzubieten.",
|
||||||
|
productionAlt: "Natürliche Ölproduktion",
|
||||||
|
},
|
||||||
|
contact: {
|
||||||
|
title: "Kontakt - ManoonOils",
|
||||||
|
description: "Kontaktieren Sie uns für Fragen zu Produkten, Bestellungen oder Zusammenarbeit.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fr: {
|
||||||
|
home: {
|
||||||
|
title: "ManoonOils - Huiles Naturelles Premium pour Cheveux & Peau",
|
||||||
|
description: "Découvrez notre collection premium d'huiles naturelles pour les soins capillaires et cutanés.",
|
||||||
|
productionAlt: "Production d'huiles naturelles",
|
||||||
|
},
|
||||||
|
products: {
|
||||||
|
title: "Produits - ManoonOils",
|
||||||
|
description: "Parcourez notre collection d'huiles naturelles premium pour les soins capillaires et cutanés.",
|
||||||
|
},
|
||||||
|
productNotFound: "Produit non trouvé",
|
||||||
|
about: {
|
||||||
|
title: "À propos - ManoonOils",
|
||||||
|
description: "En savoir plus sur ManoonOils et notre mission de fournir des produits naturels premium.",
|
||||||
|
productionAlt: "Production d'huiles naturelles",
|
||||||
|
},
|
||||||
|
contact: {
|
||||||
|
title: "Contact - ManoonOils",
|
||||||
|
description: "Contactez-nous pour toute question sur les produits, commandes ou collaborations.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getPageMetadata(locale: Locale) {
|
||||||
|
return PAGE_METADATA[locale] || PAGE_METADATA.en;
|
||||||
|
}
|
||||||
57
src/lib/i18n/productText.ts
Normal file
57
src/lib/i18n/productText.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import type { Locale } from "./locales";
|
||||||
|
|
||||||
|
const PRODUCT_TEXT: Record<Locale, {
|
||||||
|
defaultShortDescription: string;
|
||||||
|
defaultBenefits: string[];
|
||||||
|
}> = {
|
||||||
|
sr: {
|
||||||
|
defaultShortDescription: "Premium prirodno ulje za vašu rutinu lepote.",
|
||||||
|
defaultBenefits: ["Prirodno", "Organsko", "Bez okrutnosti"],
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
defaultShortDescription: "Premium natural oil for your beauty routine.",
|
||||||
|
defaultBenefits: ["Natural", "Organic", "Cruelty-free"],
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
defaultShortDescription: "Premium natürliches Öl für Ihre Schönheitsroutine.",
|
||||||
|
defaultBenefits: ["Natürlich", "Bio", "Tierversuchsfrei"],
|
||||||
|
},
|
||||||
|
fr: {
|
||||||
|
defaultShortDescription: "Huile naturelle premium pour votre routine beauté.",
|
||||||
|
defaultBenefits: ["Naturel", "Bio", "Sans cruauté"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getProductDefaults(locale: Locale) {
|
||||||
|
return PRODUCT_TEXT[locale] || PRODUCT_TEXT.en;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTranslatedBenefits(
|
||||||
|
metadataBenefits: string[] | undefined,
|
||||||
|
locale: Locale
|
||||||
|
): string[] {
|
||||||
|
const defaults = PRODUCT_TEXT[locale] || PRODUCT_TEXT.en;
|
||||||
|
|
||||||
|
if (!metadataBenefits || metadataBenefits.length === 0) {
|
||||||
|
return defaults.defaultBenefits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadataBenefits.map((benefit, index) => {
|
||||||
|
const trimmed = benefit.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
return defaults.defaultBenefits[index] || trimmed;
|
||||||
|
}
|
||||||
|
return trimmed;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTranslatedShortDescription(
|
||||||
|
description: string | undefined,
|
||||||
|
locale: Locale
|
||||||
|
): string {
|
||||||
|
if (description && description.trim()) {
|
||||||
|
return description.split('.')[0] + '.';
|
||||||
|
}
|
||||||
|
const defaults = PRODUCT_TEXT[locale] || PRODUCT_TEXT.en;
|
||||||
|
return defaults.defaultShortDescription;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user