Fix jwt-token

This commit is contained in:
2025-09-19 14:13:24 +02:00
parent e820f68b05
commit 32245f1132
7 changed files with 312 additions and 34 deletions

View File

@@ -33,7 +33,7 @@ const Layout = () => {
// Build navigation based on user permissions with translations // Build navigation based on user permissions with translations
const baseNavigation = [ const baseNavigation = [
{ name: t('navigation.dashboard'), href: '/', icon: HomeIcon }, { name: t('navigation.dashboard'), href: '/', icon: HomeIcon },
{ name: 'Map View', href: '/map', icon: MapIcon }, // TODO: Add to translations { name: t('navigation.map'), href: '/map', icon: MapIcon },
{ name: t('navigation.devices'), href: '/devices', icon: ServerIcon }, { name: t('navigation.devices'), href: '/devices', icon: ServerIcon },
{ name: t('navigation.detections'), href: '/detections', icon: ExclamationTriangleIcon }, { name: t('navigation.detections'), href: '/detections', icon: ExclamationTriangleIcon },
{ name: t('navigation.alerts'), href: '/alerts', icon: BellIcon }, { name: t('navigation.alerts'), href: '/alerts', icon: BellIcon },
@@ -106,7 +106,7 @@ const Layout = () => {
<div className="flex-1 px-4 flex justify-between items-center"> <div className="flex-1 px-4 flex justify-between items-center">
<div className="flex-1 flex"> <div className="flex-1 flex">
<h1 className="text-xl font-semibold text-gray-900"> <h1 className="text-xl font-semibold text-gray-900">
{navigation?.find(item => item.href === location.pathname)?.name || 'Drone Detection System'} {navigation?.find(item => item.href === location.pathname)?.name || t('app.title')}
</h1> </h1>
</div> </div>

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import api from '../services/api'; import api from '../services/api';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { t } from '../utils/tempTranslations';
import { import {
PlusIcon, PlusIcon,
BellIcon, BellIcon,
@@ -106,6 +107,7 @@ const Alerts = () => {
return ( return (
<div className="flex items-center justify-center h-64"> <div className="flex items-center justify-center h-64">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-primary-600"></div> <div className="animate-spin rounded-full h-32 w-32 border-b-2 border-primary-600"></div>
<span className="ml-4 text-gray-600">{t('alerts.loading')}</span>
</div> </div>
); );
} }
@@ -115,10 +117,10 @@ const Alerts = () => {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h3 className="text-lg leading-6 font-medium text-gray-900"> <h3 className="text-lg leading-6 font-medium text-gray-900">
Alert Management {t('alerts.title')}
</h3> </h3>
<p className="mt-1 text-sm text-gray-500"> <p className="mt-1 text-sm text-gray-500">
Configure and monitor alert rules for drone detections {t('alerts.description')}
</p> </p>
</div> </div>
<button <button
@@ -126,7 +128,7 @@ const Alerts = () => {
className="btn btn-primary flex items-center space-x-2" className="btn btn-primary flex items-center space-x-2"
> >
<PlusIcon className="h-4 w-4" /> <PlusIcon className="h-4 w-4" />
<span>Create Alert Rule</span> <span>{t('alerts.createAlert')}</span>
</button> </button>
</div> </div>

View File

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import api from '../services/api'; import api from '../services/api';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { t } from '../utils/tempTranslations';
import { import {
PlusIcon, PlusIcon,
PencilIcon, PencilIcon,
@@ -145,6 +146,7 @@ const Devices = () => {
return ( return (
<div className="flex items-center justify-center h-64"> <div className="flex items-center justify-center h-64">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-primary-600"></div> <div className="animate-spin rounded-full h-32 w-32 border-b-2 border-primary-600"></div>
<span className="ml-4 text-gray-600">{t('devices.loading')}</span>
</div> </div>
); );
} }
@@ -154,10 +156,10 @@ const Devices = () => {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h3 className="text-lg leading-6 font-medium text-gray-900"> <h3 className="text-lg leading-6 font-medium text-gray-900">
Devices {t('devices.title')}
</h3> </h3>
<p className="mt-1 text-sm text-gray-500"> <p className="mt-1 text-sm text-gray-500">
Manage your drone detection devices {t('devices.description')}
{pendingCount > 0 && ( {pendingCount > 0 && (
<span className="ml-2 px-2 py-1 text-xs font-medium bg-yellow-200 text-yellow-800 rounded-full"> <span className="ml-2 px-2 py-1 text-xs font-medium bg-yellow-200 text-yellow-800 rounded-full">
{pendingCount} pending approval {pendingCount} pending approval
@@ -170,7 +172,7 @@ const Devices = () => {
className="btn btn-primary flex items-center space-x-2" className="btn btn-primary flex items-center space-x-2"
> >
<PlusIcon className="h-4 w-4" /> <PlusIcon className="h-4 w-4" />
<span>Add Device</span> <span>{t('devices.addDevice')}</span>
</button> </button>
</div> </div>

View File

@@ -4,6 +4,7 @@ import { useAuth } from '../contexts/AuthContext';
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline'; import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import api from '../services/api'; import api from '../services/api';
import { t } from '../utils/tempTranslations';
const Login = () => { const Login = () => {
const [credentials, setCredentials] = useState({ const [credentials, setCredentials] = useState({
@@ -42,7 +43,7 @@ const Login = () => {
<div className="min-h-screen flex items-center justify-center bg-gray-50"> <div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="text-center"> <div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600 mx-auto"></div> <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600 mx-auto"></div>
<p className="mt-4 text-gray-600">Loading...</p> <p className="mt-4 text-gray-600">{t('common.loading')}</p>
</div> </div>
</div> </div>
); );
@@ -100,7 +101,7 @@ const Login = () => {
{tenantConfig?.tenant_name || 'Drone Detection System'} {tenantConfig?.tenant_name || 'Drone Detection System'}
</h2> </h2>
<p className="mt-2 text-center text-sm text-gray-600"> <p className="mt-2 text-center text-sm text-gray-600">
Sign in to your account {t('auth.signIn')}
</p> </p>
{tenantConfig?.auth_provider && ( {tenantConfig?.auth_provider && (
<p className="mt-1 text-center text-xs text-gray-500"> <p className="mt-1 text-center text-xs text-gray-500">
@@ -115,7 +116,7 @@ const Login = () => {
<div className="rounded-md shadow-sm -space-y-px"> <div className="rounded-md shadow-sm -space-y-px">
<div> <div>
<label htmlFor="username" className="sr-only"> <label htmlFor="username" className="sr-only">
Username or Email {t('auth.username')}
</label> </label>
<input <input
id="username" id="username"
@@ -123,7 +124,7 @@ const Login = () => {
type="text" type="text"
required required
className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-primary-500 focus:border-primary-500 focus:z-10 sm:text-sm" className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-primary-500 focus:border-primary-500 focus:z-10 sm:text-sm"
placeholder="Username or Email" placeholder={t('auth.username')}
value={credentials.username} value={credentials.username}
onChange={handleChange} onChange={handleChange}
disabled={loading} disabled={loading}
@@ -131,7 +132,7 @@ const Login = () => {
</div> </div>
<div className="relative"> <div className="relative">
<label htmlFor="password" className="sr-only"> <label htmlFor="password" className="sr-only">
Password {t('auth.password')}
</label> </label>
<input <input
id="password" id="password"
@@ -139,7 +140,7 @@ const Login = () => {
type={showPassword ? 'text' : 'password'} type={showPassword ? 'text' : 'password'}
required required
className="appearance-none rounded-none relative block w-full px-3 py-2 pr-10 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-primary-500 focus:border-primary-500 focus:z-10 sm:text-sm" className="appearance-none rounded-none relative block w-full px-3 py-2 pr-10 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-primary-500 focus:border-primary-500 focus:z-10 sm:text-sm"
placeholder="Password" placeholder={t('auth.password')}
value={credentials.password} value={credentials.password}
onChange={handleChange} onChange={handleChange}
disabled={loading} disabled={loading}
@@ -167,7 +168,7 @@ const Login = () => {
{loading ? ( {loading ? (
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div> <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
) : ( ) : (
'Sign in' t('auth.signIn')
)} )}
</button> </button>
</div> </div>

View File

@@ -6,6 +6,7 @@ import L from 'leaflet'; // For divIcon and other Leaflet utilities
import { useSocket } from '../contexts/SocketContext'; import { useSocket } from '../contexts/SocketContext';
import api from '../services/api'; import api from '../services/api';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { t } from '../utils/tempTranslations';
import { import {
ServerIcon, ServerIcon,
ExclamationTriangleIcon, ExclamationTriangleIcon,
@@ -324,10 +325,10 @@ const MapView = () => {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h3 className="text-lg leading-6 font-medium text-gray-900"> <h3 className="text-lg leading-6 font-medium text-gray-900">
Device Map {t('map.title')}
</h3> </h3>
<p className="mt-1 text-sm text-gray-500"> <p className="mt-1 text-sm text-gray-500">
Real-time view of all devices and drone detections {t('map.description')}
</p> </p>
</div> </div>

View File

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { useAuth } from '../contexts/AuthContext'; import { useAuth } from '../contexts/AuthContext';
import api from '../services/api'; import api from '../services/api';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { t } from '../utils/tempTranslations';
import { import {
CogIcon, CogIcon,
ShieldCheckIcon, ShieldCheckIcon,
@@ -90,6 +91,7 @@ const Settings = () => {
return ( return (
<div className="min-h-screen flex items-center justify-center"> <div className="min-h-screen flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600"></div> <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600"></div>
<span className="ml-4 text-gray-600">{t('settings.loading')}</span>
</div> </div>
); );
} }
@@ -115,7 +117,7 @@ const Settings = () => {
<div className="border-b border-gray-200"> <div className="border-b border-gray-200">
<div className="sm:flex sm:items-baseline"> <div className="sm:flex sm:items-baseline">
<h3 className="text-lg leading-6 font-medium text-gray-900"> <h3 className="text-lg leading-6 font-medium text-gray-900">
Tenant Settings {t('settings.title')}
</h3> </h3>
<div className="mt-4 sm:mt-0 sm:ml-10"> <div className="mt-4 sm:mt-0 sm:ml-10">
<nav className="-mb-px flex space-x-8"> <nav className="-mb-px flex space-x-8">

View File

@@ -7,7 +7,8 @@ const translations = {
devices: 'Devices', devices: 'Devices',
alerts: 'Alerts', alerts: 'Alerts',
settings: 'Settings', settings: 'Settings',
logout: 'Logout' logout: 'Logout',
map: 'Map View'
}, },
dashboard: { dashboard: {
title: 'System Overview', title: 'System Overview',
@@ -19,10 +20,19 @@ const translations = {
activeAlerts: 'Active Alerts', activeAlerts: 'Active Alerts',
totalDetections: 'Total Detections', totalDetections: 'Total Detections',
noData: 'No data available', noData: 'No data available',
loading: 'Loading...' loading: 'Loading...',
refreshData: 'Refresh Data',
notificationsEnabled: 'Notifications Enabled',
notificationsDisabled: 'Notifications Disabled',
detectionHistory: 'Detection History',
deviceStatus: 'Device Status',
lastHour: 'Last Hour',
last24Hours: 'Last 24 Hours',
thisWeek: 'This Week'
}, },
detections: { detections: {
title: 'Drone Detections', title: 'Drone Detections',
description: 'History of all drone detections from your devices',
noDetections: 'No detections found', noDetections: 'No detections found',
loading: 'Loading detections...', loading: 'Loading detections...',
timestamp: 'Timestamp', timestamp: 'Timestamp',
@@ -30,48 +40,173 @@ const translations = {
confidence: 'Confidence', confidence: 'Confidence',
location: 'Location', location: 'Location',
device: 'Device', device: 'Device',
actions: 'Actions' actions: 'Actions',
searchPlaceholder: 'Search detections...',
filterByType: 'Filter by type',
filterByDevice: 'Filter by device',
exportData: 'Export Data',
viewDetails: 'View Details',
showOnMap: 'Show on Map',
highConfidence: 'High Confidence',
mediumConfidence: 'Medium Confidence',
lowConfidence: 'Low Confidence'
}, },
devices: { devices: {
title: 'Device Management', title: 'Device Management',
description: 'Monitor and manage your detection devices',
noDevices: 'No devices found', noDevices: 'No devices found',
loading: 'Loading devices...', loading: 'Loading devices...',
name: 'Name', name: 'Name',
status: 'Status', status: 'Status',
lastSeen: 'Last Seen', lastSeen: 'Last Seen',
location: 'Location', location: 'Location',
actions: 'Actions' actions: 'Actions',
addDevice: 'Add Device',
editDevice: 'Edit Device',
deleteDevice: 'Delete Device',
deviceDetails: 'Device Details',
batteryLevel: 'Battery Level',
signalStrength: 'Signal Strength',
firmware: 'Firmware',
ipAddress: 'IP Address',
macAddress: 'MAC Address'
}, },
alerts: { alerts: {
title: 'Alert Management', title: 'Alert Management',
description: 'Configure and manage detection alerts',
noAlerts: 'No alerts found', noAlerts: 'No alerts found',
loading: 'Loading alerts...', loading: 'Loading alerts...',
type: 'Type', type: 'Type',
priority: 'Priority', priority: 'Priority',
status: 'Status', status: 'Status',
created: 'Created', created: 'Created',
actions: 'Actions' actions: 'Actions',
createAlert: 'Create Alert',
editAlert: 'Edit Alert',
deleteAlert: 'Delete Alert',
alertName: 'Alert Name',
alertDescription: 'Description',
triggerConditions: 'Trigger Conditions',
notificationSettings: 'Notification Settings',
emailNotifications: 'Email Notifications',
smsNotifications: 'SMS Notifications',
webhookUrl: 'Webhook URL',
highPriority: 'High Priority',
mediumPriority: 'Medium Priority',
lowPriority: 'Low Priority',
active: 'Active',
inactive: 'Inactive',
triggered: 'Triggered'
}, },
settings: { settings: {
title: 'Settings', title: 'Settings',
description: 'Configure your account and system preferences',
profile: 'Profile', profile: 'Profile',
notifications: 'Notifications', notifications: 'Notifications',
system: 'System' system: 'System',
account: 'Account Settings',
security: 'Security Settings',
preferences: 'Preferences',
language: 'Language',
timezone: 'Timezone',
emailSettings: 'Email Settings',
passwordSettings: 'Password Settings',
twoFactorAuth: 'Two-Factor Authentication',
apiKeys: 'API Keys',
dataRetention: 'Data Retention',
exportData: 'Export Data',
deleteAccount: 'Delete Account'
},
auth: {
login: 'Login',
logout: 'Logout',
username: 'Username',
password: 'Password',
email: 'Email',
confirmPassword: 'Confirm Password',
forgotPassword: 'Forgot Password?',
signIn: 'Sign In',
signUp: 'Sign Up',
register: 'Register',
signingIn: 'Signing in...',
registering: 'Creating account...',
rememberMe: 'Remember me',
createAccount: 'Create Account',
alreadyHaveAccount: 'Already have an account?',
dontHaveAccount: "Don't have an account?",
resetPassword: 'Reset Password',
backToLogin: 'Back to Login'
},
map: {
title: 'Map View',
description: 'Real-time detection locations and device status',
loading: 'Loading map...',
noDetections: 'No detections to display',
deviceLocation: 'Device Location',
detectionLocation: 'Detection Location',
lastDetection: 'Last Detection',
deviceOnline: 'Device Online',
deviceOffline: 'Device Offline',
zoomToLocation: 'Zoom to Location',
showAllDevices: 'Show All Devices',
showDetections: 'Show Detections',
filterByTime: 'Filter by Time',
realTimeUpdates: 'Real-time Updates'
}, },
app: { app: {
title: 'UAM-ILS Drone Detection System' title: 'UAM-ILS Drone Detection System',
subtitle: 'Real-time Drone Monitoring',
connectionStatus: 'Connection Status',
connected: 'Connected',
disconnected: 'Disconnected',
systemStatus: 'System Status',
online: 'Online',
offline: 'Offline'
}, },
common: { common: {
loading: 'Loading...', loading: 'Loading...',
error: 'Error', error: 'Error',
success: 'Success', success: 'Success',
warning: 'Warning',
info: 'Information',
cancel: 'Cancel', cancel: 'Cancel',
save: 'Save', save: 'Save',
delete: 'Delete', delete: 'Delete',
edit: 'Edit', edit: 'Edit',
view: 'View', view: 'View',
close: 'Close', close: 'Close',
refresh: 'Refresh' refresh: 'Refresh',
search: 'Search',
filter: 'Filter',
export: 'Export',
import: 'Import',
add: 'Add',
remove: 'Remove',
update: 'Update',
confirm: 'Confirm',
yes: 'Yes',
no: 'No',
ok: 'OK',
apply: 'Apply',
reset: 'Reset',
clear: 'Clear',
all: 'All',
none: 'None',
selected: 'Selected',
total: 'Total',
page: 'Page',
of: 'of',
previous: 'Previous',
next: 'Next',
first: 'First',
last: 'Last',
date: 'Date',
time: 'Time',
status: 'Status',
type: 'Type',
name: 'Name',
description: 'Description',
actions: 'Actions'
} }
}, },
sv: { sv: {
@@ -81,7 +216,8 @@ const translations = {
devices: 'Enheter', devices: 'Enheter',
alerts: 'Larm', alerts: 'Larm',
settings: 'Inställningar', settings: 'Inställningar',
logout: 'Logga ut' logout: 'Logga ut',
map: 'Kartvy'
}, },
dashboard: { dashboard: {
title: 'Systemöversikt', title: 'Systemöversikt',
@@ -93,10 +229,19 @@ const translations = {
activeAlerts: 'Aktiva larm', activeAlerts: 'Aktiva larm',
totalDetections: 'Totala detekteringar', totalDetections: 'Totala detekteringar',
noData: 'Ingen data tillgänglig', noData: 'Ingen data tillgänglig',
loading: 'Laddar...' loading: 'Laddar...',
refreshData: 'Uppdatera data',
notificationsEnabled: 'Aviseringar aktiverade',
notificationsDisabled: 'Aviseringar inaktiverade',
detectionHistory: 'Detekteringshistorik',
deviceStatus: 'Enhetsstatus',
lastHour: 'Senaste timmen',
last24Hours: 'Senaste 24 timmarna',
thisWeek: 'Denna vecka'
}, },
detections: { detections: {
title: 'Drönaredetekteringar', title: 'Drönaredetekteringar',
description: 'Historik över alla drönaredetekteringar från dina enheter',
noDetections: 'Inga detekteringar hittades', noDetections: 'Inga detekteringar hittades',
loading: 'Laddar detekteringar...', loading: 'Laddar detekteringar...',
timestamp: 'Tidsstämpel', timestamp: 'Tidsstämpel',
@@ -104,48 +249,173 @@ const translations = {
confidence: 'Säkerhet', confidence: 'Säkerhet',
location: 'Plats', location: 'Plats',
device: 'Enhet', device: 'Enhet',
actions: 'Åtgärder' actions: 'Åtgärder',
searchPlaceholder: 'Sök detekteringar...',
filterByType: 'Filtrera efter typ',
filterByDevice: 'Filtrera efter enhet',
exportData: 'Exportera data',
viewDetails: 'Visa detaljer',
showOnMap: 'Visa på karta',
highConfidence: 'Hög säkerhet',
mediumConfidence: 'Medel säkerhet',
lowConfidence: 'Låg säkerhet'
}, },
devices: { devices: {
title: 'Enhetshantering', title: 'Enhetshantering',
description: 'Övervaka och hantera dina detekteringsenheter',
noDevices: 'Inga enheter hittades', noDevices: 'Inga enheter hittades',
loading: 'Laddar enheter...', loading: 'Laddar enheter...',
name: 'Namn', name: 'Namn',
status: 'Status', status: 'Status',
lastSeen: 'Senast sedd', lastSeen: 'Senast sedd',
location: 'Plats', location: 'Plats',
actions: 'Åtgärder' actions: 'Åtgärder',
addDevice: 'Lägg till enhet',
editDevice: 'Redigera enhet',
deleteDevice: 'Ta bort enhet',
deviceDetails: 'Enhetsdetaljer',
batteryLevel: 'Batterinivå',
signalStrength: 'Signalstyrka',
firmware: 'Firmware',
ipAddress: 'IP-adress',
macAddress: 'MAC-adress'
}, },
alerts: { alerts: {
title: 'Larmhantering', title: 'Larmhantering',
description: 'Konfigurera och hantera detekteringslarm',
noAlerts: 'Inga larm hittades', noAlerts: 'Inga larm hittades',
loading: 'Laddar larm...', loading: 'Laddar larm...',
type: 'Typ', type: 'Typ',
priority: 'Prioritet', priority: 'Prioritet',
status: 'Status', status: 'Status',
created: 'Skapad', created: 'Skapad',
actions: 'Åtgärder' actions: 'Åtgärder',
createAlert: 'Skapa larm',
editAlert: 'Redigera larm',
deleteAlert: 'Ta bort larm',
alertName: 'Larmnamn',
alertDescription: 'Beskrivning',
triggerConditions: 'Utlösningsvillkor',
notificationSettings: 'Aviseringsinställningar',
emailNotifications: 'E-postaviseringar',
smsNotifications: 'SMS-aviseringar',
webhookUrl: 'Webhook URL',
highPriority: 'Hög prioritet',
mediumPriority: 'Medel prioritet',
lowPriority: 'Låg prioritet',
active: 'Aktiv',
inactive: 'Inaktiv',
triggered: 'Utlöst'
}, },
settings: { settings: {
title: 'Inställningar', title: 'Inställningar',
description: 'Konfigurera ditt konto och systempreferenser',
profile: 'Profil', profile: 'Profil',
notifications: 'Aviseringar', notifications: 'Aviseringar',
system: 'System' system: 'System',
account: 'Kontoinställningar',
security: 'Säkerhetsinställningar',
preferences: 'Preferenser',
language: 'Språk',
timezone: 'Tidszon',
emailSettings: 'E-postinställningar',
passwordSettings: 'Lösenordsinställningar',
twoFactorAuth: 'Tvåfaktorsautentisering',
apiKeys: 'API-nycklar',
dataRetention: 'Datalagring',
exportData: 'Exportera data',
deleteAccount: 'Ta bort konto'
},
auth: {
login: 'Logga in',
logout: 'Logga ut',
username: 'Användarnamn',
password: 'Lösenord',
email: 'E-post',
confirmPassword: 'Bekräfta lösenord',
forgotPassword: 'Glömt lösenord?',
signIn: 'Logga in',
signUp: 'Registrera',
register: 'Registrera',
signingIn: 'Loggar in...',
registering: 'Skapar konto...',
rememberMe: 'Kom ihåg mig',
createAccount: 'Skapa konto',
alreadyHaveAccount: 'Har du redan ett konto?',
dontHaveAccount: 'Har du inget konto?',
resetPassword: 'Återställ lösenord',
backToLogin: 'Tillbaka till inloggning'
},
map: {
title: 'Kartvy',
description: 'Realtidsdetekteringsplatser och enhetsstatus',
loading: 'Laddar karta...',
noDetections: 'Inga detekteringar att visa',
deviceLocation: 'Enhetsplats',
detectionLocation: 'Detekteringsplats',
lastDetection: 'Senaste detektion',
deviceOnline: 'Enhet online',
deviceOffline: 'Enhet offline',
zoomToLocation: 'Zooma till plats',
showAllDevices: 'Visa alla enheter',
showDetections: 'Visa detekteringar',
filterByTime: 'Filtrera efter tid',
realTimeUpdates: 'Realtidsuppdateringar'
}, },
app: { app: {
title: 'UAM-ILS Drönardetekteringssystem' title: 'UAM-ILS Drönardetekteringssystem',
subtitle: 'Realtids drönarövervakning',
connectionStatus: 'Anslutningsstatus',
connected: 'Ansluten',
disconnected: 'Frånkopplad',
systemStatus: 'Systemstatus',
online: 'Online',
offline: 'Offline'
}, },
common: { common: {
loading: 'Laddar...', loading: 'Laddar...',
error: 'Fel', error: 'Fel',
success: 'Framgång', success: 'Framgång',
warning: 'Varning',
info: 'Information',
cancel: 'Avbryt', cancel: 'Avbryt',
save: 'Spara', save: 'Spara',
delete: 'Ta bort', delete: 'Ta bort',
edit: 'Redigera', edit: 'Redigera',
view: 'Visa', view: 'Visa',
close: 'Stäng', close: 'Stäng',
refresh: 'Uppdatera' refresh: 'Uppdatera',
search: 'Sök',
filter: 'Filtrera',
export: 'Exportera',
import: 'Importera',
add: 'Lägg till',
remove: 'Ta bort',
update: 'Uppdatera',
confirm: 'Bekräfta',
yes: 'Ja',
no: 'Nej',
ok: 'OK',
apply: 'Tillämpa',
reset: 'Återställ',
clear: 'Rensa',
all: 'Alla',
none: 'Inga',
selected: 'Valda',
total: 'Totalt',
page: 'Sida',
of: 'av',
previous: 'Föregående',
next: 'Nästa',
first: 'Första',
last: 'Sista',
date: 'Datum',
time: 'Tid',
status: 'Status',
type: 'Typ',
name: 'Namn',
description: 'Beskrivning',
actions: 'Åtgärder'
} }
} }
}; };