+
+
+
+```
+
+**Add to `lang/fr.json`:**
+```json
+{
+ "sensors": {
+ "pageTitle": "Capteurs",
+ "title": "Liste des capteurs"
+ },
+ "common": {
+ "getData": "Obtenir les données"
+ }
+}
+```
+
+**Add to `lang/en.json`:**
+```json
+{
+ "sensors": {
+ "pageTitle": "Sensors",
+ "title": "Sensor List"
+ },
+ "common": {
+ "getData": "Get Data"
+ }
+}
+```
+
+## Backend Integration
+
+### Get Language Preference
+
+```javascript
+const response = await fetch('launcher.php?type=get_language');
+const data = await response.json();
+console.log(data.language); // 'fr' or 'en'
+```
+
+### Set Language Preference
+
+```javascript
+const response = await fetch('launcher.php?type=set_language&language=en');
+const data = await response.json();
+console.log(data.success); // true
+```
+
+Language preference is stored in SQLite `config_table` with key `language`.
+
+## Completed Pages
+
+- ✅ **sensors.html** - Fully translated with French/English support
+
+## TODO: Pages to Migrate
+
+- ⏳ index.html
+- ⏳ admin.html
+- ⏳ wifi.html
+- ⏳ saraR4.html
+- ⏳ map.html
+
+## Tips
+
+1. **Reuse common translations**: Put frequently used strings (buttons, actions, status messages) in the `common` section
+2. **Keep keys descriptive**: Use `sensors.bme280.title` instead of `s1` for maintainability
+3. **Test both languages**: Always verify that both French and English translations display correctly
+4. **Fallback text**: Always provide fallback text in HTML for graceful degradation
+
+## Support
+
+For issues or questions about the i18n system, refer to the implementation in:
+- `/html/assets/js/i18n.js` - Core translation library
+- `/html/lang/fr.json` - French translations
+- `/html/lang/en.json` - English translations
+- `/html/sensors.html` - Example implementation
diff --git a/html/lang/en.json b/html/lang/en.json
new file mode 100644
index 0000000..9f696c4
--- /dev/null
+++ b/html/lang/en.json
@@ -0,0 +1,53 @@
+{
+ "common": {
+ "getData": "Get Data",
+ "loading": "Loading...",
+ "error": "Error",
+ "startRecording": "Start recording",
+ "stopRecording": "Stop recording"
+ },
+ "sensors": {
+ "title": "Measurement Sensors",
+ "description": "Your NebuleAir sensor is equipped with one or more probes that measure environmental variables. Measurements are automatic, but you can verify their operation here.",
+ "npm": {
+ "title": "NextPM",
+ "description": "Particulate matter sensor.",
+ "headerUart": "UART Port"
+ },
+ "bme280": {
+ "title": "BME280 Temp/Humidity Sensor",
+ "description": "Temperature and humidity sensor on I2C port.",
+ "headerI2c": "I2C Port",
+ "temp": "Temperature",
+ "hum": "Humidity",
+ "press": "Pressure"
+ },
+ "noise": {
+ "title": "Decibel Meter",
+ "description": "Noise sensor on I2C port.",
+ "headerI2c": "I2C Port"
+ },
+ "envea": {
+ "title": "Envea Probe",
+ "description": "Gas sensor."
+ }
+ },
+ "wifi": {
+ "title": "WIFI Connection",
+ "description": "WIFI connection is not mandatory but it allows you to perform updates and enable remote control.",
+ "status": "Status",
+ "connected": "Connected",
+ "hotspot": "Hotspot",
+ "disconnected": "Disconnected",
+ "scan": "Scan",
+ "connect": "Connect",
+ "enterPassword": "Enter password for"
+ },
+ "admin": {
+ "title": "Administration",
+ "parameters": "Parameters (config)",
+ "deviceName": "Device Name",
+ "deviceID": "Device ID",
+ "modemVersion": "Modem Version"
+ }
+}
diff --git a/html/lang/fr.json b/html/lang/fr.json
new file mode 100644
index 0000000..bceb6b0
--- /dev/null
+++ b/html/lang/fr.json
@@ -0,0 +1,53 @@
+{
+ "common": {
+ "getData": "Obtenir les données",
+ "loading": "Chargement...",
+ "error": "Erreur",
+ "startRecording": "Démarrer l'enregistrement",
+ "stopRecording": "Arrêter l'enregistrement"
+ },
+ "sensors": {
+ "title": "Les sondes de mesure",
+ "description": "Votre capteur NebuleAir est équipé de une ou plusieurs sondes qui permettent de mesurer certaines variables environnementales. La mesure est automatique mais vous pouvez ici vous assurer de leur bon fonctionnement.",
+ "npm": {
+ "title": "NextPM",
+ "description": "Capteur particules fines.",
+ "headerUart": "Port UART"
+ },
+ "bme280": {
+ "title": "Capteur Temp/Humidité BME280",
+ "description": "Capteur température et humidité sur le port I2C.",
+ "headerI2c": "Port I2C",
+ "temp": "Température",
+ "hum": "Humidité",
+ "press": "Pression"
+ },
+ "noise": {
+ "title": "Sonomètre",
+ "description": "Capteur bruit sur le port I2C.",
+ "headerI2c": "Port I2C"
+ },
+ "envea": {
+ "title": "Sonde Envea",
+ "description": "Capteur gaz."
+ }
+ },
+ "wifi": {
+ "title": "Connexion WIFI",
+ "description": "La connexion WIFI n'est pas obligatoire mais elle vous permet d'effectuer des mises à jour et d'activer le contrôle à distance.",
+ "status": "Statut",
+ "connected": "Connecté",
+ "hotspot": "Point d'accès",
+ "disconnected": "Déconnecté",
+ "scan": "Scanner",
+ "connect": "Se connecter",
+ "enterPassword": "Entrer le mot de passe pour"
+ },
+ "admin": {
+ "title": "Administration",
+ "parameters": "Paramètres (config)",
+ "deviceName": "Nom de l'appareil",
+ "deviceID": "ID de l'appareil",
+ "modemVersion": "Version du modem"
+ }
+}
diff --git a/html/launcher.php b/html/launcher.php
index 7c0c0da..1449535 100755
--- a/html/launcher.php
+++ b/html/launcher.php
@@ -77,6 +77,46 @@ if ($type == "get_config_sqlite") {
}
}
+// GET language preference from SQLite
+if ($type == "get_language") {
+ try {
+ $db = new PDO("sqlite:$database_path");
+ $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ $stmt = $db->prepare("SELECT value FROM config_table WHERE key = 'language'");
+ $stmt->execute();
+ $result = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ $language = $result ? $result['value'] : 'fr'; // Default to French
+ echo json_encode(['language' => $language]);
+ } catch (Exception $e) {
+ echo json_encode(['language' => 'fr', 'error' => $e->getMessage()]);
+ }
+}
+
+// SET language preference in SQLite
+if ($type == "set_language") {
+ $language = $_GET['language'];
+
+ // Validate language (only allow fr or en)
+ if (!in_array($language, ['fr', 'en'])) {
+ echo json_encode(['success' => false, 'error' => 'Invalid language']);
+ exit;
+ }
+
+ try {
+ $db = new PDO("sqlite:$database_path");
+ $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ $stmt = $db->prepare("UPDATE config_table SET value = ? WHERE key = 'language'");
+ $stmt->execute([$language]);
+
+ echo json_encode(['success' => true, 'language' => $language]);
+ } catch (Exception $e) {
+ echo json_encode(['success' => false, 'error' => $e->getMessage()]);
+ }
+}
+
/*
*/
diff --git a/html/sensors.html b/html/sensors.html
index 7ccd120..3a6b716 100755
--- a/html/sensors.html
+++ b/html/sensors.html
@@ -49,11 +49,11 @@
-
Les sondes de mesure
-
Votre capteur NebuleAir est équipé de une ou plusieurs sondes qui permettent de mesurer certaines variables environnementales. La mesure
+
Les sondes de mesure
+
Votre capteur NebuleAir est équipé de une ou plusieurs sondes qui permettent de mesurer certaines variables environnementales. La mesure
est automatique mais vous pouvez ici vous assurer de leur bon fonctionnement.