Skip to content

Commit 415d41a

Browse files
feat: add support for the translation memory management APIs
1 parent a362312 commit 415d41a

8 files changed

Lines changed: 1915 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
allowing up to 5 glossaries to be used per translation.
2121
- Added `--style-id`, `--translation-memory-id`, and
2222
`--translation-memory-threshold` CLI arguments to the `document` command.
23+
- Added support for the translation memory management APIs:
24+
`get_translation_memory()`, `list_translation_memory_segments()`,
25+
`delete_translation_memory()`, `create_translation_memory_import()`,
26+
`upload_translation_memory_file()`, `create_translation_memory_export()`,
27+
`get_translation_memory_job()`,
28+
`wait_until_translation_memory_job_done()`, and
29+
`download_translation_memory_export()`, along with the
30+
`import_translation_memory_from_filepath()` and
31+
`export_translation_memory_to_filepath()` convenience functions that create
32+
the job, transfer the TMX file, and wait for the job to finish. Because the
33+
API detects the file upload asynchronously, an import job keeps reporting
34+
`awaiting_input` for a while after the upload; the wait loop polls through
35+
that status, so pass `timeout_s` to bound the wait.
36+
- Added the `TranslationMemorySegments`, `TranslationMemorySegment`,
37+
`TranslationMemoryTargetSegment`, `TranslationMemoryImport`,
38+
`TranslationMemoryExport`, `TranslationMemoryJob`, and
39+
`TranslationMemoryJobResult` types.
40+
- Added `creation_time` and `updated_time` properties to
41+
`TranslationMemoryInfo`.
42+
- Added the `translation-memory` CLI command with the `list`, `get`,
43+
`segments`, `import`, `export`, `job`, and `delete` subcommands.
2344

2445
## [1.30.0] - 2026-04-09
2546
### Added

README.md

Lines changed: 122 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -787,12 +787,6 @@ They can be used in text translation requests to improve consistency by matching
787787
against stored segments. Multiple translation memories can be stored with your
788788
account, each with a source language and one or more target languages.
789789

790-
#### Uploading and managing translation memories
791-
792-
Currently translation memories must be uploaded and managed in the DeepL UI via
793-
https://www.deepl.com/translation-memory. Full CRUD functionality via the APIs will
794-
come shortly.
795-
796790
#### Listing translation memories
797791

798792
`list_translation_memories()` returns a list of `TranslationMemoryInfo` objects
@@ -810,6 +804,128 @@ for tm in translation_memories:
810804
print(f" Segments: {tm.segment_count}")
811805
```
812806

807+
#### Retrieving a translation memory
808+
809+
Use `get_translation_memory()` to retrieve a single translation memory by ID.
810+
It accepts either a translation memory ID string or a `TranslationMemoryInfo`
811+
object.
812+
813+
```python
814+
tm = deepl_client.get_translation_memory("YOUR_TM_ID")
815+
print(f"{tm.name}: {tm.segment_count} segments, updated {tm.updated_time}")
816+
```
817+
818+
#### Listing the segments of a translation memory
819+
820+
`list_translation_memory_segments()` returns one page of segments as a
821+
`TranslationMemorySegments` object. Pagination is cursor-based: omit
822+
`page_cursor` on the first call, then pass the previous response's
823+
`next_page_cursor` until it is `None`. Optionally filter with `filter_text`
824+
(at least 2 characters, matched against both source and target text) and
825+
`filter_case_sensitive`. Note that `segment_count` is the translation-memory
826+
total and is not reduced by the filter.
827+
828+
```python
829+
page_cursor = None
830+
while True:
831+
page = deepl_client.list_translation_memory_segments(
832+
"YOUR_TM_ID", page_size=50, page_cursor=page_cursor
833+
)
834+
for segment in page.segments:
835+
print(segment.source_text)
836+
for target in segment.targets:
837+
print(f" {target.target_language}: {target.target_text}")
838+
page_cursor = page.next_page_cursor
839+
if not page_cursor:
840+
break
841+
```
842+
843+
#### Importing a translation memory
844+
845+
`import_translation_memory_from_filepath()` imports a TMX file as a new
846+
translation memory: it creates the import job, uploads the file, and waits for
847+
processing to finish. The returned `TranslationMemoryJob` carries the ID of the
848+
new translation memory.
849+
850+
```python
851+
job = deepl_client.import_translation_memory_from_filepath(
852+
"/path/to/legal.tmx", display_name="Legal TM", timeout_s=300
853+
)
854+
print(f"Created translation memory {job.result.translation_memory_id}")
855+
print(f"Skipped segments: {job.result.skipped_segment_count}")
856+
```
857+
858+
Importing takes a while: the API detects the uploaded file asynchronously, so
859+
the job keeps reporting `awaiting_input` for roughly half a minute after the
860+
upload before completing. Pass `timeout_s` to bound how long to wait.
861+
862+
The three steps are also available separately, for example to upload the file
863+
yourself or to poll for progress. `create_translation_memory_import()` returns
864+
an upload URL that the file must be uploaded to before processing starts, then
865+
`get_translation_memory_job()` reports the status.
866+
867+
```python
868+
created = deepl_client.create_translation_memory_import(
869+
file_name="legal.tmx",
870+
content_length=os.path.getsize("/path/to/legal.tmx"),
871+
display_name="Legal TM",
872+
)
873+
with open("/path/to/legal.tmx", "rb") as input_file:
874+
deepl_client.upload_translation_memory_file(created, input_file)
875+
876+
# The job reports "awaiting_input" both before the upload and for a while
877+
# afterwards, until the API detects it; this polls through that status.
878+
job = deepl_client.wait_until_translation_memory_job_done(
879+
created.job_id, timeout_s=300
880+
)
881+
```
882+
883+
#### Exporting a translation memory
884+
885+
`export_translation_memory_to_filepath()` exports a translation memory to a TMX
886+
file: it creates the export job, waits for it to finish, and writes the result.
887+
888+
```python
889+
job = deepl_client.export_translation_memory_to_filepath(
890+
"YOUR_TM_ID", "/path/to/exported.tmx"
891+
)
892+
```
893+
894+
As with import, the individual steps are available separately. Note that the
895+
API may reuse a previously completed export of an unchanged translation memory,
896+
indicated by `reused_existing`.
897+
898+
```python
899+
created = deepl_client.create_translation_memory_export("YOUR_TM_ID")
900+
job = deepl_client.wait_until_translation_memory_job_done(created.job_id)
901+
with open("/path/to/exported.tmx", "wb") as output_file:
902+
deepl_client.download_translation_memory_export(
903+
job, output_file, chunk_size=8192
904+
)
905+
```
906+
907+
#### Deleting a translation memory
908+
909+
Use `delete_translation_memory()` to delete a translation memory by ID.
910+
911+
```python
912+
deepl_client.delete_translation_memory("YOUR_TM_ID")
913+
```
914+
915+
#### Managing translation memories from the command line
916+
917+
The `translation-memory` command exposes the same operations:
918+
919+
```bash
920+
python3 -m deepl --auth-key=YOUR_AUTH_KEY translation-memory list
921+
python3 -m deepl --auth-key=YOUR_AUTH_KEY translation-memory get YOUR_TM_ID
922+
python3 -m deepl --auth-key=YOUR_AUTH_KEY translation-memory segments YOUR_TM_ID --all
923+
python3 -m deepl --auth-key=YOUR_AUTH_KEY translation-memory import /path/to/legal.tmx --name "Legal TM"
924+
python3 -m deepl --auth-key=YOUR_AUTH_KEY translation-memory export YOUR_TM_ID /path/to/exported.tmx
925+
python3 -m deepl --auth-key=YOUR_AUTH_KEY translation-memory job YOUR_JOB_ID
926+
python3 -m deepl --auth-key=YOUR_AUTH_KEY translation-memory delete YOUR_TM_ID
927+
```
928+
813929
#### Using a translation memory in translations
814930

815931
Pass the `translation_memory` parameter to `translate_text()` to use a

0 commit comments

Comments
 (0)