From 6def94948b65b7a6c0f8eeea331ae93faf60ee10 Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Sat, 16 May 2026 15:48:37 +0000 Subject: [PATCH] =?UTF-8?q?v1.7.15=20=E2=80=94=20appliance=20translation,?= =?UTF-8?q?=20gemini=20key=20preserve=20on=20save?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _applianceDisplayName(): reverse lookup from canonical Italian names to settings.appliances.* i18n keys, with emoji stripping — appliance chips now show 'Air fryer', 'Heißluftfritteuse', etc. in EN/DE - renderAppliances(): uses translated display name; remove button title uses t('btn.delete') instead of hardcoded 'Rimuovi' - addApplianceQuick(): toast now uses t('toast.appliance_added') instead of hardcoded Italian ' aggiunto' - saveSettings(): gemini_key in localStorage preserved when input is empty (key is not pre-populated for security — blank != user deleted the key) - saveSettings(): _geminiAvailable re-synced from server after each save so recipe buttons immediately reflect correct state without page reload --- CHANGELOG.md | 2 ++ assets/js/app.js | 65 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cea067..401e351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Quantity decimal precision** — `qtyNum` in recipe/cooking ingredient buttons and `conf` fallback display in inventory cards now limited to 1 decimal place (was showing 7+ decimal places from raw AI output, e.g. `0.25353223 conf`). - **"Errore" / "Error" fallback strings** — All remaining Italian hardcoded `'Errore'` fallbacks in `showToast()` calls replaced with `t('error.generic')`. Italian fallback strings removed from buttons that already used `t()`. - **README Italian phrases** — "La quantità è giusta (2 pz)", "🤖 Spiega", "Latte / Affettato / Panna da cucina", "Buon appetito!", "L'ho buttato" replaced with English equivalents in the README. +- **Appliance chips translated** — `renderAppliances()` now shows translated names (e.g. "Air fryer" in EN, "Heißluftfritteuse" in DE) for all known canonical Italian appliance names via `_applianceDisplayName()` lookup. `addApplianceQuick` toast no longer hardcoded Italian. Remove-button title translated. +- **Gemini API key not preserved on settings save** — `saveSettings()` was overwriting `s.gemini_key = ""` when the Gemini input field was empty (it is intentionally not pre-populated for security). Key is now preserved if the input is blank. `_geminiAvailable` is re-fetched from the server after every settings save so the recipe buttons reflect the real state immediately. ## [1.7.14] - 2026-05-16 diff --git a/assets/js/app.js b/assets/js/app.js index f1eeacc..87c3b1e 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -2599,6 +2599,53 @@ function _injectKioskOverlay() { headerLeft.appendChild(wrap); } +const _APPLIANCE_KEY_MAP = { + 'forno': 'settings.appliances.oven', + 'oven': 'settings.appliances.oven', + 'backofen': 'settings.appliances.oven', + 'microonde': 'settings.appliances.microwave', + 'microwave': 'settings.appliances.microwave', + 'mikrowelle': 'settings.appliances.microwave', + 'friggitrice ad aria': 'settings.appliances.air_fryer', + 'air fryer': 'settings.appliances.air_fryer', + 'heißluftfritteuse': 'settings.appliances.air_fryer', + 'macchina del pane': 'settings.appliances.bread_maker', + 'macchina pane': 'settings.appliances.bread_maker', + 'bread maker': 'settings.appliances.bread_maker', + 'bread machine': 'settings.appliances.bread_maker', + 'brotbackmaschine': 'settings.appliances.bread_maker', + 'brotbackautomat': 'settings.appliances.bread_maker', + 'bimby/moulinex cookeo': 'settings.appliances.bimby', + 'moulinex cookeo': 'settings.appliances.bimby', + 'bimby/cookeo': 'settings.appliances.bimby', + 'bimby': 'settings.appliances.bimby', + 'thermomix': 'settings.appliances.bimby', + 'thermomix/cookeo': 'settings.appliances.bimby', + 'planetaria': 'settings.appliances.mixer', + 'stand mixer': 'settings.appliances.mixer', + 'küchenmaschine': 'settings.appliances.mixer', + 'vaporiera': 'settings.appliances.steamer', + 'steamer': 'settings.appliances.steamer', + 'dampfgarer': 'settings.appliances.steamer', + 'pentola a pressione': 'settings.appliances.pressure_cooker', + 'pentola pressione': 'settings.appliances.pressure_cooker', + 'pressure cooker': 'settings.appliances.pressure_cooker', + 'schnellkochtopf': 'settings.appliances.pressure_cooker', + 'tostapane': 'settings.appliances.toaster', + 'toaster': 'settings.appliances.toaster', + 'frullatore/mixer': 'settings.appliances.blender', + 'frullatore': 'settings.appliances.blender', + 'blender': 'settings.appliances.blender', + 'mixer': 'settings.appliances.blender', +}; + +function _applianceDisplayName(name) { + const key = _APPLIANCE_KEY_MAP[name.toLowerCase().trim()]; + if (!key) return name; + // Strip leading emoji/symbols from the translated button label (e.g. "🔥 Oven" → "Oven") + return t(key).replace(/^[^\p{L}]+/u, '').trim() || name; +} + function renderAppliances(appliances) { const container = document.getElementById('appliances-list'); if (!appliances || appliances.length === 0) { @@ -2607,8 +2654,8 @@ function renderAppliances(appliances) { } container.innerHTML = appliances.map((a, i) => `
- 🔌 ${escapeHtml(a)} - + 🔌 ${escapeHtml(_applianceDisplayName(a))} +
`).join(''); } @@ -2657,7 +2704,7 @@ function addApplianceQuick(name) { s.appliances.push(name); saveSettingsToStorage(s); renderAppliances(s.appliances); - showToast(`${name} aggiunto`, 'success'); + showToast(t('toast.appliance_added'), 'success'); } function removeAppliance(idx) { @@ -2670,7 +2717,9 @@ function removeAppliance(idx) { async function saveSettings() { const s = getSettings(); - s.gemini_key = document.getElementById('setting-gemini-key').value.trim(); + // Only update gemini_key if user actually typed something; preserve existing key otherwise + const _newGeminiKey = document.getElementById('setting-gemini-key').value.trim(); + if (_newGeminiKey) s.gemini_key = _newGeminiKey; s.bring_email = document.getElementById('setting-bring-email').value.trim(); s.bring_password = document.getElementById('setting-bring-password').value.trim(); s.default_persons = parseInt(document.getElementById('setting-default-persons').value) || 1; @@ -2790,6 +2839,14 @@ async function saveSettings() { statusEl.style.display = 'block'; setTimeout(() => statusEl.style.display = 'none', 4000); } + // Re-sync _geminiAvailable after save (key may have been set/confirmed on server) + try { + const refreshed = await api('get_settings'); + if (refreshed && refreshed.gemini_key_set !== undefined) { + _geminiAvailable = !!(refreshed.gemini_key_set); + _updateGeminiButtonState(); + } + } catch(e) {} // Re-init screensaver watcher in case it was just enabled initInactivityWatcher(); }