feat: implement languages endpoint and refactor language handling to use languages.json

This commit is contained in:
Jokob @NetAlertX
2026-02-28 01:51:12 +00:00
parent e57fd2e81e
commit 814ba02d1c
12 changed files with 377 additions and 115 deletions

View File

@@ -42,6 +42,7 @@ from .dbquery_endpoint import read_query, write_query, update_query, delete_quer
from .sync_endpoint import handle_sync_post, handle_sync_get # noqa: E402 [flake8 lint suppression]
from .logs_endpoint import clean_log # noqa: E402 [flake8 lint suppression]
from .health_endpoint import get_health_status # noqa: E402 [flake8 lint suppression]
from .languages_endpoint import get_languages # noqa: E402 [flake8 lint suppression]
from models.user_events_queue_instance import UserEventsQueueInstance # noqa: E402 [flake8 lint suppression]
from models.event_instance import EventInstance # noqa: E402 [flake8 lint suppression]
@@ -95,6 +96,7 @@ from .openapi.schemas import ( # noqa: E402 [flake8 lint suppression]
DbQueryUpdateRequest, DbQueryDeleteRequest,
AddToQueueRequest, GetSettingResponse,
RecentEventsRequest, SetDeviceAliasRequest,
LanguagesResponse,
)
from .sse_endpoint import ( # noqa: E402 [flake8 lint suppression]
@@ -1962,6 +1964,34 @@ def check_health(payload=None):
}), 500
@app.route("/languages", methods=["GET"])
@validate_request(
operation_id="get_languages",
summary="Get Supported Languages",
description="Returns the canonical list of supported UI languages loaded from languages.json.",
response_model=LanguagesResponse,
tags=["system", "languages"],
auth_callable=is_authorized
)
def list_languages(payload=None):
"""Return the canonical language registry."""
try:
data = get_languages()
return jsonify({"success": True, **data}), 200
except FileNotFoundError:
return jsonify({
"success": False,
"error": "languages.json not found",
"message": "Language registry file is missing"
}), 500
except ValueError as e:
return jsonify({
"success": False,
"error": str(e),
"message": "Language registry file is malformed"
}), 500
# --------------------------
# Background Server Start
# --------------------------

View File

@@ -545,7 +545,7 @@ class Query(ObjectType):
language_folder = '/app/front/php/templates/language/'
if os.path.exists(language_folder):
for filename in os.listdir(language_folder):
if filename.endswith('.json'):
if filename.endswith('.json') and filename != 'languages.json':
file_lang_code = filename.replace('.json', '')
# Filter by langCode if provided

View File

@@ -0,0 +1,43 @@
"""Languages endpoint — returns the canonical language registry from languages.json."""
import json
import os
from logger import mylog
INSTALL_PATH = os.getenv("NETALERTX_APP", "/app")
LANGUAGES_JSON_PATH = os.path.join(
INSTALL_PATH, "front", "php", "templates", "language", "languages.json"
)
def get_languages():
"""
Load and return the canonical language registry.
Returns a dict with keys:
- default (str): the fallback language code
- languages (list[dict]): each entry has 'code' and 'display'
Raises:
FileNotFoundError: if languages.json is missing
ValueError: if the JSON is malformed or missing required fields
"""
try:
with open(LANGUAGES_JSON_PATH, "r", encoding="utf-8") as f:
data = json.load(f)
except FileNotFoundError:
mylog("none", [f"[languages] languages.json not found at {LANGUAGES_JSON_PATH}"])
raise
except json.JSONDecodeError as e:
mylog("none", [f"[languages] Failed to parse languages.json: {e}"])
raise ValueError(f"Malformed languages.json: {e}") from e
if "default" not in data or "languages" not in data:
raise ValueError("languages.json must contain 'default' and 'languages' keys")
return {
"default": data["default"],
"languages": data["languages"],
"count": len(data["languages"]),
}

View File

@@ -1031,6 +1031,41 @@ class GetSettingResponse(BaseResponse):
value: Any = Field(None, description="The setting value")
# =============================================================================
# LANGUAGES SCHEMAS
# =============================================================================
class LanguageEntry(BaseModel):
"""A single supported language entry."""
model_config = ConfigDict(extra="allow")
code: str = Field(..., description="ISO language code (e.g. 'en_us')")
display: str = Field(..., description="Human-readable display name (e.g. 'English (en_us)')")
class LanguagesResponse(BaseResponse):
"""Response for GET /languages — the canonical language registry."""
model_config = ConfigDict(
extra="allow",
json_schema_extra={
"examples": [{
"success": True,
"default": "en_us",
"count": 20,
"languages": [
{"code": "en_us", "display": "English (en_us)"},
{"code": "de_de", "display": "German (de_de)"}
]
}]
}
)
default: str = Field(..., description="Default/fallback language code")
count: int = Field(..., description="Total number of supported languages")
languages: List[LanguageEntry] = Field(..., description="All supported languages")
# =============================================================================
# GRAPHQL SCHEMAS
# =============================================================================