French UI batch 3: Notes, Reader, Audiobooks, Voice messages, Alarm, Map, Games (menu, Snake, Minesweeper, Game Boy)

This commit is contained in:
pelgraine committed 2026-10-07 20:50:31 +11:00
1 parent 597f3f50a0
commit fc5bb119ce
11 files changed
+214 -200

No files matched your search

+39 -37
View File
@@ -27,6 +27,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
#include <SD.h>
#include <vector>
@@ -199,7 +200,8 @@ private:
static const char* dowShort(int dow) {
static const char* names[] = {"Su","Mo","Tu","We","Th","Fr","Sa"};
return (dow >= 0 && dow < 7) ? names[dow] : "??";
static const char* names_fr[] = {"Di","Lu","Ma","Me","Je","Ve","Sa"};
return (dow >= 0 && dow < 7) ? MECK_TR(names[dow], names_fr[dow]) : "??";
}
// Day of week from epoch (0=Sunday)
@@ -210,10 +212,10 @@ private:
// Format days bitmask as human string
static void formatDays(uint8_t days, char* buf, int bufLen) {
if (days == DOW_ALL) { strncpy(buf, "Every day", bufLen); return; }
if (days == DOW_WEEKDAYS) { strncpy(buf, "Weekdays", bufLen); return; }
if (days == DOW_WEEKEND) { strncpy(buf, "Weekend", bufLen); return; }
if (days == 0) { strncpy(buf, "Never", bufLen); return; }
if (days == DOW_ALL) { strncpy(buf, MECK_TR("Every day", "Tous les jours"), bufLen); return; }
if (days == DOW_WEEKDAYS) { strncpy(buf, MECK_TR("Weekdays", "En semaine"), bufLen); return; }
if (days == DOW_WEEKEND) { strncpy(buf, MECK_TR("Weekend", "Week-end"), bufLen); return; }
if (days == 0) { strncpy(buf, MECK_TR("Never", "Jamais"), bufLen); return; }
buf[0] = '\0';
for (int i = 0; i < 7; i++) {
if (days & (1 << i)) {
@@ -451,14 +453,14 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
display.setCursor(0, 0);
display.print("Alarm Clock");
display.print(MECK_TR("Alarm Clock", "R\xC3\xA9veil"));
if (_soundFiles.empty() && _sdReady) {
// Show hint if no sounds yet
display.setColor(DisplayDriver::LIGHT);
display.setTextSize(0);
display.setCursor(0, 13);
display.print("Place 44kHz .mp3 in /alarms/");
display.print(MECK_TR("Place 44kHz .mp3 in /alarms/", ".mp3 (44 kHz) dans /alarms/"));
}
display.setColor(DisplayDriver::LIGHT);
@@ -495,7 +497,7 @@ private:
// Line 1: Alarm number + time + enabled
char line1[40];
snprintf(line1, sizeof(line1), "%d. %s %02d:%02d",
idx + 1, slot.enabled ? "ON " : "OFF", slot.hour, slot.minute);
idx + 1, slot.enabled ? MECK_TR("ON ", "OUI") : MECK_TR("OFF", "NON"), slot.hour, slot.minute);
display.setCursor(0, y);
display.print(line1);
@@ -524,7 +526,7 @@ private:
display.print(line2);
}
drawFooter(display, "O:On/Off Enter:Edit", "Q:X");
drawFooter(display, MECK_TR("O:On/Off Enter:Edit", "O:Oui/Non Ent:\xC3\x89" "diter"), "Q:X");
}
// ---- Render: Edit alarm ----
@@ -534,7 +536,7 @@ private:
display.setColor(DisplayDriver::GREEN);
display.setCursor(0, 0);
char hdr[24];
snprintf(hdr, sizeof(hdr), "Edit Alarm %d", _editSlot + 1);
snprintf(hdr, sizeof(hdr), MECK_TR("Edit Alarm %d", "Modifier le r\xC3\xA9veil %d"), _editSlot + 1);
display.print(hdr);
display.setColor(DisplayDriver::LIGHT);
@@ -550,11 +552,11 @@ private:
char value[32];
} fields[FIELD_COUNT];
snprintf(fields[FIELD_ENABLED].value, 32, "%s", _editCopy.enabled ? "ON" : "OFF");
fields[FIELD_ENABLED].label = "Enabled";
snprintf(fields[FIELD_ENABLED].value, 32, "%s", _editCopy.enabled ? MECK_TR("ON", "OUI") : MECK_TR("OFF", "NON"));
fields[FIELD_ENABLED].label = MECK_TR("Enabled", "Activ\xC3\xA9");
snprintf(fields[FIELD_HOUR].value, 32, "%02d", _editCopy.hour);
fields[FIELD_HOUR].label = "Hour";
fields[FIELD_HOUR].label = MECK_TR("Hour", "Heure");
snprintf(fields[FIELD_MINUTE].value, 32, "%02d", _editCopy.minute);
fields[FIELD_MINUTE].label = "Minute";
@@ -563,14 +565,14 @@ private:
formatDays(_editCopy.days, daysBuf, sizeof(daysBuf));
strncpy(fields[FIELD_DAYS].value, daysBuf, 31);
fields[FIELD_DAYS].value[31] = '\0';
fields[FIELD_DAYS].label = "Days";
fields[FIELD_DAYS].label = MECK_TR("Days", "Jours");
snprintf(fields[FIELD_VOLUME].value, 32, "%d", _editCopy.volume);
fields[FIELD_VOLUME].label = "Volume";
#if defined(LilyGo_TDeck_Pro_Max)
if (slotIsVibrate(_editCopy)) {
strncpy(fields[FIELD_SOUND].value, "Buzzer (vibrate)", 31);
strncpy(fields[FIELD_SOUND].value, MECK_TR("Buzzer (vibrate)", "Buzzer (vibreur)"), 31);
fields[FIELD_SOUND].value[31] = '\0';
} else
#endif
@@ -582,9 +584,9 @@ private:
if (dot) *dot = '\0';
strncpy(fields[FIELD_SOUND].value, sndDisplay, 31);
} else {
strcpy(fields[FIELD_SOUND].value, "(default)");
strcpy(fields[FIELD_SOUND].value, MECK_TR("(default)", "(d\xC3\xA9" "faut)"));
}
fields[FIELD_SOUND].label = "Sound";
fields[FIELD_SOUND].label = MECK_TR("Sound", "Son");
for (int f = 0; f < FIELD_COUNT; f++) {
int fy = y + f * lineH;
@@ -622,7 +624,7 @@ private:
int detailY = y + FIELD_COUNT * lineH + 4;
display.setColor(DisplayDriver::GREEN);
display.setCursor(0, detailY);
display.print("A/D: toggle day ");
display.print(MECK_TR("A/D: toggle day ", "A/D : jour oui/non "));
// Show individual day toggles
display.setCursor(0, detailY + 9);
for (int d = 0; d < 7; d++) {
@@ -644,7 +646,7 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
const char* prompt = (_editField == FIELD_HOUR) ? "Hour (0-23):" : "Min (0-59):";
const char* prompt = (_editField == FIELD_HOUR) ? MECK_TR("Hour (0-23):", "Heure (0-23) :") : MECK_TR("Min (0-59):", "Min (0-59) :");
display.setCursor(bx + 4, by + 4);
display.print(prompt);
@@ -655,9 +657,9 @@ private:
display.setCursor(bx + 4, by + 16);
display.print(inputDisplay);
drawFooter(display, "Type digits", "Enter:OK Sh+Del:Cancel");
drawFooter(display, MECK_TR("Type digits", "Chiffres"), MECK_TR("Enter:OK Sh+Del:Cancel", "Ent:OK Sh+Del:Annuler"));
} else {
drawFooter(display, "A/D:Adjust Enter:Type", "Q:Save");
drawFooter(display, MECK_TR("A/D:Adjust Enter:Type", "A/D:R\xC3\xA9gler Ent:Saisie"), MECK_TR("Q:Save", "Q:OK"));
}
}
@@ -667,19 +669,19 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
display.setCursor(0, 0);
display.print("Pick Alarm Sound");
display.print(MECK_TR("Pick Alarm Sound", "Choisir le son du r\xC3\xA9veil"));
display.setColor(DisplayDriver::LIGHT);
if (_soundFiles.empty() && kVibrateRows == 0) {
display.setTextSize(0);
display.setCursor(0, 20);
display.print("No .mp3 files found.");
display.print(MECK_TR("No .mp3 files found.", "Aucun fichier .mp3 trouv\xC3\xA9."));
display.setCursor(0, 30);
display.print("Place 44kHz .mp3 in");
display.print(MECK_TR("Place 44kHz .mp3 in", "Placez des .mp3 44 kHz dans"));
display.setCursor(0, 38);
display.print("/alarms/ on SD card");
drawFooter(display, "0 files", "Q:Back");
display.print(MECK_TR("/alarms/ on SD card", "/alarms/ sur la carte SD"));
drawFooter(display, MECK_TR("0 files", "0 fichier"), MECK_TR("Q:Back", "Q:Retour"));
return;
}
@@ -711,7 +713,7 @@ private:
String displayName;
if (kVibrateRows && idx == 0) {
displayName = "Buzzer (vibrate)";
displayName = MECK_TR("Buzzer (vibrate)", "Buzzer (vibreur)");
} else {
// Display filename without extension
displayName = _soundFiles[idx - kVibrateRows];
@@ -726,8 +728,8 @@ private:
}
char countBuf[12];
snprintf(countBuf, sizeof(countBuf), "%d files", (int)_soundFiles.size());
drawFooter(display, countBuf, "Enter:Pick Q:X");
snprintf(countBuf, sizeof(countBuf), MECK_TR("%d files", "%d fichiers"), (int)_soundFiles.size());
drawFooter(display, countBuf, MECK_TR("Enter:Pick Q:X", "Ent:Choisir Q:X"));
}
// ---- Render: Ringing ----
@@ -746,14 +748,14 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
char label[24];
snprintf(label, sizeof(label), "Alarm %d", _ringingSlot + 1);
snprintf(label, sizeof(label), MECK_TR("Alarm %d", "R\xC3\xA9veil %d"), _ringingSlot + 1);
display.drawTextCentered(display.width() / 2, 34, label);
// Sound name
#if defined(LilyGo_TDeck_Pro_Max)
if (slotIsVibrate(slot)) {
display.setTextSize(0);
display.drawTextCentered(display.width() / 2, 48, "Buzzer (vibrate)");
display.drawTextCentered(display.width() / 2, 48, MECK_TR("Buzzer (vibrate)", "Buzzer (vibreur)"));
} else
#endif
if (slot.sound[0] != '\0') {
@@ -771,13 +773,13 @@ private:
display.setTextSize(1);
if (meck_alarm_is_locked()) {
// Keys are ignored while locked; the user unlocks with the button first.
display.drawTextCentered(display.width() / 2, 64, "Unlock to dismiss");
display.drawTextCentered(display.width() / 2, 64, MECK_TR("Unlock to dismiss", "D\xC3\xA9verrouillez pour arr\xC3\xAAter"));
} else {
display.drawTextCentered(display.width() / 2, 64, "ANY KEY: Dismiss");
display.drawTextCentered(display.width() / 2, 64, MECK_TR("ANY KEY: Dismiss", "UNE TOUCHE : arr\xC3\xAAter"));
display.setTextSize(0);
display.setColor(DisplayDriver::LIGHT);
display.drawTextCentered(display.width() / 2, 80, "Z: Snooze 5 min");
display.drawTextCentered(display.width() / 2, 80, MECK_TR("Z: Snooze 5 min", "Z : rappel dans 5 min"));
}
// No footer in ringing mode — keep it clean and urgent
@@ -1224,11 +1226,11 @@ public:
display.setTextSize(1);
display.setColor(DisplayDriver::RED);
display.setCursor(0, 20);
display.print("No SD card");
display.print(MECK_TR("No SD card", "Pas de carte SD"));
display.setCursor(0, 35);
display.print("Insert SD card and");
display.print(MECK_TR("Insert SD card and", "Ins\xC3\xA9rez une carte SD et"));
display.setCursor(0, 43);
display.print("create /alarms/");
display.print(MECK_TR("create /alarms/", "cr\xC3\xA9" "ez /alarms/"));
return 5000;
}
@@ -29,6 +29,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
#include <SD.h>
#include <vector>
#include <algorithm>
@@ -501,13 +502,13 @@ private:
_displayRef->setTextSize(2);
_displayRef->setColor(DisplayDriver::GREEN);
_displayRef->setCursor(10, 15);
_displayRef->print("Loading");
_displayRef->print(MECK_TR("Loading", "Chargement"));
_displayRef->setCursor(10, 30);
_displayRef->print("Audiobooks");
_displayRef->print(MECK_TR("Audiobooks", "Livres audio"));
_displayRef->setTextSize(1);
_displayRef->setColor(DisplayDriver::LIGHT);
_displayRef->setCursor(10, 55);
_displayRef->print("Please wait...");
_displayRef->print(MECK_TR("Please wait...", "Veuillez patienter..."));
_displayRef->endFrame();
}
@@ -981,7 +982,7 @@ private:
display->setTextSize(1);
display->setColor(DisplayDriver::GREEN);
display->setCursor(10, 11);
display->print("Loading...");
display->print(MECK_TR("Loading...", "Chargement..."));
display->setTextSize(1);
display->setColor(DisplayDriver::LIGHT);
display->setCursor(10, 30);
@@ -1267,19 +1268,19 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
display.setCursor(0, 0);
display.print("Audiobooks");
display.print(MECK_TR("Audiobooks", "Livres audio"));
display.setColor(DisplayDriver::LIGHT);
if (_fileList.size() == 0) {
display.setCursor(0, 20);
display.print("No audiobooks found.");
display.print(MECK_TR("No audiobooks found.", "Aucun livre audio trouv\xC3\xA9."));
display.setCursor(0, 30);
display.print("Place .m4b/.mp3 in");
display.print(MECK_TR("Place .m4b/.mp3 in", "Placez des .m4b/.mp3 dans"));
display.setCursor(0, 38);
display.print("/audiobooks/ on SD");
display.print(MECK_TR("/audiobooks/ on SD", "/audiobooks/ sur la SD"));
drawFooter(display, "0 files", "Q:Back");
drawFooter(display, MECK_TR("0 files", "0 fichier"), MECK_TR("Q:Back", "Q:Retour"));
return;
}
@@ -1321,7 +1322,7 @@ private:
if (fe.isDir) {
if (fe.name == "..") {
snprintf(fullLine, sizeof(fullLine), ".. (up)");
snprintf(fullLine, sizeof(fullLine), MECK_TR(".. (up)", ".. (parent)"));
} else {
snprintf(fullLine, sizeof(fullLine), "/%s", fe.name.c_str());
}
@@ -1366,8 +1367,8 @@ private:
// Left label is always the file count — the folder path was overflowing and
// colliding with the right-hand nav text, so it is no longer shown here.
char leftBuf[32];
snprintf(leftBuf, sizeof(leftBuf), "%d files", (int)_fileList.size());
drawFooter(display, leftBuf, "W/S:Nav Enter:Open");
snprintf(leftBuf, sizeof(leftBuf), MECK_TR("%d files", "%d fichiers"), (int)_fileList.size());
drawFooter(display, leftBuf, MECK_TR("W/S:Nav Enter:Open", "W/S Ent:Ouvrir"));
}
// ---- Render: Player ----
@@ -1413,7 +1414,7 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
char chBuf[24];
snprintf(chBuf, sizeof(chBuf), "Ch %d/%d",
snprintf(chBuf, sizeof(chBuf), MECK_TR("Ch %d/%d", "Chap. %d/%d"),
_currentChapter + 1, _metadata.chapterCount);
display.drawTextCentered(display.width() / 2, y, chBuf);
y += 10;
@@ -1423,7 +1424,7 @@ private:
{
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
const char* stateStr = _isPlaying ? (_isPaused ? "Paused" : "Playing") : "Stopped";
const char* stateStr = _isPlaying ? (_isPaused ? MECK_TR("Paused", "En pause") : MECK_TR("Playing", "Lecture")) : MECK_TR("Stopped", "Arr\xC3\xAAt\xC3\xA9");
char stateBuf[24];
snprintf(stateBuf, sizeof(stateBuf), "%s Vol:%d", stateStr, _volume);
display.drawTextCentered(display.width() / 2, y, stateBuf);
@@ -1468,13 +1469,13 @@ private:
// Show track position in playlist (if multiple tracks)
if (_playlist.size() > 1 && _playlistIdx >= 0) {
char trackBuf[24];
snprintf(trackBuf, sizeof(trackBuf), "Track %d/%d",
snprintf(trackBuf, sizeof(trackBuf), MECK_TR("Track %d/%d", "Piste %d/%d"),
_playlistIdx + 1, (int)_playlist.size());
display.drawTextCentered(display.width() / 2, y, trackBuf);
y += 10;
}
display.drawTextCentered(display.width() / 2, y, "Enter: Play/Pause");
display.drawTextCentered(display.width() / 2, y, MECK_TR("Enter: Play/Pause", "Entr\xC3\xA9" "e : lecture/pause"));
y += 10;
// Sleep timer or additional hints
@@ -1487,17 +1488,17 @@ private:
int mins = remaining / 60;
int secs = remaining % 60;
char sleepBuf[32];
snprintf(sleepBuf, sizeof(sleepBuf), "Sleep: %d:%02d (Z:Off)", mins, secs);
snprintf(sleepBuf, sizeof(sleepBuf), MECK_TR("Sleep: %d:%02d (Z:Off)", "Veille : %d:%02d (Z:arr\xC3\xAAt)"), mins, secs);
display.drawTextCentered(display.width() / 2, y, sleepBuf);
} else if (_isPlaying && !_isPaused) {
display.drawTextCentered(display.width() / 2, y,
"Z: Start 45m sleep timer");
MECK_TR("Z: Start 45m sleep timer", "Z : minuterie 45 min"));
} else if (_metadata.chapterCount > 0) {
display.drawTextCentered(display.width() / 2, y,
"[/]: Prev/Next Chapter");
MECK_TR("[/]: Prev/Next Chapter", "[/] : chapitre pr\xC3\xA9" "c./suiv."));
} else if (_playlist.size() > 1) {
display.drawTextCentered(display.width() / 2, y,
"N: Next Track");
MECK_TR("N: Next Track", "N : piste suivante"));
}
}
}
@@ -1505,11 +1506,11 @@ private:
// ---- Footer Nav Bar ----
{
const char* rightText = (_isPlaying && !_isPaused) ? "Q:Leave" : "Q:Close";
const char* rightText = (_isPlaying && !_isPaused) ? MECK_TR("Q:Leave", "Q:Sortir") : MECK_TR("Q:Close", "Q:Fermer");
if (_playlist.size() > 1) {
drawFooter(display, "A/D:Seek N:Next", rightText);
drawFooter(display, MECK_TR("A/D:Seek N:Next", "A/D:Saut N:Suiv."), rightText);
} else {
drawFooter(display, "A/D:Seek W/S:Vol", rightText);
drawFooter(display, MECK_TR("A/D:Seek W/S:Vol", "A/D:Saut W/S:Vol"), rightText);
}
}
}
@@ -1677,11 +1678,11 @@ public:
display.setCursor(0, 20);
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
display.print("SD card not found");
display.print(MECK_TR("SD card not found", "Carte SD introuvable"));
display.setCursor(0, 35);
display.print("Insert SD with");
display.print(MECK_TR("Insert SD with", "Ins\xC3\xA9rez une SD avec"));
display.setCursor(0, 43);
display.print("/audiobooks/ folder");
display.print(MECK_TR("/audiobooks/ folder", "le dossier /audiobooks/"));
return 5000;
}
@@ -609,7 +609,7 @@ bool GBCEmulatorScreen::launch(int idx) {
if (!gbc_alloc_buffers()) {
gbc_release_core();
setStatus("Out of memory");
setStatus(MECK_TR("Out of memory", "M\xC3\xA9moire insuffisante"));
return false;
}
@@ -618,7 +618,7 @@ bool GBCEmulatorScreen::launch(int idx) {
if (!f) {
Serial.printf("[GBC] cannot open %s\n", path);
gbc_release_core();
setStatus("Cannot open ROM");
setStatus(MECK_TR("Cannot open ROM", "ROM illisible"));
return false;
}
const size_t sz = (size_t)f.size();
@@ -626,7 +626,7 @@ bool GBCEmulatorScreen::launch(int idx) {
f.close();
Serial.println("[GBC] file too small to be a ROM");
gbc_release_core();
setStatus("Not a ROM");
setStatus(MECK_TR("Not a ROM", "Pas une ROM"));
return false;
}
if (s_rom && s_rom_cap < sz) {
@@ -646,7 +646,7 @@ bool GBCEmulatorScreen::launch(int idx) {
Serial.printf("[GBC] ROM alloc failed (%u bytes; largest free PSRAM block %u)\n",
(unsigned)sz, (unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM));
gbc_release_core();
setStatus("Out of PSRAM");
setStatus(MECK_TR("Out of PSRAM", "PSRAM insuffisante"));
return false;
}
s_rom_cap = want;
@@ -657,7 +657,7 @@ bool GBCEmulatorScreen::launch(int idx) {
if (got != sz) {
Serial.printf("[GBC] short read (%u/%u)\n", (unsigned)got, (unsigned)sz);
gbc_release_core();
setStatus("ROM read failed");
setStatus(MECK_TR("ROM read failed", "\xC3\x89" "chec de lecture ROM"));
return false;
}
s_rom_size = sz;
@@ -681,7 +681,7 @@ bool GBCEmulatorScreen::launch(int idx) {
Serial.printf("[GBC] gb_init failed: %d\n", (int)e);
s_rom_size = 0;
gbc_release_core();
setStatus("Unsupported ROM");
setStatus(MECK_TR("Unsupported ROM", "ROM non prise en charge"));
return false;
}
if (s_gb->mbc == 2 && s_save_size == 0) s_save_size = 512;
@@ -782,7 +782,7 @@ bool GBCEmulatorScreen::launch(int idx) {
otaResumeRadio();
#endif
gbc_release_core();
setStatus("Task create failed");
setStatus(MECK_TR("Task create failed", "\xC3\x89" "chec de d\xC3\xA9marrage"));
return false;
}
_playing = idx;
@@ -822,8 +822,8 @@ void GBCEmulatorScreen::finishStop() {
gbc_release_core();
_playing = -1;
_mode = BROWSER;
if (s_core_error) setStatus("Game crashed");
else if (saved) setStatus("Saved");
if (s_core_error) setStatus(MECK_TR("Game crashed", "Le jeu a plant\xC3\xA9"));
else if (saved) setStatus(MECK_TR("Saved", "Sauvegard\xC3\xA9"));
print_heaps("after stop");
if (_eink) {
_eink->setFastWaveform(true);
@@ -913,14 +913,14 @@ bool GBCEmulatorScreen::handleInput(char c) {
if (_cursor < _romCount - 1) _cursor++;
return true;
case '\r':
if (_romCount == 0) { setStatus("No ROMs in /roms"); return true; }
if (_romCount == 0) { setStatus(MECK_TR("No ROMs in /roms", "Aucune ROM dans /roms")); return true; }
// Reading a 2 MB ROM off the SD card takes several seconds. Show the
// standard alert box first and launch from poll() once it has been
// drawn, so the panel is not left showing the ROM list meanwhile.
_pendingLaunch = _cursor;
_loadingDrawn = false;
_mode = LOADING;
_task->showAlert("Loading...", 30000);
_task->showAlert(MECK_TR("Loading...", "Chargement..."), 30000);
return true;
case KEY_CANCEL:
_wantsExit = true;
@@ -942,7 +942,7 @@ static void draw_game_header(DisplayDriver& display, UITask* task) {
NodePrefs* prefs = task->getNodePrefs();
const int hdrY = -3;
char label[16];
snprintf(label, sizeof(label), "%d Unread", task->getUnreadMsgCount());
snprintf(label, sizeof(label), MECK_TR("%d Unread", "%d non lus"), task->getUnreadMsgCount());
display.setTextSize(prefs->smallTextSize());
display.setColor(DisplayDriver::GREEN);
@@ -1022,8 +1022,8 @@ int GBCEmulatorScreen::renderBrowser(DisplayDriver& display) {
display.setTextSize(prefs->smallTextSize());
if (_romCount == 0) {
display.setColor(DisplayDriver::LIGHT);
display.drawTextEllipsized(6, headerH, display.width() - 12, "No .gb/.gbc files");
display.drawTextEllipsized(6, headerH + lineH, display.width() - 12, "in /roms on SD");
display.drawTextEllipsized(6, headerH, display.width() - 12, MECK_TR("No .gb/.gbc files", "Aucun fichier .gb/.gbc"));
display.drawTextEllipsized(6, headerH + lineH, display.width() - 12, MECK_TR("in /roms on SD", "dans /roms sur la SD"));
} else {
int y = headerH;
for (int i = _scroll; i < _romCount && i < _scroll + rows; i++) {
@@ -1051,7 +1051,7 @@ int GBCEmulatorScreen::renderBrowser(DisplayDriver& display) {
display.print(_status);
return 500;
}
display.print("Enter:Play Q:Back");
display.print(MECK_TR("Enter:Play Q:Back", "Ent:Jouer Q:Retour"));
return 5000;
}
@@ -1075,11 +1075,11 @@ int GBCEmulatorScreen::renderGame(DisplayDriver& display) {
const uint16_t fg = d.rawFgColor();
d.drawXbmRaw(GBC_IMG_X, GBC_IMG_Y, s_mono_ui, OUT_W, OUT_H, fg);
#if GBC_SOUND
d.drawTextRaw(2, 308, (_mode == STOPPING) ? "Saving..."
: (!s_audio_on ? "Q: Quit"
: (s_muted ? "Q: Quit Press Mic key to unmute" : "Q: Quit Mic: Mute")), fg);
d.drawTextRaw(2, 308, (_mode == STOPPING) ? MECK_TR("Saving...", "Sauvegarde...")
: (!s_audio_on ? MECK_TR("Q: Quit", "Q: Quitter")
: (s_muted ? MECK_TR("Q: Quit Press Mic key to unmute", "Q: Quitter Mic: remettre le son") : MECK_TR("Q: Quit Mic: Mute", "Q: Quitter Mic: Muet"))), fg);
#else
d.drawTextRaw(2, 308, (_mode == STOPPING) ? "Saving..." : "Q: Quit", fg);
d.drawTextRaw(2, 308, (_mode == STOPPING) ? MECK_TR("Saving...", "Sauvegarde...") : MECK_TR("Q: Quit", "Q: Quitter"), fg);
#endif
// No windowed refresh: it was measured to save nothing (the panel's
// waveform time is the same for any window), and it left the footer row
@@ -22,6 +22,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
class UITask;
class GxEPDDisplay;
@@ -10,6 +10,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
// Forward declarations
class UITask;
@@ -39,6 +40,7 @@ private:
GameID id;
const char* name;
const char* description;
const char* name_fr; // French name (Experimental Features > Language)
};
// The Game Boy emulator entry is present on the T-Deck Pro and Max, except on
@@ -51,10 +53,10 @@ private:
static const GameEntry* getGames() {
static const GameEntry games[NUM_GAMES] = {
{ GAME_SNAKE, "Snake", "Classic Nokia-style" },
{ GAME_MINESWEEPER, "Minesweeper", "Find the mines" },
{ GAME_SNAKE, "Snake", "Classic Nokia-style", "Snake" },
{ GAME_MINESWEEPER, "Minesweeper", "Find the mines", "D\xC3\xA9mineur" },
#if defined(LilyGo_TDeck_Pro) && !defined(MECK_40MHZ_TEST)
{ GAME_GBC, "Game Boy", "GB / GBC emulator" },
{ GAME_GBC, "Game Boy", "GB / GBC emulator", "Game Boy" },
#endif
// { GAME_2048, "2048", "Slide and merge" },
};
@@ -112,7 +114,7 @@ public:
// --- Header ---
display.setColor(DisplayDriver::GREEN);
display.setCursor(2, 2);
display.print("Games");
display.print(MECK_TR("Games", "Jeux"));
display.setColor(DisplayDriver::LIGHT);
display.drawRect(0, 12, display.width(), 1);
@@ -136,7 +138,7 @@ public:
display.setColor(DisplayDriver::LIGHT);
}
display.drawTextEllipsized(6, y, display.width() - 12, getGames()[i].name);
display.drawTextEllipsized(6, y, display.width() - 12, MECK_TR(getGames()[i].name, getGames()[i].name_fr));
y += lineH;
}
@@ -147,7 +149,7 @@ public:
int fy = display.height() - 12;
display.drawRect(0, fy - 2, display.width(), 1);
display.setCursor(2, fy);
display.print("Enter:Play Q:Back");
display.print(MECK_TR("Enter:Play Q:Back", "Ent:Jouer Q:Retour"));
return 5000; // Static menu -- slow refresh
}
+4 -3
View File
@@ -84,6 +84,7 @@
#undef local // PNGdec's zutil.h defines 'local' as 'static' — breaks any variable named 'local'
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
#include <helpers/ui/GxEPDDisplay.h>
// ---------------------------------------------------------------------------
@@ -259,9 +260,9 @@ public:
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
display.setCursor(10, 20);
display.print("SD card not found");
display.print(MECK_TR("SD card not found", "Carte SD introuvable"));
display.setCursor(10, 35);
display.print("Insert SD with");
display.print(MECK_TR("Insert SD with", "Ins\xC3\xA9rez une SD avec"));
display.setCursor(10, 48);
display.print("/tiles/{z}/{x}/{y}.png");
return 5000;
@@ -909,7 +910,7 @@ private:
display.print(left);
// Right: navigation hint
const char* right = "WASD:pan Z/X:zoom";
const char* right = MECK_TR("WASD:pan Z/X:zoom", "WASD:bouger Z/X:zoom");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
}
@@ -12,6 +12,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
// Forward declarations
class UITask;
@@ -373,35 +374,35 @@ public:
// --- READY: header + instructions + footer ---
display.setColor(DisplayDriver::GREEN);
display.setCursor(2, 2);
display.print("Minesweeper");
display.print(MECK_TR("Minesweeper", "D\xC3\xA9mineur"));
display.setColor(DisplayDriver::LIGHT);
display.drawRect(0, MINE_HDR - 2, display.width(), 1);
int cx = display.width() / 2;
int y = MINE_HDR + 10;
display.setColor(DisplayDriver::LIGHT);
display.drawTextCentered(cx, y, "Minesweeper");
display.drawTextCentered(cx, y, MECK_TR("Minesweeper", "D\xC3\xA9mineur"));
y += 16;
display.setColor(DisplayDriver::GREEN);
display.drawTextCentered(cx, y, "W/S/A/D to move cursor");
display.drawTextCentered(cx, y, MECK_TR("W/S/A/D to move cursor", "W/S/A/D pour se d\xC3\xA9placer"));
y += 11;
display.drawTextCentered(cx, y, "Enter to reveal a cell");
display.drawTextCentered(cx, y, MECK_TR("Enter to reveal a cell", "Entr\xC3\xA9" "e : r\xC3\xA9v\xC3\xA9ler une case"));
y += 11;
display.drawTextCentered(cx, y, "F to flag a mine");
display.drawTextCentered(cx, y, MECK_TR("F to flag a mine", "F : marquer une mine"));
y += 16;
display.setColor(DisplayDriver::LIGHT);
char info[32];
snprintf(info, sizeof(info), "%dx%d grid, %d mines", MINE_GRID_W, MINE_GRID_H, MINE_COUNT);
snprintf(info, sizeof(info), MECK_TR("%dx%d grid, %d mines", "Grille %dx%d, %d mines"), MINE_GRID_W, MINE_GRID_H, MINE_COUNT);
display.drawTextCentered(cx, y, info);
y += 16;
display.drawTextCentered(cx, y, "Press Enter to start");
display.drawTextCentered(cx, y, MECK_TR("Press Enter to start", "Entr\xC3\xA9" "e pour commencer"));
// Footer
display.setColor(DisplayDriver::LIGHT);
int fy = display.height() - 12;
display.drawRect(0, fy - 2, display.width(), 1);
display.setCursor(2, fy);
display.print("Enter:Start Sh+Del:Back");
display.print(MECK_TR("Enter:Start Sh+Del:Back", "Ent:Jouer Sh+Del:Retour"));
return 5000;
} else if (_state == PLAYING) {
@@ -450,13 +451,13 @@ public:
int ty = boxY + 10;
if (_state == WON) {
display.setColor(DisplayDriver::YELLOW);
display.drawTextCentered(cx, ty, "Cleared!");
display.drawTextCentered(cx, ty, MECK_TR("Cleared!", "Gagn\xC3\xA9 !"));
} else {
display.drawTextCentered(cx, ty, "Boom!");
display.drawTextCentered(cx, ty, MECK_TR("Boom!", "Boum !"));
}
ty += 16;
display.setColor(DisplayDriver::GREEN);
display.drawTextCentered(cx, ty, "Enter:Retry Sh+Del:Back");
display.drawTextCentered(cx, ty, MECK_TR("Enter:Retry Sh+Del:Back", "Ent:Rejouer Sh+Del:Retour"));
return 5000;
}
+31 -30
View File
@@ -2,6 +2,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
#include <SD.h>
#include <vector>
#include "Utf8CP437.h"
@@ -503,7 +504,7 @@ private:
int rightX = display.width() - display.getTextWidth(tmp) - 2;
if (_selectedFile >= 1 && _selectedFile <= (int)_fileList.size()) {
const char* hint = "[R:Rename]";
const char* hint = MECK_TR("[R:Rename]", "[R:Renommer]");
int hintX = rightX - display.getTextWidth(hint) - 4;
display.setCursor(hintX, 0);
display.setColor(DisplayDriver::YELLOW);
@@ -544,7 +545,7 @@ private:
if (i == 0) {
display.setColor(selected ? DisplayDriver::DARK : DisplayDriver::GREEN);
display.drawTextEllipsized(0, y, display.width() - 4,
selected ? "> + New Note" : " + New Note");
selected ? MECK_TR("> + New Note", "> + Nouvelle note") : MECK_TR(" + New Note", " + Nouvelle note"));
} else {
String line = selected ? "> " : " ";
line += _fileList[i - 1];
@@ -559,8 +560,8 @@ private:
display.drawRect(0, footerY - 2, display.width(), 1);
display.setCursor(0, footerY);
display.setColor(DisplayDriver::YELLOW);
display.print("Q:Bk");
const char* right = "Tap/Ent:Open";
display.print(MECK_TR("Q:Bk", "Q:Ret"));
const char* right = MECK_TR("Tap/Ent:Open", "Ent:Ouvrir");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
}
@@ -570,14 +571,14 @@ private:
display.setCursor(0, 14);
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
display.print("(empty note)");
display.print(MECK_TR("(empty note)", "(note vide)"));
int footerY = display.height() - 12;
display.drawRect(0, footerY - 2, display.width(), 1);
display.setColor(DisplayDriver::YELLOW);
display.setCursor(0, footerY);
display.print("Q:Bk Ent:Edit");
const char* right = "X:Delete";
display.print(MECK_TR("Q:Bk Ent:Edit", "Q:Ret Ent:\xC3\x89" "diter"));
const char* right = MECK_TR("X:Delete", "X:Suppr");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
return;
@@ -662,9 +663,9 @@ private:
display.setColor(DisplayDriver::YELLOW);
display.setCursor(0, footerY);
display.print("Q:Bk Ent:Edit");
display.print(MECK_TR("Q:Bk Ent:Edit", "Q:Ret Ent:\xC3\x89" "diter"));
const char* right = "X:Delete";
const char* right = MECK_TR("X:Delete", "X:Suppr");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
}
@@ -684,7 +685,7 @@ private:
if (shortName.length() > 18) {
shortName = shortName.substring(0, 15) + "...";
}
snprintf(header, sizeof(header), "Edit: %s%s",
snprintf(header, sizeof(header), MECK_TR("Edit: %s%s", "\xC3\x89" "dition : %s%s"),
shortName.c_str(), _dirty ? "*" : "");
display.print(header);
@@ -762,14 +763,14 @@ private:
char status[20];
int curPage = (_editMaxLines > 0) ? (cursorLine / _editMaxLines) + 1 : 1;
int totalPg = (_editMaxLines > 0) ? max(1, (_numEditorLines + _editMaxLines - 1) / _editMaxLines) : 1;
snprintf(status, sizeof(status), "Pg %d/%d", curPage, totalPg);
snprintf(status, sizeof(status), MECK_TR("Pg %d/%d", "p. %d/%d"), curPage, totalPg);
display.print(status);
const char* right;
if (_bufLen == 0 || !_dirty) {
right = "Q:Back";
right = MECK_TR("Q:Back", "Q:Retour");
} else {
right = "Sh+Del:Save";
right = MECK_TR("Sh+Del:Save", "Sh+Del:Enreg.");
}
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
@@ -779,7 +780,7 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
display.setCursor(0, 0);
display.print("Rename Note");
display.print(MECK_TR("Rename Note", "Renommer la note"));
display.setColor(DisplayDriver::LIGHT);
display.drawRect(0, 11, display.width(), 1);
@@ -787,7 +788,7 @@ private:
// Show original name
display.setCursor(0, 20);
display.setColor(DisplayDriver::LIGHT);
display.print("From: ");
display.print(MECK_TR("From: ", "De : "));
display.setTextSize(_prefs->smallTextSize());
String origDisplay = _renameOriginal;
if (origDisplay.length() > 30) origDisplay = origDisplay.substring(0, 27) + "...";
@@ -797,7 +798,7 @@ private:
display.setTextSize(1);
display.setCursor(0, 38);
display.setColor(DisplayDriver::LIGHT);
display.print("To: ");
display.print(MECK_TR("To: ", "Vers : "));
display.setTextSize(_prefs->smallTextSize());
display.setColor(DisplayDriver::GREEN);
@@ -809,15 +810,15 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
display.setCursor(0, 56);
display.print("(.txt added automatically)");
display.print(MECK_TR("(.txt added automatically)", "(.txt ajout\xC3\xA9 auto.)"));
// Footer
int footerY = display.height() - 12;
display.drawRect(0, footerY - 2, display.width(), 1);
display.setColor(DisplayDriver::YELLOW);
display.setCursor(0, footerY);
display.print("Q:Cancel");
const char* right = "Ent:Confirm";
display.print(MECK_TR("Q:Cancel", "Q:Annuler"));
const char* right = MECK_TR("Ent:Confirm", "Ent:Valider");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
}
@@ -826,13 +827,13 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
display.setCursor(0, 0);
display.print("Delete Note?");
display.print(MECK_TR("Delete Note?", "Supprimer la note ?"));
display.setColor(DisplayDriver::LIGHT);
display.drawRect(0, 11, display.width(), 1);
display.setCursor(0, 25);
display.print("File:");
display.print(MECK_TR("File:", "Fichier :"));
display.setTextSize(_prefs->smallTextSize());
display.setCursor(0, 38);
@@ -843,15 +844,15 @@ private:
display.setTextSize(1);
display.setCursor(0, 58);
display.setColor(DisplayDriver::GREEN);
display.print("This cannot be undone.");
display.print(MECK_TR("This cannot be undone.", "Action irr\xC3\xA9versible."));
// Footer
int footerY = display.height() - 12;
display.drawRect(0, footerY - 2, display.width(), 1);
display.setColor(DisplayDriver::YELLOW);
display.setCursor(0, footerY);
display.print("Q:Cancel");
const char* right = "Ent:Delete";
display.print(MECK_TR("Q:Cancel", "Q:Annuler"));
const char* right = MECK_TR("Ent:Delete", "Ent:Supprimer");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
}
@@ -982,7 +983,7 @@ private:
if (_renameLen > 0) {
String newName = String(_renameBuf) + ".txt";
if (newName != _renameOriginal) {
drawBriefSplash("Renaming...");
drawBriefSplash(MECK_TR("Renaming...", "Renommage..."));
if (renameNote(_renameOriginal, newName)) {
if (_currentFile == _renameOriginal) {
_currentFile = newName;
@@ -1022,7 +1023,7 @@ private:
bool handleDeleteConfirmInput(char c) {
// Enter - confirm delete
if (c == '\r' || c == 13) {
drawBriefSplash("Deleting...");
drawBriefSplash(MECK_TR("Deleting...", "Suppression..."));
deleteNote(_deleteTarget);
_deleteTarget = "";
_selectedFile = 0;
@@ -1285,7 +1286,7 @@ public:
void saveAndExit() {
if (_dirty && _currentFile.length() > 0) {
if (_bufLen > 0) {
drawBriefSplash("Saving...");
drawBriefSplash(MECK_TR("Saving...", "Enregistrement..."));
saveNote();
} else if (_dirty) {
Serial.printf("Notes: Skipping empty note %s\n", _currentFile.c_str());
@@ -1304,7 +1305,7 @@ public:
void deleteCurrentNote() {
if (_currentFile.length() > 0) {
drawBriefSplash("Deleting...");
drawBriefSplash(MECK_TR("Deleting...", "Suppression..."));
deleteNote(_currentFile);
}
_dirty = false;
@@ -1332,9 +1333,9 @@ public:
display.setCursor(0, 20);
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
display.print("SD card not found");
display.print(MECK_TR("SD card not found", "Carte SD introuvable"));
display.setCursor(0, 35);
display.print("Insert SD card");
display.print(MECK_TR("Insert SD card", "Ins\xC3\xA9rez une carte SD"));
return 5000;
}
+17 -14
View File
@@ -14,6 +14,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
#include <SD.h>
// Forward declarations
@@ -275,6 +276,8 @@ private:
static const int dim[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static const char* mn[] = {"Jan","Feb","Mar","Apr","May","Jun",
"Jul","Aug","Sep","Oct","Nov","Dec"};
static const char* mn_fr[] = {"janv.","f\xC3\xA9vr.","mars","avr.","mai","juin",
"juil.","ao\xC3\xBBt","sept.","oct.","nov.","d\xC3\xA9" "c."};
bool leap = ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
int month = 0;
for (month = 0; month < 12; month++) {
@@ -284,7 +287,7 @@ private:
days -= d;
}
if (month > 11) month = 11;
snprintf(buf, bufLen, "%d %s %d", (int)(days + 1), mn[month], year);
snprintf(buf, bufLen, "%d %s %d", (int)(days + 1), MECK_TR(mn[month], mn_fr[month]), year);
}
public:
@@ -374,7 +377,7 @@ public:
display.setCursor(2, 2);
display.print("Snake");
char scoreBuf[16];
snprintf(scoreBuf, sizeof(scoreBuf), "Score: %d", _score);
snprintf(scoreBuf, sizeof(scoreBuf), MECK_TR("Score: %d", "Score : %d"), _score);
int sw = display.getTextWidth(scoreBuf);
display.setCursor(display.width() - sw - 2, 2);
display.print(scoreBuf);
@@ -385,19 +388,19 @@ public:
int cx = display.width() / 2;
int y = SNAKE_HDR + 6;
display.setColor(DisplayDriver::LIGHT);
display.drawTextCentered(cx, y, "Classic Snake");
display.drawTextCentered(cx, y, MECK_TR("Classic Snake", "Snake classique"));
y += 14;
display.setColor(DisplayDriver::GREEN);
display.drawTextCentered(cx, y, "W/S/A/D to steer");
display.drawTextCentered(cx, y, MECK_TR("W/S/A/D to steer", "W/S/A/D pour diriger"));
y += 11;
display.drawTextCentered(cx, y, "Eat food to grow");
display.drawTextCentered(cx, y, MECK_TR("Eat food to grow", "Mangez pour grandir"));
y += 11;
display.drawTextCentered(cx, y, "Steer clear of walls");
display.drawTextCentered(cx, y, MECK_TR("Steer clear of walls", "\xC3\x89vitez les murs"));
y += 16;
if (_hiCount > 0) {
display.setColor(DisplayDriver::LIGHT);
display.drawTextCentered(cx, y, "-- High Scores --");
display.drawTextCentered(cx, y, MECK_TR("-- High Scores --", "-- Meilleurs scores --"));
y += 12;
display.setColor(DisplayDriver::GREEN);
int showCount = (_hiCount < 10) ? _hiCount : 10;
@@ -415,7 +418,7 @@ public:
}
display.setColor(DisplayDriver::LIGHT);
display.drawTextCentered(cx, y, "Press Enter to start");
display.drawTextCentered(cx, y, MECK_TR("Press Enter to start", "Entr\xC3\xA9" "e pour commencer"));
} else {
if (_state == PLAYING) {
unsigned long now = millis();
@@ -450,21 +453,21 @@ public:
display.drawRect(boxX, boxY, boxW, boxH);
int ty = boxY + 8;
display.drawTextCentered(cx, ty, "Game Over");
display.drawTextCentered(cx, ty, MECK_TR("Game Over", "Partie termin\xC3\xA9" "e"));
ty += 14;
char finalScore[24];
snprintf(finalScore, sizeof(finalScore), "Score: %d", _score);
snprintf(finalScore, sizeof(finalScore), MECK_TR("Score: %d", "Score : %d"), _score);
display.drawTextCentered(cx, ty, finalScore);
ty += 12;
if (_newHiScore) {
display.setColor(DisplayDriver::YELLOW);
char rankBuf[32];
snprintf(rankBuf, sizeof(rankBuf), "New #%d High Score!", _newHiRank + 1);
snprintf(rankBuf, sizeof(rankBuf), MECK_TR("New #%d High Score!", "Nouveau record n\xC2\xB0%d !"), _newHiRank + 1);
display.drawTextCentered(cx, ty, rankBuf);
ty += 12;
}
display.setColor(DisplayDriver::GREEN);
display.drawTextCentered(cx, ty, "Enter:Retry Sh+Del:Back");
display.drawTextCentered(cx, ty, MECK_TR("Enter:Retry Sh+Del:Back", "Ent:Rejouer Sh+Del:Retour"));
}
}
@@ -474,10 +477,10 @@ public:
display.drawRect(0, fy - 2, display.width(), 1);
if (_state == PLAYING) {
display.setCursor(2, fy);
display.print("Sh+Del:Back");
display.print(MECK_TR("Sh+Del:Back", "Sh+Del:Retour"));
} else if (_state == READY) {
display.setCursor(2, fy);
display.print("Enter:Start Sh+Del:Back");
display.print(MECK_TR("Enter:Start Sh+Del:Back", "Ent:Jouer Sh+Del:Retour"));
}
if (_state == PLAYING) return 100;
@@ -2,6 +2,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
#include <SD.h>
#include <vector>
#include "Utf8CP437.h"
@@ -483,9 +484,9 @@ private:
_display->setTextSize(2);
_display->setColor(DisplayDriver::GREEN);
_display->setCursor(10, 11);
_display->print("Indexing");
_display->print(MECK_TR("Indexing", "Indexation"));
_display->setCursor(10, 21);
_display->print("Pages...");
_display->print(MECK_TR("Pages...", "des pages..."));
// Word-wrapped filename in normal text
_display->setTextSize(1);
@@ -526,9 +527,9 @@ private:
// Virtual: y=87 and y=93
_display->setColor(DisplayDriver::LIGHT);
_display->setCursor(10, 87);
_display->print("Please wait.");
_display->print(MECK_TR("Please wait.", "Patientez."));
_display->setCursor(10, 93);
_display->print("Loading shortly...");
_display->print(MECK_TR("Loading shortly...", "Chargement imminent..."));
_display->endFrame();
}
@@ -544,9 +545,9 @@ private:
_display->setTextSize(2);
_display->setColor(DisplayDriver::GREEN);
_display->setCursor(10, 11);
_display->print("Indexing");
_display->print(MECK_TR("Indexing", "Indexation"));
_display->setCursor(10, 21);
_display->print("Pages...");
_display->print(MECK_TR("Pages...", "des pages..."));
_display->setTextSize(1);
_display->setColor(DisplayDriver::LIGHT);
@@ -594,7 +595,7 @@ private:
// "Please wait."
_display->setCursor(10, 87);
_display->print("Please wait.");
_display->print(MECK_TR("Please wait.", "Patientez."));
_display->endFrame();
}
@@ -850,7 +851,7 @@ private:
strncpy(shortName, filename.c_str(), sizeof(shortName) - 1);
shortName[sizeof(shortName) - 1] = '\0';
}
drawSplash("Converting EPUB...", "Please wait", shortName);
drawSplash(MECK_TR("Converting EPUB...", "Conversion EPUB..."), MECK_TR("Please wait", "Patientez"), shortName);
Serial.printf("TextReader: Converting EPUB '%s'\n", filename.c_str());
unsigned long t0 = millis();
@@ -861,7 +862,7 @@ private:
if (!ok) {
Serial.println("TextReader: EPUB conversion failed!");
drawSplash("Convert failed!", "", shortName);
drawSplash(MECK_TR("Convert failed!", "\xC3\x89" "chec de conversion !"), "", shortName);
delay(2000);
return; // Stay in file list
}
@@ -939,7 +940,7 @@ private:
strncpy(shortName, actualFilename.c_str(), sizeof(shortName) - 1);
shortName[sizeof(shortName) - 1] = '\0';
}
drawSplash("Indexing...", "Please wait", shortName);
drawSplash(MECK_TR("Indexing...", "Indexation..."), MECK_TR("Please wait", "Patientez"), shortName);
DisplayDriver* pxd = (_prefs->large_font || _display->getFontStyle() > 0) ? _display : nullptr;
if (pxd) pxd->setTextSize(_prefs->smallTextSize());
@@ -968,7 +969,7 @@ private:
strncpy(shortName, actualFilename.c_str(), sizeof(shortName) - 1);
shortName[sizeof(shortName) - 1] = '\0';
}
drawSplash("Indexing...", "Please wait", shortName);
drawSplash(MECK_TR("Indexing...", "Indexation..."), MECK_TR("Please wait", "Patientez"), shortName);
_pagePositions.push_back(0);
DisplayDriver* pxd = (_prefs->large_font || _display->getFontStyle() > 0) ? _display : nullptr;
@@ -1071,7 +1072,7 @@ private:
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
if (isAtBooksRoot()) {
display.print("Text Reader");
display.print(MECK_TR("Text Reader", "Lecteur de texte"));
} else {
// Show current subfolder name
int lastSlash = _currentPath.lastIndexOf('/');
@@ -1092,11 +1093,11 @@ private:
if (totalItems == 0) {
display.setCursor(0, 18);
display.setColor(DisplayDriver::LIGHT);
display.print("No files found");
display.print(MECK_TR("No files found", "Aucun fichier trouv\xC3\xA9"));
display.setCursor(0, 30);
display.print("Add .txt or .epub to");
display.print(MECK_TR("Add .txt or .epub to", "Ajoutez des .txt ou .epub"));
display.setCursor(0, 42);
display.print("/books/ on SD card");
display.print(MECK_TR("/books/ on SD card", "dans /books/ sur la SD"));
} else {
display.setTextSize(_prefs->smallTextSize()); // Tiny font for file list
int listLineH = _prefs->smallLineH();
@@ -1130,7 +1131,7 @@ private:
if (type == 0) {
// ".." parent directory
line += ".. (up)";
line += MECK_TR(".. (up)", ".. (parent)");
} else if (type == 1) {
// Subdirectory
line += "/" + dirNameAt(i);
@@ -1163,9 +1164,9 @@ private:
display.setColor(DisplayDriver::YELLOW);
display.setCursor(0, footerY);
display.print("Q:Bk");
display.print(MECK_TR("Q:Bk", "Q:Ret"));
const char* right = "Tap/Ent:Open";
const char* right = MECK_TR("Tap/Ent:Open", "Ent:Ouvrir");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
}
@@ -1269,7 +1270,7 @@ private:
if (_gotoMode) {
// Go-to-page input mode — show typed digits in footer
snprintf(status, sizeof(status), "Go to: %.*s_", _gotoBufLen, _gotoBuf);
snprintf(status, sizeof(status), MECK_TR("Go to: %.*s_", "Aller \xC3\xA0 %.*s_"), _gotoBufLen, _gotoBuf);
} else {
sprintf(status, "%d/%d %d%%", _currentPage + 1, _totalPages, pct);
}
@@ -1277,7 +1278,7 @@ private:
display.setCursor(0, footerY);
display.print(status);
const char* right = _gotoMode ? "Ent:Go Sh+Del:Cancel" : "Entr:Pg# Q:Bk";
const char* right = _gotoMode ? MECK_TR("Ent:Go Sh+Del:Cancel", "Ent:OK Sh+Del:Annul.") : MECK_TR("Entr:Pg# Q:Bk", "Ent:Pg# Q:Ret");
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
display.print(right);
}
@@ -1499,7 +1500,7 @@ public:
initLayout(display);
// Show initial splash
drawBootSplash(0, 0, "Scanning...");
drawBootSplash(0, 0, MECK_TR("Scanning...", "Analyse..."));
Serial.println("TextReader: Boot indexing started");
// Scan for files (includes .txt and .epub)
@@ -1731,9 +1732,9 @@ public:
display.setCursor(0, 20);
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
display.print("SD card not found");
display.print(MECK_TR("SD card not found", "Carte SD introuvable"));
display.setCursor(0, 35);
display.print("Insert SD with /books/");
display.print(MECK_TR("Insert SD with /books/", "Ins\xC3\xA9rez une SD avec /books/"));
return 5000;
}
@@ -27,6 +27,7 @@
#include <helpers/ui/UIScreen.h>
#include <helpers/ui/DisplayDriver.h>
#include "MeckLang.h"
#include <SD.h>
#include <driver/i2s.h>
#include "Audio.h"
@@ -997,14 +998,14 @@ private:
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Send Voice To:");
display.print(MECK_TR("Send Voice To:", "Envoyer le vocal \xC3\xA0 :"));
display.fillRect(0, 11, display.width(), 1);
if (_pickList.empty()) {
display.setCursor(10, 50);
display.print("No contacts with");
display.print(MECK_TR("No contacts with", "Aucun contact avec"));
display.setCursor(10, 65);
display.print("direct path.");
display.print(MECK_TR("direct path.", "chemin direct."));
} else {
int y = 14;
int lineH = 12;
@@ -1043,7 +1044,7 @@ private:
int footerY = display.height() - 12;
display.setTextSize(1);
display.setCursor(0, footerY);
display.print("Ent:Send Q:Cancel");
display.print(MECK_TR("Ent:Send Q:Cancel", "Ent:Envoyer Q:Annuler"));
// No-direct-path popup. RAW_CUSTOM voice packets are direct-route only,
// so a contact with no path set cannot receive one. Drawn last so it
@@ -1060,13 +1061,13 @@ private:
display.setColor(DisplayDriver::DARK);
display.setTextSize(1);
display.setCursor(bx + 6, by + 8);
display.print("No direct path");
display.print(MECK_TR("No direct path", "Pas de chemin direct"));
display.setCursor(bx + 6, by + 20);
display.print("to contact.");
display.print(MECK_TR("to contact.", "vers ce contact."));
display.setCursor(bx + 6, by + 34);
display.print("Set a path in");
display.print(MECK_TR("Set a path in", "D\xC3\xA9" "finissez un chemin"));
display.setCursor(bx + 6, by + 46);
display.print("Contacts (P key)");
display.print(MECK_TR("Contacts (P key)", "dans Contacts (touche P)"));
display.setColor(DisplayDriver::GREEN);
}
}
@@ -1112,23 +1113,23 @@ private:
// Title bar
display.setCursor(0, 0);
display.print("Voice Messages");
display.print(MECK_TR("Voice Messages", "Messages vocaux"));
char countStr[16];
snprintf(countStr, sizeof(countStr), "%d files", (int)_fileList.size());
snprintf(countStr, sizeof(countStr), MECK_TR("%d files", "%d fichiers"), (int)_fileList.size());
// Place the count just after the title rather than right-aligned to the
// screen edge. The right-aligned position pushed the trailing 's' of
// "files" off the right edge, where it wrapped onto the next line.
display.setCursor(display.getTextWidth("Voice Messages") + 6, 0);
display.setCursor(display.getTextWidth(MECK_TR("Voice Messages", "Messages vocaux")) + 6, 0);
display.print(countStr);
display.fillRect(0, 11, display.width(), 1); // horizontal rule
if (_fileList.empty()) {
display.setCursor(10, 60);
display.print("No voice messages.");
display.print(MECK_TR("No voice messages.", "Aucun message vocal."));
display.setCursor(10, 80);
display.print("Hold Mic key to record.");
display.print(MECK_TR("Hold Mic key to record.", "Mic maintenu : enregistrer"));
} else {
// File list
int y = 14;
@@ -1172,11 +1173,11 @@ private:
display.setTextSize(1);
display.setCursor(0, footerY);
if (_listPlaying) {
display.print("Playing... Q:Stop");
display.print(MECK_TR("Playing... Q:Stop", "Lecture... Q:Arr\xC3\xAAt"));
} else if (!_fileList.empty()) {
display.print("Mic:Rec Ent:Ply F:Snd D:Del");
display.print(MECK_TR("Mic:Rec Ent:Ply F:Snd D:Del", "Mic:Enr Ent:Lire F:Env D:Sup"));
} else {
display.print("Mic:Record Q:Exit");
display.print(MECK_TR("Mic:Record Q:Exit", "Mic:Enregistrer Q:Quitter"));
}
// "Loading" popup while a forward-send file is read off SD and encoded.
@@ -1194,9 +1195,9 @@ private:
display.setColor(DisplayDriver::DARK);
display.setTextSize(1);
display.setCursor(bx + 6, by + 8);
display.print("Loading...");
display.print(MECK_TR("Loading...", "Chargement..."));
display.setCursor(bx + 6, by + 20);
display.print("Encoding voice");
display.print(MECK_TR("Encoding voice", "Encodage du vocal"));
display.setColor(DisplayDriver::GREEN);
_loadingDrawn = true;
}
@@ -1207,7 +1208,7 @@ private:
display.setTextSize(1);
display.setCursor(0, 0);
display.print("RECORDING");
display.print(MECK_TR("RECORDING", "ENREGISTREMENT"));
// Elapsed time
float elapsed = _recSamples / (float)VOICE_SAMPLE_RATE;
@@ -1262,7 +1263,7 @@ private:
int footerY = display.height() - 12;
display.setTextSize(1);
display.setCursor(0, footerY);
display.print("Release Mic to stop");
display.print(MECK_TR("Release Mic to stop", "Rel\xC3\xA2" "chez Mic pour arr\xC3\xAAter"));
}
void renderReview(DisplayDriver& display) {
@@ -1270,7 +1271,7 @@ private:
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Review Recording");
display.print(MECK_TR("Review Recording", "\xC3\x89" "couter l'enregistrement"));
display.fillRect(0, 11, display.width(), 1); // horizontal rule
// Filename
@@ -1280,7 +1281,7 @@ private:
// Duration
float secs = _recSamples / (float)VOICE_SAMPLE_RATE;
char durStr[32];
snprintf(durStr, sizeof(durStr), "Duration: %.1f seconds", secs);
snprintf(durStr, sizeof(durStr), MECK_TR("Duration: %.1f seconds", "Dur\xC3\xA9" "e : %.1f secondes"), secs);
display.setCursor(10, 50);
display.print(durStr);
@@ -1288,9 +1289,9 @@ private:
uint32_t sizeBytes = 44 + _recSamples * sizeof(int16_t);
char sizeStr[32];
if (sizeBytes > 1024) {
snprintf(sizeStr, sizeof(sizeStr), "Size: %.1f KB", sizeBytes / 1024.0f);
snprintf(sizeStr, sizeof(sizeStr), MECK_TR("Size: %.1f KB", "Taille : %.1f Ko"), sizeBytes / 1024.0f);
} else {
snprintf(sizeStr, sizeof(sizeStr), "Size: %d bytes", sizeBytes);
snprintf(sizeStr, sizeof(sizeStr), MECK_TR("Size: %d bytes", "Taille : %d octets"), sizeBytes);
}
display.setCursor(10, 70);
display.print(sizeStr);
@@ -1299,21 +1300,21 @@ private:
if (_c2Valid) {
int packets = (_c2Bytes + VOICE_MESH_PAYLOAD - 1) / VOICE_MESH_PAYLOAD;
char c2Str[48];
snprintf(c2Str, sizeof(c2Str), "Codec2: %d bytes (%d pkt%s)",
snprintf(c2Str, sizeof(c2Str), MECK_TR("Codec2: %d bytes (%d pkt%s)", "Codec2 : %d o (%d paquet%s)"),
_c2Bytes, packets, packets == 1 ? "" : "s");
display.setCursor(10, 90);
display.print(c2Str);
} else {
display.setCursor(10, 90);
display.print("Codec2: encode failed");
display.print(MECK_TR("Codec2: encode failed", "Codec2 : \xC3\xA9" "chec d'encodage"));
}
// Status
display.setCursor(10, 110);
if (_reviewPlaying) {
display.print("Playing...");
display.print(MECK_TR("Playing...", "Lecture..."));
} else {
display.print("Ready");
display.print(MECK_TR("Ready", "Pr\xC3\xAAt"));
}
// Footer
@@ -1321,11 +1322,11 @@ private:
display.setTextSize(1);
display.setCursor(0, footerY);
if (_reviewPlaying) {
display.print("Q:Stop");
display.print(MECK_TR("Q:Stop", "Q:Arr\xC3\xAAt"));
} else if (_c2Valid) {
display.print("S:Send Ent:Play Mic:Redo Q:List");
display.print(MECK_TR("S:Send Ent:Play Mic:Redo Q:List", "S:Env Ent:Lire Mic:Enr Q:Liste"));
} else {
display.print("Ent:Play Mic:Redo D:Del Q:List");
display.print(MECK_TR("Ent:Play Mic:Redo D:Del Q:List", "Ent:Lire Mic:Enr D:Sup Q:Liste"));
}
}