feat: Implement internationalization
This commit is contained in:
@@ -21,7 +21,7 @@ const CurrencySelector = () => {
|
|||||||
<SelectTrigger className="w-[180px]">
|
<SelectTrigger className="w-[180px]">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent className="bg-white z-[100]">
|
||||||
{currencies.map((curr) => (
|
{currencies.map((curr) => (
|
||||||
<SelectItem key={curr.value} value={curr.value}>
|
<SelectItem key={curr.value} value={curr.value}>
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex items-center gap-2">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useAuth } from '@/contexts/AuthContext';
|
|||||||
import { useLanguage } from '@/contexts/LanguageContext';
|
import { useLanguage } from '@/contexts/LanguageContext';
|
||||||
import DashboardStyles from '@/components/layouts/DashboardStyles';
|
import DashboardStyles from '@/components/layouts/DashboardStyles';
|
||||||
import CurrencySelector from '@/components/CurrencySelector';
|
import CurrencySelector from '@/components/CurrencySelector';
|
||||||
|
import LanguageSelector from '@/components/LanguageSelector';
|
||||||
import {
|
import {
|
||||||
Home,
|
Home,
|
||||||
Plus,
|
Plus,
|
||||||
@@ -480,6 +481,9 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
|
|
||||||
{/* Right Side */}
|
{/* Right Side */}
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
|
{/* Language Selector */}
|
||||||
|
<LanguageSelector />
|
||||||
|
|
||||||
{/* Currency Selector */}
|
{/* Currency Selector */}
|
||||||
<CurrencySelector />
|
<CurrencySelector />
|
||||||
|
|
||||||
|
|||||||
38
src/components/LanguageSelector.tsx
Normal file
38
src/components/LanguageSelector.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
|
import { useLanguage } from '@/contexts/LanguageContext';
|
||||||
|
import { Globe } from 'lucide-react';
|
||||||
|
|
||||||
|
type Language = 'en' | 'es' | 'fr';
|
||||||
|
|
||||||
|
const languages: { value: Language; label: string; flag: string }[] = [
|
||||||
|
{ value: 'en', label: 'English', flag: '🇺🇸' },
|
||||||
|
{ value: 'es', label: 'Español', flag: '🇪🇸' },
|
||||||
|
{ value: 'fr', label: 'Français', flag: '🇫🇷' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const LanguageSelector = () => {
|
||||||
|
const { language, setLanguage } = useLanguage();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Globe className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<Select value={language} onValueChange={(value) => setLanguage(value as Language)}>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="bg-white z-[100]">
|
||||||
|
{languages.map((lang) => (
|
||||||
|
<SelectItem key={lang.value} value={lang.value}>
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<span>{lang.flag}</span>
|
||||||
|
<span>{lang.label}</span>
|
||||||
|
</span>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LanguageSelector;
|
||||||
@@ -15,7 +15,7 @@ const LanguageContext = createContext<LanguageContextType | undefined>(undefined
|
|||||||
export const LanguageProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
export const LanguageProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
const [language, setLanguageState] = useState<Language>(() => {
|
const [language, setLanguageState] = useState<Language>(() => {
|
||||||
const saved = localStorage.getItem('karibeo-language');
|
const saved = localStorage.getItem('karibeo-language');
|
||||||
return (saved as Language) || 'es';
|
return (saved as Language) || 'en';
|
||||||
});
|
});
|
||||||
|
|
||||||
const setLanguage = (lang: Language) => {
|
const setLanguage = (lang: Language) => {
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ export const translations = {
|
|||||||
delete: 'Eliminar',
|
delete: 'Eliminar',
|
||||||
edit: 'Editar',
|
edit: 'Editar',
|
||||||
view: 'Ver',
|
view: 'Ver',
|
||||||
|
search: 'Buscar',
|
||||||
|
add: 'Agregar',
|
||||||
|
create: 'Crear',
|
||||||
|
update: 'Actualizar',
|
||||||
|
|
||||||
// Process section
|
// Process section
|
||||||
processTitle: 'Encuentra Tu Lugar Soñado De La Mejor Manera',
|
processTitle: 'Encuentra Tu Lugar Soñado De La Mejor Manera',
|
||||||
@@ -82,7 +86,98 @@ export const translations = {
|
|||||||
// Explore section
|
// Explore section
|
||||||
topRegions: 'Principales Regiones',
|
topRegions: 'Principales Regiones',
|
||||||
exploreCities: 'Explorar Ciudades',
|
exploreCities: 'Explorar Ciudades',
|
||||||
exploreMore: 'Explorar más'
|
exploreMore: 'Explorar más',
|
||||||
|
|
||||||
|
// Commerce Module
|
||||||
|
commerce: 'Comercios',
|
||||||
|
myStore: 'Mi Comercio',
|
||||||
|
posTerminal: 'POS Ventas',
|
||||||
|
inventory: 'Inventario',
|
||||||
|
customers: 'Clientes',
|
||||||
|
staff: 'Personal',
|
||||||
|
cashier: 'Caja',
|
||||||
|
reports: 'Reportes',
|
||||||
|
sales: 'Ventas',
|
||||||
|
|
||||||
|
// Store
|
||||||
|
storeInfo: 'Información de la tienda',
|
||||||
|
storeName: 'Nombre del Comercio',
|
||||||
|
storeDescription: 'Descripción',
|
||||||
|
storeCategory: 'Categoría',
|
||||||
|
storeAddress: 'Dirección',
|
||||||
|
storePhone: 'Teléfono',
|
||||||
|
storeEmail: 'Email',
|
||||||
|
storeWebsite: 'Sitio Web',
|
||||||
|
openingHours: 'Horario de Atención',
|
||||||
|
storeStatus: 'Estado del Comercio',
|
||||||
|
active: 'Activo',
|
||||||
|
inactive: 'Inactivo',
|
||||||
|
basicInfo: 'Información Básica',
|
||||||
|
contactInfo: 'Información de Contacto',
|
||||||
|
|
||||||
|
// Inventory
|
||||||
|
product: 'Producto',
|
||||||
|
products: 'Productos',
|
||||||
|
productName: 'Nombre del Producto',
|
||||||
|
category: 'Categoría',
|
||||||
|
price: 'Precio',
|
||||||
|
stock: 'Stock',
|
||||||
|
quantity: 'Cantidad',
|
||||||
|
unit: 'Unidad',
|
||||||
|
minStock: 'Stock Mínimo',
|
||||||
|
supplier: 'Proveedor',
|
||||||
|
barcode: 'Código de Barras',
|
||||||
|
lowStock: 'Stock Bajo',
|
||||||
|
|
||||||
|
// POS
|
||||||
|
currentSale: 'Venta Actual',
|
||||||
|
processPay: 'Procesar Pago',
|
||||||
|
total: 'Total',
|
||||||
|
cartEmpty: 'El carrito está vacío',
|
||||||
|
noProducts: 'No hay productos',
|
||||||
|
addProducts: 'Agrega productos desde la sección de Inventario',
|
||||||
|
|
||||||
|
// Customers
|
||||||
|
customer: 'Cliente',
|
||||||
|
customerName: 'Nombre del Cliente',
|
||||||
|
customerEmail: 'Email del Cliente',
|
||||||
|
customerPhone: 'Teléfono del Cliente',
|
||||||
|
customerAddress: 'Dirección del Cliente',
|
||||||
|
totalPurchases: 'Total compras',
|
||||||
|
customerSince: 'Cliente desde',
|
||||||
|
|
||||||
|
// Staff
|
||||||
|
employee: 'Empleado',
|
||||||
|
employees: 'Empleados',
|
||||||
|
firstName: 'Nombre',
|
||||||
|
lastName: 'Apellido',
|
||||||
|
role: 'Rol',
|
||||||
|
salary: 'Salario',
|
||||||
|
|
||||||
|
// Cashier
|
||||||
|
cashierControl: 'Control de Caja',
|
||||||
|
openingBalance: 'Saldo Inicial',
|
||||||
|
currentBalance: 'Saldo Actual',
|
||||||
|
dailySales: 'Ventas del Día',
|
||||||
|
expenses: 'Gastos',
|
||||||
|
openCashier: 'Abrir Caja',
|
||||||
|
closeCashier: 'Cerrar Caja',
|
||||||
|
transaction: 'Transacción',
|
||||||
|
transactionType: 'Tipo de Transacción',
|
||||||
|
amount: 'Monto',
|
||||||
|
description: 'Descripción',
|
||||||
|
registerTransaction: 'Registrar Transacción',
|
||||||
|
recentTransactions: 'Transacciones Recientes',
|
||||||
|
|
||||||
|
// Days of week
|
||||||
|
monday: 'Lunes',
|
||||||
|
tuesday: 'Martes',
|
||||||
|
wednesday: 'Miércoles',
|
||||||
|
thursday: 'Jueves',
|
||||||
|
friday: 'Viernes',
|
||||||
|
saturday: 'Sábado',
|
||||||
|
sunday: 'Domingo',
|
||||||
|
closed: 'Cerrado'
|
||||||
},
|
},
|
||||||
|
|
||||||
en: {
|
en: {
|
||||||
@@ -157,6 +252,10 @@ export const translations = {
|
|||||||
delete: 'Delete',
|
delete: 'Delete',
|
||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
view: 'View',
|
view: 'View',
|
||||||
|
search: 'Search',
|
||||||
|
add: 'Add',
|
||||||
|
create: 'Create',
|
||||||
|
update: 'Update',
|
||||||
|
|
||||||
// Process section
|
// Process section
|
||||||
processTitle: 'Find Your Dream Place The Best Way',
|
processTitle: 'Find Your Dream Place The Best Way',
|
||||||
@@ -168,7 +267,98 @@ export const translations = {
|
|||||||
// Explore section
|
// Explore section
|
||||||
topRegions: 'Top Regions',
|
topRegions: 'Top Regions',
|
||||||
exploreCities: 'Explore Cities',
|
exploreCities: 'Explore Cities',
|
||||||
exploreMore: 'Explore more'
|
exploreMore: 'Explore more',
|
||||||
|
|
||||||
|
// Commerce Module
|
||||||
|
commerce: 'Commerce',
|
||||||
|
myStore: 'My Store',
|
||||||
|
posTerminal: 'POS Sales',
|
||||||
|
inventory: 'Inventory',
|
||||||
|
customers: 'Customers',
|
||||||
|
staff: 'Staff',
|
||||||
|
cashier: 'Cashier',
|
||||||
|
reports: 'Reports',
|
||||||
|
sales: 'Sales',
|
||||||
|
|
||||||
|
// Store
|
||||||
|
storeInfo: 'Store information',
|
||||||
|
storeName: 'Store Name',
|
||||||
|
storeDescription: 'Description',
|
||||||
|
storeCategory: 'Category',
|
||||||
|
storeAddress: 'Address',
|
||||||
|
storePhone: 'Phone',
|
||||||
|
storeEmail: 'Email',
|
||||||
|
storeWebsite: 'Website',
|
||||||
|
openingHours: 'Opening Hours',
|
||||||
|
storeStatus: 'Store Status',
|
||||||
|
active: 'Active',
|
||||||
|
inactive: 'Inactive',
|
||||||
|
basicInfo: 'Basic Information',
|
||||||
|
contactInfo: 'Contact Information',
|
||||||
|
|
||||||
|
// Inventory
|
||||||
|
product: 'Product',
|
||||||
|
products: 'Products',
|
||||||
|
productName: 'Product Name',
|
||||||
|
category: 'Category',
|
||||||
|
price: 'Price',
|
||||||
|
stock: 'Stock',
|
||||||
|
quantity: 'Quantity',
|
||||||
|
unit: 'Unit',
|
||||||
|
minStock: 'Minimum Stock',
|
||||||
|
supplier: 'Supplier',
|
||||||
|
barcode: 'Barcode',
|
||||||
|
lowStock: 'Low Stock',
|
||||||
|
|
||||||
|
// POS
|
||||||
|
currentSale: 'Current Sale',
|
||||||
|
processPay: 'Process Payment',
|
||||||
|
total: 'Total',
|
||||||
|
cartEmpty: 'Cart is empty',
|
||||||
|
noProducts: 'No products',
|
||||||
|
addProducts: 'Add products from Inventory section',
|
||||||
|
|
||||||
|
// Customers
|
||||||
|
customer: 'Customer',
|
||||||
|
customerName: 'Customer Name',
|
||||||
|
customerEmail: 'Customer Email',
|
||||||
|
customerPhone: 'Customer Phone',
|
||||||
|
customerAddress: 'Customer Address',
|
||||||
|
totalPurchases: 'Total purchases',
|
||||||
|
customerSince: 'Customer since',
|
||||||
|
|
||||||
|
// Staff
|
||||||
|
employee: 'Employee',
|
||||||
|
employees: 'Employees',
|
||||||
|
firstName: 'First Name',
|
||||||
|
lastName: 'Last Name',
|
||||||
|
role: 'Role',
|
||||||
|
salary: 'Salary',
|
||||||
|
|
||||||
|
// Cashier
|
||||||
|
cashierControl: 'Cash Register Control',
|
||||||
|
openingBalance: 'Opening Balance',
|
||||||
|
currentBalance: 'Current Balance',
|
||||||
|
dailySales: 'Daily Sales',
|
||||||
|
expenses: 'Expenses',
|
||||||
|
openCashier: 'Open Register',
|
||||||
|
closeCashier: 'Close Register',
|
||||||
|
transaction: 'Transaction',
|
||||||
|
transactionType: 'Transaction Type',
|
||||||
|
amount: 'Amount',
|
||||||
|
description: 'Description',
|
||||||
|
registerTransaction: 'Register Transaction',
|
||||||
|
recentTransactions: 'Recent Transactions',
|
||||||
|
|
||||||
|
// Days of week
|
||||||
|
monday: 'Monday',
|
||||||
|
tuesday: 'Tuesday',
|
||||||
|
wednesday: 'Wednesday',
|
||||||
|
thursday: 'Thursday',
|
||||||
|
friday: 'Friday',
|
||||||
|
saturday: 'Saturday',
|
||||||
|
sunday: 'Sunday',
|
||||||
|
closed: 'Closed'
|
||||||
},
|
},
|
||||||
|
|
||||||
fr: {
|
fr: {
|
||||||
@@ -243,6 +433,10 @@ export const translations = {
|
|||||||
delete: 'Supprimer',
|
delete: 'Supprimer',
|
||||||
edit: 'Modifier',
|
edit: 'Modifier',
|
||||||
view: 'Voir',
|
view: 'Voir',
|
||||||
|
search: 'Rechercher',
|
||||||
|
add: 'Ajouter',
|
||||||
|
create: 'Créer',
|
||||||
|
update: 'Mettre à jour',
|
||||||
|
|
||||||
// Process section
|
// Process section
|
||||||
processTitle: 'Trouvez Votre Lieu de Rêve de la Meilleure Façon',
|
processTitle: 'Trouvez Votre Lieu de Rêve de la Meilleure Façon',
|
||||||
@@ -254,6 +448,97 @@ export const translations = {
|
|||||||
// Explore section
|
// Explore section
|
||||||
topRegions: 'Principales Régions',
|
topRegions: 'Principales Régions',
|
||||||
exploreCities: 'Explorer les Villes',
|
exploreCities: 'Explorer les Villes',
|
||||||
exploreMore: 'Explorer plus'
|
exploreMore: 'Explorer plus',
|
||||||
|
|
||||||
|
// Commerce Module
|
||||||
|
commerce: 'Commerce',
|
||||||
|
myStore: 'Mon Magasin',
|
||||||
|
posTerminal: 'POS Ventes',
|
||||||
|
inventory: 'Inventaire',
|
||||||
|
customers: 'Clients',
|
||||||
|
staff: 'Personnel',
|
||||||
|
cashier: 'Caisse',
|
||||||
|
reports: 'Rapports',
|
||||||
|
sales: 'Ventes',
|
||||||
|
|
||||||
|
// Store
|
||||||
|
storeInfo: 'Informations du magasin',
|
||||||
|
storeName: 'Nom du Magasin',
|
||||||
|
storeDescription: 'Description',
|
||||||
|
storeCategory: 'Catégorie',
|
||||||
|
storeAddress: 'Adresse',
|
||||||
|
storePhone: 'Téléphone',
|
||||||
|
storeEmail: 'Email',
|
||||||
|
storeWebsite: 'Site Web',
|
||||||
|
openingHours: 'Heures d\'Ouverture',
|
||||||
|
storeStatus: 'Statut du Magasin',
|
||||||
|
active: 'Actif',
|
||||||
|
inactive: 'Inactif',
|
||||||
|
basicInfo: 'Informations de Base',
|
||||||
|
contactInfo: 'Coordonnées',
|
||||||
|
|
||||||
|
// Inventory
|
||||||
|
product: 'Produit',
|
||||||
|
products: 'Produits',
|
||||||
|
productName: 'Nom du Produit',
|
||||||
|
category: 'Catégorie',
|
||||||
|
price: 'Prix',
|
||||||
|
stock: 'Stock',
|
||||||
|
quantity: 'Quantité',
|
||||||
|
unit: 'Unité',
|
||||||
|
minStock: 'Stock Minimum',
|
||||||
|
supplier: 'Fournisseur',
|
||||||
|
barcode: 'Code-barres',
|
||||||
|
lowStock: 'Stock Faible',
|
||||||
|
|
||||||
|
// POS
|
||||||
|
currentSale: 'Vente Actuelle',
|
||||||
|
processPay: 'Traiter le Paiement',
|
||||||
|
total: 'Total',
|
||||||
|
cartEmpty: 'Le panier est vide',
|
||||||
|
noProducts: 'Aucun produit',
|
||||||
|
addProducts: 'Ajoutez des produits depuis la section Inventaire',
|
||||||
|
|
||||||
|
// Customers
|
||||||
|
customer: 'Client',
|
||||||
|
customerName: 'Nom du Client',
|
||||||
|
customerEmail: 'Email du Client',
|
||||||
|
customerPhone: 'Téléphone du Client',
|
||||||
|
customerAddress: 'Adresse du Client',
|
||||||
|
totalPurchases: 'Total des achats',
|
||||||
|
customerSince: 'Client depuis',
|
||||||
|
|
||||||
|
// Staff
|
||||||
|
employee: 'Employé',
|
||||||
|
employees: 'Employés',
|
||||||
|
firstName: 'Prénom',
|
||||||
|
lastName: 'Nom',
|
||||||
|
role: 'Rôle',
|
||||||
|
salary: 'Salaire',
|
||||||
|
|
||||||
|
// Cashier
|
||||||
|
cashierControl: 'Contrôle de Caisse',
|
||||||
|
openingBalance: 'Solde d\'Ouverture',
|
||||||
|
currentBalance: 'Solde Actuel',
|
||||||
|
dailySales: 'Ventes du Jour',
|
||||||
|
expenses: 'Dépenses',
|
||||||
|
openCashier: 'Ouvrir la Caisse',
|
||||||
|
closeCashier: 'Fermer la Caisse',
|
||||||
|
transaction: 'Transaction',
|
||||||
|
transactionType: 'Type de Transaction',
|
||||||
|
amount: 'Montant',
|
||||||
|
description: 'Description',
|
||||||
|
registerTransaction: 'Enregistrer la Transaction',
|
||||||
|
recentTransactions: 'Transactions Récentes',
|
||||||
|
|
||||||
|
// Days of week
|
||||||
|
monday: 'Lundi',
|
||||||
|
tuesday: 'Mardi',
|
||||||
|
wednesday: 'Mercredi',
|
||||||
|
thursday: 'Jeudi',
|
||||||
|
friday: 'Vendredi',
|
||||||
|
saturday: 'Samedi',
|
||||||
|
sunday: 'Dimanche',
|
||||||
|
closed: 'Fermé'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user