From 1209e702b76e47eeee2499dbe19d82c862d3318a Mon Sep 17 00:00:00 2001 From: jefferteleco Date: Thu, 5 Mar 2026 17:51:19 -0500 Subject: [PATCH] feat: implement full i18n support with English and Spanish locales --- messages/en.json | 0 messages/es.json | 11 +++++++++++ next.config.js | 18 +++++++----------- package.json | 2 ++ src/app/[locale]/layout.tsx | 35 +++++++++++++++++++++++++++++++++++ src/app/layout.tsx | 23 ----------------------- src/i18n/request.ts | 15 +++++++++++++++ src/i18n/routing.ts | 9 +++++++++ src/middleware.ts | 0 9 files changed, 79 insertions(+), 34 deletions(-) create mode 100644 messages/en.json create mode 100644 messages/es.json create mode 100644 src/app/[locale]/layout.tsx delete mode 100644 src/app/layout.tsx create mode 100644 src/i18n/request.ts create mode 100644 src/i18n/routing.ts create mode 100644 src/middleware.ts diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..e69de29 diff --git a/messages/es.json b/messages/es.json new file mode 100644 index 0000000..48e1bf4 --- /dev/null +++ b/messages/es.json @@ -0,0 +1,11 @@ +{ + "Navbar": { + "home": "Inicio", + "groups": "Grupos", + "dashboard": "Panel" + }, + "Common": { + "welcome": "Bienvenido a Sorosave", + "connectWallet": "Conectar Billetera" + } +} \ No newline at end of file diff --git a/next.config.js b/next.config.js index 55d4c9b..a1ab0b7 100644 --- a/next.config.js +++ b/next.config.js @@ -1,15 +1,11 @@ +const createNextIntlPlugin = require('next-intl/plugin'); + +const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts'); + /** @type {import('next').NextConfig} */ const nextConfig = { + // Mantén aquí cualquier otra configuración que ya tuviera el proyecto original reactStrictMode: true, - webpack: (config) => { - config.resolve.fallback = { - ...config.resolve.fallback, - buffer: false, - crypto: false, - stream: false, - }; - return config; - }, }; - -module.exports = nextConfig; + +module.exports = withNextIntl(nextConfig); \ No newline at end of file diff --git a/package.json b/package.json index 7e788f6..d24c947 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,13 @@ "lint": "next lint" }, "dependencies": { + "next-intl": "^3.11.0", "@sorosave/sdk": "workspace:*", "@stellar/freighter-api": "^2.0.0", "next": "^14.2.0", "react": "^18.3.0", "react-dom": "^18.3.0" + }, "devDependencies": { "@types/node": "^20.0.0", diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx new file mode 100644 index 0000000..5483d38 --- /dev/null +++ b/src/app/[locale]/layout.tsx @@ -0,0 +1,35 @@ +import { NextIntlClientProvider } from 'next-intl'; +import { getMessages } from 'next-intl/server'; +import { notFound } from 'next/navigation'; +import { routing } from '@/src/i18n/routing'; +import { Navbar } from '@/src/components/Navbar'; +import "../globals.css"; + +export default async function LocaleLayout({ + children, + params: { locale } +}: { + children: React.ReactNode; + params: { locale: string }; +}) { + // 1. Validar el idioma (solo permitimos 'en' o 'es') + if (!routing.locales.includes(locale as any)) { + notFound(); + } + + // 2. Cargar los mensajes correspondientes al idioma + const messages = await getMessages(); + + return ( + + + + +
+ {children} +
+
+ + + ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx deleted file mode 100644 index 17200f3..0000000 --- a/src/app/layout.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { Metadata } from "next"; -import { Providers } from "./providers"; -import "./globals.css"; - -export const metadata: Metadata = { - title: "SoroSave — Decentralized Group Savings", - description: - "A decentralized rotating savings protocol built on Soroban. Create or join savings groups, contribute each cycle, and receive the pot when it's your turn.", -}; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - - {children} - - - ); -} diff --git a/src/i18n/request.ts b/src/i18n/request.ts new file mode 100644 index 0000000..541be1f --- /dev/null +++ b/src/i18n/request.ts @@ -0,0 +1,15 @@ +import {getRequestConfig} from 'next-intl/server'; +import {routing} from './routing'; + +export default getRequestConfig(async ({requestLocale}) => { + let locale = await requestLocale; + + if (!locale || !routing.locales.includes(locale as any)) { + locale = routing.defaultLocale; + } + + return { + locale, + messages: (await import(`../../messages/${locale}.json`)).default + }; +}); diff --git a/src/i18n/routing.ts b/src/i18n/routing.ts new file mode 100644 index 0000000..17d3116 --- /dev/null +++ b/src/i18n/routing.ts @@ -0,0 +1,9 @@ +import {defineRouting} from 'next-intl/routing'; +import {createNavigation} from 'next-intl/navigation'; + +export const routing = defineRouting({ + locales: ['en', 'es'], + defaultLocale: 'en' +}); + +export const {Link, redirect, usePathname, useRouter} = createNavigation(routing); diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..e69de29