diff --git a/meshview/lang/en.json b/meshview/lang/en.json index d28029b..a8bd506 100644 --- a/meshview/lang/en.json +++ b/meshview/lang/en.json @@ -1,110 +1,141 @@ -{ - "base": { - "conversations": "Conversations", - "nodes": "Nodes", - "everything": "See Everything", - "graph": "Mesh Graphs", - "net": "Weekly Net", - "map": "Live Map", - "stats": "Stats", - "top": "Top Traffic Nodes", - "footer": "Visit Meshview on GitHub", - "node id": "Node id", - "go to node": "Go to Node", - "all": "All", - "portnum_options": { - "1": "Text Message", - "3": "Position", - "4": "Node Info", - "67": "Telemetry", - "70": "Traceroute", - "71": "Neighbor Info" - } + { + "base": { + "conversations": "Conversations", + "nodes": "Nodes", + "everything": "See Everything", + "graph": "Mesh Graphs", + "net": "Weekly Net", + "map": "Live Map", + "stats": "Stats", + "top": "Top Traffic Nodes", + "footer": "Visit Meshview on GitHub", + "node id": "Node id", + "go to node": "Go to Node", + "all": "All", + "portnum_options": { + "1": "Text Message", + "3": "Position", + "4": "Node Info", + "67": "Telemetry", + "70": "Traceroute", + "71": "Neighbor Info" + } + }, + "chat": { + "replying_to": "Replying to:", + "view_packet_details": "View packet details" + }, + "nodelist": { + "search_placeholder": "Search by name or ID...", + "all_roles": "All Roles", + "all_channels": "All Channels", + "all_hw_models": "All HW Models", + "all_firmware": "All Firmware", + "export_csv": "Export CSV", + "clear_filters": "Clear Filters", + "showing": "Showing", + "nodes": "nodes", + "short": "Short", + "long_name": "Long Name", + "hw_model": "HW Model", + "firmware": "Firmware", + "role": "Role", + "last_lat": "Last Latitude", + "last_long": "Last Longitude", + "channel": "Channel", + "last_update": "Last Update", + "loading_nodes": "Loading nodes...", + "no_nodes": "No nodes found", + "error_nodes": "Error loading nodes" }, - "chat": { - "replying_to": "Replying to:", - "view_packet_details": "View packet details" - }, - "nodelist": { - "search_placeholder": "Search by name or ID...", - "all_roles": "All Roles", - "all_channels": "All Channels", - "all_hw_models": "All HW Models", - "all_firmware": "All Firmware", - "export_csv": "Export CSV", - "clear_filters": "Clear Filters", - "showing": "Showing", - "nodes": "nodes", - "short": "Short", - "long_name": "Long Name", - "hw_model": "HW Model", - "firmware": "Firmware", - "role": "Role", - "last_lat": "Last Latitude", - "last_long": "Last Longitude", - "channel": "Channel", - "last_update": "Last Update", - "loading_nodes": "Loading nodes...", - "no_nodes": "No nodes found", - "error_nodes": "Error loading nodes" - }, - "net": { - "number_of_checkins": "Number of Check-ins:", - "view_packet_details": "View packet details", - "view_all_packets_from_node": "View all packets from this node", - "no_packets_found": "No packets found." - }, - "map": { - "channel": "Channel:", - "model": "Model:", - "role": "Role:", - "last_seen": "Last seen:", - "firmware": "Firmware:", - "show_routers_only": "Show Routers Only", - "share_view": "Share This View" - }, - "stats": - { - "mesh_stats_summary": "Mesh Statistics - Summary (all available in Database)", - "total_nodes": "Total Nodes", - "total_packets": "Total Packets", - "total_packets_seen": "Total Packets Seen", - "packets_per_day_all": "Packets per Day - All Ports (Last 14 Days)", - "packets_per_day_text": "Packets per Day - Text Messages (Port 1, Last 14 Days)", - "packets_per_hour_all": "Packets per Hour - All Ports", - "packets_per_hour_text": "Packets per Hour - Text Messages (Port 1)", - "packet_types_last_24h": "Packet Types - Last 24 Hours", - "hardware_breakdown": "Hardware Breakdown", - "role_breakdown": "Role Breakdown", - "channel_breakdown": "Channel Breakdown", - "expand_chart": "Expand Chart", - "export_csv": "Export CSV", - "all_channels": "All Channels" - }, - "top": - { - "top_traffic_nodes": "Top Traffic Nodes (last 24 hours)", - "chart_description_1": "This chart shows a bell curve (normal distribution) based on the total \"Times Seen\" values for all nodes. It helps visualize how frequently nodes are heard, relative to the average.", - "chart_description_2": "This \"Times Seen\" value is the closest that we can get to Mesh utilization by node.", - "mean_label": "Mean:", - "stddev_label": "Standard Deviation:", - "long_name": "Long Name", - "short_name": "Short Name", - "channel": "Channel", - "packets_sent": "Packets Sent", - "times_seen": "Times Seen", - "seen_percent": "Seen % of Mean", - "no_nodes": "No top traffic nodes available." - }, - "nodegraph": - { - "channel_label": "Channel:", - "search_node_placeholder": "Search node...", - "search_button": "Search", - "long_name_label": "Long Name:", - "short_name_label": "Short Name:", - "role_label": "Role:", - "hw_model_label": "Hardware Model:", - "node_not_found": "Node not found in current channel!" - } -} \ No newline at end of file + "net": { + "number_of_checkins": "Number of Check-ins:", + "view_packet_details": "View packet details", + "view_all_packets_from_node": "View all packets from this node", + "no_packets_found": "No packets found." + }, + "map": { + "channel": "Channel:", + "model": "Model:", + "role": "Role:", + "last_seen": "Last seen:", + "firmware": "Firmware:", + "show_routers_only": "Show Routers Only", + "share_view": "Share This View" + }, + "stats": + { + "mesh_stats_summary": "Mesh Statistics - Summary (all available in Database)", + "total_nodes": "Total Nodes", + "total_packets": "Total Packets", + "total_packets_seen": "Total Packets Seen", + "packets_per_day_all": "Packets per Day - All Ports (Last 14 Days)", + "packets_per_day_text": "Packets per Day - Text Messages (Port 1, Last 14 Days)", + "packets_per_hour_all": "Packets per Hour - All Ports", + "packets_per_hour_text": "Packets per Hour - Text Messages (Port 1)", + "packet_types_last_24h": "Packet Types - Last 24 Hours", + "hardware_breakdown": "Hardware Breakdown", + "role_breakdown": "Role Breakdown", + "channel_breakdown": "Channel Breakdown", + "expand_chart": "Expand Chart", + "export_csv": "Export CSV", + "all_channels": "All Channels", + "node_id": "Node ID" + }, + "top": + { + "top_traffic_nodes": "Top Traffic Nodes (last 24 hours)", + "chart_description_1": "This chart shows a bell curve (normal distribution) based on the total \"Times Seen\" values for all nodes. It helps visualize how frequently nodes are heard, relative to the average.", + "chart_description_2": "This \"Times Seen\" value is the closest that we can get to Mesh utilization by node.", + "mean_label": "Mean:", + "stddev_label": "Standard Deviation:", + "long_name": "Long Name", + "short_name": "Short Name", + "channel": "Channel", + "packets_sent": "Packets Sent", + "times_seen": "Times Seen", + "seen_percent": "Seen % of Mean", + "no_nodes": "No top traffic nodes available." + }, + "nodegraph": + { + "channel_label": "Channel:", + "search_node_placeholder": "Search node...", + "search_button": "Search", + "long_name_label": "Long Name:", + "short_name_label": "Short Name:", + "role_label": "Role:", + "hw_model_label": "Hardware Model:", + "node_not_found": "Node not found in current channel!" + }, + "firehose": + { + "live_feed": "📡 Live Feed", + "pause": "Pause", + "resume": "Resume", + "time": "Time", + "packet_id": "Packet ID", + "from": "From", + "to": "To", + "port": "Port", + "links": "Links", + + "unknown_app": "UNKNOWN APP", + "text_message": "Text Message", + "position": "Position", + "node_info": "Node Info", + "routing": "Routing", + "administration": "Administration", + "waypoint": "Waypoint", + "store_forward": "Store Forward", + "telemetry": "Telemetry", + "trace_route": "Trace Route", + "neighbor_info": "Neighbor Info", + + "direct_to_mqtt": "direct to MQTT", + "all": "All", + "map": "Map", + "graph": "Graph" + } + + } \ No newline at end of file diff --git a/meshview/lang/es.json b/meshview/lang/es.json index c78810d..e430b12 100644 --- a/meshview/lang/es.json +++ b/meshview/lang/es.json @@ -108,5 +108,35 @@ "other": "Otro", "unknown": "Desconocido", "node_not_found": "¡Nodo no encontrado en el canal actual!" - } + }, + "firehose": + { + "live_feed": "📡 Flujo en Vivo", + "pause": "Pausar", + "resume": "Continuar", + "time": "Hora", + "packet_id": "ID del Paquete", + "from": "De", + "to": "Para", + "port": "Puerto", + "links": "Enlaces", + + "unknown_app": "APLICACIÓN DESCONOCIDA", + "text_message": "Mensaje de Texto", + "position": "Posición", + "node_info": "Información del Nodo", + "routing": "Enrutamiento", + "administration": "Administración", + "waypoint": "Punto de Ruta", + "store_forward": "Almacenar y Reenviar", + "telemetry": "Telemetría", + "trace_route": "Rastreo de Ruta", + "neighbor_info": "Información de Vecinos", + + "direct_to_mqtt": "Directo a MQTT", + "all": "Todos", + "map": "Mapa", + "graph": "Gráfico" + } + } diff --git a/meshview/templates/base.html b/meshview/templates/base.html index 2cfb0be..3dfdcdd 100644 --- a/meshview/templates/base.html +++ b/meshview/templates/base.html @@ -10,7 +10,7 @@ - + @@ -22,9 +22,7 @@ opacity: 0; transition: opacity 0.3s ease-in-out; } - body.ready { - opacity: 1; - } + body.ready { opacity: 1; } .htmx-indicator { opacity: 0; transition: opacity 500ms ease-in; } .htmx-request .htmx-indicator { opacity: 1; } #search_form { z-index: 4000; } @@ -46,7 +44,7 @@ id="q" type="text" name="q" - data-translate-lang="node id" + data-translate="node id" placeholder="Node id" autocomplete="off" list="node_options" @@ -60,146 +58,151 @@ {% endfor %} - {% set options = { - 1: "Text Message", - 3: "Position", - 4: "Node Info", - 67: "Telemetry", - 70: "Traceroute", - 71: "Neighbor Info", - } - %} - - + + + + + {% block body %}{% endblock %}
- +
ver. unknown

- +// --- Wait for config before deciding which language to load --- +if (!window._langPromise) { + window._langPromise = (async () => { + try { + const cfg = await window._siteConfigPromise; + const site = cfg.site || {}; + const userLang = site.language || "en"; // <-- ✅ read language from /api/config + const section = "base"; + + const url = `/api/lang?lang=${userLang}§ion=${section}`; + const res = await fetch(url); + const lang = await res.json(); + window._lang = lang; + console.log(`Loaded language (${userLang}):`, lang); + return lang; + } catch (err) { + console.error("Failed to load language:", err); + return {}; + } + })(); +} + +// --- Translation Helper --- +function applyTranslations(dict) { + document.querySelectorAll("[data-translate]").forEach(el => { + const key = el.dataset.translate; + const value = dict[key]; + if (!value) return; + + if (el.placeholder) { + el.placeholder = value; + } else if (el.tagName === "INPUT" && el.value) { + el.value = value; + } else if (key === "footer") { + el.innerHTML = value; + } else { + el.textContent = value; + } + }); +} + +// --- Fill