Compare commits

..

2 Commits

Author SHA1 Message Date
github-actions[bot]
174a3e0976 🎨 Auto format 2026-01-21 09:44:13 +00:00
Yurii Motov
2a0d5ee2af Integrate check_translation function to translate_page - retry up to 3 times if translation check failed 2026-01-21 10:21:36 +01:00
9 changed files with 71 additions and 45 deletions

View File

@@ -164,6 +164,8 @@ $ pip install "fastapi[standard]"
Create a file `main.py` with: Create a file `main.py` with:
```Python ```Python
from typing import Union
from fastapi import FastAPI from fastapi import FastAPI
app = FastAPI() app = FastAPI()
@@ -175,7 +177,7 @@ def read_root():
@app.get("/items/{item_id}") @app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None): def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q} return {"item_id": item_id, "q": q}
``` ```
@@ -184,7 +186,9 @@ def read_item(item_id: int, q: str | None = None):
If your code uses `async` / `await`, use `async def`: If your code uses `async` / `await`, use `async def`:
```Python hl_lines="7 12" ```Python hl_lines="9 14"
from typing import Union
from fastapi import FastAPI from fastapi import FastAPI
app = FastAPI() app = FastAPI()
@@ -196,7 +200,7 @@ async def read_root():
@app.get("/items/{item_id}") @app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None): async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q} return {"item_id": item_id, "q": q}
``` ```
@@ -287,7 +291,9 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic. Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="2 7-10 23-25" ```Python hl_lines="4 9-12 25-27"
from typing import Union
from fastapi import FastAPI from fastapi import FastAPI
from pydantic import BaseModel from pydantic import BaseModel
@@ -297,7 +303,7 @@ app = FastAPI()
class Item(BaseModel): class Item(BaseModel):
name: str name: str
price: float price: float
is_offer: bool | None = None is_offer: Union[bool, None] = None
@app.get("/") @app.get("/")
@@ -306,7 +312,7 @@ def read_root():
@app.get("/items/{item_id}") @app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None): def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q} return {"item_id": item_id, "q": q}

View File

@@ -189,7 +189,7 @@ Siehe Abschnitt `### Links` im allgemeinen Prompt in `scripts/translate.py`.
//// ////
## HTML-„abbr“-Elemente { #html-abbr-elements } ## HTML „abbr“-Elemente { #html-abbr-elements }
//// tab | Test //// tab | Test

View File

@@ -56,19 +56,19 @@ from app.routers import items
Die gleiche Dateistruktur mit Kommentaren: Die gleiche Dateistruktur mit Kommentaren:
```bash ```
. .
├── app # "app" ist ein Python-Package ├── app # app ist ein Python-Package
│   ├── __init__.py # diese Datei macht "app" zu einem "Python-Package" │   ├── __init__.py # diese Datei macht app zu einem Python-Package
│   ├── main.py # "main"-Modul, z. B. import app.main │   ├── main.py # main-Modul, z. B. import app.main
│   ├── dependencies.py # "dependencies"-Modul, z. B. import app.dependencies │   ├── dependencies.py # dependencies-Modul, z. B. import app.dependencies
│   └── routers # "routers" ist ein "Python-Subpackage" │   └── routers # routers ist ein Python-Subpackage
│   │ ├── __init__.py # macht "routers" zu einem "Python-Subpackage" │   │ ├── __init__.py # macht routers zu einem Python-Subpackage
│   │ ├── items.py # "items"-Submodul, z. B. import app.routers.items │   │ ├── items.py # items-Submodul, z. B. import app.routers.items
│   │ └── users.py # "users"-Submodul, z. B. import app.routers.users │   │ └── users.py # users-Submodul, z. B. import app.routers.users
│   └── internal # "internal" ist ein "Python-Subpackage" │   └── internal # internal ist ein Python-Subpackage
│   ├── __init__.py # macht "internal" zu einem "Python-Subpackage" │   ├── __init__.py # macht internal zu einem Python-Subpackage
│   └── admin.py # "admin"-Submodul, z. B. import app.internal.admin │   └── admin.py # admin-Submodul, z. B. import app.internal.admin
``` ```
## `APIRouter` { #apirouter } ## `APIRouter` { #apirouter }
@@ -479,7 +479,7 @@ $ fastapi dev app/main.py
</div> </div>
Und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>. und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Sie sehen die automatische API-Dokumentation, einschließlich der Pfade aller Submodule, mit den richtigen Pfaden (und Präfixen) und den richtigen Tags: Sie sehen die automatische API-Dokumentation, einschließlich der Pfade aller Submodule, mit den richtigen Pfaden (und Präfixen) und den richtigen Tags:

View File

@@ -145,6 +145,8 @@ There are other formats and tools to define and install package dependencies.
* Create a `main.py` file with: * Create a `main.py` file with:
```Python ```Python
from typing import Union
from fastapi import FastAPI from fastapi import FastAPI
app = FastAPI() app = FastAPI()
@@ -156,7 +158,7 @@ def read_root():
@app.get("/items/{item_id}") @app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None): def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q} return {"item_id": item_id, "q": q}
``` ```

View File

@@ -161,6 +161,8 @@ $ pip install "fastapi[standard]"
Create a file `main.py` with: Create a file `main.py` with:
```Python ```Python
from typing import Union
from fastapi import FastAPI from fastapi import FastAPI
app = FastAPI() app = FastAPI()
@@ -172,7 +174,7 @@ def read_root():
@app.get("/items/{item_id}") @app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None): def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q} return {"item_id": item_id, "q": q}
``` ```
@@ -181,7 +183,9 @@ def read_item(item_id: int, q: str | None = None):
If your code uses `async` / `await`, use `async def`: If your code uses `async` / `await`, use `async def`:
```Python hl_lines="7 12" ```Python hl_lines="9 14"
from typing import Union
from fastapi import FastAPI from fastapi import FastAPI
app = FastAPI() app = FastAPI()
@@ -193,7 +197,7 @@ async def read_root():
@app.get("/items/{item_id}") @app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None): async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q} return {"item_id": item_id, "q": q}
``` ```
@@ -284,7 +288,9 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic. Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="2 7-10 23-25" ```Python hl_lines="4 9-12 25-27"
from typing import Union
from fastapi import FastAPI from fastapi import FastAPI
from pydantic import BaseModel from pydantic import BaseModel
@@ -294,7 +300,7 @@ app = FastAPI()
class Item(BaseModel): class Item(BaseModel):
name: str name: str
price: float price: float
is_offer: bool | None = None is_offer: Union[bool, None] = None
@app.get("/") @app.get("/")
@@ -303,7 +309,7 @@ def read_root():
@app.get("/items/{item_id}") @app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None): def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q} return {"item_id": item_id, "q": q}

View File

@@ -18,8 +18,6 @@ hide:
### Translations ### Translations
* 🌐 Update translations for de (update-outdated). PR [#14690](https://github.com/fastapi/fastapi/pull/14690) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update LLM prompt for Russian translations. PR [#14733](https://github.com/fastapi/fastapi/pull/14733) by [@YuriiMotov](https://github.com/YuriiMotov).
* 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo). * 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translations for pt (update-outdated). PR [#14724](https://github.com/fastapi/fastapi/pull/14724) by [@tiangolo](https://github.com/tiangolo). * 🌐 Update translations for pt (update-outdated). PR [#14724](https://github.com/fastapi/fastapi/pull/14724) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update Korean LLM prompt. PR [#14740](https://github.com/fastapi/fastapi/pull/14740) by [@hard-coders](https://github.com/hard-coders). * 🌐 Update Korean LLM prompt. PR [#14740](https://github.com/fastapi/fastapi/pull/14740) by [@hard-coders](https://github.com/hard-coders).

View File

@@ -102,16 +102,15 @@ Of course, you can also declare additional query parameters whenever you need, a
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do: As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:
```Python
q: str | None = None
```
Or in Python 3.9:
```Python ```Python
q: Union[str, None] = None q: Union[str, None] = None
``` ```
Or in Python 3.10 and above:
```Python
q: str | None = None
```
For example: For example:

View File

@@ -90,12 +90,5 @@ For the following technical terms, use these specific translations to ensure con
* serve (meaning providing access to something): «отдавать» (or `предоставлять доступ к`) * serve (meaning providing access to something): «отдавать» (or `предоставлять доступ к`)
* recap (noun): резюме * recap (noun): резюме
* utility function: вспомогательная функция * utility function: вспомогательная функция
* fast to code: позволяет быстро писать код
* Tutorial - User Guide: Учебник - Руководство пользователя
* submodule: подмодуль
* subpackage: подпакет
* router: роутер
* building, deploying, accessing (when describing features of FastAPI Cloud): созданиe образа, развертывание и доступ
* type checker tool: инструмент проверки типов
Do not add whitespace in `т.д.`, `т.п.`. Do not add whitespace in `т.д.`, `т.п.`.

View File

@@ -10,6 +10,7 @@ from typing import Annotated
import git import git
import typer import typer
import yaml import yaml
from doc_parsing_utils import check_translation
from github import Github from github import Github
from pydantic_ai import Agent from pydantic_ai import Agent
from rich import print from rich import print
@@ -119,9 +120,30 @@ def translate_page(
] ]
) )
prompt = "\n\n".join(prompt_segments) prompt = "\n\n".join(prompt_segments)
print(f"Running agent for {out_path}")
result = agent.run_sync(prompt) MAX_ATTEMPTS = 3
out_content = f"{result.output.strip()}\n" for attempt_no in range(1, MAX_ATTEMPTS + 1):
print(f"Running agent for {out_path} (attempt {attempt_no}/{MAX_ATTEMPTS})")
result = agent.run_sync(prompt)
out_content = f"{result.output.strip()}\n"
try:
check_translation(
doc_lines=out_content.splitlines(),
en_doc_lines=original_content.splitlines(),
lang_code=language,
auto_fix=False,
path=str(out_path),
)
break # Exit loop if no errors
except ValueError as e:
print(
f"Translation check failed on attempt {attempt_no}/{MAX_ATTEMPTS}: {e}"
)
continue # Retry if not reached max attempts
else: # Max retry attempts reached
print(f"Translation failed for {out_path} after {MAX_ATTEMPTS} attempts")
raise typer.Exit(code=1)
print(f"Saving translation to {out_path}") print(f"Saving translation to {out_path}")
out_path.write_text(out_content, encoding="utf-8", newline="\n") out_path.write_text(out_content, encoding="utf-8", newline="\n")