Skip to content

Commit f798962

Browse files
committed
feat: Add support for v3 glossary endpoints
1 parent 7469a47 commit f798962

10 files changed

+1822
-139
lines changed

CHANGELOG.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88
### Added
9-
<!-- * add to here -->
10-
### Changed
11-
<!-- * add to here -->
9+
* Added support for the /v3 Glossary APIs in the client library while providing backwards
10+
compatability for the previous /v2 Glossary endpoints. Please refer to the README for
11+
usage instructions.
12+
1213

1314
## [1.21.1] - 2025-03-12
1415
### Added
1516
* (beta) optional parameter to specify timeout for document translation calls
1617

18+
1719
## [1.21.0] - 2025-01-15
1820
### Added
1921
* Added support for the Write API in the client library, the implementation
@@ -333,6 +335,7 @@ Version increased to avoid conflicts with old packages on PyPI.
333335
## [0.1.0] - 2021-07-26
334336
Initial version.
335337

338+
336339
<!-- Unreleased shoud never be deleted -->
337340
[Unreleased]: https://github.com/DeepLcom/deepl-python/compare/v1.21.1...HEAD
338341
[1.21.1]: https://github.com/DeepLcom/deepl-python/compare/v1.21.0...v1.21.1

README.md

Lines changed: 145 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -323,46 +323,70 @@ Glossaries allow you to customize your translations using user-defined terms.
323323
Multiple glossaries can be stored with your account, each with a user-specified
324324
name and a uniquely-assigned ID.
325325

326+
#### v2 versus v3 glossary APIs
327+
328+
The newest version of the glossary APIs are the `/v3` endpoints, allowing both
329+
editing functionality plus support for multilingual glossaries. New methods and
330+
objects have been created to support interacting with these new glossaries.
331+
Due to this new functionality, users are recommended to utilize these
332+
multilingual glossary methods. However, to continue using the `v2` glossary API
333+
endpoints, please continue to use the existing endpoints in the `translator.py`
334+
(e.g. `create_glossary()`, `get_glossary()`, etc).
335+
336+
To migrate to use the new multilingual glossary methods from the current
337+
monolingual glossary methods, please refer to
338+
[this migration guide](upgrade_to_multilingual_glossaries.md).
339+
340+
The following sections describe how to interact with multilingual glossaries
341+
using the new functionality:
342+
326343
#### Creating a glossary
327344

328-
You can create a glossary with your desired terms and name using
329-
`create_glossary()`. Each glossary applies to a single source-target language
330-
pair. Note: Glossaries are only supported for some language pairs, see
345+
You can create a multi-lingual glossary with your desired terms and name using
346+
`create_multilingual_glossary()`. Glossaries created via the /v3 endpoints can now
347+
support multiple source-target language pairs. Note: Glossaries are only
348+
supported for some language pairs, see
331349
[Listing available glossary languages](#listing-available-glossary-languages)
332350
for more information. The entries should be specified as a dictionary.
333351

334352
If successful, the glossary is created and stored with your DeepL account, and
335-
a `GlossaryInfo` object is returned including the ID, name, languages and entry
336-
count.
353+
a `MultilingualGlossaryInfo` object is returned including the ID, name, and glossary
354+
dictionaries. The glossary dictionaries would be an array of
355+
`MultilingualGlossaryDictionaryInfo` objects, each containing its own languages and
356+
entry count.
337357

338358
```python
339-
# Create an English to German glossary with two terms:
359+
# Create a glossary with an English to German dictionary containing two terms:
340360
entries = {"artist": "Maler", "prize": "Gewinn"}
341-
my_glossary = deepl_client.create_glossary(
361+
dictionaries = [MultilingualGlossaryDictionaryEntries("EN", "DE", entries)]
362+
my_glossary = deepl_client.create_multilingual_glossary(
342363
"My glossary",
343-
source_lang="EN",
344-
target_lang="DE",
345-
entries=entries,
364+
dictionaries
346365
)
366+
my_glossary_dict = my_glossary.dictionaries[0]
347367
print(
348368
f"Created '{my_glossary.name}' ({my_glossary.glossary_id}) "
349-
f"{my_glossary.source_lang}->{my_glossary.target_lang} "
350-
f"containing {my_glossary.entry_count} entries"
369+
f"with {len(my_glossary.dictionaries)} dictionary where "
370+
f"its language pair is {my_glossary_dict.source_lang}->"
371+
f"{my_glossary_dict.target_lang} containing "
372+
f"{my_glossary.entry_count} entries"
351373
)
352-
# Example: Created 'My glossary' (559192ed-8e23-...) EN->DE containing 2 entries
374+
# Example: Created 'My glossary' (559192ed-8e23-...) with 1 dictionary where
375+
# its language pair is EN->DE containing 2 entries
353376
```
354377

355378
You can also upload a glossary downloaded from the DeepL website using
356-
`create_glossary_from_csv()`. Instead of supplying the entries as a dictionary,
357-
specify the CSV data as `csv_data` either as a file-like object or string or
358-
bytes containing file content:
379+
`create_multilingual_glossary_from_csv()`. Instead of supplying the entries as a
380+
dictionary within a MultilingualGlossaryDictionaryEntries object, you can specify
381+
the CSV data as `csv_data` either as a file-like object or string or bytes
382+
containing file content:
359383

360384
```python
361385
# Open the CSV file assuming UTF-8 encoding. If your file contains a BOM,
362386
# consider using encoding='utf-8-sig' instead.
363387
with open('/path/to/glossary_file.csv', 'r', encoding='utf-8') as csv_file:
364388
csv_data = csv_file.read() # Read the file contents as a string
365-
my_csv_glossary = deepl_client.create_glossary_from_csv(
389+
my_csv_glossary = deepl_client.create_multilingual_glossary_from_csv(
366390
"CSV glossary",
367391
source_lang="EN",
368392
target_lang="DE",
@@ -373,49 +397,134 @@ with open('/path/to/glossary_file.csv', 'r', encoding='utf-8') as csv_file:
373397
The [API documentation][api-docs-csv-format] explains the expected CSV format in
374398
detail.
375399

376-
#### Getting, listing and deleting stored glossaries
400+
#### Getting, listing, and deleting stored glossaries
377401

378402
Functions to get, list, and delete stored glossaries are also provided:
379403

380-
- `get_glossary()` takes a glossary ID and returns a `GlossaryInfo` object for a
381-
stored glossary, or raises an exception if no such glossary is found.
382-
- `list_glossaries()` returns a list of `GlossaryInfo` objects corresponding to
383-
all of your stored glossaries.
384-
- `delete_glossary()` takes a glossary ID or `GlossaryInfo` object and deletes
385-
the stored glossary from the server, or raises an exception if no such
386-
glossary is found.
404+
- `get_multilingual_glossary()` takes a glossary ID and returns a
405+
`MultilingualGlossaryInfo` object for a stored glossary, or raises an
406+
exception if no such glossary is found.
407+
- `list_multilingual_glossaries()` returns a list of `MultilingualGlossaryInfo` objects
408+
corresponding to all of your stored glossaries.
409+
- `delete_multilingual_glossary()` takes a glossary ID or `MultilingualGlossaryInfo`
410+
object and deletes the stored glossary from the server, or raises an
411+
exception if no such glossary is found.
412+
- `delete_multilingual_glossary_dictionary()` takes a glossary ID or `GlossaryInfo` object to
413+
identify the glossary. Additionally takes in a source and target language or a
414+
`MultilingualGlossaryDictionaryInfo` object and deletes the stored dictionary
415+
from the server, or raises an exception if no such glossary dictionary is found.
387416

388417
```python
389418
# Retrieve a stored glossary using the ID
390419
glossary_id = "559192ed-8e23-..."
391-
my_glossary = deepl_client.get_glossary(glossary_id)
420+
my_glossary = deepl_client.get_multilingual_glossary(glossary_id)
421+
422+
# Delete a glossary dictionary from a stored glossary
423+
deepl_client.delete_multilingual_glossary_dictionary(my_glossary, my_glossary.dictionaries[0])
392424

393425
# Find and delete glossaries named 'Old glossary'
394-
glossaries = deepl_client.list_glossaries()
426+
glossaries = deepl_client.list_multilingual_glossaries()
395427
for glossary in glossaries:
396428
if glossary.name == "Old glossary":
397-
deepl_client.delete_glossary(glossary)
429+
deepl_client.delete_multilingual_glossary(glossary)
398430
```
399431

400432
#### Listing entries in a stored glossary
401433

402-
The `GlossaryInfo` object does not contain the glossary entries, but instead
403-
only the number of entries in the `entry_count` property.
434+
The `MultilingualGlossaryInfo` object does not contain the glossary entries, but
435+
instead only the number of entries in the `entry_count` property.
404436

405437
To list the entries contained within a stored glossary, use
406-
`get_glossary_entries()` providing either the `GlossaryInfo` object or glossary
407-
ID:
438+
`get_multilingual_glossary_entries()` providing either the `MultilingualGlossaryInfo` object or glossary
439+
ID and either a `MultilingualGlossaryDictionaryInfo` or source and target language pair:
440+
441+
```python
442+
entries = deepl_client.get_multilingual_glossary_entries(my_glossary, "EN", "DE")
443+
print(entries.dictionaries[0]) # "{'artist': 'Maler', 'prize': 'Gewinn'}"
444+
```
445+
446+
#### Editing a glossary
447+
448+
Functions to edit stored glossaries are also provided:
449+
450+
- `update_multilingual_glossary_dictionary()` takes a glossary ID or `MultilingualGlossaryInfo`
451+
object, plus a source language, target language, and a dictionary of entries.
452+
It will then either update the list of entries for that dictionary (either
453+
inserting new entires or replacing the target phrase for any existing
454+
entries) or will insert a new glossary dictionary if that language pair is
455+
not currently in the stored glossary.
456+
- `replace_multilingual_glossary_dictionary()` takes a glossary ID or `MultilingualGlossaryInfo`
457+
object, plus a source language, target language, and a dictionary of entries.
458+
It will then either set the entries to the parameter value, completely
459+
replacing any pre-existing entries for that language pair.
460+
- `update_multilingual_glossary_name()` takes a glossary ID or `MultilingualGlossaryInfo`
461+
object, plus the new name of the glossary.
408462

409463
```python
410-
entries = deepl_client.get_glossary_entries(my_glossary)
411-
print(entries) # "{'artist': 'Maler', 'prize': 'Gewinn'}"
464+
# Update glossary dictionary
465+
entries = {"artist": "Maler", "hello": "guten tag"}
466+
dictionaries = [MultilingualGlossaryDictionaryEntries("EN", "DE", entries)]
467+
my_glossary = deepl_client.create_multilingual_glossary(
468+
"My glossary",
469+
dictionaries
470+
)
471+
new_entries = {"hello": "hallo", "prize": "Gewinn"}
472+
glossary_dict = MultilingualGlossaryDictionaryEntries("EN", "DE", new_entries)
473+
updated_glossary = deepl_client.update_multilingual_glossary_dictionary(
474+
my_glossary,
475+
glossary_dict
476+
)
477+
478+
entries_response = deepl_client.get_multilingual_glossary_entries(my_glossary, "EN", "DE")
479+
print(entries_response.dictionaries[0]) # "{'artist': 'Maler', 'hello': 'hallo', 'prize': 'Gewinn'}"
480+
481+
# Update a glossary dictionary from CSV
482+
# Open the CSV file assuming UTF-8 encoding. If your file contains a BOM,
483+
# consider using encoding='utf-8-sig' instead.
484+
with open('/path/to/glossary_file.csv', 'r', encoding='utf-8') as csv_file:
485+
csv_data = csv_file.read() # Read the file contents as a string
486+
my_csv_glossary = deepl_client.update_multilingual_glossary_dictionary_from_csv(
487+
glossary="4c81ffb4-2e...",
488+
source_lang="EN",
489+
target_lang="DE",
490+
csv_data=csv_data,
491+
)
492+
493+
# Replace glossary dictionary
494+
replacement_entries = {"goodbye": "Auf Wiedersehen"}
495+
glossary_dict = MultilingualGlossaryDictionaryEntries("EN", "DE", replacement_entries)
496+
updated_glossary = deepl_client.replace_multilingual_glossary_dictionary(
497+
my_glossary,
498+
glossary_dict)
499+
entries_response = deepl_client.get_multilingual_glossary_entries(my_glossary, "EN", "DE")
500+
print(entries_response.dictionaries[0]) # "{'goodbye': 'Auf Wiedersehen'}"
501+
502+
# Replace a glossary dictionary from CSV
503+
# Open the CSV file assuming UTF-8 encoding. If your file contains a BOM,
504+
# consider using encoding='utf-8-sig' instead.
505+
with open('/path/to/glossary_file.csv', 'r', encoding='utf-8') as csv_file:
506+
csv_data = csv_file.read() # Read the file contents as a string
507+
my_csv_glossary = deepl_client.replace_multilingual_glossary_dictionary_from_csv(
508+
glossary="4c81ffb4-2e...",
509+
source_lang="EN",
510+
target_lang="DE",
511+
csv_data=csv_data,
512+
)
513+
514+
# Update the glossary name
515+
updated_glossary = deepl_client.update_multilingual_glossary_name(
516+
my_glossary,
517+
"My new glossary name"
518+
)
519+
print(updated_glossary.name) # 'My new glossary name'
412520
```
413521

414522
#### Using a stored glossary
415523

416524
You can use a stored glossary for text translation by setting the `glossary`
417-
argument to either the glossary ID or `GlossaryInfo` object. You must also
418-
specify the `source_lang` argument (it is required when using a glossary):
525+
argument to either the glossary ID or `GlossaryInfo`/`MultilingualGlossaryInfo` object.
526+
You must also specify the `source_lang` argument (it is required when using a
527+
glossary):
419528

420529
```python
421530
text = "The artist was awarded a prize."

0 commit comments

Comments
 (0)