gemification_admin bekötve
This commit is contained in:
548
docs/gamification_i18n_audit_and_fix_proposal.md
Normal file
548
docs/gamification_i18n_audit_and_fix_proposal.md
Normal file
@@ -0,0 +1,548 @@
|
||||
# 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:**
|
||||
|
||||
```json
|
||||
{
|
||||
"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:**
|
||||
```typescript
|
||||
const { t } = useI18n()
|
||||
```
|
||||
|
||||
**2. Template szövegek cseréje:**
|
||||
```vue
|
||||
<!-- 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:**
|
||||
```typescript
|
||||
// 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"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`):
|
||||
|
||||
```python
|
||||
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:
|
||||
|
||||
```python
|
||||
# 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.
|
||||
Reference in New Issue
Block a user