diff --git a/messages/ar.json b/messages/ar.json index 2ffd446..29919f6 100644 --- a/messages/ar.json +++ b/messages/ar.json @@ -2,6 +2,7 @@ "Common": { "copyAddress": "نسخ {label}", "copied": "تم النسخ", + "viewInvestment": "عرض استثمارك", "viewOnExplorer": "عرض {label} على Stellar Expert", "shareLink": "مشاركة الرابط" }, @@ -21,12 +22,14 @@ "testnet": "شبكة الاختبار (نشطة)", "networkStatus": "الشبكة: شبكة الاختبار نشطة", "portfolio": "محفظتك", + "watchlist": "قائمة المراقبة", "switchToDark": "التبديل إلى الوضع الداكن", "switchToLight": "التبديل إلى الوضع الفاتح", "language": "اللغة", "account": "الحساب", "copyAddress": "نسخ العنوان", "copied": "تم النسخ", + "viewInvestment": "عرض استثمارك", "viewOnExplorer": "عرض على Stellar Expert", "shareLink": "مشاركة رابط الإحالة", "disconnect": "قطع الاتصال", @@ -110,9 +113,9 @@ "Explore": { "title": "أين يعمل المجمع", "sub": "كل مشروع يموله المجمع، مع درجات مؤكدة من Oracle. استكشف بحرية — توصيل المحفظة يأتي لاحقاً.", - "filterAll": "الكل", + "searchLabel": "ابحث في المشاريع", "searchPlaceholder": "ابحث بالاسم أو الموقع", - "searchAriaLabel": "ابحث في المشاريع بالاسم أو الموقع", + "filterAll": "الكل", "countSorted": "{count} مشاريع", "cardFundedFromPool": "ممول من المجمع", "cardVerifiedAgo": "تم التحقق قبل {ago}", @@ -121,6 +124,21 @@ "loadMore": "عرض {count} المزيد", "showingCount": "عرض {shown} من {total} مشاريع" }, + "Watchlist": { + "title": "قائمة المراقبة الخاصة بك", + "sub": "السندات التي تتابعها. حفظ سند لا يعني الاستثمار — بل يبقيه في متناول اليد ويشير إلى وقت فتحه للتمويل.", + "cardFundedFromPool": "ممول من المجمع", + "emptyTitle": "لا شيء محفوظ حتى الآن", + "emptySub": "افتح سنداً من استكشف وانقر على النجمة لإضافته هنا. سنشير هنا عندما يكون السند المحفوظ مفتوحاً للتمويل.", + "added": "تمت الإضافة إلى قائمة المراقبة", + "removed": "تمت الإزالة من قائمة المراقبة", + "saveLabel": "إضافة {name} إلى قائمة المراقبة", + "removeLabel": "إزالة {name} من قائمة المراقبة", + "availableBanner": "{count, plural, one {سند واحد متابع مفتوح للتمويل الآن.} other {# سندات متابعة مفتوحة للتمويل الآن.}}", + "statusOpen": "مفتوح للتمويل", + "statusUpcoming": "غير متاح بعد", + "notYetAvailable": "سنشير هنا بمجرد فتحه." + }, "Deposit": { "stepAmount": "المبلغ", "stepReview": "مراجعة", @@ -152,6 +170,7 @@ "pendingTx": "tx a91f…3c0d · عرض على Stellar Expert ↗", "successH1": "مرحباً بك في المجمع", "successBody": "حصلت على {shares} HBS وتدعم الآن {count} مشاريع مؤكدة.", + "viewInvestment": "عرض استثمارك", "viewExpert": "عرض على Stellar Expert", "goPortfolio": "انتقل إلى المحفظة" }, @@ -168,6 +187,11 @@ "impactBody": "حصتك تساعد في تمويل {count} مشاريع مؤكدة في 6 دول.", "projectsBacked": "المشاريع المدعومة", "weightedGreen": "الدرجة الخضراء المرجحة", + "riskScore": "درجة مخاطر المحفظة", + "riskTierConservative": "محافظ", + "riskTierModerate": "معتدل", + "riskTierAggressive": "عالي المخاطر", + "riskCaption": "بناءً على مزيج تصنيفات السندات في حيازاتك.", "activityTitle": "النشاط", "activityNote": "كل إدخال → Stellar Expert" }, diff --git a/messages/es.json b/messages/es.json index a61f5de..01d711b 100644 --- a/messages/es.json +++ b/messages/es.json @@ -2,6 +2,7 @@ "Common": { "copyAddress": "Copy {label}", "copied": "Copied", + "viewInvestment": "Ver tu inversión", "viewOnExplorer": "View {label} on Stellar Expert", "referralProgramShareLink": "Enlace para compartir el programa de referidos" }, @@ -14,12 +15,14 @@ "testnet": "Testnet (active)", "networkStatus": "Network: Testnet active", "portfolio": "Your portfolio", + "watchlist": "Lista de seguimiento", "switchToDark": "Switch to dark", "switchToLight": "Switch to light", "language": "Language", "account": "Account", "copyAddress": "Copy address", "copied": "Copied", + "viewInvestment": "Ver tu inversión", "viewOnExplorer": "View on Stellar Expert", "disconnect": "Disconnect", "disconnectConfirm": "Yes, disconnect", @@ -103,8 +106,8 @@ "Explore": { "title": "Where the pool works", "sub": "Every project the pool funds, with oracle-verified scores. Explore freely — connecting a wallet comes later.", + "searchLabel": "Buscar proyectos", "searchPlaceholder": "Search by name or location", - "searchAriaLabel": "Search projects", "filterAll": "All", "countSorted": "{count} projects", "cardFundedFromPool": "Funded from the pool", @@ -114,6 +117,21 @@ "loadMore": "Show {count} more", "showingCount": "Showing {shown} of {total} projects" }, + "Watchlist": { + "title": "Tu lista de seguimiento", + "sub": "Los bonos que sigues. Guardar uno no invierte — lo mantiene a mano y te avisa cuando se abre a financiación.", + "cardFundedFromPool": "Financiado por el fondo", + "emptyTitle": "Nada guardado por ahora", + "emptySub": "Abre un bono desde Explorar y toca la estrella para añadirlo aquí. Te avisaremos cuando un bono guardado esté abierto a financiación.", + "added": "Añadido a la lista de seguimiento", + "removed": "Eliminado de la lista de seguimiento", + "saveLabel": "Añadir {name} a la lista de seguimiento", + "removeLabel": "Eliminar {name} de la lista de seguimiento", + "availableBanner": "{count, plural, one {# bono seguido está abierto a financiación ahora mismo.} other {# bonos seguidos están abiertos a financiación ahora mismo.}}", + "statusOpen": "Abierto a financiación", + "statusUpcoming": "Aún no disponible", + "notYetAvailable": "Te avisaremos aquí en cuanto se abra." + }, "Deposit": { "stepAmount": "Amount", "stepReview": "Review", @@ -145,6 +163,7 @@ "pendingTx": "tx a91f…3c0d · view on Stellar Expert ↗", "successH1": "Welcome to the pool", "successBody": "You received {shares} HBS and now back {count} verified projects.", + "viewInvestment": "Ver tu inversión", "viewExpert": "View on Stellar Expert", "goPortfolio": "Go to portfolio" }, @@ -161,6 +180,11 @@ "impactBody": "Your stake helps fund {count} verified projects across 6 countries.", "projectsBacked": "Projects backed", "weightedGreen": "Weighted green score", + "riskScore": "Puntuación de riesgo de la cartera", + "riskTierConservative": "Conservador", + "riskTierModerate": "Moderado", + "riskTierAggressive": "Agresivo", + "riskCaption": "Basado en la combinación de calificaciones de bonos en sus tenencias.", "activityTitle": "Activity", "activityNote": "every entry → Stellar Expert" }, diff --git a/messages/fr.json b/messages/fr.json index 2fcf464..7e58ea7 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -2,6 +2,7 @@ "Common": { "copyAddress": "Copier {label}", "copied": "Copié", + "viewInvestment": "Voir votre investissement", "referralShareLink": "Lien de parrainage", "viewOnExplorer": "Voir {label} sur Stellar Expert" }, @@ -12,7 +13,7 @@ "creator": "Créateurs", "connect": "Se connecter", "testnet": "Testnet (actif)", - "networkStatus": "Réseau : Testnet actif", + "networkStatus": "Réseau : Testnet actif", "portfolio": "Votre portefeuille", "switchToDark": "Passer en sombre", "switchToLight": "Passer en clair", @@ -21,6 +22,7 @@ "watchlist": "Liste de suivi", "copyAddress": "Copier l'adresse", "copied": "Copié", + "viewInvestment": "Voir votre investissement", "referralShareLink": "Lien de parrainage", "viewOnExplorer": "Voir sur Stellar Expert", "disconnect": "Se déconnecter", @@ -161,6 +163,7 @@ "pendingTx": "tx a91f…3c0d · voir sur Stellar Expert ↗", "successH1": "Bienvenue dans le pool", "successBody": "Vous avez reçu {shares} HBS et soutenez désormais {count} projets vérifiés.", + "viewInvestment": "Voir votre investissement", "viewExpert": "Voir sur Stellar Expert", "goPortfolio": "Aller au portefeuille" }, @@ -177,6 +180,11 @@ "impactBody": "Votre participation aide à financer {count} projets vérifiés dans 6 pays.", "projectsBacked": "Projets soutenus", "weightedGreen": "Score vert pondéré", + "riskScore": "Score de risque du portefeuille", + "riskTierConservative": "Conservateur", + "riskTierModerate": "Modéré", + "riskTierAggressive": "Agressif", + "riskCaption": "Basé sur la répartition des notations d'obligations dans vos avoirs.", "activityTitle": "Activité", "activityNote": "chaque entrée → Stellar Expert" }, @@ -223,10 +231,6 @@ "rejectionReason": "Raison", "actionRevoke": "Révoquer", "revokeConfirm": "Oui, révoquer", - "revokeConfirmBody": "Cette action révoque l'accès du créateur au registre. Voulez-vous continuer ?", - "revokeCancel": "Annuler", - "revokeToast": "Créateur révoqué", - "revokeUndo": "Annuler"voquer", "revokeConfirmBody": "La révocation retirera immédiatement l'accès de ce créateur. Vous pourrez annuler cette action.", "revokeCancel": "Annuler", "revokeToast": "Créateur révoqué", diff --git a/next.config.ts b/next.config.ts index 102f4ab..4a1a39c 100644 --- a/next.config.ts +++ b/next.config.ts @@ -3,14 +3,25 @@ import createNextIntlPlugin from 'next-intl/plugin' const nextConfig: NextConfig = { reactStrictMode: true, - // Turbopack (dev) handles code-splitting automatically — no webpack override needed. - // The three/react-three chunk is naturally split by Turbopack's dependency graph. - // - // If you ever need to opt specific packages into a custom Turbopack rule, use: - // experimental: { turbo: { rules: { ... } } } - // Reference: https://nextjs.org/docs/app/api-reference/next-config-js/turbopack + webpack(config) { + const splitChunks = config.optimization.splitChunks || {} + config.optimization.splitChunks = { + ...splitChunks, + cacheGroups: { + ...(splitChunks.cacheGroups || {}), + three: { + test: /[\\/]node_modules[\\/](?:three|@react-three\/fiber)(?:[\\/]|$)/, + name: 'three', + chunks: 'async', + priority: 40, + enforce: true, + }, + }, + } + return config + }, } const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts') -export default withNextIntl(nextConfig) +export default withNextIntl(nextConfig) \ No newline at end of file diff --git a/src/__tests__/catalog-parity.test.ts b/src/__tests__/catalog-parity.test.ts index 53c262b..3fd8a23 100644 --- a/src/__tests__/catalog-parity.test.ts +++ b/src/__tests__/catalog-parity.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest' import en from '../../messages/en.json' import fr from '../../messages/fr.json' import es from '../../messages/es.json' +import ar from '../../messages/ar.json' function getLeafKeys(obj: Record, prefix = ''): string[] { const keys: string[] = [] @@ -21,6 +22,7 @@ describe('Message catalog parity', () => { it.each([ ['fr.json', fr], ['es.json', es], + ['ar.json', ar], ] as const)('en.json and %s have identical key sets', (_name, catalog) => { const enKeys = getLeafKeys(en).sort() const catalogKeys = getLeafKeys(catalog).sort() diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3815ed6..455ea74 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -8,8 +8,8 @@ import { type Locale, RTL_LOCALES } from '../i18n/request' import { THEME_SCRIPT } from '../theme/themeScript' import '../styles/index.css' -const TopBar = dynamic(() => import('../shell/TopBar')) -const Footer = dynamic(() => import('../shell/Footer')) +const TopBar = dynamic(() => import('../shell/TopBar').then((m) => m.TopBar)) +const Footer = dynamic(() => import('../shell/Footer').then((m) => m.Footer)) export const metadata: Metadata = { title: 'Heliobond — sunlight made financial', @@ -66,7 +66,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo suppressHydrationWarning > -