Files
ShooterHub/frontend/js/i18n.js
2026-04-02 11:24:30 +02:00

926 lines
47 KiB
JavaScript

// ── Internationalisation ───────────────────────────────────────────────────────
// Depends on api.js (getLang)
const TRANSLATIONS = {
en: {
// ── Navigation ──
'nav.dashboard': 'Dashboard',
'nav.gear': 'My Gear',
'nav.reloads': 'My Reloads',
'nav.tools': 'Tools',
'nav.photos': 'Photos',
'nav.sessions': 'Sessions',
'nav.profile': 'Profile',
'nav.signout': 'Sign out',
'nav.signin': 'Sign in',
'nav.register': 'Register',
'nav.admin': 'Admin',
// ── Index ──
'index.lead': 'Your all-in-one platform to manage your firearms & gear, log and analyse your shooting performance, develop custom reloads, and share your results with other shooters.',
'index.cta': 'Get started free',
'index.cta2': 'Explore tools',
'index.cta3': 'Ready to elevate your shooting?',
'index.cta4': 'Create your account',
'index.feat.title': 'Everything a serious shooter needs',
'index.feat.sub': 'From the first round to competition-level analysis.',
'index.feat.gear.title': 'Gear Inventory',
'index.feat.gear.desc': 'Catalogue every firearm, scope, suppressor, bipod and magazine you own. Build custom rigs and share them publicly.',
'index.feat.sessions.title': 'Session Logging',
'index.feat.sessions.desc': 'Log every shooting session with chrono data, shot groups, weather conditions and notes in one place.',
'index.feat.analysis.title': 'Performance Analysis',
'index.feat.analysis.desc': 'Visualise velocity SD, ES, group sizes over time and identify trends in your shooting performance.',
'index.feat.reload.title': 'Reload Development',
'index.feat.reload.desc': 'Build load recipes, vary powder charge across batches, link each batch to shot groups and find the most accurate charge.',
'index.recent.title': 'Recent Analyses',
'index.recent.subtitle': 'Publicly shared chronograph sessions — no account required to view.',
'index.recent.upload': 'Upload your own',
'index.recent.empty': 'No analyses uploaded yet. Be the first!',
// ── Dashboard ──
'dash.title': 'Dashboard',
'dash.welcome': 'Welcome back!',
'dash.welcome.name': 'Welcome back, {name}!',
'dash.stat.gear': 'Gear items',
'dash.stat.rigs': 'Rigs',
'dash.stat.recipes': 'Load recipes',
'dash.stat.batches': 'Ammo batches',
'dash.quicklinks': 'Quick links',
'dash.quicklink.gears': 'Manage gears & rigs',
'dash.quicklink.reloads': 'Reload development',
'dash.quicklink.sessions': 'Shooting sessions',
'dash.quicklink.chrono': 'Chronograph analyses',
'dash.quicklink.profile': 'My profile',
'profile.link.analyses': 'My analyses',
'profile.link.sessions': 'My sessions',
'profile.link.photos': 'My photos',
'profile.link.gears': 'My gears',
// ── Gear page ──
'gear.title': 'Gears & Rigs',
'gear.tab.inv': 'My Inventory',
'gear.tab.rigs': 'My Rigs',
'gear.my.gear': 'My gear',
'gear.add': 'Add gear',
'gear.my.rigs': 'My rigs',
'gear.new.rig': 'New rig',
'gear.empty.inv': "You haven't added any gear yet.",
'gear.empty.rigs': "You haven't created any rig yet.",
// ── Reloads page ──
'reload.title': 'Reload Development',
'reload.recipes': 'Recipes',
'reload.no.sel': 'Select a recipe to view its batches',
// ── Profile page ──
'profile.title': 'My Profile',
'profile.tab.prof': 'Profile',
'profile.tab.pw': 'Change password',
'profile.avatar.upload': 'Upload avatar',
'profile.personal.title': 'Personal information',
'profile.form.first_name': 'First name',
'profile.form.last_name': 'Last name',
'profile.form.email': 'Email',
'profile.form.email.ro': '(read-only)',
'profile.form.save': 'Save changes',
'profile.pw.title': 'Change password',
'profile.form.pw.current': 'Current password',
'profile.form.pw.new': 'New password',
'profile.form.pw.confirm': 'Confirm new password',
'profile.form.pw.change': 'Change password',
'profile.rigs.title': 'My rigs',
'profile.rigs.empty': 'You have no rigs yet.',
'profile.table.name': 'Name',
'profile.table.items': 'Items',
'profile.table.visibility': 'Visibility',
// ── Admin page ──
'admin.title': 'Administration',
'admin.tab.users': 'Users',
'admin.tab.catalog': 'Gear catalog',
'admin.tab.comps': 'Reload components',
'admin.tab.calibers': 'Calibers',
'admin.add.gear': 'Add gear item',
'admin.users.new': 'New user',
'admin.users.create.title': 'Create new user',
'admin.users.username': 'Username',
'admin.users.email': 'Email',
'admin.users.password': 'Password',
'admin.users.staff': 'Staff / Admin',
'admin.users.first_name': 'First name',
'admin.users.last_name': 'Last name',
'admin.users.create.btn': 'Create user',
'admin.table.username': 'Username',
'admin.table.email': 'Email',
'admin.table.name': 'Name',
'admin.table.staff': 'Staff',
'admin.table.active': 'Active',
'admin.table.joined': 'Joined',
'admin.filter.all_types': 'All types',
'admin.filter.firearms': 'Firearms',
'admin.filter.scopes': 'Scopes',
'admin.filter.suppressors': 'Suppressors',
'admin.filter.bipods': 'Bipods',
'admin.filter.magazines': 'Magazines',
'admin.filter.all_statuses': 'All statuses',
'admin.filter.pending': 'Pending',
'admin.filter.verified': 'Verified',
'admin.filter.rejected': 'Rejected',
'admin.catalog.col.type': 'Type',
'admin.catalog.col.brand': 'Brand',
'admin.catalog.col.model': 'Model',
'admin.catalog.col.caliber': 'Caliber',
'admin.catalog.col.status': 'Status',
'admin.add.btn': 'Add to catalog',
'admin.comp.primers': 'Primers',
'admin.comp.brass': 'Brass',
'admin.comp.bullets': 'Bullets',
'admin.comp.powders': 'Powders',
// ── Tools page ──
'tools.title': 'Tools',
'tools.subtitle': 'Standalone ballistics and reloading tools — no account required.',
'tools.ballistics.title': 'Ballistics Calculator',
'tools.ballistics.desc': 'Point-mass trajectory — drop, wind drift, corrections in MOA/MRAD. No account required.',
'tools.ballistics.soon': 'Coming soon — trajectory, wind drift and holdover charts.',
'tools.chrono.title': 'Chronograph Analyser',
'tools.chrono.desc': 'Upload a CSV from your chrono — get group detection, SD, ES, velocity charts and a PDF report.',
'tools.open': 'Open',
'tools.groupsize.title': 'Group Size Calculator',
'tools.groupsize.desc': 'Annotate a target photo — measure ES, mean radius and scope correction in mm and MOA.',
'tools.oal.title': 'OAL Calculator',
'tools.oal.soon': 'Coming soon — calculate optimal cartridge overall length.',
// ── Sessions page ──
'sessions.title': 'Shooting Sessions',
'sessions.subtitle': 'Prepare and record PRS, free practice, or speed shooting sessions.',
'sessions.soon': 'Coming soon — session logging and analysis will be available here.',
'sessions.milestone': 'Session logging is part of the next milestone. Stay tuned!',
'sessions.tab.prs': 'PRS Match',
'sessions.tab.fp': 'Free Practice',
'sessions.tab.speed': 'Speed Shooting',
'sessions.new': 'New Session',
'sessions.none': 'Select a session or create a new one',
'sessions.empty': 'No sessions yet.',
'sessions.delete.confirm': 'Delete this session and all its data?',
'sessions.meta.competition': 'Competition',
'sessions.meta.category': 'Category',
'sessions.meta.date': 'Date',
'sessions.meta.location': 'Location',
'sessions.meta.rig': 'Rig',
'sessions.meta.ammo': 'Ammo',
'sessions.meta.distance': 'Distance',
'sessions.meta.target': 'Target',
'sessions.meta.rounds': 'Rounds fired',
'sessions.meta.format': 'Format',
'sessions.weather.title': 'Weather conditions',
'sessions.weather.temp': 'Temp (°C)',
'sessions.weather.wind': 'Wind (m/s)',
'sessions.weather.dir': 'Dir (°)',
'sessions.weather.humidity': 'Humidity (%)',
'sessions.weather.pressure': 'Pressure (hPa)',
'sessions.weather.notes': 'Notes',
'sessions.weather.save': 'Save weather',
'sessions.analysis.title': 'Linked analysis',
'sessions.analysis.none': 'No analysis linked.',
'sessions.analysis.link': 'Link analysis',
'sessions.analysis.unlink':'Unlink',
'sessions.analysis.view': 'View in Chronograph',
'sessions.analysis.photos':'Photos from this analysis',
'sessions.stages.title': 'Stages',
'sessions.stages.add': 'Add Stage',
'sessions.stages.none': 'No stages yet. Add the first stage to start planning.',
'sessions.stage.prep': 'Prep',
'sessions.stage.corrections': 'Scope corrections',
'sessions.stage.results': 'Results',
'sessions.stage.target': 'Target',
'sessions.stage.maxtime': 'Max time',
'sessions.stage.shots': 'Shots',
'sessions.stage.notes': 'Notes',
'sessions.stage.computed.elev': 'Computed elev.',
'sessions.stage.computed.wind': 'Computed wind.',
'sessions.stage.actual.elev': 'Actual elev.',
'sessions.stage.actual.wind': 'Actual wind.',
'sessions.stage.hits': 'Hits',
'sessions.stage.score': 'Score',
'sessions.stage.time': 'Time (s)',
'sessions.stage.save.corrections': 'Save',
'sessions.stage.save.results': 'Save results',
'sessions.stage.badge.done': 'Results recorded',
'sessions.stage.badge.pending': 'Pending',
'sessions.create.name': 'Session name',
'sessions.create.date': 'Date',
'sessions.create.location':'Location',
'sessions.create.competition': 'Competition name',
'sessions.create.category':'Category',
'sessions.create.distance':'Distance (m)',
'sessions.create.target': 'Target description',
'sessions.create.format': 'Format',
'sessions.create.rig': 'Rig',
'sessions.create.ammo': 'Ammo',
'sessions.create.ammo.none':'None',
'sessions.create.ammo.factory':'Factory',
'sessions.create.ammo.reload': 'Reloaded batch',
'sessions.create.ammo.suggest': "Can't find your ammo? Suggest it",
'sessions.create.ammo.suggest.note': 'Your suggestion will be visible to all once an admin verifies it.',
'sessions.stage.modal.title': 'Add Stage',
'sessions.stage.modal.order': 'Stage #',
'sessions.stage.modal.position': 'Position',
'sessions.stage.modal.distance': 'Distance (m)',
'sessions.stage.modal.maxtime': 'Max time (s)',
'sessions.stage.modal.shots': 'Shots',
'sessions.stage.modal.tw': 'Target W (cm)',
'sessions.stage.modal.th': 'Target H (cm)',
'sessions.stage.modal.notes': 'Prep notes',
// ── Common ──
'btn.save': 'Save',
'btn.cancel': 'Cancel',
'btn.delete': 'Delete',
'btn.add': 'Add',
'btn.edit': 'Edit',
'btn.verify': 'Verify',
'btn.reject': 'Reject',
'btn.search': 'Search',
'btn.submit': 'Submit',
},
fr: {
'nav.dashboard': 'Tableau de bord',
'nav.gear': 'Mon équipement',
'nav.reloads': 'Mes rechargements',
'nav.tools': 'Outils',
'nav.photos': 'Photos',
'nav.sessions': 'Sessions',
'nav.profile': 'Profil',
'nav.signout': 'Se déconnecter',
'nav.signin': 'Se connecter',
'nav.register': "S'inscrire",
'nav.admin': 'Administration',
'index.lead': 'Votre plateforme tout-en-un pour gérer vos armes et équipements, journaliser vos performances, développer des rechargements et partager vos résultats.',
'index.cta': 'Commencer gratuitement',
'index.cta2': 'Explorer les outils',
'index.cta3': 'Prêt à améliorer vos performances ?',
'index.cta4': 'Créer votre compte',
'index.feat.title': 'Tout ce dont un tireur sérieux a besoin',
'index.feat.sub': "Du premier tir à l'analyse de niveau compétition.",
'index.feat.gear.title': 'Inventaire équipement',
'index.feat.gear.desc': "Cataloguez chaque arme, lunette, suppresseur, bipied et chargeur que vous possédez. Créez des configurations personnalisées et partagez-les.",
'index.feat.sessions.title': 'Journal de sessions',
'index.feat.sessions.desc': 'Enregistrez chaque session de tir avec les données chrono, groupes de tirs, conditions météo et notes au même endroit.',
'index.feat.analysis.title': 'Analyse de performance',
'index.feat.analysis.desc': "Visualisez l'écart-type de vitesse, l'écart extrême, la taille des groupes dans le temps et identifiez vos tendances.",
'index.feat.reload.title': 'Développement de charges',
'index.feat.reload.desc': "Créez des recettes de charge, variez la quantité de poudre entre lots, liez chaque lot à des groupes de tirs et trouvez la charge la plus précise.",
'index.recent.title': 'Analyses récentes',
'index.recent.subtitle': 'Sessions chronographe partagées publiquement — aucun compte requis.',
'index.recent.upload': 'Importer la vôtre',
'index.recent.empty': 'Aucune analyse importée pour l\'instant. Soyez le premier !',
'dash.title': 'Tableau de bord',
'dash.welcome': 'Bon retour !',
'dash.welcome.name': 'Bon retour, {name} !',
'dash.stat.gear': 'Équipements',
'dash.stat.rigs': 'Configurations',
'dash.stat.recipes': 'Recettes de charge',
'dash.stat.batches': 'Lots de munitions',
'dash.quicklinks': 'Accès rapide',
'dash.quicklink.gears': 'Gérer équipements & configs',
'dash.quicklink.reloads': 'Développement de charges',
'dash.quicklink.sessions': 'Sessions de tir',
'dash.quicklink.chrono': 'Analyses chronographe',
'dash.quicklink.profile': 'Mon profil',
'profile.link.analyses': 'Mes analyses',
'profile.link.sessions': 'Mes sessions',
'profile.link.photos': 'Mes photos',
'profile.link.gears': 'Mes équipements',
'gear.title': 'Équipement & Configs',
'gear.tab.inv': 'Mon inventaire',
'gear.tab.rigs': 'Mes configs',
'gear.my.gear': 'Mon équipement',
'gear.add': 'Ajouter équipement',
'gear.my.rigs': 'Mes configurations',
'gear.new.rig': 'Nouvelle config',
'gear.empty.inv': "Vous n'avez pas encore ajouté d'équipement.",
'gear.empty.rigs': "Vous n'avez pas encore créé de configuration.",
'reload.title': 'Développement de charges',
'reload.recipes': 'Recettes',
'reload.no.sel': 'Sélectionnez une recette pour voir ses lots',
'profile.title': 'Mon profil',
'profile.tab.prof': 'Profil',
'profile.tab.pw': 'Changer le mot de passe',
'profile.avatar.upload': 'Charger un avatar',
'profile.personal.title': 'Informations personnelles',
'profile.form.first_name': 'Prénom',
'profile.form.last_name': 'Nom de famille',
'profile.form.email': 'E-mail',
'profile.form.email.ro': '(lecture seule)',
'profile.form.save': 'Enregistrer',
'profile.pw.title': 'Changer le mot de passe',
'profile.form.pw.current': 'Mot de passe actuel',
'profile.form.pw.new': 'Nouveau mot de passe',
'profile.form.pw.confirm': 'Confirmer le nouveau mot de passe',
'profile.form.pw.change': 'Changer le mot de passe',
'profile.rigs.title': 'Mes configurations',
'profile.rigs.empty': "Vous n'avez pas encore de configuration.",
'profile.table.name': 'Nom',
'profile.table.items': 'Éléments',
'profile.table.visibility': 'Visibilité',
'admin.title': 'Administration',
'admin.tab.users': 'Utilisateurs',
'admin.tab.catalog': 'Catalogue équipement',
'admin.tab.comps': 'Composants de rechargement',
'admin.tab.calibers': 'Calibres',
'admin.add.gear': 'Ajouter un équipement',
'admin.users.new': 'Nouvel utilisateur',
'admin.users.create.title': 'Créer un nouvel utilisateur',
'admin.users.username': "Nom d'utilisateur",
'admin.users.email': 'E-mail',
'admin.users.password': 'Mot de passe',
'admin.users.staff': 'Personnel / Admin',
'admin.users.first_name': 'Prénom',
'admin.users.last_name': 'Nom de famille',
'admin.users.create.btn': "Créer l'utilisateur",
'admin.table.username': 'Utilisateur',
'admin.table.email': 'E-mail',
'admin.table.name': 'Nom',
'admin.table.staff': 'Personnel',
'admin.table.active': 'Actif',
'admin.table.joined': 'Inscription',
'admin.filter.all_types': 'Tous types',
'admin.filter.firearms': 'Armes à feu',
'admin.filter.scopes': 'Lunettes',
'admin.filter.suppressors': 'Suppresseurs',
'admin.filter.bipods': 'Bipodes',
'admin.filter.magazines': 'Chargeurs',
'admin.filter.all_statuses': 'Tous statuts',
'admin.filter.pending': 'En attente',
'admin.filter.verified': 'Vérifié',
'admin.filter.rejected': 'Rejeté',
'admin.catalog.col.type': 'Type',
'admin.catalog.col.brand': 'Marque',
'admin.catalog.col.model': 'Modèle',
'admin.catalog.col.caliber': 'Calibre',
'admin.catalog.col.status': 'Statut',
'admin.add.btn': 'Ajouter au catalogue',
'admin.comp.primers': 'Amorces',
'admin.comp.brass': 'Douilles',
'admin.comp.bullets': 'Projectiles',
'admin.comp.powders': 'Poudres',
'tools.title': 'Outils',
'tools.subtitle': 'Outils balistiques et de rechargement — aucun compte requis.',
'tools.ballistics.title': 'Calculateur balistique',
'tools.ballistics.desc': 'Trajectoire point-masse — chute, dérive au vent, corrections MOA/MRAD. Sans compte.',
'tools.ballistics.soon': 'Bientôt — courbes de trajectoire, dérive au vent et compensations.',
'tools.chrono.title': 'Analyseur chronographe',
'tools.chrono.desc': 'Importez un CSV de votre chrono — détection de groupes, ET, ES, courbes de vitesse et rapport PDF.',
'tools.open': 'Ouvrir',
'tools.groupsize.title': 'Calculateur de groupe',
'tools.groupsize.desc': 'Annotez une photo de cible — mesurez l\'ES, le rayon moyen et la correction lunette en mm et MOA.',
'tools.oal.title': 'Calculateur OAL',
'tools.oal.soon': 'Bientôt — calculez la longueur totale optimale de la cartouche.',
'sessions.title': 'Sessions de tir',
'sessions.subtitle': 'Préparez et enregistrez vos sessions PRS, entraînement libre ou tir de vitesse.',
'sessions.soon': "Bientôt disponible — l'enregistrement et l'analyse des sessions seront disponibles ici.",
'sessions.milestone': "L'enregistrement des sessions fait partie du prochain jalon. Restez à l'écoute !",
'sessions.tab.prs': 'Match PRS',
'sessions.tab.fp': 'Entraînement libre',
'sessions.tab.speed': 'Tir de vitesse',
'sessions.new': 'Nouvelle session',
'sessions.none': 'Sélectionnez une session ou créez-en une nouvelle',
'sessions.empty': 'Aucune session.',
'sessions.delete.confirm': 'Supprimer cette session et toutes ses données ?',
'sessions.meta.competition': 'Compétition',
'sessions.meta.category': 'Catégorie',
'sessions.meta.date': 'Date',
'sessions.meta.location': 'Lieu',
'sessions.meta.rig': 'Configuration',
'sessions.meta.ammo': 'Munitions',
'sessions.meta.distance': 'Distance',
'sessions.meta.target': 'Cible',
'sessions.meta.rounds': 'Cartouches tirées',
'sessions.meta.format': 'Format',
'sessions.weather.title': 'Conditions météo',
'sessions.weather.temp': 'Temp (°C)',
'sessions.weather.wind': 'Vent (m/s)',
'sessions.weather.dir': 'Dir (°)',
'sessions.weather.humidity': 'Humidité (%)',
'sessions.weather.pressure': 'Pression (hPa)',
'sessions.weather.notes': 'Notes',
'sessions.weather.save': 'Enregistrer météo',
'sessions.analysis.title': 'Analyse liée',
'sessions.analysis.none': 'Aucune analyse liée.',
'sessions.analysis.link': 'Lier une analyse',
'sessions.analysis.unlink':'Délier',
'sessions.analysis.view': 'Voir dans le chronographe',
'sessions.analysis.photos':'Photos de cette analyse',
'sessions.stages.title': 'Stands',
'sessions.stages.add': 'Ajouter un stand',
'sessions.stages.none': 'Aucun stand. Ajoutez le premier pour commencer la préparation.',
'sessions.stage.prep': 'Préparation',
'sessions.stage.corrections': 'Corrections lunette',
'sessions.stage.results': 'Résultats',
'sessions.stage.target': 'Cible',
'sessions.stage.maxtime': 'Temps max',
'sessions.stage.shots': 'Tirs',
'sessions.stage.notes': 'Notes',
'sessions.stage.computed.elev': 'Élév. calculée',
'sessions.stage.computed.wind': 'Dérive calculée',
'sessions.stage.actual.elev': 'Élév. réelle',
'sessions.stage.actual.wind': 'Dérive réelle',
'sessions.stage.hits': 'Touches',
'sessions.stage.score': 'Score',
'sessions.stage.time': 'Temps (s)',
'sessions.stage.save.corrections': 'Enregistrer',
'sessions.stage.save.results': 'Enregistrer résultats',
'sessions.stage.badge.done': 'Résultats enregistrés',
'sessions.stage.badge.pending': 'En attente',
'sessions.create.name': 'Nom de la session',
'sessions.create.date': 'Date',
'sessions.create.location':'Lieu',
'sessions.create.competition': 'Nom de la compétition',
'sessions.create.category':'Catégorie',
'sessions.create.distance':'Distance (m)',
'sessions.create.target': 'Description de la cible',
'sessions.create.format': 'Format',
'sessions.create.rig': 'Configuration',
'sessions.create.ammo': 'Munitions',
'sessions.create.ammo.none':'Aucune',
'sessions.create.ammo.factory':'Industrielles',
'sessions.create.ammo.reload': 'Lot rechargé',
'sessions.create.ammo.suggest': 'Munitions introuvables ? Suggérez-les',
'sessions.create.ammo.suggest.note': 'Votre suggestion sera visible de tous après vérification par un administrateur.',
'sessions.stage.modal.title': 'Ajouter un stand',
'sessions.stage.modal.order': 'Stand n°',
'sessions.stage.modal.position': 'Position',
'sessions.stage.modal.distance': 'Distance (m)',
'sessions.stage.modal.maxtime': 'Temps max (s)',
'sessions.stage.modal.shots': 'Tirs',
'sessions.stage.modal.tw': 'Largeur cible (cm)',
'sessions.stage.modal.th': 'Hauteur cible (cm)',
'sessions.stage.modal.notes': 'Notes de préparation',
'btn.save': 'Enregistrer',
'btn.cancel': 'Annuler',
'btn.delete': 'Supprimer',
'btn.add': 'Ajouter',
'btn.edit': 'Modifier',
'btn.verify': 'Vérifier',
'btn.reject': 'Rejeter',
'btn.search': 'Rechercher',
'btn.submit': 'Soumettre',
},
de: {
'nav.dashboard': 'Übersicht',
'nav.gear': 'Mein Equipment',
'nav.reloads': 'Meine Ladungen',
'nav.tools': 'Werkzeuge',
'nav.photos': 'Fotos',
'nav.sessions': 'Sessions',
'nav.profile': 'Profil',
'nav.signout': 'Abmelden',
'nav.signin': 'Anmelden',
'nav.register': 'Registrieren',
'nav.admin': 'Administration',
'index.lead': 'Ihre Rundum-Plattform zur Verwaltung von Waffen und Ausrüstung, Protokollierung von Schießleistungen, Ladungsentwicklung und Teilen Ihrer Ergebnisse.',
'index.cta': 'Kostenlos starten',
'index.cta2': 'Tools entdecken',
'index.cta3': 'Bereit, Ihr Schießen zu verbessern?',
'index.cta4': 'Konto erstellen',
'index.feat.title': 'Alles, was ein ernsthafter Schütze braucht',
'index.feat.sub': 'Vom ersten Schuss bis zur Wettkampfanalyse.',
'index.feat.gear.title': 'Ausrüstungsinventar',
'index.feat.gear.desc': 'Katalogisieren Sie jede Waffe, jedes Zielfernrohr, jeden Schalldämpfer, jedes Zweibein und jedes Magazin. Erstellen und teilen Sie Konfigurationen.',
'index.feat.sessions.title': 'Session-Protokoll',
'index.feat.sessions.desc': 'Protokollieren Sie jede Schießsitzung mit Chronodaten, Gruppen, Wetterbedingungen und Notizen an einem Ort.',
'index.feat.analysis.title': 'Leistungsanalyse',
'index.feat.analysis.desc': 'Visualisieren Sie Geschwindigkeits-SD, ES, Gruppengrößen über Zeit und erkennen Sie Trends in Ihrer Schießleistung.',
'index.feat.reload.title': 'Ladungsentwicklung',
'index.feat.reload.desc': 'Erstellen Sie Ladungsrezepte, variieren Sie die Pulvermenge, verknüpfen Sie Chargen mit Schussgruppen und finden Sie die genaueste Ladung.',
'index.recent.title': 'Aktuelle Analysen',
'index.recent.subtitle': 'Öffentlich geteilte Chronographen-Sitzungen — kein Konto zum Ansehen erforderlich.',
'index.recent.upload': 'Eigene hochladen',
'index.recent.empty': 'Noch keine Analysen hochgeladen. Seien Sie der Erste!',
'dash.title': 'Übersicht',
'dash.welcome': 'Willkommen zurück!',
'dash.welcome.name': 'Willkommen zurück, {name}!',
'dash.stat.gear': 'Ausrüstung',
'dash.stat.rigs': 'Konfigurationen',
'dash.stat.recipes': 'Ladungsrezepte',
'dash.stat.batches': 'Munitionschargen',
'dash.quicklinks': 'Schnellzugriff',
'dash.quicklink.gears': 'Ausrüstung & Konfigurationen',
'dash.quicklink.reloads': 'Ladungsentwicklung',
'dash.quicklink.sessions': 'Schießsitzungen',
'dash.quicklink.chrono': 'Chronographenanalysen',
'dash.quicklink.profile': 'Mein Profil',
'profile.link.analyses': 'Meine Analysen',
'profile.link.sessions': 'Meine Sitzungen',
'profile.link.photos': 'Meine Fotos',
'profile.link.gears': 'Meine Ausrüstung',
'gear.title': 'Ausrüstung & Konfigurationen',
'gear.tab.inv': 'Mein Inventar',
'gear.tab.rigs': 'Meine Konfigs',
'gear.my.gear': 'Meine Ausrüstung',
'gear.add': 'Ausrüstung hinzufügen',
'gear.my.rigs': 'Meine Konfigurationen',
'gear.new.rig': 'Neue Konfiguration',
'gear.empty.inv': 'Sie haben noch keine Ausrüstung hinzugefügt.',
'gear.empty.rigs': 'Sie haben noch keine Konfiguration erstellt.',
'reload.title': 'Ladungsentwicklung',
'reload.recipes': 'Rezepte',
'reload.no.sel': 'Wählen Sie ein Rezept aus, um die Chargen anzuzeigen',
'profile.title': 'Mein Profil',
'profile.tab.prof': 'Profil',
'profile.tab.pw': 'Passwort ändern',
'profile.avatar.upload': 'Avatar hochladen',
'profile.personal.title': 'Persönliche Angaben',
'profile.form.first_name': 'Vorname',
'profile.form.last_name': 'Nachname',
'profile.form.email': 'E-Mail',
'profile.form.email.ro': '(schreibgeschützt)',
'profile.form.save': 'Speichern',
'profile.pw.title': 'Passwort ändern',
'profile.form.pw.current': 'Aktuelles Passwort',
'profile.form.pw.new': 'Neues Passwort',
'profile.form.pw.confirm': 'Neues Passwort bestätigen',
'profile.form.pw.change': 'Passwort ändern',
'profile.rigs.title': 'Meine Konfigurationen',
'profile.rigs.empty': 'Sie haben noch keine Konfigurationen.',
'profile.table.name': 'Name',
'profile.table.items': 'Elemente',
'profile.table.visibility': 'Sichtbarkeit',
'admin.title': 'Administration',
'admin.tab.users': 'Benutzer',
'admin.tab.catalog': 'Ausrüstungskatalog',
'admin.tab.comps': 'Ladekomponenten',
'admin.tab.calibers': 'Kaliber',
'admin.add.gear': 'Ausrüstung hinzufügen',
'admin.users.new': 'Neuer Benutzer',
'admin.users.create.title': 'Neuen Benutzer erstellen',
'admin.users.username': 'Benutzername',
'admin.users.email': 'E-Mail',
'admin.users.password': 'Passwort',
'admin.users.staff': 'Mitarbeiter / Admin',
'admin.users.first_name': 'Vorname',
'admin.users.last_name': 'Nachname',
'admin.users.create.btn': 'Benutzer erstellen',
'admin.table.username': 'Benutzername',
'admin.table.email': 'E-Mail',
'admin.table.name': 'Name',
'admin.table.staff': 'Mitarbeiter',
'admin.table.active': 'Aktiv',
'admin.table.joined': 'Beigetreten',
'admin.filter.all_types': 'Alle Typen',
'admin.filter.firearms': 'Schusswaffen',
'admin.filter.scopes': 'Zielfernrohre',
'admin.filter.suppressors': 'Schalldämpfer',
'admin.filter.bipods': 'Zweibeine',
'admin.filter.magazines': 'Magazine',
'admin.filter.all_statuses': 'Alle Status',
'admin.filter.pending': 'Ausstehend',
'admin.filter.verified': 'Bestätigt',
'admin.filter.rejected': 'Abgelehnt',
'admin.catalog.col.type': 'Typ',
'admin.catalog.col.brand': 'Marke',
'admin.catalog.col.model': 'Modell',
'admin.catalog.col.caliber': 'Kaliber',
'admin.catalog.col.status': 'Status',
'admin.add.btn': 'Zum Katalog hinzufügen',
'admin.comp.primers': 'Zündhütchen',
'admin.comp.brass': 'Hülsen',
'admin.comp.bullets': 'Geschosse',
'admin.comp.powders': 'Pulver',
'tools.title': 'Werkzeuge',
'tools.subtitle': 'Ballistische Werkzeuge und Ladewerkzeuge — kein Konto erforderlich.',
'tools.ballistics.title': 'Ballistikrechner',
'tools.ballistics.desc': 'Punktmasse-Trajektorie — Abfall, Windabdrift, Korrekturen in MOA/MRAD. Ohne Konto.',
'tools.ballistics.soon': 'Demnächst — Flugbahn, Windabdrift und Haltepunktdiagramme.',
'tools.chrono.title': 'Chronograph-Analysator',
'tools.chrono.desc': 'CSV von Ihrem Chrono hochladen — Gruppenerkennung, SD, ES, Geschwindigkeitskurven und PDF-Bericht.',
'tools.open': 'Öffnen',
'tools.groupsize.title': 'Gruppengrößenrechner',
'tools.groupsize.desc': 'Zielscheibenfoto annotieren — ES, mittleren Radius und Richtkorrekturen in mm und MOA messen.',
'tools.oal.title': 'OAL-Rechner',
'tools.oal.soon': 'Demnächst — optimale Gesamtlänge der Patrone berechnen.',
'sessions.title': 'Schießsitzungen',
'sessions.subtitle': 'PRS-, Freiübungs- oder Schnellschießsitzungen vorbereiten und aufzeichnen.',
'sessions.soon': 'Demnächst — Sitzungsprotokoll und Analyse werden hier verfügbar sein.',
'sessions.milestone': 'Die Sitzungsprotokollierung ist Teil des nächsten Meilensteins. Bleiben Sie dran!',
'sessions.tab.prs': 'PRS-Match',
'sessions.tab.fp': 'Freiübung',
'sessions.tab.speed': 'Schnellschießen',
'sessions.new': 'Neue Sitzung',
'sessions.none': 'Sitzung auswählen oder neue erstellen',
'sessions.empty': 'Keine Sitzungen vorhanden.',
'sessions.delete.confirm': 'Diese Sitzung und alle Daten löschen?',
'sessions.meta.competition': 'Wettkampf',
'sessions.meta.category': 'Kategorie',
'sessions.meta.date': 'Datum',
'sessions.meta.location': 'Ort',
'sessions.meta.rig': 'Konfiguration',
'sessions.meta.ammo': 'Munition',
'sessions.meta.distance': 'Entfernung',
'sessions.meta.target': 'Ziel',
'sessions.meta.rounds': 'Abgefeuerte Schüsse',
'sessions.meta.format': 'Format',
'sessions.weather.title': 'Wetterbedingungen',
'sessions.weather.temp': 'Temp (°C)',
'sessions.weather.wind': 'Wind (m/s)',
'sessions.weather.dir': 'Richtung (°)',
'sessions.weather.humidity': 'Luftfeuchtigkeit (%)',
'sessions.weather.pressure': 'Druck (hPa)',
'sessions.weather.notes': 'Notizen',
'sessions.weather.save': 'Wetter speichern',
'sessions.analysis.title': 'Verknüpfte Analyse',
'sessions.analysis.none': 'Keine Analyse verknüpft.',
'sessions.analysis.link': 'Analyse verknüpfen',
'sessions.analysis.unlink':'Verknüpfung lösen',
'sessions.analysis.view': 'Im Chronograph anzeigen',
'sessions.analysis.photos':'Fotos dieser Analyse',
'sessions.stages.title': 'Stände',
'sessions.stages.add': 'Stand hinzufügen',
'sessions.stages.none': 'Noch keine Stände. Ersten Stand hinzufügen.',
'sessions.stage.prep': 'Vorbereitung',
'sessions.stage.corrections': 'Absehenkorrekturen',
'sessions.stage.results': 'Ergebnisse',
'sessions.stage.target': 'Ziel',
'sessions.stage.maxtime': 'Max. Zeit',
'sessions.stage.shots': 'Schüsse',
'sessions.stage.notes': 'Notizen',
'sessions.stage.computed.elev': 'Ber. Höhe',
'sessions.stage.computed.wind': 'Ber. Wind',
'sessions.stage.actual.elev': 'Tats. Höhe',
'sessions.stage.actual.wind': 'Tats. Wind',
'sessions.stage.hits': 'Treffer',
'sessions.stage.score': 'Punkte',
'sessions.stage.time': 'Zeit (s)',
'sessions.stage.save.corrections': 'Speichern',
'sessions.stage.save.results': 'Ergebnisse speichern',
'sessions.stage.badge.done': 'Ergebnisse gespeichert',
'sessions.stage.badge.pending': 'Ausstehend',
'sessions.create.name': 'Sitzungsname',
'sessions.create.date': 'Datum',
'sessions.create.location':'Ort',
'sessions.create.competition': 'Wettkampfname',
'sessions.create.category':'Kategorie',
'sessions.create.distance':'Entfernung (m)',
'sessions.create.target': 'Zielbeschreibung',
'sessions.create.format': 'Format',
'sessions.create.rig': 'Konfiguration',
'sessions.create.ammo': 'Munition',
'sessions.create.ammo.none':'Keine',
'sessions.create.ammo.factory':'Fabrikmunition',
'sessions.create.ammo.reload': 'Wiederladung',
'sessions.create.ammo.suggest': 'Munition nicht gefunden? Vorschlagen',
'sessions.create.ammo.suggest.note': 'Ihr Vorschlag wird nach Admin-Prüfung für alle sichtbar.',
'sessions.stage.modal.title': 'Stand hinzufügen',
'sessions.stage.modal.order': 'Stand-Nr.',
'sessions.stage.modal.position': 'Position',
'sessions.stage.modal.distance': 'Entfernung (m)',
'sessions.stage.modal.maxtime': 'Max. Zeit (s)',
'sessions.stage.modal.shots': 'Schüsse',
'sessions.stage.modal.tw': 'Zielbreite (cm)',
'sessions.stage.modal.th': 'Zielhöhe (cm)',
'sessions.stage.modal.notes': 'Vorbereitungsnotizen',
'btn.save': 'Speichern',
'btn.cancel': 'Abbrechen',
'btn.delete': 'Löschen',
'btn.add': 'Hinzufügen',
'btn.edit': 'Bearbeiten',
'btn.verify': 'Bestätigen',
'btn.reject': 'Ablehnen',
'btn.search': 'Suchen',
'btn.submit': 'Absenden',
},
es: {
'nav.dashboard': 'Panel',
'nav.gear': 'Mi equipamiento',
'nav.reloads': 'Mis recargas',
'nav.tools': 'Herramientas',
'nav.photos': 'Fotos',
'nav.sessions': 'Sesiones',
'nav.profile': 'Perfil',
'nav.signout': 'Cerrar sesión',
'nav.signin': 'Iniciar sesión',
'nav.register': 'Registrarse',
'nav.admin': 'Administración',
'index.lead': 'Su plataforma integral para gestionar armas y equipamiento, registrar rendimiento, desarrollar recargas y compartir resultados con otros tiradores.',
'index.cta': 'Empezar gratis',
'index.cta2': 'Explorar herramientas',
'index.cta3': '¿Listo para mejorar su tiro?',
'index.cta4': 'Crear cuenta',
'index.feat.title': 'Todo lo que necesita un tirador serio',
'index.feat.sub': 'Desde el primer disparo hasta el análisis de competición.',
'index.feat.gear.title': 'Inventario de equipamiento',
'index.feat.gear.desc': 'Catalogue cada arma, mira, silenciador, bípode y cargador que posee. Cree configuraciones personalizadas y compártalas.',
'index.feat.sessions.title': 'Registro de sesiones',
'index.feat.sessions.desc': 'Registre cada sesión de tiro con datos de cronógrafo, grupos, condiciones meteorológicas y notas en un solo lugar.',
'index.feat.analysis.title': 'Análisis de rendimiento',
'index.feat.analysis.desc': 'Visualice la desviación típica, el extremo de la serie, tamaño de grupos a lo largo del tiempo e identifique tendencias.',
'index.feat.reload.title': 'Desarrollo de recargas',
'index.feat.reload.desc': 'Cree recetas de carga, varíe la carga de pólvora entre lotes, vincule cada lote a grupos de disparos y encuentre la carga más precisa.',
'index.recent.title': 'Análisis recientes',
'index.recent.subtitle': 'Sesiones de cronógrafo compartidas públicamente — no se requiere cuenta para ver.',
'index.recent.upload': 'Subir la suya',
'index.recent.empty': '¡Aún no hay análisis. Sea el primero!',
'dash.title': 'Panel',
'dash.welcome': '¡Bienvenido de nuevo!',
'dash.welcome.name': '¡Bienvenido de nuevo, {name}!',
'dash.stat.gear': 'Equipamiento',
'dash.stat.rigs': 'Configuraciones',
'dash.stat.recipes': 'Recetas de carga',
'dash.stat.batches': 'Lotes de munición',
'dash.quicklinks': 'Acceso rápido',
'dash.quicklink.gears': 'Gestionar equipamiento y configs',
'dash.quicklink.reloads': 'Desarrollo de recargas',
'dash.quicklink.sessions': 'Sesiones de tiro',
'dash.quicklink.chrono': 'Análisis de cronógrafo',
'dash.quicklink.profile': 'Mi perfil',
'profile.link.analyses': 'Mis análisis',
'profile.link.sessions': 'Mis sesiones',
'profile.link.photos': 'Mis fotos',
'profile.link.gears': 'Mi equipamiento',
'gear.title': 'Equipamiento y configs',
'gear.tab.inv': 'Mi inventario',
'gear.tab.rigs': 'Mis configs',
'gear.my.gear': 'Mi equipamiento',
'gear.add': 'Añadir equipamiento',
'gear.my.rigs': 'Mis configuraciones',
'gear.new.rig': 'Nueva config',
'gear.empty.inv': 'Aún no ha añadido equipamiento.',
'gear.empty.rigs': 'Aún no ha creado ninguna configuración.',
'reload.title': 'Desarrollo de cargas',
'reload.recipes': 'Recetas',
'reload.no.sel': 'Seleccione una receta para ver sus lotes',
'profile.title': 'Mi perfil',
'profile.tab.prof': 'Perfil',
'profile.tab.pw': 'Cambiar contraseña',
'profile.avatar.upload': 'Subir avatar',
'profile.personal.title': 'Información personal',
'profile.form.first_name': 'Nombre',
'profile.form.last_name': 'Apellido',
'profile.form.email': 'Correo electrónico',
'profile.form.email.ro': '(solo lectura)',
'profile.form.save': 'Guardar cambios',
'profile.pw.title': 'Cambiar contraseña',
'profile.form.pw.current': 'Contraseña actual',
'profile.form.pw.new': 'Nueva contraseña',
'profile.form.pw.confirm': 'Confirmar nueva contraseña',
'profile.form.pw.change': 'Cambiar contraseña',
'profile.rigs.title': 'Mis configuraciones',
'profile.rigs.empty': 'Aún no tiene configuraciones.',
'profile.table.name': 'Nombre',
'profile.table.items': 'Elementos',
'profile.table.visibility': 'Visibilidad',
'admin.title': 'Administración',
'admin.tab.users': 'Usuarios',
'admin.tab.catalog': 'Catálogo de equipamiento',
'admin.tab.comps': 'Componentes de recarga',
'admin.tab.calibers': 'Calibres',
'admin.add.gear': 'Añadir equipamiento',
'admin.users.new': 'Nuevo usuario',
'admin.users.create.title': 'Crear nuevo usuario',
'admin.users.username': 'Nombre de usuario',
'admin.users.email': 'Correo electrónico',
'admin.users.password': 'Contraseña',
'admin.users.staff': 'Personal / Admin',
'admin.users.first_name': 'Nombre',
'admin.users.last_name': 'Apellido',
'admin.users.create.btn': 'Crear usuario',
'admin.table.username': 'Usuario',
'admin.table.email': 'Correo',
'admin.table.name': 'Nombre',
'admin.table.staff': 'Personal',
'admin.table.active': 'Activo',
'admin.table.joined': 'Registro',
'admin.filter.all_types': 'Todos los tipos',
'admin.filter.firearms': 'Armas de fuego',
'admin.filter.scopes': 'Miras telescópicas',
'admin.filter.suppressors': 'Silenciadores',
'admin.filter.bipods': 'Bípodes',
'admin.filter.magazines': 'Cargadores',
'admin.filter.all_statuses': 'Todos los estados',
'admin.filter.pending': 'Pendiente',
'admin.filter.verified': 'Verificado',
'admin.filter.rejected': 'Rechazado',
'admin.catalog.col.type': 'Tipo',
'admin.catalog.col.brand': 'Marca',
'admin.catalog.col.model': 'Modelo',
'admin.catalog.col.caliber': 'Calibre',
'admin.catalog.col.status': 'Estado',
'admin.add.btn': 'Añadir al catálogo',
'admin.comp.primers': 'Cebadores',
'admin.comp.brass': 'Vainas',
'admin.comp.bullets': 'Proyectiles',
'admin.comp.powders': 'Pólvoras',
'tools.title': 'Herramientas',
'tools.subtitle': 'Herramientas balísticas y de recarga — no se requiere cuenta.',
'tools.ballistics.title': 'Calculadora balística',
'tools.ballistics.desc': 'Trayectoria de masa puntual — caída, deriva por viento, correcciones MOA/MRAD. Sin cuenta.',
'tools.ballistics.soon': 'Próximamente — trayectorias, deriva por viento y compensaciones.',
'tools.chrono.title': 'Analizador de cronógrafo',
'tools.chrono.desc': 'Suba un CSV de su cronógrafo — detección de grupos, DT, ES, gráficas de velocidad e informe PDF.',
'tools.open': 'Abrir',
'tools.groupsize.title': 'Calculadora de grupo',
'tools.groupsize.desc': 'Anote una foto de blanco — mida ES, radio medio y corrección de mira en mm y MOA.',
'tools.oal.title': 'Calculadora OAL',
'tools.oal.soon': 'Próximamente — calcule la longitud total óptima del cartucho.',
'sessions.title': 'Sesiones de tiro',
'sessions.subtitle': 'Prepare y registre sesiones de PRS, práctica libre o tiro de velocidad.',
'sessions.soon': 'Próximamente — el registro y análisis de sesiones estará disponible aquí.',
'sessions.milestone': 'El registro de sesiones forma parte del próximo hito. ¡Estén atentos!',
'sessions.tab.prs': 'Match PRS',
'sessions.tab.fp': 'Práctica libre',
'sessions.tab.speed': 'Tiro de velocidad',
'sessions.new': 'Nueva sesión',
'sessions.none': 'Seleccione una sesión o cree una nueva',
'sessions.empty': 'Sin sesiones.',
'sessions.delete.confirm': '¿Eliminar esta sesión y todos sus datos?',
'sessions.meta.competition': 'Competición',
'sessions.meta.category': 'Categoría',
'sessions.meta.date': 'Fecha',
'sessions.meta.location': 'Lugar',
'sessions.meta.rig': 'Configuración',
'sessions.meta.ammo': 'Munición',
'sessions.meta.distance': 'Distancia',
'sessions.meta.target': 'Blanco',
'sessions.meta.rounds': 'Disparos realizados',
'sessions.meta.format': 'Formato',
'sessions.weather.title': 'Condiciones meteorológicas',
'sessions.weather.temp': 'Temp (°C)',
'sessions.weather.wind': 'Viento (m/s)',
'sessions.weather.dir': 'Dir (°)',
'sessions.weather.humidity': 'Humedad (%)',
'sessions.weather.pressure': 'Presión (hPa)',
'sessions.weather.notes': 'Notas',
'sessions.weather.save': 'Guardar clima',
'sessions.analysis.title': 'Análisis vinculado',
'sessions.analysis.none': 'Ningún análisis vinculado.',
'sessions.analysis.link': 'Vincular análisis',
'sessions.analysis.unlink':'Desvincular',
'sessions.analysis.view': 'Ver en cronógrafo',
'sessions.analysis.photos':'Fotos de este análisis',
'sessions.stages.title': 'Puestos',
'sessions.stages.add': 'Añadir puesto',
'sessions.stages.none': 'Sin puestos. Añada el primero para empezar.',
'sessions.stage.prep': 'Preparación',
'sessions.stage.corrections': 'Correcciones de mira',
'sessions.stage.results': 'Resultados',
'sessions.stage.target': 'Blanco',
'sessions.stage.maxtime': 'Tiempo máx.',
'sessions.stage.shots': 'Disparos',
'sessions.stage.notes': 'Notas',
'sessions.stage.computed.elev': 'Elev. calculada',
'sessions.stage.computed.wind': 'Deriv. calculada',
'sessions.stage.actual.elev': 'Elev. real',
'sessions.stage.actual.wind': 'Deriv. real',
'sessions.stage.hits': 'Impactos',
'sessions.stage.score': 'Puntuación',
'sessions.stage.time': 'Tiempo (s)',
'sessions.stage.save.corrections': 'Guardar',
'sessions.stage.save.results': 'Guardar resultados',
'sessions.stage.badge.done': 'Resultados registrados',
'sessions.stage.badge.pending': 'Pendiente',
'sessions.create.name': 'Nombre de sesión',
'sessions.create.date': 'Fecha',
'sessions.create.location':'Lugar',
'sessions.create.competition': 'Nombre de competición',
'sessions.create.category':'Categoría',
'sessions.create.distance':'Distancia (m)',
'sessions.create.target': 'Descripción del blanco',
'sessions.create.format': 'Formato',
'sessions.create.rig': 'Configuración',
'sessions.create.ammo': 'Munición',
'sessions.create.ammo.none':'Ninguna',
'sessions.create.ammo.factory':'Comercial',
'sessions.create.ammo.reload': 'Lote recargado',
'sessions.create.ammo.suggest': '¿No encuentra su munición? Sugiérala',
'sessions.create.ammo.suggest.note': 'Su sugerencia será visible para todos tras verificación del administrador.',
'sessions.stage.modal.title': 'Añadir puesto',
'sessions.stage.modal.order': 'Puesto n°',
'sessions.stage.modal.position': 'Posición',
'sessions.stage.modal.distance': 'Distancia (m)',
'sessions.stage.modal.maxtime': 'Tiempo máx. (s)',
'sessions.stage.modal.shots': 'Disparos',
'sessions.stage.modal.tw': 'Ancho blanco (cm)',
'sessions.stage.modal.th': 'Alto blanco (cm)',
'sessions.stage.modal.notes': 'Notas de preparación',
'btn.save': 'Guardar',
'btn.cancel': 'Cancelar',
'btn.delete': 'Eliminar',
'btn.add': 'Añadir',
'btn.edit': 'Editar',
'btn.verify': 'Verificar',
'btn.reject': 'Rechazar',
'btn.search': 'Buscar',
'btn.submit': 'Enviar',
},
};
function t(key) {
const lang = getLang();
const dict = TRANSLATIONS[lang] || TRANSLATIONS['en'];
return dict[key] || TRANSLATIONS['en'][key] || key;
}
function applyTranslations() {
document.querySelectorAll('[data-i18n]').forEach(el => {
el.textContent = t(el.dataset.i18n);
});
document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
el.placeholder = t(el.dataset.i18nPlaceholder);
});
}