From b0dac1ec58ee446ab2ba6aee4c229ca7b4c93898 Mon Sep 17 00:00:00 2001
From: koichixD <207069770+koichixD@users.noreply.github.com>
Date: Mon, 9 Feb 2026 23:05:50 +0100
Subject: [PATCH] Outsourcing languages and adding duplicate detection
---
src/App.jsx | 481 +++++----------------------------------
src/i18n/translations.js | 435 +++++++++++++++++++++++++++++++++++
2 files changed, 494 insertions(+), 422 deletions(-)
create mode 100644 src/i18n/translations.js
diff --git a/src/App.jsx b/src/App.jsx
index 743799e..9283dc4 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useRef, useState } from "react";
+import React, { useEffect, useMemo, useRef, useState } from "react";
import { convertFileSrc } from "@tauri-apps/api/core";
import { basename, join } from "@tauri-apps/api/path";
import { open } from "@tauri-apps/plugin-dialog";
@@ -7,6 +7,7 @@ import { copyFile, exists, readTextFile, writeTextFile } from "@tauri-apps/plugi
import { parseLuaItems, buildLuaFromItems } from "./parser/luaParser.js";
import pkg from "../package.json";
import appConfig from "./config/appConfig.js";
+import { languageOptions, translations } from "./i18n/translations.js";
const categoryIcons = {
All: "/icons/all.png",
@@ -38,421 +39,6 @@ const ammoOptions = [
const ALL_CATEGORY = "__ALL__";
const UNCATEGORIZED = "Nicht zugeordnet";
-const languageOptions = [
- { value: "de", label: "Deutsch", flagSrc: "/flags/de.svg", flagAlt: "DE" },
- { value: "en", label: "English", flagSrc: "/flags/us.svg", flagAlt: "US" },
- { value: "es", label: "Espanol", flagSrc: "/flags/es.svg", flagAlt: "ES" },
- { value: "fr", label: "Francais", flagSrc: "/flags/fr.svg", flagAlt: "FR" },
- { value: "pt-BR", label: "Portugues (BR)", flagSrc: "/flags/pt-br.svg", flagAlt: "BR" },
- { value: "it", label: "Italiano", flagSrc: "/flags/it.svg", flagAlt: "IT" },
- { value: "pl", label: "Polski", flagSrc: "/flags/pl.svg", flagAlt: "PL" },
- { value: "tr", label: "Turkce", flagSrc: "/flags/tr.svg", flagAlt: "TR" },
- { value: "ru", label: "Russkiy", flagSrc: "/flags/ru.svg", flagAlt: "RU" },
-];
-const translations = {
- de: {
- allItems: "Alle Items",
- uncategorized: "Nicht zugeordnet",
- categories: "Kategorien",
- category: "Kategorie",
- newCategoryPlaceholder: "Neue Kategorie anlegen...",
- searchPlaceholder: "Item suchen...",
- inventoryOpen: "Inventory \u00f6ffnen",
- inventoryLabel: "Inventory",
- loadedFile: "Geladen",
- chooseItemHint: "W\u00e4hle links eine Kategorie und dann ein Item aus.",
- applyChanges: "\u00c4nderungen \u00fcbernehmen",
- selectInventoryTitle: "QS Inventory Ordner ausw\u00e4hlen",
- itemsFileMissing: "items.lua nicht gefunden. Bitte den qs-inventory Ordner w\u00e4hlen.",
- imagesMissing: "Bilderordner nicht gefunden: qs-inventory\\html\\images",
- noItemsDetected:
- "Keine Items erkannt. Stelle sicher, dass die Datei mit `ItemList = {` oder `QBShared.Items = {` beginnt.",
- loadedItems: ({ count }) => `Geladen: ${count} Items`,
- loadError: ({ message }) => `Fehler beim Laden: ${message}`,
- saved: "Gespeichert",
- saveError: ({ message }) => `Fehler beim Speichern: ${message}`,
- backupError: ({ message }) => `Backup konnte nicht erstellt werden: ${message}`,
- language: "Sprache",
- newItem: "Neues Item",
- template: "Template",
- create: "Erstellen",
- cancel: "Abbrechen",
- itemId: "Item ID",
- itemLabel: "Label",
- idRequired: "Bitte eine Item-ID angeben.",
- idExists: ({ id }) => `Item-ID existiert bereits: ${id}`,
- templateNormal: "Normale Items",
- templateNormalRare: "Normale Items mit Rarit\u00e4t",
- templateWeapon: "Waffen",
- templateFood: "Nahrungsmittel",
- templateDrink: "Getränk",
- selectTemplateTitle: "Template auswählen",
- createItemTitle: "Neues Item bearbeiten",
- close: "Schließen",
- itemCreated: "Item gespeichert",
- imageAdd: "Bild hinzufügen",
- imageAddError: ({ message }) => `Bild konnte nicht hinzugefügt werden: ${message}`,
- imageAdded: "Bild hinzugefügt",
- },
- en: {
- allItems: "All Items",
- uncategorized: "Unassigned",
- categories: "Categories",
- category: "Category",
- newCategoryPlaceholder: "Create new category...",
- searchPlaceholder: "Search items...",
- inventoryOpen: "Open inventory",
- inventoryLabel: "Inventory",
- loadedFile: "Loaded",
- chooseItemHint: "Choose a category on the left and then select an item.",
- applyChanges: "Apply changes",
- selectInventoryTitle: "Select QS inventory folder",
- itemsFileMissing: "items.lua not found. Please select the qs-inventory folder.",
- imagesMissing: "Images folder not found: qs-inventory\\html\\images",
- noItemsDetected:
- "No items detected. Ensure the file starts with `ItemList = {` or `QBShared.Items = {`.",
- loadedItems: ({ count }) => `Loaded: ${count} items`,
- loadError: ({ message }) => `Load error: ${message}`,
- saved: "Saved",
- saveError: ({ message }) => `Save error: ${message}`,
- backupError: ({ message }) => `Backup failed: ${message}`,
- language: "Language",
- newItem: "New Item",
- template: "Template",
- create: "Create",
- cancel: "Cancel",
- itemId: "Item ID",
- itemLabel: "Label",
- idRequired: "Please provide an item ID.",
- idExists: ({ id }) => `Item ID already exists: ${id}`,
- templateNormal: "Normal Items",
- templateNormalRare: "Normal Items with Rarity",
- templateWeapon: "Weapons",
- templateFood: "Food",
- templateDrink: "Drink",
- selectTemplateTitle: "Select template",
- createItemTitle: "Edit new item",
- close: "Close",
- itemCreated: "Item saved",
- imageAdd: "Add image",
- imageAddError: ({ message }) => `Failed to add image: ${message}`,
- imageAdded: "Image added",
- },
- es: {
- allItems: "Todos los items",
- uncategorized: "Sin asignar",
- categories: "Categorías",
- category: "Categoría",
- newCategoryPlaceholder: "Crear nueva categoría...",
- searchPlaceholder: "Buscar item...",
- inventoryOpen: "Abrir inventario",
- inventoryLabel: "Inventario",
- loadedFile: "Cargado",
- chooseItemHint: "Elige una categoría a la izquierda y luego selecciona un item.",
- applyChanges: "Aplicar cambios",
- selectInventoryTitle: "Seleccionar carpeta de QS inventory",
- itemsFileMissing: "No se encontró items.lua. Selecciona la carpeta qs-inventory.",
- imagesMissing: "No se encontró la carpeta de imágenes: qs-inventory\\html\\images",
- noItemsDetected:
- "No se detectaron items. Asegúrate de que el archivo empiece con `ItemList = {` o `QBShared.Items = {`.",
- loadedItems: ({ count }) => `Cargado: ${count} items`,
- loadError: ({ message }) => `Error al cargar: ${message}`,
- saved: "Guardado",
- saveError: ({ message }) => `Error al guardar: ${message}`,
- backupError: ({ message }) => `No se pudo crear la copia de seguridad: ${message}`,
- language: "Idioma",
- newItem: "Nuevo item",
- template: "Plantilla",
- create: "Crear",
- cancel: "Cancelar",
- itemId: "ID del item",
- itemLabel: "Etiqueta",
- idRequired: "Introduce un ID de item.",
- idExists: ({ id }) => `El ID del item ya existe: ${id}`,
- templateNormal: "Items normales",
- templateNormalRare: "Items normales con rareza",
- templateWeapon: "Armas",
- templateFood: "Comida",
- templateDrink: "Bebida",
- selectTemplateTitle: "Seleccionar plantilla",
- createItemTitle: "Editar nuevo item",
- close: "Cerrar",
- itemCreated: "Item guardado",
- imageAdd: "Añadir imagen",
- imageAddError: ({ message }) => `No se pudo añadir la imagen: ${message}`,
- imageAdded: "Imagen añadida",
- },
- fr: {
- allItems: "Tous les items",
- uncategorized: "Non attribué",
- categories: "Catégories",
- category: "Catégorie",
- newCategoryPlaceholder: "Créer une nouvelle catégorie...",
- searchPlaceholder: "Rechercher un item...",
- inventoryOpen: "Ouvrir l'inventaire",
- inventoryLabel: "Inventaire",
- loadedFile: "Chargé",
- chooseItemHint: "Choisis une catégorie à gauche puis sélectionne un item.",
- applyChanges: "Appliquer les modifications",
- selectInventoryTitle: "Sélectionner le dossier QS inventory",
- itemsFileMissing: "items.lua introuvable. Sélectionne le dossier qs-inventory.",
- imagesMissing: "Dossier d'images introuvable : qs-inventory\\html\\images",
- noItemsDetected:
- "Aucun item détecté. Vérifie que le fichier commence par `ItemList = {` ou `QBShared.Items = {`.",
- loadedItems: ({ count }) => `Chargé : ${count} items`,
- loadError: ({ message }) => `Erreur de chargement : ${message}`,
- saved: "Enregistré",
- saveError: ({ message }) => `Erreur d'enregistrement : ${message}`,
- backupError: ({ message }) => `Échec de la sauvegarde : ${message}`,
- language: "Langue",
- newItem: "Nouvel item",
- template: "Modèle",
- create: "Créer",
- cancel: "Annuler",
- itemId: "ID de l'item",
- itemLabel: "Libellé",
- idRequired: "Veuillez saisir un ID d'item.",
- idExists: ({ id }) => `L'ID de l'item existe déjà : ${id}`,
- templateNormal: "Items normaux",
- templateNormalRare: "Items normaux avec rareté",
- templateWeapon: "Armes",
- templateFood: "Nourriture",
- templateDrink: "Boisson",
- selectTemplateTitle: "Sélectionner un modèle",
- createItemTitle: "Modifier le nouvel item",
- close: "Fermer",
- itemCreated: "Item enregistré",
- imageAdd: "Ajouter une image",
- imageAddError: ({ message }) => `Impossible d'ajouter l'image : ${message}`,
- imageAdded: "Image ajoutée",
- },
- "pt-BR": {
- allItems: "Todos os itens",
- uncategorized: "Nao atribuido",
- categories: "Categorias",
- category: "Categoria",
- newCategoryPlaceholder: "Criar nova categoria...",
- searchPlaceholder: "Buscar item...",
- inventoryOpen: "Abrir inventario",
- inventoryLabel: "Inventario",
- loadedFile: "Carregado",
- chooseItemHint: "Escolha uma categoria a esquerda e depois selecione um item.",
- applyChanges: "Aplicar alteracoes",
- selectInventoryTitle: "Selecionar pasta do QS inventory",
- itemsFileMissing: "items.lua nao encontrado. Selecione a pasta qs-inventory.",
- imagesMissing: "Pasta de imagens nao encontrada: qs-inventory\\html\\images",
- noItemsDetected:
- "Nenhum item detectado. Verifique se o arquivo comeca com `ItemList = {` ou `QBShared.Items = {`.",
- loadedItems: ({ count }) => `Carregado: ${count} itens`,
- loadError: ({ message }) => `Erro ao carregar: ${message}`,
- saved: "Salvo",
- saveError: ({ message }) => `Erro ao salvar: ${message}`,
- backupError: ({ message }) => `Falha ao criar backup: ${message}`,
- language: "Idioma",
- newItem: "Novo item",
- template: "Modelo",
- create: "Criar",
- cancel: "Cancelar",
- itemId: "ID do item",
- itemLabel: "Rotulo",
- idRequired: "Informe um ID de item.",
- idExists: ({ id }) => `ID de item ja existe: ${id}`,
- templateNormal: "Itens normais",
- templateNormalRare: "Itens normais com raridade",
- templateWeapon: "Armas",
- templateFood: "Comida",
- templateDrink: "Bebida",
- selectTemplateTitle: "Selecionar modelo",
- createItemTitle: "Editar novo item",
- close: "Fechar",
- itemCreated: "Item salvo",
- imageAdd: "Adicionar imagem",
- imageAddError: ({ message }) => `Falha ao adicionar imagem: ${message}`,
- imageAdded: "Imagem adicionada",
- },
- it: {
- allItems: "Tutti gli item",
- uncategorized: "Non assegnato",
- categories: "Categorie",
- category: "Categoria",
- newCategoryPlaceholder: "Crea una nuova categoria...",
- searchPlaceholder: "Cerca item...",
- inventoryOpen: "Apri inventario",
- inventoryLabel: "Inventario",
- loadedFile: "Caricato",
- chooseItemHint: "Scegli una categoria a sinistra e poi seleziona un item.",
- applyChanges: "Applica modifiche",
- selectInventoryTitle: "Seleziona cartella QS inventory",
- itemsFileMissing: "items.lua non trovato. Seleziona la cartella qs-inventory.",
- imagesMissing: "Cartella immagini non trovata: qs-inventory\\html\\images",
- noItemsDetected:
- "Nessun item rilevato. Assicurati che il file inizi con `ItemList = {` o `QBShared.Items = {`.",
- loadedItems: ({ count }) => `Caricati: ${count} item`,
- loadError: ({ message }) => `Errore di caricamento: ${message}`,
- saved: "Salvato",
- saveError: ({ message }) => `Errore di salvataggio: ${message}`,
- backupError: ({ message }) => `Backup non riuscito: ${message}`,
- language: "Lingua",
- newItem: "Nuovo item",
- template: "Modello",
- create: "Crea",
- cancel: "Annulla",
- itemId: "ID item",
- itemLabel: "Etichetta",
- idRequired: "Inserisci un ID item.",
- idExists: ({ id }) => `ID item gia esistente: ${id}`,
- templateNormal: "Item normali",
- templateNormalRare: "Item normali con rarita",
- templateWeapon: "Armi",
- templateFood: "Cibo",
- templateDrink: "Bevanda",
- selectTemplateTitle: "Seleziona modello",
- createItemTitle: "Modifica nuovo item",
- close: "Chiudi",
- itemCreated: "Item salvato",
- imageAdd: "Aggiungi immagine",
- imageAddError: ({ message }) => `Impossibile aggiungere l'immagine: ${message}`,
- imageAdded: "Immagine aggiunta",
- },
- pl: {
- allItems: "Wszystkie przedmioty",
- uncategorized: "Nieprzypisane",
- categories: "Kategorie",
- category: "Kategoria",
- newCategoryPlaceholder: "Utworz nowa kategorie...",
- searchPlaceholder: "Szukaj przedmiotu...",
- inventoryOpen: "Otworz ekwipunek",
- inventoryLabel: "Ekwipunek",
- loadedFile: "Wczytano",
- chooseItemHint: "Wybierz kategorie po lewej stronie, a nastepnie przedmiot.",
- applyChanges: "Zastosuj zmiany",
- selectInventoryTitle: "Wybierz folder QS inventory",
- itemsFileMissing: "Nie znaleziono items.lua. Wybierz folder qs-inventory.",
- imagesMissing: "Nie znaleziono folderu obrazow: qs-inventory\\html\\images",
- noItemsDetected:
- "Nie wykryto przedmiotow. Upewnij sie, ze plik zaczyna sie od `ItemList = {` lub `QBShared.Items = {`.",
- loadedItems: ({ count }) => `Wczytano: ${count} przedmiotow`,
- loadError: ({ message }) => `Blad wczytywania: ${message}`,
- saved: "Zapisano",
- saveError: ({ message }) => `Blad zapisu: ${message}`,
- backupError: ({ message }) => `Nie udalo sie utworzyc kopii zapasowej: ${message}`,
- language: "Jezyk",
- newItem: "Nowy przedmiot",
- template: "Szablon",
- create: "Utworz",
- cancel: "Anuluj",
- itemId: "ID przedmiotu",
- itemLabel: "Etykieta",
- idRequired: "Podaj ID przedmiotu.",
- idExists: ({ id }) => `ID przedmiotu juz istnieje: ${id}`,
- templateNormal: "Zwykle przedmioty",
- templateNormalRare: "Zwykle przedmioty z rzadkoscia",
- templateWeapon: "Bron",
- templateFood: "Jedzenie",
- templateDrink: "Napoj",
- selectTemplateTitle: "Wybierz szablon",
- createItemTitle: "Edytuj nowy przedmiot",
- close: "Zamknij",
- itemCreated: "Przedmiot zapisany",
- imageAdd: "Dodaj obraz",
- imageAddError: ({ message }) => `Nie udalo sie dodac obrazu: ${message}`,
- imageAdded: "Obraz dodany",
- },
- tr: {
- allItems: "Tum ogeler",
- uncategorized: "Atanmamis",
- categories: "Kategoriler",
- category: "Kategori",
- newCategoryPlaceholder: "Yeni kategori olustur...",
- searchPlaceholder: "Oge ara...",
- inventoryOpen: "Envanteri ac",
- inventoryLabel: "Envanter",
- loadedFile: "Yuklendi",
- chooseItemHint: "Soldan bir kategori secin ve sonra bir oge secin.",
- applyChanges: "Degisiklikleri uygula",
- selectInventoryTitle: "QS inventory klasorunu sec",
- itemsFileMissing: "items.lua bulunamadi. Lutfen qs-inventory klasorunu secin.",
- imagesMissing: "Gorsel klasoru bulunamadi: qs-inventory\\html\\images",
- noItemsDetected:
- "Oge bulunamadi. Dosyanin `ItemList = {` veya `QBShared.Items = {` ile basladigindan emin olun.",
- loadedItems: ({ count }) => `Yuklendi: ${count} oge`,
- loadError: ({ message }) => `Yukleme hatasi: ${message}`,
- saved: "Kaydedildi",
- saveError: ({ message }) => `Kaydetme hatasi: ${message}`,
- backupError: ({ message }) => `Yedek olusturulamadi: ${message}`,
- language: "Dil",
- newItem: "Yeni oge",
- template: "Sablon",
- create: "Olustur",
- cancel: "Iptal",
- itemId: "Oge ID",
- itemLabel: "Etiket",
- idRequired: "Lutfen bir oge ID girin.",
- idExists: ({ id }) => `Oge ID zaten mevcut: ${id}`,
- templateNormal: "Normal ogeler",
- templateNormalRare: "Nadirlikli normal ogeler",
- templateWeapon: "Silahlar",
- templateFood: "Yiyecek",
- templateDrink: "Icecek",
- selectTemplateTitle: "Sablon sec",
- createItemTitle: "Yeni ogeyi duzenle",
- close: "Kapat",
- itemCreated: "Oge kaydedildi",
- imageAdd: "Gorsel ekle",
- imageAddError: ({ message }) => `Gorsel eklenemedi: ${message}`,
- imageAdded: "Gorsel eklendi",
- },
- ru: {
- allItems: "\u0412\u0441\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b",
- uncategorized: "\u0411\u0435\u0437 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438",
- categories: "\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438",
- category: "\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f",
- newCategoryPlaceholder: "\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e...",
- searchPlaceholder: "\u041f\u043e\u0438\u0441\u043a \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430...",
- inventoryOpen: "\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0438\u043d\u0432\u0435\u043d\u0442\u0430\u0440\u044c",
- inventoryLabel: "\u0418\u043d\u0432\u0435\u043d\u0442\u0430\u0440\u044c",
- loadedFile: "\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043e",
- chooseItemHint:
- "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e \u0441\u043b\u0435\u0432\u0430, \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442.",
- applyChanges: "\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f",
- selectInventoryTitle: "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 QS inventory",
- itemsFileMissing:
- "\u0424\u0430\u0439\u043b items.lua \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d. \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 qs-inventory.",
- imagesMissing:
- "\u041f\u0430\u043f\u043a\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430: qs-inventory\\html\\images",
- noItemsDetected:
- "\u041f\u0440\u0435\u0434\u043c\u0435\u0442\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 `ItemList = {` \u0438\u043b\u0438 `QBShared.Items = {`.",
- loadedItems: ({ count }) => `\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043e: ${count} \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432`,
- loadError: ({ message }) => `\u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438: ${message}`,
- saved: "\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043e",
- saveError: ({ message }) => `\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f: ${message}`,
- backupError: ({ message }) =>
- `\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e: ${message}`,
- language: "\u042f\u0437\u044b\u043a",
- newItem: "\u041d\u043e\u0432\u044b\u0439 \u043f\u0440\u0435\u0434\u043c\u0435\u0442",
- template: "\u0428\u0430\u0431\u043b\u043e\u043d",
- create: "\u0421\u043e\u0437\u0434\u0430\u0442\u044c",
- cancel: "\u041e\u0442\u043c\u0435\u043d\u0430",
- itemId: "ID \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430",
- itemLabel: "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435",
- idRequired: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 ID \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430.",
- idExists: ({ id }) => `ID \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442: ${id}`,
- templateNormal: "\u041e\u0431\u044b\u0447\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b",
- templateNormalRare: "\u041e\u0431\u044b\u0447\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b \u0441 \u0440\u0435\u0434\u043a\u043e\u0441\u0442\u044c\u044e",
- templateWeapon: "\u041e\u0440\u0443\u0436\u0438\u0435",
- templateFood: "\u0415\u0434\u0430",
- templateDrink: "\u041d\u0430\u043f\u0438\u0442\u043e\u043a",
- selectTemplateTitle: "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0448\u0430\u0431\u043b\u043e\u043d",
- createItemTitle: "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430",
- close: "\u0417\u0430\u043a\u0440\u044b\u0442\u044c",
- itemCreated: "\u041f\u0440\u0435\u0434\u043c\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d",
- imageAdd: "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",
- imageAddError: ({ message }) =>
- `\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435: ${message}`,
- imageAdded: "\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e",
- },
-};
-
const itemTemplates = [
{
key: "normal",
@@ -663,6 +249,24 @@ export default function App() {
() => categories.filter((c) => c !== ALL_CATEGORY),
[categories]
);
+ const duplicateIdCounts = useMemo(() => {
+ const counts = {};
+ for (const item of items) {
+ const id = item?.id;
+ if (!id) continue;
+ counts[id] = (counts[id] || 0) + 1;
+ }
+ const duplicates = {};
+ for (const [id, count] of Object.entries(counts)) {
+ if (count > 1) duplicates[id] = count;
+ }
+ return duplicates;
+ }, [items]);
+ const duplicateIds = useMemo(
+ () => Object.keys(duplicateIdCounts).sort((a, b) => a.localeCompare(b)),
+ [duplicateIdCounts]
+ );
+ const duplicatePreview = useMemo(() => duplicateIds.slice(0, 6), [duplicateIds]);
const filteredItems = useMemo(() => {
let list = items;
@@ -686,6 +290,7 @@ export default function App() {
const selectedItem = useMemo(() => {
return items.find((i) => i.id === selectedItemId) || null;
}, [items, selectedItemId]);
+ const selectedItemDuplicateCount = selectedItem ? duplicateIdCounts[selectedItem.id] || 0 : 0;
const selectedLanguageOption = useMemo(
() => languageOptions.find((option) => option.value === language) || languageOptions[0],
[language]
@@ -1202,8 +807,16 @@ export default function App() {
)}
{status && {status}
}
+ {duplicateIds.length > 0 && (
+
+ {t("duplicatesFound", { count: duplicateIds.length })}: {duplicatePreview.join(", ")}
+ {duplicateIds.length > duplicatePreview.length
+ ? ` +${duplicateIds.length - duplicatePreview.length}`
+ : ""}
+
+ )}
- Made with ❤️ by{" "}
+ Made with love by{" "}
{
@@ -1214,7 +827,7 @@ export default function App() {
>
koichixD
{" "}
- for the Quasar Store community ✨
+ for the Quasar Store community {"\u2764"}
@@ -1261,7 +874,14 @@ export default function App() {
alt={selectedLanguageOption.flagAlt}
className="w-6 h-4 object-cover rounded-sm border border-slate-600"
/>
- ▾
+
{languageMenuOpen && (
@@ -1338,16 +958,19 @@ export default function App() {
- {filteredItems.map((it) => {
+ {filteredItems.map((it, idx) => {
const imageSrc = getImageSrc(it);
+ const duplicateCount = duplicateIdCounts[it.id] || 0;
return (
- setSelectedItemId(it.id)}
className={`cursor-pointer p-2 rounded border transition-colors ${
selectedItemId === it.id
? "bg-slate-700/80 ring-1 ring-slate-600 border-slate-600"
- : "border-slate-700 hover:bg-slate-800"
+ : duplicateCount > 1
+ ? "border-amber-500/70 bg-amber-500/10 hover:bg-amber-500/20"
+ : "border-slate-700 hover:bg-slate-800"
}`}
>
@@ -1360,6 +983,11 @@ export default function App() {
{it.label || it.id}
{it.id}
+ {duplicateCount > 1 && (
+
+ {duplicateCount}x
+
+ )}
);
@@ -1379,6 +1007,14 @@ export default function App() {
{selectedItem.label || selectedItem.id}
{selectedItem.id}
+ {selectedItemDuplicateCount > 1 && (
+
+ {t("duplicateSelectedHint", {
+ id: selectedItem.id,
+ count: selectedItemDuplicateCount,
+ })}
+
+ )}