feat: CMS com limites de caracteres, traduções auto e painel de notificações

This commit is contained in:
Erik
2025-11-27 12:05:23 -03:00
parent ea0c4ac5a6
commit 6e32ffdc95
40 changed files with 3665 additions and 278 deletions

View File

@@ -0,0 +1,85 @@
'use client';
import React, { createContext, useContext, useEffect, useState } from 'react';
import { useRouter, usePathname } from 'next/navigation';
import { type Locale, locales, defaultLocale, getNestedValue } from '@/lib/i18n';
// Importar traduções estaticamente
import ptTranslations from '@/locales/pt.json';
import enTranslations from '@/locales/en.json';
import esTranslations from '@/locales/es.json';
const translations: Record<Locale, typeof ptTranslations> = {
pt: ptTranslations,
en: enTranslations,
es: esTranslations,
};
interface LocaleContextType {
locale: Locale;
setLocale: (locale: Locale) => void;
t: (key: string) => string;
translations: typeof ptTranslations;
}
const LocaleContext = createContext<LocaleContextType | undefined>(undefined);
interface LocaleProviderProps {
children: React.ReactNode;
locale: Locale;
}
export function LocaleProvider({ children, locale: initialLocale }: LocaleProviderProps) {
const [locale, setLocaleState] = useState<Locale>(initialLocale);
const router = useRouter();
const pathname = usePathname();
// Função para trocar idioma (navega para nova URL)
const setLocale = (newLocale: Locale) => {
// Salvar preferência no cookie
document.cookie = `locale=${newLocale};path=/;max-age=31536000`; // 1 ano
// Remover locale atual do pathname
let newPathname = pathname;
// Verificar se pathname começa com locale
for (const loc of locales) {
if (pathname.startsWith(`/${loc}/`) || pathname === `/${loc}`) {
newPathname = pathname.replace(`/${loc}`, '') || '/';
break;
}
}
// Construir nova URL
if (newLocale === defaultLocale) {
// Português não tem prefixo
router.push(newPathname);
} else {
router.push(`/${newLocale}${newPathname === '/' ? '' : newPathname}`);
}
setLocaleState(newLocale);
};
// Função t() para obter tradução
const t = (key: string): string => {
return getNestedValue(translations[locale] as Record<string, unknown>, key);
};
return (
<LocaleContext.Provider value={{ locale, setLocale, t, translations: translations[locale] }}>
{children}
</LocaleContext.Provider>
);
}
export function useLocale() {
const context = useContext(LocaleContext);
if (context === undefined) {
throw new Error('useLocale must be used within a LocaleProvider');
}
return context;
}
// Alias para compatibilidade
export const useLanguage = useLocale;