Files
office_translator/schemas/glossary_schemas.py
sepehr b2d918c832
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 1m31s
feat: add multilingual glossary support (backend + frontend types)
Backend:
- Add source_language column to glossaries table
- Add translations JSON column to glossary_terms table
- Alembic migration for schema changes
- format_glossary_for_prompt now language-aware: extracts correct
  translation per target language, falls back to EN reference for
  templates with only FR→EN data
- CRUD routes accept/return source_language and translations
- Pydantic schemas updated

Frontend:
- Types updated: GlossaryTerm now has translations: Record<string, string>
- Glossary/GlossaryListItem now have source_language
- Added SUPPORTED_LANGUAGES constant (13 languages)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 15:25:28 +02:00

111 lines
2.9 KiB
Python

"""
Pydantic schemas for glossary endpoints.
Story 3.9: Glossaires - Endpoint CRUD
"""
from datetime import datetime
from uuid import UUID
from typing import Optional
from pydantic import BaseModel, Field, field_validator
class GlossaryTermCreate(BaseModel):
"""Schema for creating a single term."""
source: str = Field(..., min_length=1, max_length=500, description="Terme source")
target: str = Field(
..., min_length=1, max_length=500, description="Traduction cible"
)
translations: Optional[dict[str, str]] = Field(
None, description="Traductions multilingues: {\"en\": \"coil\", \"de\": \"Spule\", ...}"
)
@field_validator("source", "target")
@classmethod
def strip_whitespace(cls, v: str) -> str:
return v.strip()
class GlossaryTermResponse(BaseModel):
"""Schema for term in response."""
id: str
source: str
target: str
translations: dict[str, str] = {}
created_at: Optional[datetime] = None
model_config = {"from_attributes": True}
class GlossaryCreate(BaseModel):
"""Schema for creating a glossary."""
name: str = Field(..., min_length=1, max_length=255, description="Nom du glossaire")
source_language: str = Field(
default="fr", max_length=10, description="Langue source (ISO code)"
)
terms: list[GlossaryTermCreate] = Field(
default_factory=list, description="Liste des termes"
)
@field_validator("name")
@classmethod
def strip_name(cls, v: str) -> str:
return v.strip()
class GlossaryUpdate(BaseModel):
"""Schema for updating a glossary (all fields optional)."""
name: Optional[str] = Field(None, min_length=1, max_length=255)
source_language: Optional[str] = Field(None, max_length=10)
terms: Optional[list[GlossaryTermCreate]] = Field(None)
@field_validator("name")
@classmethod
def strip_name(cls, v: Optional[str]) -> Optional[str]:
return v.strip() if v else None
class GlossaryResponse(BaseModel):
"""Schema for glossary in response (with full terms)."""
id: str
name: str
source_language: str = "fr"
terms: list[GlossaryTermResponse] = []
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
model_config = {"from_attributes": True}
class GlossaryListItem(BaseModel):
"""Schema for glossary in list (without full terms)."""
id: str
name: str
source_language: str = "fr"
terms_count: int = Field(
default=0, description="Nombre de termes dans le glossaire"
)
created_at: Optional[datetime] = None
model_config = {"from_attributes": True}
class GlossaryListResponse(BaseModel):
"""Schema for glossaries list response."""
data: list[GlossaryListItem] = []
meta: dict = Field(default_factory=dict)
class GlossaryDetailResponse(BaseModel):
"""Schema for single glossary response."""
data: GlossaryResponse
meta: dict = Field(default_factory=dict)