feat: add internationalization support with Spanish and English translations

This commit is contained in:
jpiere-vailos
2025-03-17 13:12:00 -05:00
parent 2ac461968b
commit 4368b5ce31
6 changed files with 97 additions and 12 deletions
+18 -9
View File
@@ -9,14 +9,23 @@ import tailwindcss from "@tailwindcss/vite";
// https://astro.build/config
export default defineConfig({
integrations: [svelte()],
output: "server",
integrations: [svelte()],
output: "server",
adapter: node({
mode: "standalone",
}),
adapter: node({
mode: "standalone",
}),
vite: {
plugins: [tailwindcss()],
},
});
vite: {
plugins: [tailwindcss()],
},
i18n: {
locales: ["es", "en"],
defaultLocale: "es",
routing: {
prefixDefaultLocale: false,
redirectToDefaultLocale: true,
},
},
});
+21
View File
@@ -0,0 +1,21 @@
export const languagesList = {
es: "Español",
en: "English",
};
export const labels = {
es: {
metadata: {
title: "Inicio",
description: "Página de inicio",
},
title: "Hola!",
},
en: {
metadata: {
title: "Home",
description: "Home page",
},
title: "Hello!",
},
};
+33
View File
@@ -0,0 +1,33 @@
import { labels } from "./ui";
const defaultLang = "es";
/**
* Retrieves a nested value from an object using a dot-separated path.
*
* @param {Record<string, unknown>} obj - The object to search within.
* @param {string} path - The dot-separated path to the desired value.
* @returns {string | undefined} - The retrieved value or `undefined` if not found.
*/
function getNestedValue(obj: Record<string, unknown>, path: string): string | undefined {
return path
.split(".")
.reduce<unknown>(
(acc, part) =>
acc && typeof acc === "object" ? (acc as Record<string, unknown>)[part] : undefined,
obj,
) as string | undefined;
}
/**
* Hook to retrieve a translation function based on the selected language.
*
* @template T - The key of the language within the `labels` object.
* @param {T} lang - The language code to use for translations.
* @returns {(key: string) => string} - A function that takes a translation key and returns the translated string.
*/
export function useTranslations<T extends keyof typeof labels>(lang: T) {
return (key: string): string => {
return getNestedValue(labels[lang], key) ?? getNestedValue(labels[defaultLang], key) ?? key;
};
}
+2 -1
View File
@@ -6,10 +6,11 @@ export interface Props {
description: string;
}
const { title, description } = Astro.props;
const currentLang = Astro.currentLocale || "es";
---
<!doctype html>
<html lang="en">
<html lang={currentLang}>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+14
View File
@@ -0,0 +1,14 @@
---
import type { languagesList } from "../../i18n/ui";
import { useTranslations } from "../../i18n/utils";
import Layout from "../../layouts/Layout.astro";
const currentLang = Astro.currentLocale || "es";
const translateLabels = useTranslations(currentLang as keyof typeof languagesList);
---
<Layout
title={translateLabels("metadata.title")}
description={translateLabels("metadata.description")}
>
<div>{translateLabels("title")}</div>
</Layout>
+9 -2
View File
@@ -1,7 +1,14 @@
---
import type { languagesList } from "../i18n/ui";
import { useTranslations } from "../i18n/utils";
import Layout from "../layouts/Layout.astro";
const currentLang = Astro.currentLocale || "es";
const translateLabels = useTranslations(currentLang as keyof typeof languagesList);
---
<Layout title="Home" description="This is the home page">
<div>Hello!</div>
<Layout
title={translateLabels("metadata.title")}
description={translateLabels("metadata.description")}
>
<div>{translateLabels("title")}</div>
</Layout>