From 0702eef39bee4f0495ada2a759a7c0cb8748b798 Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Sun, 7 Jun 2026 17:59:42 +0900 Subject: [PATCH 01/15] Add export and import buttons for badge presets --- index.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/index.php b/index.php index 948977816..f595513b1 100644 --- a/index.php +++ b/index.php @@ -1167,6 +1167,8 @@ class="joystickBase" />
+ +
-
+
From 0aae37a4597db71ded46b7fd45e9578ca0a82937 Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 01:08:03 +0900 Subject: [PATCH 07/15] Update .css --- play.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/play.css b/play.css index 3056079cf..97eb07aa0 100644 --- a/play.css +++ b/play.css @@ -4161,5 +4161,8 @@ html[dir="rtl"] .messageSender { } .badgePresetActions { - display: flex + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px; } From 82bdd1d503ae874298d98261db48f82c12342004 Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 01:08:29 +0900 Subject: [PATCH 08/15] Remove badgepresetio.js script from index.php --- index.php | 1 - 1 file changed, 1 deletion(-) diff --git a/index.php b/index.php index 7e0f888e7..6bbc82099 100644 --- a/index.php +++ b/index.php @@ -2281,7 +2281,6 @@ class="joystickBase" /> - From 446faded38f95d96fea2372d234772e25b032356 Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 01:09:03 +0900 Subject: [PATCH 09/15] Update init.js to include badgepresetio.js script in the injection list --- init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init.js b/init.js index 4b49d4de7..94e310a1e 100644 --- a/init.js +++ b/init.js @@ -82,7 +82,7 @@ let initBlocker = Promise.resolve(); async function injectScripts() { const supportsSimd = await wasmFeatureDetect.simd(); - let scripts = [ 'chat.js', 'playerlist.js', 'friends.js', 'parties.js', 'system.js', 'preloads.js', 'locations.js', 'schedules.js', 'report.js', 'notifications.js', '2kki.js', 'play.js', 'gamecanvas.js', `ynoengine${supportsSimd ? '-simd' : ''}.js` ]; + let scripts = [ 'chat.js', 'playerlist.js', 'friends.js', 'parties.js', 'system.js', 'preloads.js', 'locations.js', 'schedules.js', 'report.js', 'notifications.js', '2kki.js', 'badgepresetio.js', 'play.js', 'gamecanvas.js', `ynoengine${supportsSimd ? '-simd' : ''}.js` ]; dependencyFiles['play.css'] = null; From a338916658cee6eb3f999583fb03c1916d2776ee Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 01:58:23 +0900 Subject: [PATCH 10/15] Add init badge preset io func call --- badges.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/badges.js b/badges.js index 63325c0c6..2d88ad69b 100644 --- a/badges.js +++ b/badges.js @@ -997,6 +997,9 @@ function initBadgeGalleryModal() { } function initBadgePresetModal() { + if (typeof initBadgePresetIO === 'function') + initBadgePresetIO(); + addLoader(document.getElementById('badgePresetModal')); apiFetch(`badge?command=presetGet&preset=${document.getElementById('badgePresetSelection').value}`) From 345473c72cad5d9dfb3aeb487274bbeb4cc829fc Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 02:00:12 +0900 Subject: [PATCH 11/15] Update file ext, add file handling for exports and improve error handling --- badgepresetio.js | 73 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/badgepresetio.js b/badgepresetio.js index d834c846d..54da1fecb 100644 --- a/badgepresetio.js +++ b/badgepresetio.js @@ -1,14 +1,13 @@ -const PRESET_FILE_EXT = '.badge-preset'; -const PRESET_FILE_ACCEPT = '.badge-preset,.json'; +const PRESET_FILE_EXT = '.badgepreset'; +const PRESET_FILE_ACCEPT = '.badgepreset,.json'; const PRESET_FILE_MAX_BYTES = 64 * 1024; -const BADGE_ID_PATTERN = /^[a-zA-Z0-9_]+$/; +const PRESET_FILE_MAX_ROWS = 10; // max badge slot based on server +const PRESET_FILE_MAX_COLS = 7; +const BADGE_ID_PATTERN = /^[a-zA-Z0-9_ ]+$/; const SLOT_SET_CONCURRENCY = 8; function getPresetIoMessage(key, fallback) { - const i18nextInstance = /** @type {any} */ (window).i18next; - if (i18nextInstance) - return i18nextInstance.t(`modal.badgePreset.io.${key}`, fallback); - return fallback; + return i18next.t(`modal.badgePreset.io.${key}`, fallback); } function showPresetIoSuccess(message) { @@ -75,7 +74,7 @@ function expandBadgeSlotsToGrid(badgeSlots, rows, cols) { const expandedRow = []; for (let c = 0; c < cols; c++) { const badgeId = badgeSlots?.[r]?.[c]; - if (badgeId === null || badgeId === 'null' || typeof badgeId === 'undefined') + if (badgeId == null || badgeId === 'null') expandedRow.push('null'); else expandedRow.push(badgeId); @@ -125,7 +124,13 @@ async function placeNonNullSlotsConcurrent(changes, concurrency) { .map(({ r, c, targetId }) => async () => { try { const response = await fetchSlotSet(targetId, r + 1, c + 1); - return { ok: response.ok }; + if (response.ok) + return { ok: true }; + const message = await response.text(); + return { + ok: message.includes('unknown badge') + || message.includes('specified badge is locked') + }; } catch { return { ok: false }; } @@ -169,10 +174,15 @@ function formatExportFilename(presetIndex) { const minute = `${now.getMinutes()}`.padStart(2, '0'); const second = `${now.getSeconds()}`.padStart(2, '0'); const formattedDate = `${year}-${month}-${day}-${hour}h${minute}m${second}s`; - const presetNumber = `${(Number.parseInt(presetIndex, 10) || 0) + 1}`.padStart(2, '0'); + const presetNumber = `${(parseInt(presetIndex, 10) || 0) + 1}`.padStart(2, '0'); return `badge_preset_${presetNumber}-${formattedDate}${PRESET_FILE_EXT}`; } +const PRESET_FILE_SAVE_TYPES = [{ + description: 'Badge Preset', + accept: { 'application/json': ['.badgepreset', '.json'] } +}]; + function downloadJSON(data, filename) { const json = JSON.stringify(data, null, 2); const blob = new Blob([json], { type: 'application/json' }); @@ -195,6 +205,22 @@ async function handleExport() { try { const presetId = presetSelection.value; + const filename = formatExportFilename(presetId); + let fileHandle; + + if (typeof showSaveFilePicker === 'function') { + try { + fileHandle = await showSaveFilePicker({ + suggestedName: filename, + types: PRESET_FILE_SAVE_TYPES + }); + } catch (error) { + if (error instanceof DOMException && error.name === 'AbortError') + return; + throw error; + } + } + const presetSlots = await getPresetData(presetId); if (!presetSlots) { alert(getPresetIoMessage('exportFailed', 'Export failed.')); @@ -208,7 +234,14 @@ async function handleExport() { const { rows, cols } = getCurrentGridDimensions(presetSlots); const fullGridSlots = expandBadgeSlotsToGrid(presetSlots, rows, cols); - downloadJSON({ badgeSlots: fullGridSlots }, formatExportFilename(presetId)); + const exportData = { badgeSlots: fullGridSlots }; + if (fileHandle) { + const writable = await fileHandle.createWritable(); + await writable.write(JSON.stringify(exportData, null, 2)); + await writable.close(); + } else { + downloadJSON(exportData, filename); + } showPresetIoSuccess(getPresetIoMessage('exportSuccess', 'Badge preset exported successfully.')); } catch (error) { console.error('Export failed:', error); @@ -238,14 +271,12 @@ async function applyPresetToSlot(badgeSlots) { const playerRows = backupSlots.length; const playerCols = backupSlots[0]?.length || 0; - if (!validateBadgeSlots(badgeSlots, playerRows, playerCols)) - return false; - const normalizedSlots = expandBadgeSlotsToGrid(badgeSlots, playerRows, playerCols); const changes = computeChanges(normalizedSlots, backupSlots, playerRows, playerCols); const clearResults = await clearChangedSlotsFromChanges(changes); + // if invalid badge id, skip place const placeResults = await placeNonNullSlotsConcurrent(changes, SLOT_SET_CONCURRENCY); - changedServerSlots = clearResults.length > 0 || placeResults.length > 0; + changedServerSlots = true; const allResults = [...clearResults, ...placeResults]; if (allResults.some(result => !result.ok)) @@ -263,6 +294,8 @@ async function applyPresetToSlot(badgeSlots) { try { if (changedServerSlots && backupSlots) await rollbackSlots(backupSlots); + } catch (error) { + console.error('Badge preset import rollback failed:', error); } finally { if (presetModal && typeof removeLoader === 'function') removeLoader(presetModal); @@ -277,8 +310,7 @@ function handleImport() { input.type = 'file'; input.accept = PRESET_FILE_ACCEPT; input.onchange = (event) => { - const fileInput = /** @type {HTMLInputElement} */ (event.target); - const file = fileInput?.files?.[0]; + const file = event.target.files[0]; if (!file) return; @@ -290,10 +322,7 @@ function handleImport() { const reader = new FileReader(); reader.onload = async (loadEvent) => { try { - const rawText = `${loadEvent.target?.result || ''}`; - const maxRows = typeof maxBadgeSlotRows === 'number' ? maxBadgeSlotRows : 8; - const maxCols = typeof maxBadgeSlotCols === 'number' ? maxBadgeSlotCols : 7; - const badgeSlots = parsePresetFile(rawText, maxRows, maxCols); + const badgeSlots = parsePresetFile(loadEvent.target.result, PRESET_FILE_MAX_ROWS, PRESET_FILE_MAX_COLS); if (!badgeSlots) { alert(getPresetIoMessage('invalidFile', 'Invalid preset file.')); @@ -333,5 +362,3 @@ function initBadgePresetIO() { importButton.onclick = handleImport; exportButton.dataset.initialized = 'true'; } - -window.initBadgePresetIO = initBadgePresetIO; From 0ce9b65e2c3b3c168422fe2398486dc794ba4f5a Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 02:50:27 +0900 Subject: [PATCH 12/15] Add func to check for non-null badges outside grid bounds --- badgepresetio.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/badgepresetio.js b/badgepresetio.js index 54da1fecb..653b123d2 100644 --- a/badgepresetio.js +++ b/badgepresetio.js @@ -68,6 +68,22 @@ function parsePresetFile(rawText, maxRows, maxCols) { return badgeSlots; } +function hasNonNullBadgeOutsideGrid(badgeSlots, rows, cols) { + for (let r = 0; r < badgeSlots.length; r++) { + const row = badgeSlots[r]; + if (!Array.isArray(row)) + continue; + for (let c = 0; c < row.length; c++) { + if (r >= rows || c >= cols) { + const badgeId = row[c]; + if (badgeId != null && badgeId !== 'null') + return true; + } + } + } + return false; +} + function expandBadgeSlotsToGrid(badgeSlots, rows, cols) { const expanded = []; for (let r = 0; r < rows; r++) { @@ -271,6 +287,9 @@ async function applyPresetToSlot(badgeSlots) { const playerRows = backupSlots.length; const playerCols = backupSlots[0]?.length || 0; + if (hasNonNullBadgeOutsideGrid(badgeSlots, playerRows, playerCols)) + return false; + const normalizedSlots = expandBadgeSlotsToGrid(badgeSlots, playerRows, playerCols); const changes = computeChanges(normalizedSlots, backupSlots, playerRows, playerCols); const clearResults = await clearChangedSlotsFromChanges(changes); From bd0f158e63ef3cf73d9f97e618946e57d7b91d7b Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 03:13:46 +0900 Subject: [PATCH 13/15] Update ja.json --- lang/ja.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lang/ja.json b/lang/ja.json index 10baa8377..512131d0c 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "バッジプリセット", "selectPreset": "プリセット選択", - "presetName": "プリセット{{index}}" + "presetName": "プリセット{{index}}", + "export": "書き出し", + "import": "読み込み", + "io": { + "exportSuccess": "バッジプリセットの書き出しに成功しました。", + "importSuccess": "バッジプリセットの読み込みに成功しました。", + "empty": "このプリセットは空です。", + "invalidFile": "無効なプリセットファイルです。", + "exportFailed": "書き出しに失敗しました。", + "importFailed": "読み込みに失敗しました。" + } }, "save": { "title": "セーブデータ管理", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file From 6b93557b4b231a86580f5f38c3036da233a74074 Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 03:14:39 +0900 Subject: [PATCH 14/15] Update multiple language files --- lang/ar.json | 14 ++++++++++++-- lang/de.json | 12 +++++++++++- lang/eo.json | 14 ++++++++++++-- lang/es.json | 14 ++++++++++++-- lang/fr.json | 14 ++++++++++++-- lang/id.json | 14 ++++++++++++-- lang/it.json | 14 ++++++++++++-- lang/ja.json | 4 ++-- lang/ko.json | 17 ++++++++++++++--- lang/pl.json | 14 ++++++++++++-- lang/pt.json | 14 ++++++++++++-- lang/ro.json | 14 ++++++++++++-- lang/ru.json | 14 ++++++++++++-- lang/tr.json | 14 ++++++++++++-- lang/uk.json | 18 ++++++++++++++---- lang/vi.json | 14 ++++++++++++-- lang/zh.json | 14 ++++++++++++-- 17 files changed, 197 insertions(+), 36 deletions(-) diff --git a/lang/ar.json b/lang/ar.json index e4f65bae7..e3d1c6210 100644 --- a/lang/ar.json +++ b/lang/ar.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Manage Badge Presets", "selectPreset": "Select Preset", - "presetName": "Preset {{index}}" + "presetName": "Preset {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "إدارة حفظ البيانات", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/de.json b/lang/de.json index 19b8e8484..df4697105 100644 --- a/lang/de.json +++ b/lang/de.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Abzeichen Presets verwalten", "selectPreset": "Presets auswählen", - "presetName": "Preset {{index}}" + "presetName": "Preset {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Save verwalten", diff --git a/lang/eo.json b/lang/eo.json index 1ab475857..0078be300 100644 --- a/lang/eo.json +++ b/lang/eo.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Manage Badge Presets", "selectPreset": "Select Preset", - "presetName": "Preset {{index}}" + "presetName": "Preset {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Administri Konservdatumojn", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/es.json b/lang/es.json index 4153a56ae..7b034bb1d 100644 --- a/lang/es.json +++ b/lang/es.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Administrar Preajustes de Insignias", "selectPreset": "Seleccionar Preajuste", - "presetName": "Preajuste {{index}}" + "presetName": "Preajuste {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Gestionar Datos de Guardado", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/fr.json b/lang/fr.json index cf2b26331..6622355f7 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Gérer les préréglages de badges", "selectPreset": "Choisir un préréglage", - "presetName": "Préréglage {{index}}" + "presetName": "Préréglage {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Gérer les Données de Sauvegarde", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/id.json b/lang/id.json index de53f8d66..ffe3cded9 100644 --- a/lang/id.json +++ b/lang/id.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Manage Badge Presets", "selectPreset": "Select Preset", - "presetName": "Preset {{index}}" + "presetName": "Preset {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Manage Save Data", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/it.json b/lang/it.json index 352efb383..ed3e20301 100644 --- a/lang/it.json +++ b/lang/it.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Manage Badge Presets", "selectPreset": "Select Preset", - "presetName": "Preset {{index}}" + "presetName": "Preset {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Gestisci Dati di Salvataggio", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/ja.json b/lang/ja.json index 512131d0c..4d6167f85 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -428,8 +428,8 @@ "importSuccess": "バッジプリセットの読み込みに成功しました。", "empty": "このプリセットは空です。", "invalidFile": "無効なプリセットファイルです。", - "exportFailed": "書き出しに失敗しました。", - "importFailed": "読み込みに失敗しました。" + "exportFailed": "バッジプリセットの書き出しに失敗しました。", + "importFailed": "バッジプリセットの読み込みに失敗しました。" } }, "save": { diff --git a/lang/ko.json b/lang/ko.json index 096f753dd..f9a6c38c9 100644 --- a/lang/ko.json +++ b/lang/ko.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "배지 프리셋 설정", "selectPreset": "프리셋 선택", - "presetName": "프리셋 {{index}}" + "presetName": "프리셋 {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "세이브 데이터 관리", @@ -581,7 +591,8 @@ "subtitle": "일부 게임에는 다음과 같은 내용이 포함되어 있을 수 있습니다. 게임 플레이 시 주의하시길 바랍니다.", "warning1": "광과민성 환자에게 영향을 끼칠 수 있는 번쩍거리는 빛의 연속적이거나 규칙적인 깜빡임", "warning2": "자해 혹은 자살에 관련된 언급", - "warning3": "불편하거나 충격적인 이미지" + "warning3": "불편하거나 충격적인 이미지", + "warning4": "Depictions of drug use." }, "explorerUndiscoveredLocations": { "title": "미발견 장소", @@ -1237,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/pl.json b/lang/pl.json index 20c29b9a3..3ab3eb4a8 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Manage Badge Presets", "selectPreset": "Select Preset", - "presetName": "Preset {{index}}" + "presetName": "Preset {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Zarządzaj zapisami", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/pt.json b/lang/pt.json index cd52b5499..71de1c8ad 100644 --- a/lang/pt.json +++ b/lang/pt.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Gerenciar Predefinições de Emblema", "selectPreset": "Selecionar Predefinição", - "presetName": "Predefinição {{index}}" + "presetName": "Predefinição {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Gerenciar Dados Salvos", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/ro.json b/lang/ro.json index 8a84b027b..678e400f8 100644 --- a/lang/ro.json +++ b/lang/ro.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Gestionare Presetări pt. Insigne", "selectPreset": "Selectează Presetarea", - "presetName": "Presetare {{index}}" + "presetName": "Presetare {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Gestionează Datele Salvate", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/ru.json b/lang/ru.json index e194b681c..be28ded98 100644 --- a/lang/ru.json +++ b/lang/ru.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Manage Badge Presets", "selectPreset": "Select Preset", - "presetName": "Preset {{index}}" + "presetName": "Preset {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Управление данными сохранений", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/tr.json b/lang/tr.json index ee1fc37f0..254e6bd33 100644 --- a/lang/tr.json +++ b/lang/tr.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Rozet Öntasarımlarını Ayarla", "selectPreset": "Öntasarım Seç", - "presetName": "Öntasarı {{index}}" + "presetName": "Öntasarı {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Kayıt Verisini Yönet", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/uk.json b/lang/uk.json index e26f2bc34..a323f49d3 100644 --- a/lang/uk.json +++ b/lang/uk.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Керування колекціями", "selectPreset": "Обрати колекцію", - "presetName": "Колекція {{index}}" + "presetName": "Колекція {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Керування даними збереження", @@ -893,12 +903,12 @@ "markdownSupport": "Чат підтримує форматування за допомогою спеціальних символів. Доступні: **жирний** (\\*\\*текст\\*\\*), *курсив* (\\*текст\\*, \\_текст\\_), __підкреслений__ (\\_\\_текст\\_\\_), ~~закреслений~~ (\\~\\~текст\\~\\~) і ||спойлер|| (\\|\\|текст\\|\\|).", "tabToChat": "На ПК, клавішою TAB можна перемикатися між грою та чатом. Цю функцію можна вимкнути у налаштуваннях.", "chatTabNotifications": "Вкладинка чату підсвічується при нових повідомленнях, якщо ви знаходитесь у будь якій з них окрім «Усі».", - "clearChat": "У правому верхньому кутку чату є кнопка Очистити. Нею можна видалити повідомлення з обраної вкладинки чату. Якщо натистуни її в «Усі» - вона очистить кожну вкладинку.", + "clearChat": "У правому верхньому кутку чату є кнопка Очистити. Нею можна видалити повідомлення з обраної вкладинки чату. Якщо натистуни її в «Усі» - вона очистить кожну вкладинку.", "chatHistoryLimit": "На слабких пристроях гра може лагати від довгої історії чату. Кількість повідомлень можна обмежити у налаштуваннях.", "parties": "Групи дуже зручні для подорожей разом. Ви можете бачити місцезнаходження учасників групи та спілкуватися з ними у окремому чаті.", "immersionMode": "Якщо вам подобається більш особистий ігровий процес, а не соціальний, спробуйте режим занурення. Цей режим вимикає глобальний чат, список гравців та їхню кількість, що робить випадкові зустрічі цікавішими.", "friendsMenu": "Права кнопка миші (або довгий дотик на мобільному пристрої) на гравці у списку, відчинить віконце де можна надіслати запит у друзі, згадати гравця або заблокувати його.", - "easySettingsMenu": "На ПК можна натистуни клавішу F1, вона відчиняє меню важливих налаштувань (зміна керування, якість зображення гри, тощо).", + "easySettingsMenu": "На ПК можна натистуни клавішу F1, вона відчиняє меню важливих налаштувань (зміна керування, якість зображення гри, тощо).", "floatingControls": "Якщо ви граєте на сенсорному пристрої і вам не подобається керування, спробуйте плаваючі типи елементів керування. Їх можна знайти у налаштуваннях мобільного керування.", "recentBadges": "Випадково закрили сповіщення про отриманий значок? Його можна подивитись у меню значків обравши «Знайдені нещодавно».", "desktopHotkeys": "На ПК, клавіші Alt+Enter перемикають повноекранний режим, F7 робить знімок екрану, англійська T відкриває чат.", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/vi.json b/lang/vi.json index 67e3bc846..f300ecb12 100644 --- a/lang/vi.json +++ b/lang/vi.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "Khuôn mẫu huy hiệu", "selectPreset": "Chọn khuôn mẫu", - "presetName": "Mẫu {{index}}" + "presetName": "Mẫu {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "Quản lý Dữ liệu lưu", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file diff --git a/lang/zh.json b/lang/zh.json index 66e36105a..33d09bf98 100644 --- a/lang/zh.json +++ b/lang/zh.json @@ -420,7 +420,17 @@ "badgePreset": { "title": "管理徽章预设", "selectPreset": "选择预设", - "presetName": "预设 {{index}}" + "presetName": "预设 {{index}}", + "export": "Export", + "import": "Import", + "io": { + "exportSuccess": "Badge preset exported successfully.", + "importSuccess": "Badge preset imported successfully.", + "empty": "This preset is empty.", + "invalidFile": "Invalid preset file.", + "exportFailed": "Export failed.", + "importFailed": "Import failed." + } }, "save": { "title": "存档", @@ -1238,4 +1248,4 @@ } } } -} +} \ No newline at end of file From 05fe63d15e0d24abdd3abd1fc8cda3fd0e7427fa Mon Sep 17 00:00:00 2001 From: zebraed <30438415+zebraed@users.noreply.github.com> Date: Mon, 8 Jun 2026 03:40:15 +0900 Subject: [PATCH 15/15] Remove redundant init func call --- badges.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/badges.js b/badges.js index 2d88ad69b..63325c0c6 100644 --- a/badges.js +++ b/badges.js @@ -997,9 +997,6 @@ function initBadgeGalleryModal() { } function initBadgePresetModal() { - if (typeof initBadgePresetIO === 'function') - initBadgePresetIO(); - addLoader(document.getElementById('badgePresetModal')); apiFetch(`badge?command=presetGet&preset=${document.getElementById('badgePresetSelection').value}`)