Files
service-finder/docs/gamification_i18n_audit_and_fix_proposal.md
2026-06-30 08:56:55 +00:00

20 KiB

Gamification Nyelvi Modul Audit és Javítási Javaslat

Összefoglaló

Dátum: 2026-06-29 Auditor: Rendszer-Architect Vizsgált fájlok: 16 db (3 backend + 12 frontend admin + 1 konfig) Gitea Issue: #339


1. Vizsgált Fájlok Listája

Backend (3 fájl)

# Fájl Sorok Érintettség
1 backend/app/models/gamification/gamification.py 174 Nincs hardcoded string (ORM modellek)
2 backend/app/services/gamification_service.py 231 1 db hardcoded emoji string (L197)
3 backend/app/api/v1/endpoints/gamification.py 907 ~25+ hardcoded string (hibaüzenetek, kvíz, achievementek)

Frontend Admin (12 Vue fájl)

# Fájl Sorok Hardcoded szövegek
1 frontend_admin/pages/gamification/badges.vue 363 Minden UI szöveg magyar
2 frontend_admin/pages/gamification/competitions.vue 494 Minden UI szöveg magyar
3 frontend_admin/pages/gamification/config.vue 543 Minden UI szöveg magyar
4 frontend_admin/pages/gamification/index.vue 220 Minden UI szöveg magyar
5 frontend_admin/pages/gamification/leaderboard.vue 398 Minden UI szöveg magyar
6 frontend_admin/pages/gamification/ledger.vue 390 Minden UI szöveg magyar
7 frontend_admin/pages/gamification/levels.vue 369 Minden UI szöveg magyar
8 frontend_admin/pages/gamification/parameters.vue 283 Minden UI szöveg magyar
9 frontend_admin/pages/gamification/point-rules.vue 362 Minden UI szöveg magyar
10 frontend_admin/pages/gamification/seasons.vue 406 Minden UI szöveg magyar
11 frontend_admin/pages/gamification/users/index.vue 250 Minden UI szöveg magyar
12 frontend_admin/pages/gamification/users/[id].vue 390 Minden UI szöveg magyar

Lokációs fájlok (4 db)

# Fájl Meglévő kulcsok Gamification kulcsok
1 frontend_admin/locales/en.json packages, permissions, garages, persons, users, dashboard NINCS
2 frontend_admin/locales/hu.json packages, permissions, garages, persons, users, dashboard NINCS
3 backend/static/locales/en.json AUTH, SENTINEL, COMMON, EMAIL, ORGANIZATION, REGISTRATION_DOCUMENTS NINCS
4 backend/static/locales/hu.json AUTH, SENTINEL, COMMON, EMAIL, ORGANIZATION, REGISTRATION_DOCUMENTS NINCS

2. Részletes Hardcoded Stringek

2.1 Backend API (backend/app/api/v1/endpoints/gamification.py)

2.1.1 Magyar nyelvű hibaüzenetek

Sor Kód Szöveg
289 detail= "Önvédelmi korlátozás miatt nem küldhetsz be új szerviz adatokat."
380 detail= f"Hiba a pontozás során: {str(e)}"
387 message: "Szerviz beküldve a rendszerbe elemzésre!"
394 detail= f"Hiba a beküldés során: {str(e)}"

2.1.2 Angol nyelvű hibaüzenetek

Sor Kód Szöveg
191 detail= "Season not found"
488-492 detail= "You have already played the daily quiz today..."
810-811 detail= "Badge not found"

2.1.3 Keménykódolt kvíz tartalom (magyar)

Sor Tartalom
496-517 3 db kvíz kérdés teljes egészében magyar nyelven: kérdések, válaszlehetőségek, magyarázatok
553-557 Kvíz válasz adatok magyar nyelven

2.1.4 Achievement címek (angol)

Sor Cím
857-861 "Novice", "Apprentice", "Expert", "Master" (XP achievementek)
884-888 "Quiz Beginner", "Quiz Enthusiast", "Quiz Master" (kvíz achievementek)

2.2 Backend Service (backend/app/services/gamification_service.py)

Sor Kód
197 f"🔴 PENALTY: {reason}" - emoji + angol szöveg a penalty bejegyzéshez

2.3 Frontend Admin Vue Oldalak

Minden a 12 gamification Vue oldal 100%-ban hardcoded magyar nyelvű szövegeket használ. Sehol sem található useI18n() vagy $t() hívás.

Kulcskategóriák oldalanként:

Oldal Hardcoded szövegek kategóriái
badges.vue "Kitüntetések", "Még nincsenek kitüntetések", "Új kitüntetés", "Név", "Leírás", "Ikon URL", "Mégse", "Mentés", "Létrehozás", "Biztosan törölni szeretnéd?"
competitions.vue "Versenyek", "Szezonális versenyek kezelése", "Új Verseny", "Draft", "Aktív", "Befejezett", "Törölt", "Érvénytelen JSON formátum!"
config.vue "Rendszer Konfig", "XP Logic", "Conversion Logic", "Penalty Logic", "Level Rewards", "Hatás Kalkulátor", "Nyers JSON Szerkesztő"
index.vue "Gamification HQ", "Összes Felhasználó", "Aktív Szezon", "Függő Hozzájárulások", "Ma Szerzett XP", "Gyors Műveletek"
leaderboard.vue "Ranglista", "Keresés", "Név vagy email...", "Szint", "Összes szint", "Minimum XP", "Rendezés", "Enyhe", "Közepes", "Súlyos"
ledger.vue "Pontnapló", "User ID", "Dátumtól", "Dátumig", "Keresés", "Törlés", "CSV", "Előző", "Következő"
levels.vue "Szintek", "Új szint", "Rang", "Min. Pont", "Típus", "Büntető", "Normál", "Szint Fa Diagram"
parameters.vue "Rendszerparaméterek", "Kulcs", "Érték", "Kategória", "Hatósugár", "Scope ID"
point-rules.vue "Pontszabályok", "Új pontszabály", "Akció Kulcs", "Pont", "Leírás", "Státusz", "Aktív", "Inaktív"
seasons.vue "Szezonok", "Új Szezon", "Név", "Kezdő dátum", "Záró dátum", "Szezon Aktiválása"
users/index.vue "Gamification Felhasználók", "Összes szint", "Csak büntetettek", "Csak büntetlenek", "Részletek"
users/[id].vue "Vissza a listához", "Összes XP", "Büntetőpontok", "Restrikciós Szint", "Büntetés Kiszabása", "Jutalom Kiosztása"

3. Javítási Javaslat (Fix Proposal)

3.1 Frontend Admin - i18n Migráció

3.1.1 Lokációs kulcs struktúra javaslat

A frontend_admin/locales/en.json és frontend_admin/locales/hu.json fájlokba be kell vezetni egy új gamification kulcs hierarchical struktúrát.

Teljes kulcs struktúra:

{
  "gamification": {
    "dashboard": {
      "title": "Gamification HQ",
      "subtitle": "Gamification system overview dashboard",
      "total_users": "Total Users",
      "active_season": "Active Season",
      "pending_contributions": "Pending Contributions",
      "xp_today": "XP Earned Today",
      "quick_actions": "Quick Actions",
      "manage_point_rules": "Manage Point Rules",
      "manage_badges": "Manage Badges",
      "manage_seasons": "Manage Seasons",
      "recent_ledger": "Recent Ledger Entries",
      "top_5_leaderboard": "Top 5 Leaderboard"
    },
    "badges": {
      "title": "Badges",
      "subtitle": "Badge management — CRUD",
      "loading": "Loading badges...",
      "error": "Failed to load badges",
      "create_new": "Create New Badge",
      "edit": "Edit Badge",
      "delete": "Delete Badge",
      "name": "Name",
      "description": "Description",
      "icon_url": "Icon URL",
      "cancel": "Cancel",
      "save": "Save",
      "create": "Create",
      "delete_confirm": "Are you sure you want to delete this badge?",
      "save_success": "Badge saved successfully!",
      "create_success": "Badge created successfully!",
      "no_badges": "No badges yet. Create one with the button above!"
    },
    "competitions": {
      "title": "Competitions",
      "subtitle": "Seasonal competition management",
      "create_new": "Create Competition",
      "filter_season": "Filter by season:",
      "all_seasons": "All seasons",
      "active": "(Active)",
      "loading": "Loading competitions...",
      "error": "Failed to load competitions",
      "no_competitions": "No competitions created yet.",
      "create_first": "Create First Competition",
      "name": "Name",
      "description": "Description",
      "season": "Season",
      "start_date": "Start Date",
      "end_date": "End Date",
      "status": "Status",
      "status_draft": "Draft",
      "status_active": "Active",
      "status_completed": "Completed",
      "status_cancelled": "Cancelled",
      "view_rules": "View Rules",
      "edit": "Edit",
      "invalid_json": "Invalid JSON format!"
    },
    "config": {
      "title": "System Config",
      "subtitle": "Gamification master configuration editor",
      "loading": "Loading configuration...",
      "error": "Failed to load configuration",
      "last_saved": "Last saved:",
      "save": "Save Configuration",
      "xp_logic": "XP Logic",
      "conversion_logic": "Conversion Logic",
      "penalty_logic": "Penalty Logic",
      "level_rewards": "Level Rewards",
      "impact_calculator": "Impact Calculator",
      "raw_json_editor": "Raw JSON Editor",
      "user_level": "User Level:",
      "daily_activities": "Daily Activities:",
      "social_points": "Social Points:",
      "estimated_results": "Estimated Results",
      "daily_xp": "Daily XP",
      "xp_to_next_level": "XP Until Next Level"
    },
    "leaderboard": {
      "title": "Leaderboard",
      "subtitle": "Gamification leaderboard admin view",
      "search": "Search",
      "search_placeholder": "Name or email...",
      "level": "Level",
      "all_levels": "All levels",
      "min_xp": "Minimum XP",
      "sort": "Sort",
      "sort_xp": "By XP",
      "sort_points": "By Points",
      "sort_social": "By Social Points",
      "sort_level": "By Level",
      "filter": "Filter",
      "reset": "Reset",
      "ascending": "Ascending",
      "descending": "Descending",
      "rank": "#",
      "user": "User",
      "email": "Email",
      "xp": "XP",
      "level": "Level",
      "points": "Points",
      "social": "Social",
      "penalty": "Penalty",
      "restriction": "Restriction",
      "discoveries": "Discoveries",
      "services": "Services",
      "last_modified": "Last Modified",
      "actions": "Actions",
      "restriction_mild": "Mild",
      "restriction_moderate": "Moderate",
      "restriction_severe": "Severe",
      "prev": "Previous",
      "next": "Next",
      "per_page": "/ page"
    },
    "ledger": {
      "title": "Points Ledger",
      "subtitle": "Gamification points ledger with filtering and detailed logging",
      "loading": "Loading ledger...",
      "error": "Failed to load ledger",
      "user_id": "User ID",
      "date_from": "Date From",
      "date_to": "Date To",
      "reason": "Reason (text)",
      "search": "Search",
      "clear": "Clear",
      "csv": "CSV Export",
      "no_results": "No results with the current filters.",
      "id": "ID",
      "user": "User",
      "points": "Points",
      "penalty": "Penalty",
      "xp": "XP",
      "reason_col": "Reason",
      "source": "Source",
      "date": "Date",
      "prev": "Previous",
      "next": "Next",
      "of": "of",
      "showing": "Showing",
      "filtered": "(filtered)"
    },
    "levels": {
      "title": "Levels",
      "subtitle": "Level configurations management — CRUD",
      "create_new": "Create New Level",
      "level": "Level",
      "rank": "Rank",
      "min_points": "Min Points",
      "type": "Type",
      "actions": "Actions",
      "type_penalty": "Penalty",
      "type_normal": "Normal",
      "level_tree": "Level Tree Diagram",
      "no_levels": "No level configurations yet.",
      "level_number": "Level Number",
      "rank_name": "Rank Name",
      "minimum_points": "Minimum Points",
      "is_penalty": "Penalty Level",
      "positive_hint": "Positive: normal level, Negative: penalty level"
    },
    "parameters": {
      "title": "System Parameters",
      "subtitle": "Gamification category system parameters",
      "loading": "Loading parameters...",
      "key": "Key",
      "value": "Value",
      "category": "Category",
      "scope": "Scope",
      "scope_id": "Scope ID",
      "actions": "Actions",
      "edit": "Edit Parameter",
      "cancel": "Cancel",
      "save": "Save"
    },
    "point_rules": {
      "title": "Point Rules",
      "subtitle": "Gamification point rules management — CRUD",
      "create_new": "Create New Point Rule",
      "action_key": "Action Key",
      "points": "Points",
      "description": "Description",
      "status": "Status",
      "active": "Active",
      "inactive": "Inactive",
      "edit": "Edit Point Rule",
      "point_value": "Point Value",
      "cancel": "Cancel",
      "save": "Save",
      "delete": "Delete",
      "duplicate_key": "A rule with this action key already exists.",
      "save_success": "Point rule saved successfully!",
      "create_success": "Point rule created successfully!"
    },
    "seasons": {
      "title": "Seasons",
      "subtitle": "Gamification season management",
      "create_new": "Create Season",
      "loading": "Loading seasons...",
      "error": "Failed to load seasons",
      "no_seasons": "No seasons created yet.",
      "create_first": "Create First Season",
      "active": "Active",
      "inactive": "Inactive",
      "edit": "Edit Season",
      "new_season": "New Season",
      "name": "Name",
      "start_date": "Start Date",
      "end_date": "End Date",
      "activate_on_create": "Activate on creation",
      "activate": "Activate Season",
      "activate_confirm": "Are you sure you want to activate this season?",
      "save_success": "Season saved successfully!",
      "create_success": "Season created successfully!"
    },
    "users": {
      "title": "Gamification Users",
      "subtitle": "User gamification statistics management",
      "level": "Level",
      "all_levels": "All levels",
      "min_xp": "Minimum XP",
      "max_xp": "Maximum XP",
      "penalty": "Penalty",
      "all_penalty": "All",
      "only_penalized": "Penalized only",
      "only_non_penalized": "Non-penalized only",
      "filter": "Filter",
      "reset": "Reset",
      "user_id": "User ID",
      "xp": "XP",
      "level": "Level",
      "points": "Points",
      "penalty": "Penalty",
      "restriction": "Restriction",
      "services": "Services",
      "discoveries": "Discoveries",
      "last_modified": "Last Modified",
      "actions": "Actions",
      "restriction_mild": "Mild",
      "restriction_moderate": "Moderate",
      "restriction_severe": "Severe",
      "restriction_none": "None",
      "details": "Details",
      "prev": "Previous",
      "next": "Next",
      "user_detail_title": "User Gamification Details",
      "back_to_list": "Back to list",
      "total_xp": "Total XP",
      "total_points": "Total Points",
      "social_points": "Social Points",
      "penalty_points": "Penalty Points",
      "restriction_level": "Restriction Level",
      "penalty_quota": "Penalty Quota",
      "banned": "Banned",
      "services": "Services",
      "discovered_places": "Discovered Places",
      "validated_places": "Validated Places",
      "added_providers": "Added Providers",
      "assign_penalty": "Assign Penalty",
      "assign_reward": "Assign Reward",
      "penalty_points_label": "Penalty Points",
      "reason": "Reason",
      "xp_reward": "XP Reward",
      "social_reward": "Social Points Reward",
      "apply_penalty": "Apply Penalty",
      "apply_reward": "Apply Reward",
      "ledger": "Points Ledger",
      "entries": "entries",
      "date": "Date",
      "points": "Points",
      "penalty": "Penalty",
      "xp": "XP",
      "reason": "Reason",
      "source": "Source"
    }
  }
}

3.1.2 Vue komponensek átalakítása

Minden Vue fájlban a következő módosításokat kell elvégezni:

1. useI18n() import hozzáadása:

const { t } = useI18n()

2. Template szövegek cseréje:

<!-- Eredeti: -->
<h1 class="text-2xl font-bold text-white">Kitüntetések</h1>

<!-- Javított: -->
<h1 class="text-2xl font-bold text-white">{{ t('gamification.badges.title') }}</h1>

3. Script szekcióban használt szövegek:

// Eredeti:
message.value = 'Kitüntetés sikeresen frissítve!'

// Javított:
message.value = t('gamification.badges.save_success')

3.2 Backend - i18n Migráció

3.2.1 Lokációs kulcs struktúra backendhez

A backend/static/locales/en.json és backend/static/locales/hu.json fájlokba be kell vezetni:

{
  "GAMIFICATION": {
    "SUBMIT_SERVICE": {
      "SELF_DEFENSE_BLOCKED": "You cannot submit new service data due to self-defense restriction.",
      "SUCCESS": "Service submitted to the system for analysis!",
      "POINTS_ERROR": "Error during scoring: {error}",
      "SUBMIT_ERROR": "Error during submission: {error}"
    },
    "QUIZ": {
      "ALREADY_PLAYED": "You have already played the daily quiz today. Come back tomorrow!",
      "NO_QUIZ_AVAILABLE": "No quiz available for today."
    },
    "BADGE": {
      "NOT_FOUND": "Badge not found.",
      "ALREADY_AWARDED": "Badge already awarded to this user."
    },
    "SEASON": {
      "NOT_FOUND": "Season not found."
    },
    "ACHIEVEMENTS": {
      "XP_NOVICE": "Novice",
      "XP_APPRENTICE": "Apprentice",
      "XP_EXPERT": "Expert",
      "XP_MASTER": "Master",
      "QUIZ_BEGINNER": "Quiz Beginner",
      "QUIZ_ENTHUSIAST": "Quiz Enthusiast",
      "QUIZ_MASTER": "Quiz Master"
    }
  }
}

3.2.2 Backend API módosítások

A backend végpontokban a hardcoded stringek helyett egy i18n/lokalizációs segédfüggvényt kell használni, amely a kérés nyelvi preferenciája (Accept-Language header vagy a felhasználó beállított nyelve) alapján választja ki a megfelelő szöveget.

Példa implementáció (app/core/i18n.py):

import json
from pathlib import Path

_LOCALES_DIR = Path(__file__).parent.parent.parent / "static" / "locales"
_cache = {}

def get_locale(lang: str = "hu") -> dict:
    if lang not in _cache:
        path = _LOCALES_DIR / f"{lang}.json"
        if path.exists():
            with open(path, "r", encoding="utf-8") as f:
                _cache[lang] = json.load(f)
        else:
            _cache[lang] = {}
    return _cache[lang]

def t(key: str, lang: str = "hu", **kwargs) -> str:
    """Translate a dot-notation key using the locale file."""
    locale = get_locale(lang)
    parts = key.split(".")
    value = locale
    for part in parts:
        if isinstance(value, dict):
            value = value.get(part, key)
        else:
            return key
    if isinstance(value, str) and kwargs:
        return value.format(**kwargs)
    return value if isinstance(value, str) else key

3.2.3 Kvíz tartalom lokalizációja

A kvíz kérdéseket ki kell venni a kódból, és adatbázisba vagy JSON fájlba kell helyezni nyelvi kulcsokkal.

3.3 Backend Service módosítás

A backend/app/services/gamification_service.py L197-es sorában:

# Eredeti:
f"🔴 PENALTY: {reason}"

# Javasolt:
# A reason paraméter tartalmazza a lokalizált szöveget, amit a hívó fél (API endpoint) már lefordított
reason

3.4 Migrációs Terv (Ütemezés)

Fázis Feladat Érintett fájlok Logikai készültség
1. fázis Gamification i18n kulcsok felvétele a frontend_admin/locales/*.json fájlokba 2 db Előkészület
2. fázis 12 Vue oldal átalakítása: useI18n() bevezetése, t() hívások 12 db Tervezés alatt
3. fázis Backend i18n helper megírása (app/core/i18n.py) 1 db Tervezés alatt
4. fázis Gamification kulcsok felvétele a backend/static/locales/*.json fájlokba 2 db Előkészület
5. fázis Backend API endpointok átalakítása, hardcoded stringek eltávolítása 1 db Tervezés alatt
6. fázis Kvíz tartalom kiszervezése JSON/DB-be, nyelvi kulcsokkal 1 db Tervezés alatt
7. fázis Tesztelés: magyar és angol nyelvű felület ellenőrzése - Függőben

4. Konklúzió

A gamification modulban súlyos nyelvi modul hiányosság áll fenn:

  1. A frontend admin felület 12 Vue oldalán 0% az i18n használat - minden UI szöveg hardcoded magyar nyelven van.
  2. A lokációs fájlok egyetlen gamification kulcsot sem tartalmaznak - a teljes gamification szótár hiányzik.
  3. A backend API vegyesen használ magyar és angol hardcoded szövegeket.
  4. A kvíz rendszer teljes egészében hardcoded magyar nyelvű.
  5. A meglévő i18n infrastruktúra (@nuxtjs/i18n) jól konfigurált - csak a gamification modul nem használja.

A javítási javaslat 7 fázisban, körülbelül 15-20 fájl módosításával oldható meg.