Translate UI and user-facing messages to Ukrainian (#5)

- All frontend pages, labels, notices and errors; html lang=uk, uk-UA money format
- Brand "Assistant System" in the top bar and page title
- Backend error details returned to the UI (auth, orders, receipts,
  cash registers, Checkbox/CRM/NP errors) and CLI output
- Tests updated for the new messages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 15:27:39 +03:00
co-authored by Claude Opus 5.5
parent 47df3a78dc
commit b8f2fe6b6e
38 changed files with 232 additions and 230 deletions
+1 -1
View File
@@ -70,7 +70,7 @@ async def change_password(
) -> Response:
if not verify_password(payload.current_password, user.password_hash):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail="Текущий пароль указан неверно"
status_code=status.HTTP_400_BAD_REQUEST, detail="Поточний пароль вказано неправильно"
)
user.password_hash = hash_password(payload.new_password)
+3 -3
View File
@@ -44,7 +44,7 @@ async def _ensure_np_key_unique(
if same:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"Этот ключ Новой Почты уже привязан к кассе «{register.name}»",
detail=f"Цей ключ Нової Пошти вже прив'язаний до каси «{register.name}»",
)
@@ -101,7 +101,7 @@ async def update_cash_register(
) -> CashRegisterOut:
register = await session.get(CashRegister, register_id)
if register is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Касса не найдена")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Касу не знайдено")
changes = payload.model_dump(exclude_unset=True)
if "license_key" in changes:
@@ -139,7 +139,7 @@ async def check_cash_register(
"""Пробный вход кассира в Checkbox — проверка ключа лицензии и PIN."""
register = await session.get(CashRegister, register_id)
if register is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Касса не найдена")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Касу не знайдено")
try:
await checkbox.sign_in(credentials(register))
except (CheckboxError, crypto.DecryptionError) as exc:
+2 -2
View File
@@ -50,7 +50,7 @@ async def update_order(
except orders_service.OrderEditError as exc:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc
if result is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Заказ не найден")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Замовлення не знайдено")
order, changed = result
if changed:
@@ -75,7 +75,7 @@ async def delete_order(
) -> None:
order = await orders_service.delete_order(session, order_id)
if order is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Заказ не найден")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Замовлення не знайдено")
await audit.record(
session,
+2 -2
View File
@@ -60,7 +60,7 @@ async def list_receipts(session: SessionDep, order_id: str | None = None) -> lis
async def get_receipt(receipt_id: uuid.UUID, session: SessionDep) -> ReceiptOut:
receipt = await session.get(Receipt, receipt_id)
if receipt is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Чек не найден")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Чек не знайдено")
return ReceiptOut.from_receipt(receipt)
@@ -83,5 +83,5 @@ async def cancel_receipt(
status_code=status.HTTP_502_BAD_GATEWAY, detail=f"Checkbox: {exc}"
) from exc
if receipt is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Чек не найден")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Чек не знайдено")
return ReceiptOut.from_receipt(receipt)
+4 -4
View File
@@ -71,7 +71,7 @@ async def create_user(
await session.rollback()
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Пользователь с таким email уже существует",
detail="Користувач із таким email уже існує",
) from exc
return UserOut.model_validate(user)
@@ -87,7 +87,7 @@ async def update_user(
) -> UserOut:
user = await session.get(User, user_id)
if user is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Пользователь не найден")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Користувача не знайдено")
changes = payload.model_dump(exclude_unset=True)
@@ -97,12 +97,12 @@ async def update_user(
if changes.get("is_active") is False:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Нельзя отключить собственную учётную запись",
detail="Не можна вимкнути власний обліковий запис",
)
if "role" in changes and changes["role"] != UserRole.ADMIN:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Нельзя снять с себя роль администратора",
detail="Не можна зняти із себе роль адміністратора",
)
if (new_password := changes.pop("password", None)) is not None: