From 1641cf48cd6a9a1b8a97dee4babb5f034063ae59 Mon Sep 17 00:00:00 2001 From: racuna Date: Tue, 12 Mar 2024 07:34:49 -0300 Subject: [PATCH 1/2] feat: i18n --- astro.config.mjs | 12 ++- src/components/AboutMe.astro | 28 ++----- src/components/Experience.astro | 37 +++++---- src/components/ExperienceItem.astro | 5 +- src/components/Footer.astro | 12 ++- src/components/Header.astro | 41 ++++++---- src/components/Hero.astro | 17 +++-- src/components/LanguagePicker.astro | 20 +++++ src/components/Projects.astro | 89 ++++++++++++---------- src/components/ThemeToggle.astro | 110 ++++++++++++++------------- src/i18n/ui.ts | 114 ++++++++++++++++++++++++++++ src/i18n/utils.ts | 21 +++++ src/layouts/Layout.astro | 4 +- src/pages/en/index.astro | 62 +++++++++++++++ src/pages/index.astro | 16 ++-- 15 files changed, 418 insertions(+), 170 deletions(-) create mode 100644 src/components/LanguagePicker.astro create mode 100644 src/i18n/ui.ts create mode 100644 src/i18n/utils.ts create mode 100644 src/pages/en/index.astro diff --git a/astro.config.mjs b/astro.config.mjs index 07bf52f5..d2754aba 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -6,5 +6,15 @@ import robotsTxt from "astro-robots-txt" // https://astro.build/config export default defineConfig({ integrations: [tailwind(), robotsTxt()], - site: 'https://porfolio.dev/' + site: 'https://porfolio.dev/', + i18n: { + defaultLocale: 'es', + locales: ['es', 'en'], + routing: { + prefixDefaultLocale: false + }, + fallback: { + en: 'en' + } + } }) diff --git a/src/components/AboutMe.astro b/src/components/AboutMe.astro index 1d94ed15..d2ee6c3f 100644 --- a/src/components/AboutMe.astro +++ b/src/components/AboutMe.astro @@ -1,33 +1,17 @@ --- +import { getLangFromUrl, useTranslations } from "@/i18n/utils" + +const lang = getLangFromUrl(Astro.url) +const t = useTranslations(lang); + const personalImageAlt = "Miguel Ángel" ---
-

- Me llamo Miguel Ángel pero mis amigos me llaman midu. Empecé en la - programación con un Amstrad, tenía 10 años. Actualmente estoy liderando equipos de desarrollo en multinacionales. -

- -

- Algunos de mis éxitos incluyen colaborar con Mozilla para el desarrollo de las primeras apps en su - sistema FirefoxOS. Aunque hoy está desaparecido fue un gran avance en el mundo del - desarrollo web. -

- -

- Como creador de contenido, cuento con el canal de habla hispana más visto del mundo en la - categoría de Software & Game Development en Twitch. Mi objetivo es mejorar la empleabilidad de la comunidad hispana y el - acceso a contenido de calidad. -

{personalImageAlt} diff --git a/src/components/Experience.astro b/src/components/Experience.astro index 74442a54..e433a8b7 100644 --- a/src/components/Experience.astro +++ b/src/components/Experience.astro @@ -1,29 +1,28 @@ --- import ExperienceItem from "./ExperienceItem.astro" -const EXPERIENCIE = [ - { - date: "Actualmente...", - title: "Creador de Contenido", - company: "Twitch", - description: - "Divulgo sobre programación y desarrollo web en diferentes plataformas. Galardonado como mejor creador de contenido de habla no-inglesa en 2022 y mejor comunidad en 2023 por GitHub.", - link: "https://twitch.tv/midudev", - }, - { - date: "Septiembre 2022", - title: "Principal Frontend Engineer", - company: "Adevinta Spain", - description: - "Responsable de la plataforma, componentes y utilidades para la creación y desarrollo de aplicaciones web. Mejora de un 30% en la entrega de software. Implantación de medidas de integración continua y despliegue con A/B testing en más de 15 equipos.", - }, -] +import { getLangFromUrl, useTranslations } from "@/i18n/utils" + +type tLang = (str: any) => any; + +const lang = getLangFromUrl(Astro.url) +const t:tLang = useTranslations(lang); + +type Experience = { + title: string; + company: string; + date: string; + description: string; + link: string; +} + +const EXP: Experience[] = t('exp'); ---
    { - EXPERIENCIE.map((experiencie) => ( + EXP.map((experience) => (
  1. - +
  2. )) } diff --git a/src/components/ExperienceItem.astro b/src/components/ExperienceItem.astro index 786e1981..5db482d3 100644 --- a/src/components/ExperienceItem.astro +++ b/src/components/ExperienceItem.astro @@ -6,10 +6,11 @@ interface Props { company: string description: string link?: string + linkLabel?: string date: string } -const { title, company, description, link, date } = Astro.props +const { title, company, description, link, linkLabel, date } = Astro.props ---
    - Saber más{" "} + {linkLabel} © {currentYear} - midudev. Casi - todos los derechos reservados + midudev. + {t('footer.rights')} diff --git a/src/components/Header.astro b/src/components/Header.astro index 7426133d..316314d1 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -1,28 +1,36 @@ --- import ThemeToggle from "./ThemeToggle.astro" +import { getLangFromUrl, useTranslations } from '../i18n/utils'; +import LanguagePicker from "./LanguagePicker.astro"; + +const lang = getLangFromUrl(Astro.url) +const t = useTranslations(lang); + +const { currentLocale } = Astro const navItems = [ { - title: "Experiencia", + title: t('nav.home'), label: "experiencia", - url: "/#experiencia", + url: currentLocale === 'en' ? '/en#experiencia' : '/#experiencia', }, { - title: "Proyectos", + title: t('nav.projects'), label: "proyectos", - url: "/#proyectos", + url: currentLocale === 'en' ? '/en#proyectos' : '/#proyectos', }, { - title: "Sobre mí", + title: t('nav.about'), label: "sobre-mi", - url: "/#sobre-mi", + url: currentLocale === 'en' ? '/en#sobre-mi' : '/#sobre-mi', }, { - title: "Contacto", + title: t('nav.contact'), label: "contacto", url: "mailto:miduga@gmail.com", }, ] + ---
    - { - navItems.map((link) => ( - - {link.title} - + { + navItems.map((link) => ( + + {link.title} + )) } +
    diff --git a/src/components/Hero.astro b/src/components/Hero.astro index f96d5a89..0f2d6e7e 100644 --- a/src/components/Hero.astro +++ b/src/components/Hero.astro @@ -4,6 +4,10 @@ import Badge from "@/components/Badge.astro" import LinkedInIcon from "@/components/icons/LinkedIn.astro" import MailIcon from "@/components/icons/Mail.astro" import SocialPill from "@/components/SocialPill.astro" +import { getLangFromUrl, useTranslations } from "@/i18n/utils" + +const lang = getLangFromUrl(Astro.url) +const t = useTranslations(lang); ---
    @@ -19,30 +23,27 @@ import SocialPill from "@/components/SocialPill.astro" rel="noopener" class="flex items-center transition md:justify-center md:hover:scale-105" > - Disponible para trabajar + {t('hero.badge')}

    - Hey, soy midudev + {t('hero.title')}

    - +15 años de experiencia. Ingeniero de Software y Creador de Contenido sobre Programación de Barcelona, España 🇪🇸. Especializado en el desarrollo de aplicaciones web - únicas.

    diff --git a/src/components/LanguagePicker.astro b/src/components/LanguagePicker.astro new file mode 100644 index 00000000..456537d6 --- /dev/null +++ b/src/components/LanguagePicker.astro @@ -0,0 +1,20 @@ +--- +import { languages } from '@/i18n/ui'; +import { getLangFromUrl, useTranslatedPath } from '@/i18n/utils'; + +const lang = getLangFromUrl(Astro.url); +const translatePath = useTranslatedPath(lang); +--- + +
    + { + Object.entries(languages).map(([langPrefix, label]) => { + if (langPrefix == lang) return <> + return ( + {label}) + }) + } +
    \ No newline at end of file diff --git a/src/components/Projects.astro b/src/components/Projects.astro index 8b3d7893..80588aa7 100644 --- a/src/components/Projects.astro +++ b/src/components/Projects.astro @@ -4,38 +4,47 @@ import NextJS from "./icons/NextJS.astro" import Tailwind from "./icons/Tailwind.astro" import Link from "./icons/Link.astro" import LinkButton from "./LinkButton.astro" +import { getLangFromUrl, useTranslations } from "@/i18n/utils" -const TAGS = { - NEXT: { - name: "Next.js", - class: "bg-black text-white", +type tLang = (str: any) => any; + +const lang = getLangFromUrl(Astro.url) +const t:tLang = useTranslations(lang); + + +type TagType = { + name: string; + class: string; + icon: (_props: Record) => any; +}; + +type TagsType = { + [key: string]: TagType; +}; + +const TAGS: TagsType = { + nextjs: { + name: 'Next.js', + class: 'bg-[#000] text-white dark:bg-white dark:text-[#000]', icon: NextJS, }, - TAILWIND: { - name: "Tailwind CSS", - class: "bg-[#003159] text-white", + tailwindcss: { + name: 'Tailwind CSS', + class: 'bg-[#06b6d4] text-white', icon: Tailwind, }, +}; + +interface ProjectType { + image: string; + imageAlt: string; + title: string; + description: string; + tags: string[]; + link?: string; + github?: string; } -const PROJECTS = [ - { - title: "SVGL - A beautiful library with SVG logos", - description: - "Biblioteca de logos SVG de las marcas más populares. +10k visitas al mes. +2K svgs descargados. Creado desde cero con Next.js, React y Tailwind CSS.", - link: "https://svgl.vercel.app/", - github: "https://github.com/pheralb/svgl", - image: "/projects/svgl.webp", - tags: [TAGS.NEXT, TAGS.TAILWIND], - }, - { - title: "AdventJS - Retos de programación con JavaScript y TypeScript", - description: - "Plataforma gratuita con retos de programación. Más de 1 millón de visitas en un mes. +50K retos completados. Creada desde cero con Next.js, React y Tailwind CSS.", - link: "https://adventjs.dev", - image: "/projects/adventjs.webp", - tags: [TAGS.NEXT, TAGS.TAILWIND], - }, -] +const PROJECTS:ProjectType[] = t('projects'); ---
    @@ -53,18 +62,22 @@ const PROJECTS = [ {title}
    -
      - {tags.map((tag) => ( -
    • - - - {tag.name} - -
    • - ))} -
    +
      + {tags.map((item) => { + const tag:TagType = TAGS[item]; + if(tag) { + return ( +
    • + + {tag.name} + +
    • + ) + } + })} +
    {description}