272 lines
10 KiB
JavaScript
272 lines
10 KiB
JavaScript
/**
|
|
* Internationalization utility for backend error messages and system messages
|
|
*/
|
|
|
|
const SUPPORTED_LANGUAGES = ['en', 'sv'];
|
|
const DEFAULT_LANGUAGE = 'en';
|
|
|
|
// Error message translations
|
|
const ERROR_MESSAGES = {
|
|
en: {
|
|
// Authentication errors
|
|
TOKEN_EXPIRED: 'Your session has expired. Please log in again.',
|
|
INVALID_TOKEN: 'Invalid authentication token. Please log in again.',
|
|
TOKEN_NOT_ACTIVE: 'Authentication token is not yet active.',
|
|
USER_NOT_FOUND: 'User account not found. Please contact support.',
|
|
ACCOUNT_DEACTIVATED: 'Your account has been deactivated. Please contact support.',
|
|
AUTH_REQUIRED: 'Authentication is required to access this resource.',
|
|
NO_TOKEN: 'No authentication token provided.',
|
|
|
|
// Authorization errors
|
|
INSUFFICIENT_PERMISSIONS: 'Access denied. This action requires {requiredRoles} permissions, but you have {userRole} permissions.',
|
|
PERMISSION_DENIED: 'You do not have permission to perform this action.',
|
|
INSUFFICIENT_MANAGEMENT_PRIVILEGES: 'Insufficient management privileges to access this resource.',
|
|
|
|
// Management errors
|
|
AUTHENTICATION_REQUIRED: 'Management authentication required.',
|
|
INSUFFICIENT_PRIVILEGES: 'Insufficient management privileges.',
|
|
INVALID_MANAGEMENT_CREDENTIALS: 'Invalid management credentials.',
|
|
MANAGEMENT_AUTH_ERROR: 'Management authentication error.',
|
|
|
|
// Tenant management
|
|
TENANT_NOT_FOUND: 'Tenant not found.',
|
|
TENANT_CREATION_FAILED: 'Failed to create tenant.',
|
|
TENANT_UPDATE_FAILED: 'Failed to update tenant.',
|
|
TENANT_DELETE_FAILED: 'Failed to delete tenant.',
|
|
TENANT_SLUG_EXISTS: 'Tenant slug already exists.',
|
|
DOMAIN_EXISTS: 'Domain already exists for another tenant.',
|
|
CANNOT_DELETE_DEFAULT: 'Cannot delete default tenant.',
|
|
NAME_SLUG_REQUIRED: 'Name and slug are required.',
|
|
TENANT_CREATED: 'Tenant created successfully.',
|
|
TENANT_UPDATED: 'Tenant updated successfully.',
|
|
TENANT_DELETED: 'Tenant deleted successfully.',
|
|
FETCH_TENANTS_FAILED: 'Failed to fetch tenants.',
|
|
FETCH_TENANT_FAILED: 'Failed to fetch tenant.',
|
|
|
|
// System errors
|
|
SYSTEM_INFO_FAILED: 'Failed to fetch system information.',
|
|
DOCKER_ACCESS_ERROR: 'This could mean Docker is not running, no containers are active, or the monitoring system needs Docker access.',
|
|
MANAGEMENT_AUTH_REQUIRED: 'Management authentication is required to access this resource.',
|
|
INVALID_MANAGEMENT_TOKEN: 'Invalid management authentication token.',
|
|
|
|
// General errors
|
|
AUTHENTICATION_FAILED: 'Authentication failed. Please try again.',
|
|
ACCESS_DENIED: 'Access denied.',
|
|
VALIDATION_ERROR: 'Validation error occurred.',
|
|
INTERNAL_ERROR: 'An internal error occurred. Please try again later.'
|
|
},
|
|
sv: {
|
|
// Authentication errors
|
|
TOKEN_EXPIRED: 'Din session har löpt ut. Vänligen logga in igen.',
|
|
INVALID_TOKEN: 'Ogiltig autentiseringstoken. Vänligen logga in igen.',
|
|
TOKEN_NOT_ACTIVE: 'Autentiseringstoken är inte aktiv ännu.',
|
|
USER_NOT_FOUND: 'Användarkonto hittades inte. Vänligen kontakta support.',
|
|
ACCOUNT_DEACTIVATED: 'Ditt konto har inaktiverats. Vänligen kontakta support.',
|
|
AUTH_REQUIRED: 'Autentisering krävs för att komma åt denna resurs.',
|
|
NO_TOKEN: 'Ingen autentiseringstoken tillhandahållen.',
|
|
|
|
// Authorization errors
|
|
INSUFFICIENT_PERMISSIONS: 'Åtkomst nekad. Denna åtgärd kräver {requiredRoles} behörigheter, men du har {userRole} behörigheter.',
|
|
PERMISSION_DENIED: 'Du har inte behörighet att utföra denna åtgärd.',
|
|
INSUFFICIENT_MANAGEMENT_PRIVILEGES: 'Otillräckliga förvaltningsprivilegier för att komma åt denna resurs.',
|
|
|
|
// Management errors
|
|
MANAGEMENT_AUTH_REQUIRED: 'Förvaltningsautentisering krävs för att komma åt denna resurs.',
|
|
INVALID_MANAGEMENT_TOKEN: 'Ogiltig förvaltningsautentiseringstoken.',
|
|
AUTHENTICATION_REQUIRED: 'Förvaltningsautentisering krävs.',
|
|
INSUFFICIENT_PRIVILEGES: 'Otillräckliga förvaltningsprivilegier.',
|
|
INVALID_MANAGEMENT_CREDENTIALS: 'Ogiltiga förvaltningsuppgifter.',
|
|
MANAGEMENT_AUTH_ERROR: 'Förvaltningsautentiseringsfel.',
|
|
|
|
// Tenant management
|
|
TENANT_NOT_FOUND: 'Hyresgäst hittades inte.',
|
|
TENANT_CREATION_FAILED: 'Misslyckades att skapa hyresgäst.',
|
|
TENANT_UPDATE_FAILED: 'Misslyckades att uppdatera hyresgäst.',
|
|
TENANT_DELETE_FAILED: 'Misslyckades att ta bort hyresgäst.',
|
|
TENANT_SLUG_EXISTS: 'Hyresgästslug finns redan.',
|
|
DOMAIN_EXISTS: 'Domän finns redan för en annan hyresgäst.',
|
|
CANNOT_DELETE_DEFAULT: 'Kan inte ta bort standardhyresgäst.',
|
|
NAME_SLUG_REQUIRED: 'Namn och slug krävs.',
|
|
TENANT_CREATED: 'Hyresgäst skapad framgångsrikt.',
|
|
TENANT_UPDATED: 'Hyresgäst uppdaterad framgångsrikt.',
|
|
TENANT_DELETED: 'Hyresgäst borttagen framgångsrikt.',
|
|
FETCH_TENANTS_FAILED: 'Misslyckades att hämta hyresgäster.',
|
|
FETCH_TENANT_FAILED: 'Misslyckades att hämta hyresgäst.',
|
|
|
|
// System errors
|
|
SYSTEM_INFO_FAILED: 'Misslyckades att hämta systeminformation.',
|
|
DOCKER_ACCESS_ERROR: 'Detta kan betyda att Docker inte körs, inga behållare är aktiva eller att övervakningssystemet behöver Docker-åtkomst.',
|
|
|
|
// General errors
|
|
AUTHENTICATION_FAILED: 'Autentisering misslyckades. Vänligen försök igen.',
|
|
ACCESS_DENIED: 'Åtkomst nekad.',
|
|
VALIDATION_ERROR: 'Valideringsfel inträffade.',
|
|
INTERNAL_ERROR: 'Ett internt fel inträffade. Vänligen försök igen senare.'
|
|
}
|
|
};
|
|
|
|
// System message translations (for alerts, notifications, etc.)
|
|
const SYSTEM_MESSAGES = {
|
|
en: {
|
|
// Alert messages
|
|
CRITICAL_THREAT_DETECTED: 'CRITICAL THREAT: {droneType} DETECTED - IMMEDIATE RESPONSE REQUIRED',
|
|
HIGH_THREAT_DETECTED: 'HIGH THREAT: {droneType} detected at {distance}m',
|
|
MEDIUM_THREAT_DETECTED: 'MEDIUM THREAT: {droneType} detected in vicinity',
|
|
LOW_THREAT_DETECTED: 'LOW THREAT: {droneType} detected at distance',
|
|
MONITORING_DETECTED: 'MONITORING: {droneType} detected at long range',
|
|
MILITARY_THREAT_ENHANCED: 'MILITARY THREAT: {droneType} DETECTED - ENHANCED RESPONSE REQUIRED',
|
|
|
|
// Device messages
|
|
DEVICE_OFFLINE: 'Device {deviceName} is offline',
|
|
DEVICE_ONLINE: 'Device {deviceName} is back online',
|
|
HEARTBEAT_RECEIVED: 'Heartbeat received from {deviceName}',
|
|
|
|
// General system messages
|
|
OPERATION_SUCCESSFUL: 'Operation completed successfully',
|
|
OPERATION_FAILED: 'Operation failed',
|
|
DATA_SAVED: 'Data saved successfully',
|
|
DATA_DELETED: 'Data deleted successfully'
|
|
},
|
|
sv: {
|
|
// Alert messages
|
|
CRITICAL_THREAT_DETECTED: 'KRITISKT HOT: {droneType} UPPTÄCKT - OMEDELBAR RESPONS KRÄVS',
|
|
HIGH_THREAT_DETECTED: 'HÖGT HOT: {droneType} upptäckt på {distance}m',
|
|
MEDIUM_THREAT_DETECTED: 'MEDELHÖGT HOT: {droneType} upptäckt i närheten',
|
|
LOW_THREAT_DETECTED: 'LÅGT HOT: {droneType} upptäckt på avstånd',
|
|
MONITORING_DETECTED: 'ÖVERVAKNING: {droneType} upptäckt på långt avstånd',
|
|
MILITARY_THREAT_ENHANCED: 'MILITÄRT HOT: {droneType} UPPTÄCKT - FÖRSTÄRKT RESPONS KRÄVS',
|
|
|
|
// Device messages
|
|
DEVICE_OFFLINE: 'Enhet {deviceName} är offline',
|
|
DEVICE_ONLINE: 'Enhet {deviceName} är online igen',
|
|
HEARTBEAT_RECEIVED: 'Heartbeat mottagen från {deviceName}',
|
|
|
|
// General system messages
|
|
OPERATION_SUCCESSFUL: 'Operationen slutfördes framgångsrikt',
|
|
OPERATION_FAILED: 'Operationen misslyckades',
|
|
DATA_SAVED: 'Data sparad framgångsrikt',
|
|
DATA_DELETED: 'Data raderad framgångsrikt'
|
|
}
|
|
};
|
|
|
|
// Drone type translations
|
|
const DRONE_TYPES = {
|
|
en: {
|
|
0: 'Unknown Drone',
|
|
1: 'DJI Mavic',
|
|
2: 'Orlan',
|
|
3: 'Racing Drone',
|
|
4: 'DJI Phantom',
|
|
5: 'Zala Lancet',
|
|
6: 'Eleron',
|
|
7: 'Commercial Drone',
|
|
8: 'Professional Drone'
|
|
},
|
|
sv: {
|
|
0: 'Okänd Drönare',
|
|
1: 'DJI Mavic',
|
|
2: 'Orlan',
|
|
3: 'Racing Drönare',
|
|
4: 'DJI Phantom',
|
|
5: 'Zala Lancet',
|
|
6: 'Eleron',
|
|
7: 'Kommersiell Drönare',
|
|
8: 'Professionell Drönare'
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get user's preferred language from request headers
|
|
*/
|
|
function getLanguageFromRequest(req) {
|
|
// Check for explicit language header
|
|
const explicitLang = req.headers['accept-language-override'] || req.headers['x-language'];
|
|
if (explicitLang && SUPPORTED_LANGUAGES.includes(explicitLang)) {
|
|
return explicitLang;
|
|
}
|
|
|
|
// Parse Accept-Language header
|
|
const acceptLanguage = req.headers['accept-language'];
|
|
if (acceptLanguage) {
|
|
const languages = acceptLanguage
|
|
.split(',')
|
|
.map(lang => lang.split(';')[0].trim().toLowerCase())
|
|
.map(lang => lang.split('-')[0]); // Get just the language part (sv from sv-SE)
|
|
|
|
for (const lang of languages) {
|
|
if (SUPPORTED_LANGUAGES.includes(lang)) {
|
|
return lang;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DEFAULT_LANGUAGE;
|
|
}
|
|
|
|
/**
|
|
* Get localized error message
|
|
*/
|
|
function getErrorMessage(messageKey, language = DEFAULT_LANGUAGE, params = {}) {
|
|
const lang = SUPPORTED_LANGUAGES.includes(language) ? language : DEFAULT_LANGUAGE;
|
|
let message = ERROR_MESSAGES[lang]?.[messageKey] || ERROR_MESSAGES[DEFAULT_LANGUAGE]?.[messageKey] || messageKey;
|
|
|
|
// Replace parameters in message
|
|
Object.keys(params).forEach(key => {
|
|
message = message.replace(new RegExp(`{${key}}`, 'g'), params[key]);
|
|
});
|
|
|
|
return message;
|
|
}
|
|
|
|
/**
|
|
* Get localized system message
|
|
*/
|
|
function getSystemMessage(messageKey, language = DEFAULT_LANGUAGE, params = {}) {
|
|
const lang = SUPPORTED_LANGUAGES.includes(language) ? language : DEFAULT_LANGUAGE;
|
|
let message = SYSTEM_MESSAGES[lang]?.[messageKey] || SYSTEM_MESSAGES[DEFAULT_LANGUAGE]?.[messageKey] || messageKey;
|
|
|
|
// Replace parameters in message
|
|
Object.keys(params).forEach(key => {
|
|
message = message.replace(new RegExp(`{${key}}`, 'g'), params[key]);
|
|
});
|
|
|
|
return message;
|
|
}
|
|
|
|
/**
|
|
* Get localized drone type name
|
|
*/
|
|
function getDroneTypeName(droneType, language = DEFAULT_LANGUAGE) {
|
|
const lang = SUPPORTED_LANGUAGES.includes(language) ? language : DEFAULT_LANGUAGE;
|
|
return DRONE_TYPES[lang]?.[droneType] || DRONE_TYPES[DEFAULT_LANGUAGE]?.[droneType] || 'Unknown';
|
|
}
|
|
|
|
/**
|
|
* Create localized error response
|
|
*/
|
|
function createErrorResponse(req, status, errorCode, params = {}) {
|
|
const language = getLanguageFromRequest(req);
|
|
const message = getErrorMessage(errorCode, language, params);
|
|
|
|
return {
|
|
status,
|
|
json: {
|
|
success: false,
|
|
message,
|
|
error: errorCode,
|
|
errorCode,
|
|
language,
|
|
...params
|
|
}
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
getLanguageFromRequest,
|
|
getErrorMessage,
|
|
getSystemMessage,
|
|
getDroneTypeName,
|
|
createErrorResponse,
|
|
SUPPORTED_LANGUAGES,
|
|
DEFAULT_LANGUAGE
|
|
}; |