v0.248.0: i18n slice 1 release A — apps and settings in English, Hungarian byte-identical (R-556)
gates / gates (push) Successful in 20s

Ten pages converted against fixtures captured from unconverted templates (6be55a0); marker
coverage test; English page mask narrowed; English retrieval-promise stems; common keys;
title keys and infraMeta from the bundle; old wording tests read the Hungarian expansion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-17 17:36:08 +02:00
parent 6be55a0eb3
commit ff68b0b433
30 changed files with 1690 additions and 651 deletions
@@ -3,22 +3,22 @@
<div class="page-header">
<div style="display:flex;align-items:center;gap:1rem">
<a href="/stacks" class="btn btn-sm btn-outline">&larr; Alkalmazások</a>
<h2>Alkalmazás importálás</h2>
<a href="/stacks" class="btn btn-sm btn-outline">{{T "app_import.alkalmazasok"}}</a>
<h2>{{T "app_import.alkalmazas_importalas"}}</h2>
</div>
</div>
<!-- Browser .fab upload (v0.128.0) — chunked, because the Cloudflare tunnel caps request bodies (~100 MB) -->
<div class="card" style="max-width:900px;margin-bottom:1rem">
<div id="fabUploadZone" style="border:1px dashed var(--line);border-radius:var(--radius);padding:1.25rem;text-align:center;cursor:pointer" onclick="fabPick()">
<p style="color:var(--text-2);margin:0 0 .75rem">.fab csomag feltöltése &mdash; húzza ide, vagy válassza ki a fájlt</p>
<button type="button" class="btn btn-sm btn-outline">Fájl kiválasztása</button>
<p style="color:var(--text-2);margin:0 0 .75rem">{{T "app_import.fab_csomag_feltoltese_huzza_ide"}}</p>
<button type="button" class="btn btn-sm btn-outline">{{T "app_import.fajl_kivalasztasa"}}</button>
<input type="file" id="fabFileInput" accept=".fab" style="display:none">
</div>
<div id="fabUpProgress" style="display:none;margin-top:1rem">
<div style="display:flex;justify-content:space-between;align-items:center;gap:1rem">
<span id="fabUpText" style="color:var(--text-2)">Feltöltés: 0%</span>
<button type="button" class="btn btn-sm btn-outline" onclick="fabCancel()">Megszakítás</button>
<span id="fabUpText" style="color:var(--text-2)">{{T "app_import.feltoltes_0"}}</span>
<button type="button" class="btn btn-sm btn-outline" onclick="fabCancel()">{{T "app_import.megszakitas"}}</button>
</div>
<div style="background:var(--bg-2);border-radius:var(--radius);height:6px;margin-top:.5rem;overflow:hidden">
<div id="fabUpBar" style="background:var(--blue);height:100%;width:0%"></div>
@@ -29,19 +29,19 @@
{{if not .Bundles}}
<div class="card" style="max-width:700px">
<p style="color:var(--text-3)">Nem található .fab csomag a regisztrált tárolókon.</p>
<p style="color:var(--text-3);font-size:.85rem">Exportálj egy alkalmazást az alkalmazás oldaláról, tölts fel egy .fab fájlt itt fent, vagy másolj egyet a <code>{tároló}/felhom-data/exports/</code> könyvtárba.</p>
<p style="color:var(--text-3)">{{T "app_import.nem_talalhato_fab_csomag_a"}}</p>
<p style="color:var(--text-3);font-size:.85rem">{{T "app_import.exportalj_egy_alkalmazast_az_alkalmazas"}}</p>
</div>
{{else}}
<div class="card" style="max-width:900px">
<table class="table" style="width:100%">
<thead>
<tr>
<th>Alkalmazás</th>
<th>Dátum</th>
<th>Méret</th>
<th>Tároló</th>
<th>Titkos</th>
<th>{{T "app_import.alkalmazas"}}</th>
<th>{{T "app_import.datum"}}</th>
<th>{{T "app_import.meret"}}</th>
<th>{{T "app_import.tarolo"}}</th>
<th>{{T "app_import.titkos"}}</th>
<th></th>
</tr>
</thead>
@@ -53,7 +53,7 @@
<td>{{.SizeHuman}}</td>
<td>{{if .DriveLabel}}{{.DriveLabel}}{{else}}{{.DrivePath}}{{end}}</td>
<td>{{if .Encrypted}}&#128274;{{end}}</td>
<td><button class="btn btn-sm btn-outline" onclick="showPreview('{{.Path}}', {{.Encrypted}})">Részletek &raquo;</button></td>
<td><button class="btn btn-sm btn-outline" onclick="showPreview('{{.Path}}', {{.Encrypted}})">{{T "app_import.reszletek"}}</button></td>
</tr>
{{end}}
</tbody>
@@ -63,13 +63,13 @@
<!-- Preview / password modal -->
<div id="previewCard" class="card" style="max-width:700px;display:none">
<h3 id="previewTitle">Csomag részletei</h3>
<h3 id="previewTitle">{{T "app_import.csomag_reszletei"}}</h3>
<div id="passwordPrompt" style="display:none;margin-bottom:1rem">
<p>Ez a csomag jelszóval védett. Kérlek add meg a jelszót:</p>
<p>{{T "app_import.ez_a_csomag_jelszoval_vedett"}}</p>
<div style="display:flex;gap:.5rem">
<input type="password" id="importPassword" class="form-input" autocomplete="off" placeholder="Jelszó" style="flex:1">
<button class="btn btn-primary" onclick="loadManifest()">Megnyitás</button>
<input type="password" id="importPassword" class="form-input" autocomplete="off" placeholder="{{T "common.jelszo"}}" style="flex:1">
<button class="btn btn-primary" onclick="loadManifest()">{{T "app_import.megnyitas"}}</button>
</div>
<div id="passwordError" style="display:none;color:var(--crit);margin-top:.5rem"></div>
</div>
@@ -77,52 +77,52 @@
<div id="manifestInfo" style="display:none">
<div style="background:var(--bg-2);border-radius:8px;padding:1rem;margin-bottom:1rem">
<div style="display:flex;justify-content:space-between;margin-bottom:.25rem">
<span>Alkalmazás:</span>
<span>{{T "app_import.alkalmazas_2"}}</span>
<strong id="mfName">-</strong>
</div>
<div style="display:flex;justify-content:space-between;margin-bottom:.25rem">
<span>Exportálva:</span>
<span>{{T "app_import.exportalva"}}</span>
<span id="mfDate">-</span>
</div>
<div style="display:flex;justify-content:space-between;margin-bottom:.25rem">
<span>Controller verzió:</span>
<span>{{T "app_import.controller_verzio"}}</span>
<span id="mfVersion">-</span>
</div>
<div id="mfDBRow" style="display:flex;justify-content:space-between;margin-bottom:.25rem">
<span>Adatbázis:</span>
<span>{{T "app_import.adatbazis"}}</span>
<span id="mfDB">-</span>
</div>
<div style="display:flex;justify-content:space-between;margin-bottom:.25rem">
<span>Adatok:</span>
<span>{{T "app_import.adatok"}}</span>
<span id="mfDataType">-</span>
</div>
<div style="display:flex;justify-content:space-between">
<span>Méret:</span>
<span>{{T "app_import.meret_2"}}</span>
<span id="mfSize">-</span>
</div>
</div>
<div id="overwriteWarning" style="display:none;background:var(--warning-bg, #fff3cd);border:1px solid var(--warning-border, #ffc107);border-radius:8px;padding:1rem;margin-bottom:1rem">
<strong>&#9888; FIGYELEM:</strong> A meglévő <span id="overwriteAppName"></span> alkalmazás konfigurációja és összes adata felül lesz írva!
{{T "app_import.figyelem_a_meglevo"}} <span id="overwriteAppName"></span> {{T "app_import.alkalmazas_konfiguracioja_es_osszes_adat"}}
</div>
<button id="importBtn" class="btn btn-primary" onclick="startImport()" style="width:100%">
Visszaállítás indítása
{{T "app_import.visszaallitas_inditasa"}}
</button>
</div>
</div>
<!-- Progress -->
<div id="progressCard" class="card" style="max-width:700px;display:none">
<h3>Importálás folyamata</h3>
<h3>{{T "app_import.importalas_folyamata"}}</h3>
<div id="progressSteps"></div>
<div id="progressError" style="display:none;color:var(--crit);margin-top:1rem;font-weight:600"></div>
</div>
<div id="doneCard" class="card" style="max-width:700px;display:none">
<h3 style="color:var(--blue)">Importálás kész!</h3>
<p>Az alkalmazás sikeresen visszaállítva.</p>
<a id="doneLink" href="/stacks" class="btn btn-primary">Alkalmazások megtekintése</a>
<h3 style="color:var(--blue)">{{T "app_import.importalas_kesz"}}</h3>
<p>{{T "app_import.az_alkalmazas_sikeresen_visszaallitva"}}</p>
<a id="doneLink" href="/stacks" class="btn btn-primary">{{T "app_import.alkalmazasok_megtekintese"}}</a>
</div>
<script>
@@ -170,7 +170,7 @@ async function loadManifest() {
if (!data.ok) {
if (selectedEncrypted) {
document.getElementById('passwordError').textContent = data.error || 'Hibás jelszó';
document.getElementById('passwordError').textContent = data.error || '{{T "app_import.hibas_jelszo"}}';
document.getElementById('passwordError').style.display = 'block';
}
return;
@@ -193,7 +193,7 @@ function showManifest(m) {
document.getElementById('passwordPrompt').style.display = 'none';
document.getElementById('manifestInfo').style.display = 'block';
document.getElementById('previewTitle').textContent = (m.display_name || m.app_name) + ' — Csomag részletei';
document.getElementById('previewTitle').textContent = (m.display_name || m.app_name) + ' {{T "app_import.csomag_reszletei_2"}}';
document.getElementById('mfName').textContent = m.display_name || m.app_name;
document.getElementById('mfDate').textContent = m.exported_at ? new Date(m.exported_at).toLocaleString('hu-HU') : '-';
document.getElementById('mfVersion').textContent = m.controller_version || '-';
@@ -208,7 +208,7 @@ function showManifest(m) {
var dataType = [];
if (m.has_hdd_data) dataType.push('HDD');
if (m.has_volume_data) dataType.push('Docker volume');
document.getElementById('mfDataType').textContent = dataType.length ? dataType.join(', ') : 'Nincs';
document.getElementById('mfDataType').textContent = dataType.length ? dataType.join(', ') : '{{T "app_import.nincs"}}';
// Format size
var bytes = m.total_size_bytes || 0;
@@ -240,7 +240,7 @@ async function startImport() {
});
var data = await resp.json();
if (!data.ok) {
showError(data.error || 'Hiba történt');
showError(data.error || '{{T "common.hiba_tortent"}}');
return;
}
pollStatus();
@@ -269,7 +269,7 @@ function pollStatus() {
document.getElementById('doneCard').style.display = 'block';
if (data.stack_name) {
document.getElementById('doneLink').href = '/stacks/' + data.stack_name + '/deploy';
document.getElementById('doneLink').textContent = 'Alkalmazás megtekintése';
document.getElementById('doneLink').textContent = '{{T "app_import.alkalmazas_megtekintese"}}';
}
}
} catch(e) {
@@ -305,7 +305,7 @@ function showError(msg) {
// network error, re-syncing from the server's 409 received_bytes echo; progress from bytes acked.
var fabUploadId = null;
var fabCancelled = false;
var fabNetErrText = 'A feltöltés megszakadt — ellenőrizze a kapcsolatot, majd próbálja újra.';
var fabNetErrText = '{{T "app_import.a_feltoltes_megszakadt_ellenorizze_a"}}';
function csrfRawH() {
var el = document.querySelector('meta[name="csrf-token"]');
@@ -323,7 +323,7 @@ function fabGB(b) {
function fabProgress(done, total) {
var pct = total > 0 ? Math.floor(done * 100 / total) : 0;
document.getElementById('fabUpText').textContent =
'Feltöltés: ' + pct + '% (' + fabGB(done) + ' / ' + fabGB(total) + ' GB)';
'{{T "app_import.feltoltes"}} ' + pct + '% (' + fabGB(done) + ' / ' + fabGB(total) + ' GB)';
document.getElementById('fabUpBar').style.width = pct + '%';
}
@@ -355,7 +355,7 @@ async function fabStart(file) {
if (!file) return;
document.getElementById('fabUpError').style.display = 'none';
if (!file.name.toLowerCase().endsWith('.fab')) {
fabFail('Csak .fab fájl tölthető fel.');
fabFail('{{T "app_import.csak_fab_fajl_toltheto_fel"}}');
return;
}
fabCancelled = false;
@@ -410,7 +410,7 @@ async function fabStart(file) {
var fd = await fin.json();
if (!fd.ok) { fabFail(fd.error || fabNetErrText); return; }
fabUploadId = null;
document.getElementById('fabUpText').textContent = 'Feltöltés kész: ' + fd.filename;
document.getElementById('fabUpText').textContent = '{{T "app_import.feltoltes_kesz"}} ' + fd.filename;
document.getElementById('fabUpBar').style.width = '100%';
// Refresh the bundle list through the EXISTING scan (the page render runs it).
setTimeout(function(){ window.location.reload(); }, 800);