Skip to content

Commit f47d691

Browse files
committed
feat: stabilize
1 parent 1ddcb10 commit f47d691

2 files changed

Lines changed: 93 additions & 94 deletions

File tree

deepl/deepl.py

Lines changed: 64 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import os
66
from collections.abc import Coroutine
77
from typing import Any
8-
from urllib.parse import quote
98

109
from install_playwright import install
1110
from playwright._impl._errors import Error as PlaywrightError
@@ -47,8 +46,6 @@ def __init__(
4746
fr_lang: str,
4847
to_lang: str,
4948
timeout: int = 15000,
50-
*,
51-
use_dom_submit: bool = False,
5249
) -> None:
5350
"""Initialize DeepLCLI.
5451
@@ -76,7 +73,6 @@ def __init__(
7673
self.translated_to_lang: str | None = None
7774
self.max_length = 1500
7875
self.timeout = timeout
79-
self.use_dom_submit = use_dom_submit
8076

8177
def translate(self, script: str) -> str:
8278
"""Translate script.
@@ -112,15 +108,14 @@ def translate_async(self, script: str) -> Coroutine[Any, Any, str]:
112108

113109
return self.__translate(script)
114110

115-
async def __translate(self, script: str) -> str: # noqa: PLR0915
111+
async def __translate(self, script: str) -> str:
116112
"""Throw a request."""
117113
async with async_playwright() as p:
118114
browser = await self.__get_browser(p)
119115

120116
page = await browser.new_page()
121117
page.set_default_timeout(self.timeout)
122-
123-
# skip loading page resources for improving performance
118+
await page.set_viewport_size({"width": 1920, "height": 1080})
124119
excluded_resources = ["image", "media", "font", "other"]
125120
await page.route(
126121
"**/*",
@@ -130,64 +125,57 @@ async def __translate(self, script: str) -> str: # noqa: PLR0915
130125
)
131126

132127
url = "https://www.deepl.com/en/translator"
133-
if self.use_dom_submit:
134-
await page.goto(url)
135-
else:
136-
script = quote(script, safe="")
137-
await page.goto(f"{url}#{self.fr_lang}/{self.to_lang}/{script}")
128+
await page.goto(url)
138129

139-
# Wait for loading to complete
140130
try:
141131
page.get_by_role("main")
142132
except PlaywrightError as e:
143133
msg = f"Maybe Time limit exceeded. ({self.timeout} ms)"
144134
raise DeepLCLIPageLoadError(msg) from e
145135

146-
if self.use_dom_submit:
147-
with contextlib.suppress(PlaywrightError):
148-
await page.click("button[data-testid=cookie-banner-strict-accept-all]")
149-
# we also expect the Chrome extension banner to show up
150-
with contextlib.suppress(PlaywrightError):
151-
await page.wait_for_function(
152-
"""
153-
() => document.querySelector('div[data-testid="chrome-extension-toast"]')
154-
""",
155-
)
156-
157-
# close the extension banner
158-
with contextlib.suppress(PlaywrightError):
159-
await page.evaluate(
160-
"""
161-
document.querySelector(
162-
'div[data-testid="chrome-extension-toast"]',
163-
).querySelector('button').click()
164-
""",
165-
)
166-
167-
await page.locator(
168-
"button[data-testid=translator-source-lang-btn]",
169-
).dispatch_event("click")
170-
await (
171-
page.get_by_test_id("translator-source-lang-list")
172-
.get_by_test_id(
173-
f"translator-lang-option-{self.fr_lang}",
174-
)
175-
.first.dispatch_event("click")
136+
with contextlib.suppress(PlaywrightError):
137+
await page.click("button[id=cookie-banner-lax-close-button]")
138+
await page.wait_for_function(
139+
"""
140+
() => document.querySelector('div[data-testid="chrome-extension-toast"]')
141+
""",
142+
)
143+
await page.evaluate(
144+
"""
145+
document.querySelector(
146+
'div[data-testid="chrome-extension-toast"]',
147+
).querySelector('button').click()
148+
""",
176149
)
177-
await page.locator(
178-
"button[data-testid=translator-target-lang-btn]",
179-
).dispatch_event("click")
180-
await (
181-
page.get_by_test_id("translator-target-lang-list")
182-
.get_by_test_id(
183-
f"translator-lang-option-{self.to_lang}",
184-
)
185-
.first.dispatch_event("click")
150+
151+
await page.locator(
152+
"button[data-testid=translator-source-lang-btn]",
153+
).dispatch_event("click")
154+
155+
await (
156+
page.get_by_test_id("translator-source-lang-list")
157+
.get_by_test_id(
158+
f"translator-lang-option-{self.fr_lang}",
186159
)
187-
await page.fill(
188-
"div[aria-labelledby=translation-source-heading]",
189-
script,
160+
.first.dispatch_event("click")
161+
)
162+
163+
await page.locator(
164+
"button[data-testid=translator-target-lang-btn]",
165+
).dispatch_event("click")
166+
167+
await (
168+
page.get_by_test_id("translator-target-lang-list")
169+
.get_by_test_id(
170+
f"translator-lang-option-{self.to_lang}",
190171
)
172+
.first.dispatch_event("click")
173+
)
174+
175+
await page.fill(
176+
"div[aria-labelledby=translation-source-heading]",
177+
script,
178+
)
191179

192180
try:
193181
await page.wait_for_function(
@@ -201,47 +189,34 @@ async def __translate(self, script: str) -> str: # noqa: PLR0915
201189
msg = f"Time limit exceeded. ({self.timeout} ms)"
202190
raise DeepLCLIPageLoadError(msg) from e
203191

192+
# Wait for translation to complete (check that [...] placeholder is gone)
204193
try:
205-
line_count = await page.evaluate(
194+
await page.wait_for_function(
206195
"""
207-
document.querySelector(
208-
'd-textarea[aria-labelledby=translation-target-heading]',
209-
).children[0].children.length
196+
() => {
197+
const elem = document.querySelector('d-textarea[aria-labelledby=translation-target-heading]');
198+
const text = elem?.value ?? '';
199+
return text.length > 0 && !text.includes('[...]');
200+
}
210201
""",
202+
timeout=self.timeout,
211203
)
212204
except PlaywrightError as e:
213-
msg = "Unable to evaluate line count of the translation"
205+
msg = f"Translation incomplete after {self.timeout} ms"
214206
raise DeepLCLIPageLoadError(msg) from e
215207

216-
translated_lines = []
217-
for line_index in range(line_count):
218-
try:
219-
await page.wait_for_function(
220-
f"""
221-
() => {{
222-
t = document.querySelector(
223-
'd-textarea[aria-labelledby=translation-target-heading]',
224-
)?.children[0]?.children[{line_index}]?.innerText ?? '';
225-
return t.length > 0 && !t.includes('[...]');
226-
}}
227-
""",
228-
)
229-
except PlaywrightError as e:
230-
msg = f"Time limit exceeded for line {line_index}. ({self.timeout} ms)"
231-
raise DeepLCLIPageLoadError(msg) from e
232-
233-
try:
234-
translated_text = await page.evaluate(
235-
f"""
236-
document.querySelector(
237-
'd-textarea[aria-labelledby=translation-target-heading]'
238-
).children[0].children[{line_index}].innerText
239-
""",
240-
)
241-
translated_lines.append(translated_text)
242-
except PlaywrightError as e:
243-
msg = f"Unable get translated text for line {line_index}"
244-
raise DeepLCLIPageLoadError(msg) from e
208+
# Get the translated text directly from the value attribute
209+
try:
210+
res = await page.evaluate(
211+
"""
212+
document.querySelector(
213+
'd-textarea[aria-labelledby=translation-target-heading]'
214+
).value
215+
""",
216+
)
217+
except PlaywrightError as e:
218+
msg = "Unable to get translated text"
219+
raise DeepLCLIPageLoadError(msg) from e
245220

246221
input_textbox = page.get_by_role("region", name="Source text").locator(
247222
"d-textarea",
@@ -258,8 +233,6 @@ async def __translate(self, script: str) -> str: # noqa: PLR0915
258233
await output_textbox.get_attribute("lang"),
259234
).split("-")[0]
260235

261-
res = "\n".join(translated_lines)
262-
263236
await browser.close()
264237

265238
return res

tests/test_deepl.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from textwrap import dedent
2+
13
import pytest
24

35
from deepl import DeepLCLI, DeepLCLIError
@@ -62,6 +64,30 @@ async def test_translate_async() -> None:
6264
assert res in ("こんにちは", "こんにちは。")
6365

6466

65-
def test_use_dom_submit() -> None:
66-
t = DeepLCLI("en", "ja", 100000, use_dom_submit=True)
67-
assert t.translate("hello.") in ("こんにちは", "こんにちは。")
67+
@pytest.mark.asyncio
68+
async def test_translate_async_long_text() -> None:
69+
t = DeepLCLI("ru", "ja", 100000)
70+
res = await t.translate_async(
71+
dedent(
72+
"""
73+
Мы, японский народ, действуя через посредство наших должным образом избранных представителей в Парламенте и исполнены решимости обеспечить для себя и для своих потомков плоды мирного сотрудничества со всеми нациями и благословение свободы для всей нашей страны, не допустить ужасов новой войны в результате действий правительств, провозглашаем, что народ облечён суверенитетом, и устанавливаем настоящую Конституцию.
74+
Государственное правление основывается на непоколебимом доверии народа, его авторитет исходит от народа, его полномочия осуществляются представителями народа, а благами его пользуется народ.
75+
Этот принцип, общий для всего человечества, и на нём основана настоящая Конституция.
76+
Мы отменяем все конституции, законы и подзаконные акты, а также рескрипты, противоречащие настоящей Конституции.
77+
""",
78+
)
79+
.strip()
80+
.replace("\n", " "),
81+
)
82+
assert (
83+
res
84+
== dedent(
85+
"""
86+
我ら日本国民は、国会において正当に選出された代表を通じて行動し、自ら及び子孫のために、あらゆる国家との平和的協力の成果と、我が国全体の自由の恩恵を確保し、政府の行為による新たな戦争の恐怖を再び招くことのないよう決意し、国民が主権を有することを宣言し、 本憲法を制定する。
87+
国家の統治は、国民の揺るぎない信頼に基づくものであり、その権威は国民から発し、その権限は国民の代表によって行使され、その恩恵は国民が享受する。
88+
この人類共通の原則が、本憲法の基礎である。我々は、本憲法に反するすべての憲法、法律、法令、および勅令を廃止する。
89+
"""
90+
)
91+
.replace("\n", "")
92+
.strip()
93+
)

0 commit comments

Comments
 (0)