diff --git a/package.json b/package.json
index 3919bf0..ff37c72 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
- "prestart": "node -e \"const fs=require('fs'); if(!fs.existsSync('dist/index.html')){console.log('Building frontend...'); require('child_process').execSync('npm run build',{stdio:'inherit'})}\"",
+ "prestart": "npm run build",
"start": "node server.js",
"server": "node server.js",
"test": "echo \"Tests passing\" && exit 0"
diff --git a/src/components/SettingsPanel.jsx b/src/components/SettingsPanel.jsx
index 8566d4c..63770fc 100644
--- a/src/components/SettingsPanel.jsx
+++ b/src/components/SettingsPanel.jsx
@@ -5,6 +5,7 @@
import React, { useState, useEffect } from 'react';
import { calculateGridSquare } from '../utils/geo.js';
import { useTranslation, Trans } from 'react-i18next';
+import { LANGUAGES } from '../lang/i18n.js';
export const SettingsPanel = ({ isOpen, onClose, config, onSave }) => {
const [callsign, setCallsign] = useState(config?.callsign || '');
@@ -14,7 +15,7 @@ export const SettingsPanel = ({ isOpen, onClose, config, onSave }) => {
const [theme, setTheme] = useState(config?.theme || 'dark');
const [layout, setLayout] = useState(config?.layout || 'modern');
const [dxClusterSource, setDxClusterSource] = useState(config?.dxClusterSource || 'dxspider-proxy');
- const { t } = useTranslation();
+ const { t, i18n } = useTranslation();
// Layer controls
const [layers, setLayers] = useState([]);
@@ -478,6 +479,40 @@ export const SettingsPanel = ({ isOpen, onClose, config, onSave }) => {
{t('station.settings.dx.describe')}
+
+ {/* Language */}
+
+
+
+ {LANGUAGES.map((lang) => (
+
+ ))}
+
+
>
)}
diff --git a/src/lang/de.json b/src/lang/de.json
new file mode 100644
index 0000000..7097c55
--- /dev/null
+++ b/src/lang/de.json
@@ -0,0 +1,48 @@
+{
+ "cancel": "Abbrechen",
+ "station.settings.language": "Sprache",
+ "station.settings.language.en": "English",
+ "station.settings.language.fr": "Français",
+ "station.settings.language.es": "Español",
+ "station.settings.language.de": "Deutsch",
+ "station.settings.language.pt": "Português",
+ "station.settings.language.ja": "日本語",
+ "station.settings.language.it": "Italiano",
+ "station.settings.altitude": "Höhe (m)",
+ "station.settings.antenna": "Antenne",
+ "station.settings.button.save": "Einstellungen Speichern",
+ "station.settings.button.save.confirm": "Einstellungen werden im Browser gespeichert",
+ "station.settings.callsign": "Dein Rufzeichen",
+ "station.settings.describe": "Bitte gib dein Rufzeichen und Locator ein. Deine Einstellungen werden im Browser gespeichert.",
+ "station.settings.dx.describe": "→ Echtzeit DX Spider Feed über unseren dedizierten Proxy-Dienst",
+ "station.settings.dx.option1": "⭐ DX Spider Proxy (Empfohlen)",
+ "station.settings.dx.option2": "HamQTH Cluster",
+ "station.settings.dx.option3": "DXWatch",
+ "station.settings.dx.option4": "Auto (alle Quellen versuchen)",
+ "station.settings.dx.title": "DX Cluster Quelle",
+ "station.settings.layout": "Layout",
+ "station.settings.layout.classic": "Klassisch",
+ "station.settings.layout.classic.describe": "→ Original HamClock-Layout",
+ "station.settings.layout.modern": "Modern",
+ "station.settings.layout.modern.describe": "→ Modernes responsives Grid-Layout",
+ "station.settings.latitude": "Breitengrad",
+ "station.settings.locator": "Locator (oder Lat/Lon unten eingeben)",
+ "station.settings.longitude": "Längengrad",
+ "station.settings.power": "Leistung (W)",
+ "station.settings.theme": "DESIGN",
+ "station.settings.theme.dark": "Dunkel",
+ "station.settings.theme.dark.describe": "→ Modernes dunkles Design (Standard)",
+ "station.settings.theme.legacy": "Legacy",
+ "station.settings.theme.legacy.describe": "→ Grüner CRT-Terminal-Stil",
+ "station.settings.theme.light": "Hell",
+ "station.settings.theme.light.describe": "→ Helles Design für Tagbetrieb",
+ "station.settings.theme.retro": "Retro",
+ "station.settings.theme.retro.describe": "→ 90er Windows Retro-Stil",
+ "station.settings.timezone": "Zeitzone",
+ "station.settings.title": "⚙ Stationseinstellungen",
+ "station.settings.tip.env": "💡 Tipp: Für dauerhafte Konfiguration kopiere .env.example nach .env und setze CALLSIGN und LOCATOR",
+ "station.settings.useLocation": "📍 Meinen Standort verwenden",
+ "station.settings.useLocation.error1": "Standort konnte nicht ermittelt werden. Bitte manuell eingeben.",
+ "station.settings.useLocation.error2": "Geolokalisierung wird von deinem Browser nicht unterstützt.",
+ "station.settings.welcome": "👋 Willkommen bei OpenHamClock!"
+}
diff --git a/src/lang/en.json b/src/lang/en.json
index 41da978..5a9cd72 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -1,5 +1,13 @@
{
"cancel": "Cancel",
+ "station.settings.language": "Language",
+ "station.settings.language.en": "English",
+ "station.settings.language.fr": "Français",
+ "station.settings.language.es": "Español",
+ "station.settings.language.de": "Deutsch",
+ "station.settings.language.pt": "Português",
+ "station.settings.language.ja": "日本語",
+ "station.settings.language.it": "Italiano",
"station.settings.altitude": "Altitude (m)",
"station.settings.antenna": "Antenna",
"station.settings.button.save": "Save Settings",
diff --git a/src/lang/es.json b/src/lang/es.json
new file mode 100644
index 0000000..750cfec
--- /dev/null
+++ b/src/lang/es.json
@@ -0,0 +1,48 @@
+{
+ "cancel": "Cancelar",
+ "station.settings.language": "Idioma",
+ "station.settings.language.en": "English",
+ "station.settings.language.fr": "Français",
+ "station.settings.language.es": "Español",
+ "station.settings.language.de": "Deutsch",
+ "station.settings.language.pt": "Português",
+ "station.settings.language.ja": "日本語",
+ "station.settings.language.it": "Italiano",
+ "station.settings.altitude": "Altitud (m)",
+ "station.settings.antenna": "Antena",
+ "station.settings.button.save": "Guardar Configuración",
+ "station.settings.button.save.confirm": "La configuración se guarda en tu navegador",
+ "station.settings.callsign": "Tu Indicativo",
+ "station.settings.describe": "Ingresa tu indicativo y cuadrícula para comenzar. Tu configuración se guardará en el navegador.",
+ "station.settings.dx.describe": "→ Feed en tiempo real de DX Spider a través de nuestro servicio proxy dedicado",
+ "station.settings.dx.option1": "⭐ Proxy DX Spider (Recomendado)",
+ "station.settings.dx.option2": "Cluster HamQTH",
+ "station.settings.dx.option3": "DXWatch",
+ "station.settings.dx.option4": "Auto (probar todas las fuentes)",
+ "station.settings.dx.title": "Fuente del Cluster DX",
+ "station.settings.layout": "Diseño",
+ "station.settings.layout.classic": "Clásico",
+ "station.settings.layout.classic.describe": "→ Diseño estilo HamClock original",
+ "station.settings.layout.modern": "Moderno",
+ "station.settings.layout.modern.describe": "→ Diseño moderno con cuadrícula adaptable",
+ "station.settings.latitude": "Latitud",
+ "station.settings.locator": "Cuadrícula (o ingresa Lat/Lon abajo)",
+ "station.settings.longitude": "Longitud",
+ "station.settings.power": "Potencia (W)",
+ "station.settings.theme": "TEMA",
+ "station.settings.theme.dark": "Oscuro",
+ "station.settings.theme.dark.describe": "→ Tema oscuro moderno (predeterminado)",
+ "station.settings.theme.legacy": "Legacy",
+ "station.settings.theme.legacy.describe": "→ Estilo terminal CRT verde",
+ "station.settings.theme.light": "Claro",
+ "station.settings.theme.light.describe": "→ Tema claro para uso diurno",
+ "station.settings.theme.retro": "Retro",
+ "station.settings.theme.retro.describe": "→ Estilo retro Windows años 90",
+ "station.settings.timezone": "Zona horaria",
+ "station.settings.title": "⚙ Configuración de Estación",
+ "station.settings.tip.env": "💡 Consejo: Para configuración permanente, copia .env.example a .env y configura CALLSIGN y LOCATOR",
+ "station.settings.useLocation": "📍 Usar Mi Ubicación Actual",
+ "station.settings.useLocation.error1": "No se pudo obtener la ubicación. Por favor ingrésala manualmente.",
+ "station.settings.useLocation.error2": "La geolocalización no es compatible con tu navegador.",
+ "station.settings.welcome": "👋 ¡Bienvenido a OpenHamClock!"
+}
diff --git a/src/lang/fr.json b/src/lang/fr.json
index b1c0e93..14a2790 100644
--- a/src/lang/fr.json
+++ b/src/lang/fr.json
@@ -1,5 +1,13 @@
{
- "Cancel": "Annuler",
+ "cancel": "Annuler",
+ "station.settings.language": "Langue",
+ "station.settings.language.en": "English",
+ "station.settings.language.fr": "Français",
+ "station.settings.language.es": "Español",
+ "station.settings.language.de": "Deutsch",
+ "station.settings.language.pt": "Português",
+ "station.settings.language.ja": "日本語",
+ "station.settings.language.it": "Italiano",
"station.settings.altitude": "Altitude (m)",
"station.settings.antenna": "Antenne",
"station.settings.button.save": "Enregistrer les paramètres",
diff --git a/src/lang/i18n.js b/src/lang/i18n.js
index 0596300..e7bf69e 100644
--- a/src/lang/i18n.js
+++ b/src/lang/i18n.js
@@ -2,30 +2,47 @@ import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
-import translationFR from './fr.json';
import translationEN from './en.json';
+import translationFR from './fr.json';
+import translationES from './es.json';
+import translationDE from './de.json';
+import translationPT from './pt.json';
+import translationJA from './ja.json';
+import translationIT from './it.json';
+
+export const LANGUAGES = [
+ { code: 'en', name: 'English', flag: '🇬🇧' },
+ { code: 'fr', name: 'Français', flag: '🇫🇷' },
+ { code: 'es', name: 'Español', flag: '🇪🇸' },
+ { code: 'de', name: 'Deutsch', flag: '🇩🇪' },
+ { code: 'pt', name: 'Português', flag: '🇧🇷' },
+ { code: 'ja', name: '日本語', flag: '🇯🇵' },
+ { code: 'it', name: 'Italiano', flag: '🇮🇹' }
+];
export const resources = {
+ en: { translation: translationEN },
fr: { translation: translationFR },
- en: { translation: translationEN }
-} ;
+ es: { translation: translationES },
+ de: { translation: translationDE },
+ pt: { translation: translationPT },
+ ja: { translation: translationJA },
+ it: { translation: translationIT }
+};
i18n
- .use(LanguageDetector) // Automatically detects the user's language
+ .use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
- resources: {
- fr: {
- translation: translationFR
- },
- en: {
- translation: translationEN
- }
- },
+ resources,
interpolation: {
escapeValue: false
+ },
+ detection: {
+ order: ['localStorage', 'navigator'],
+ caches: ['localStorage']
}
});
-export default i18n;
\ No newline at end of file
+export default i18n;
diff --git a/src/lang/it.json b/src/lang/it.json
new file mode 100644
index 0000000..8406773
--- /dev/null
+++ b/src/lang/it.json
@@ -0,0 +1,48 @@
+{
+ "cancel": "Annulla",
+ "station.settings.language": "Lingua",
+ "station.settings.language.en": "English",
+ "station.settings.language.fr": "Français",
+ "station.settings.language.es": "Español",
+ "station.settings.language.de": "Deutsch",
+ "station.settings.language.pt": "Português",
+ "station.settings.language.ja": "日本語",
+ "station.settings.language.it": "Italiano",
+ "station.settings.altitude": "Altitudine (m)",
+ "station.settings.antenna": "Antenna",
+ "station.settings.button.save": "Salva Impostazioni",
+ "station.settings.button.save.confirm": "Le impostazioni vengono salvate nel browser",
+ "station.settings.callsign": "Il Tuo Nominativo",
+ "station.settings.describe": "Inserisci il tuo nominativo e il locatore per iniziare. Le impostazioni saranno salvate nel browser.",
+ "station.settings.dx.describe": "→ Feed in tempo reale da DX Spider tramite il nostro servizio proxy dedicato",
+ "station.settings.dx.option1": "⭐ Proxy DX Spider (Consigliato)",
+ "station.settings.dx.option2": "Cluster HamQTH",
+ "station.settings.dx.option3": "DXWatch",
+ "station.settings.dx.option4": "Auto (prova tutte le fonti)",
+ "station.settings.dx.title": "Fonte Cluster DX",
+ "station.settings.layout": "Layout",
+ "station.settings.layout.classic": "Classico",
+ "station.settings.layout.classic.describe": "→ Layout stile HamClock originale",
+ "station.settings.layout.modern": "Moderno",
+ "station.settings.layout.modern.describe": "→ Layout moderno con griglia reattiva",
+ "station.settings.latitude": "Latitudine",
+ "station.settings.locator": "Locatore (o inserisci Lat/Lon sotto)",
+ "station.settings.longitude": "Longitudine",
+ "station.settings.power": "Potenza (W)",
+ "station.settings.theme": "TEMA",
+ "station.settings.theme.dark": "Scuro",
+ "station.settings.theme.dark.describe": "→ Tema scuro moderno (predefinito)",
+ "station.settings.theme.legacy": "Legacy",
+ "station.settings.theme.legacy.describe": "→ Stile terminale CRT verde",
+ "station.settings.theme.light": "Chiaro",
+ "station.settings.theme.light.describe": "→ Tema chiaro per uso diurno",
+ "station.settings.theme.retro": "Retro",
+ "station.settings.theme.retro.describe": "→ Stile retro Windows anni '90",
+ "station.settings.timezone": "Fuso orario",
+ "station.settings.title": "⚙ Impostazioni Stazione",
+ "station.settings.tip.env": "💡 Suggerimento: Per una configurazione permanente, copia .env.example in .env e imposta CALLSIGN e LOCATOR",
+ "station.settings.useLocation": "📍 Usa la Mia Posizione Attuale",
+ "station.settings.useLocation.error1": "Impossibile ottenere la posizione. Inseriscila manualmente.",
+ "station.settings.useLocation.error2": "La geolocalizzazione non è supportata dal tuo browser.",
+ "station.settings.welcome": "👋 Benvenuto su OpenHamClock!"
+}
diff --git a/src/lang/ja.json b/src/lang/ja.json
new file mode 100644
index 0000000..7378688
--- /dev/null
+++ b/src/lang/ja.json
@@ -0,0 +1,48 @@
+{
+ "cancel": "キャンセル",
+ "station.settings.language": "言語",
+ "station.settings.language.en": "English",
+ "station.settings.language.fr": "Français",
+ "station.settings.language.es": "Español",
+ "station.settings.language.de": "Deutsch",
+ "station.settings.language.pt": "Português",
+ "station.settings.language.ja": "日本語",
+ "station.settings.language.it": "Italiano",
+ "station.settings.altitude": "標高 (m)",
+ "station.settings.antenna": "アンテナ",
+ "station.settings.button.save": "設定を保存",
+ "station.settings.button.save.confirm": "設定はブラウザに保存されます",
+ "station.settings.callsign": "コールサイン",
+ "station.settings.describe": "コールサインとグリッドロケーターを入力してください。設定はブラウザに保存されます。",
+ "station.settings.dx.describe": "→ 専用プロキシサービス経由のリアルタイムDX Spiderフィード",
+ "station.settings.dx.option1": "⭐ DX Spider プロキシ(推奨)",
+ "station.settings.dx.option2": "HamQTH クラスター",
+ "station.settings.dx.option3": "DXWatch",
+ "station.settings.dx.option4": "自動(すべてのソースを試行)",
+ "station.settings.dx.title": "DXクラスターソース",
+ "station.settings.layout": "レイアウト",
+ "station.settings.layout.classic": "クラシック",
+ "station.settings.layout.classic.describe": "→ オリジナルHamClockスタイルのレイアウト",
+ "station.settings.layout.modern": "モダン",
+ "station.settings.layout.modern.describe": "→ モダンなレスポンシブグリッドレイアウト",
+ "station.settings.latitude": "緯度",
+ "station.settings.locator": "グリッドロケーター(または下に緯度/経度を入力)",
+ "station.settings.longitude": "経度",
+ "station.settings.power": "出力 (W)",
+ "station.settings.theme": "テーマ",
+ "station.settings.theme.dark": "ダーク",
+ "station.settings.theme.dark.describe": "→ モダンなダークテーマ(デフォルト)",
+ "station.settings.theme.legacy": "レガシー",
+ "station.settings.theme.legacy.describe": "→ グリーンCRTターミナルスタイル",
+ "station.settings.theme.light": "ライト",
+ "station.settings.theme.light.describe": "→ 日中使用向けライトテーマ",
+ "station.settings.theme.retro": "レトロ",
+ "station.settings.theme.retro.describe": "→ 90年代Windowsレトロスタイル",
+ "station.settings.timezone": "タイムゾーン",
+ "station.settings.title": "⚙ 局設定",
+ "station.settings.tip.env": "💡 ヒント: 恒久的な設定には .env.example を .env にコピーしてCALLSIGNとLOCATORを設定",
+ "station.settings.useLocation": "📍 現在地を使用",
+ "station.settings.useLocation.error1": "位置情報を取得できません。手動で入力してください。",
+ "station.settings.useLocation.error2": "お使いのブラウザはジオロケーションに対応していません。",
+ "station.settings.welcome": "👋 OpenHamClockへようこそ!"
+}
diff --git a/src/lang/pt.json b/src/lang/pt.json
new file mode 100644
index 0000000..f7a81df
--- /dev/null
+++ b/src/lang/pt.json
@@ -0,0 +1,48 @@
+{
+ "cancel": "Cancelar",
+ "station.settings.language": "Idioma",
+ "station.settings.language.en": "English",
+ "station.settings.language.fr": "Français",
+ "station.settings.language.es": "Español",
+ "station.settings.language.de": "Deutsch",
+ "station.settings.language.pt": "Português",
+ "station.settings.language.ja": "日本語",
+ "station.settings.language.it": "Italiano",
+ "station.settings.altitude": "Altitude (m)",
+ "station.settings.antenna": "Antena",
+ "station.settings.button.save": "Salvar Configurações",
+ "station.settings.button.save.confirm": "As configurações são salvas no seu navegador",
+ "station.settings.callsign": "Seu Indicativo",
+ "station.settings.describe": "Digite seu indicativo e localizador para começar. Suas configurações serão salvas no navegador.",
+ "station.settings.dx.describe": "→ Feed em tempo real do DX Spider através do nosso serviço proxy dedicado",
+ "station.settings.dx.option1": "⭐ Proxy DX Spider (Recomendado)",
+ "station.settings.dx.option2": "Cluster HamQTH",
+ "station.settings.dx.option3": "DXWatch",
+ "station.settings.dx.option4": "Auto (tentar todas as fontes)",
+ "station.settings.dx.title": "Fonte do Cluster DX",
+ "station.settings.layout": "Layout",
+ "station.settings.layout.classic": "Clássico",
+ "station.settings.layout.classic.describe": "→ Layout estilo HamClock original",
+ "station.settings.layout.modern": "Moderno",
+ "station.settings.layout.modern.describe": "→ Layout moderno com grade responsiva",
+ "station.settings.latitude": "Latitude",
+ "station.settings.locator": "Localizador (ou digite Lat/Lon abaixo)",
+ "station.settings.longitude": "Longitude",
+ "station.settings.power": "Potência (W)",
+ "station.settings.theme": "TEMA",
+ "station.settings.theme.dark": "Escuro",
+ "station.settings.theme.dark.describe": "→ Tema escuro moderno (padrão)",
+ "station.settings.theme.legacy": "Legacy",
+ "station.settings.theme.legacy.describe": "→ Estilo terminal CRT verde",
+ "station.settings.theme.light": "Claro",
+ "station.settings.theme.light.describe": "→ Tema claro para uso diurno",
+ "station.settings.theme.retro": "Retro",
+ "station.settings.theme.retro.describe": "→ Estilo retro Windows anos 90",
+ "station.settings.timezone": "Fuso horário",
+ "station.settings.title": "⚙ Configurações da Estação",
+ "station.settings.tip.env": "💡 Dica: Para configuração permanente, copie .env.example para .env e defina CALLSIGN e LOCATOR",
+ "station.settings.useLocation": "📍 Usar Minha Localização Atual",
+ "station.settings.useLocation.error1": "Não foi possível obter a localização. Por favor, insira manualmente.",
+ "station.settings.useLocation.error2": "Geolocalização não é suportada pelo seu navegador.",
+ "station.settings.welcome": "👋 Bem-vindo ao OpenHamClock!"
+}