Skip to content

Commit a362312

Browse files
feat: support multiple glossaries (glossary_ids) and document style/translation-memory options
1 parent b8f12ae commit a362312

8 files changed

Lines changed: 419 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- Added support for using multiple glossaries via the `glossary_ids` parameter
10+
(up to 5 glossaries) in `translate_text()`, `translate_document()`,
11+
`translate_document_upload()`, and `translate_document_from_filepath()`.
12+
- Added support for style rules in document translation via the `style_rule`
13+
parameter in `translate_document()`, `translate_document_upload()`, and
14+
`translate_document_from_filepath()`.
15+
- Added support for translation memories in document translation via the
16+
`translation_memory` and `translation_memory_threshold` parameters in
17+
`translate_document()`, `translate_document_upload()`, and
18+
`translate_document_from_filepath()`.
19+
- Added `--glossary-ids` CLI argument for the `text` and `document` commands,
20+
allowing up to 5 glossaries to be used per translation.
21+
- Added `--style-id`, `--translation-memory-id`, and
22+
`--translation-memory-threshold` CLI arguments to the `document` command.
823

924
## [1.30.0] - 2026-04-09
1025
### Added

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ arguments are:
160160
- `glossary`: specifies a glossary to use with translation, either as a string
161161
containing the glossary ID, or a `GlossaryInfo` as returned by
162162
`get_glossary()`.
163+
- `glossary_ids`: specifies a list of up to 5 glossaries to use with
164+
translation, applied in order. Each entry may be a string containing the
165+
glossary ID or a `GlossaryInfo` object. Requires `source_lang` to be set and
166+
cannot be combined with the `glossary` parameter. On the command line, use the
167+
repeatable `--glossary-ids` argument (available on both the `text` and
168+
`document` commands), for example:
169+
`--from=EN --to=DE --glossary-ids=ID1 --glossary-ids=ID2`.
163170
- `context`: specifies additional context to influence translations, that is not
164171
translated itself. Characters in the `context` parameter are not counted toward billing.
165172
See the [API documentation][api-docs-context-param] for more information and
@@ -333,6 +340,10 @@ arguments, the available `translate_document()` and
333340

334341
- `formality`: same as in [Text translation options](#text-translation-options).
335342
- `glossary`: same as in [Text translation options](#text-translation-options).
343+
- `glossary_ids`: same as in [Text translation options](#text-translation-options).
344+
- `style_rule`: same as in [Text translation options](#text-translation-options).
345+
- `translation_memory`: same as in [Text translation options](#text-translation-options).
346+
- `translation_memory_threshold`: same as in [Text translation options](#text-translation-options).
336347
- `output_format`: (`translate_document()` only)
337348
file extension of desired format of translated file, for example: `'pdf'`. If
338349
unspecified, by default the translated file will be in the same format as the
@@ -756,10 +767,17 @@ deepl_client.delete_style_rule("YOUR_STYLE_ID")
756767

757768
#### Using a style rule in translations
758769

759-
Style rules can also be used with the command line interface for text translation:
770+
Style rules can also be used with the command line interface for text
771+
translation:
760772

761773
```bash
762774
python3 -m deepl --auth-key=YOUR_AUTH_KEY text --to=DE --style-id=YOUR_STYLE_ID "Text to translate"
775+
```
776+
777+
The `document` command also accepts `--style-id` for document translation:
778+
779+
```bash
780+
python3 -m deepl --auth-key=YOUR_AUTH_KEY document --to=DE --style-id=YOUR_STYLE_ID /path/to/document.docx /path/to/output_dir
763781
```
764782

765783
### Translation Memories
@@ -824,6 +842,13 @@ Translation memories can also be used with the command line interface:
824842
python3 -m deepl --auth-key=YOUR_AUTH_KEY text --to=DE --translation-memory-id=YOUR_TM_ID --translation-memory-threshold=75 "Text to translate"
825843
```
826844

845+
The `document` command also accepts `--translation-memory-id` and
846+
`--translation-memory-threshold` for document translation:
847+
848+
```bash
849+
python3 -m deepl --auth-key=YOUR_AUTH_KEY document --to=DE --translation-memory-id=YOUR_TM_ID --translation-memory-threshold=75 /path/to/document.docx /path/to/output_dir
850+
```
851+
827852
### Writing a Plugin
828853

829854
If you use this library in an application, please identify the application with

deepl/__main__.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,16 @@ def add_common_arguments(subparser: argparse.ArgumentParser):
323323
type=str,
324324
help="ID of glossary to use for translation",
325325
)
326+
subparser.add_argument(
327+
"--glossary-ids",
328+
dest="glossary_ids",
329+
action="append",
330+
type=str,
331+
metavar="id",
332+
help="ID of a glossary to use for translation; may be repeated to "
333+
"use up to 5 glossaries, applied in order. Requires --from and "
334+
"cannot be combined with --glossary-id",
335+
)
326336
subparser.add_argument(
327337
"--extra-body-parameters",
328338
dest="extra_body_parameters",
@@ -503,6 +513,25 @@ def add_common_arguments(subparser: argparse.ArgumentParser):
503513
description="translate document(s)",
504514
)
505515
add_common_arguments(parser_document)
516+
parser_document.add_argument(
517+
"--style-id",
518+
dest="style_rule",
519+
type=str,
520+
help="ID of style rule to use for translation",
521+
)
522+
parser_document.add_argument(
523+
"--translation-memory-id",
524+
dest="translation_memory",
525+
type=str,
526+
help="ID of translation memory to use for translation",
527+
)
528+
parser_document.add_argument(
529+
"--translation-memory-threshold",
530+
dest="translation_memory_threshold",
531+
type=int,
532+
help="minimum matching percentage (0-100) for translation memory "
533+
"fuzzy matches, recommended minimum is 75",
534+
)
506535
parser_document.add_argument(
507536
"file", nargs="+", help="file(s) to be translated."
508537
)

deepl/translator.py

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ def _check_language_and_formality(
267267
style_rule: Union[str, StyleRuleInfo, None] = None,
268268
translation_memory: Union[str, TranslationMemoryInfo, None] = None,
269269
translation_memory_threshold: Optional[int] = None,
270+
glossary_ids: Optional[
271+
List[Union[str, GlossaryInfo, MultilingualGlossaryInfo]]
272+
] = None,
270273
) -> dict:
271274
# target_lang and source_lang are case insensitive
272275
target_lang = str(target_lang).upper()
@@ -276,6 +279,21 @@ def _check_language_and_formality(
276279
if glossary is not None and source_lang is None:
277280
raise ValueError("source_lang is required if using a glossary")
278281

282+
if glossary_ids is not None:
283+
if glossary is not None:
284+
raise ValueError(
285+
"glossary_ids cannot be used together with the glossary "
286+
"parameter"
287+
)
288+
if source_lang is None:
289+
raise ValueError(
290+
"source_lang is required if using glossary_ids"
291+
)
292+
if len(glossary_ids) > 5:
293+
raise ValueError(
294+
"glossary_ids must not contain more than 5 glossary IDs"
295+
)
296+
279297
if isinstance(glossary, GlossaryInfo):
280298
if (
281299
Language.remove_regional_variant(target_lang)
@@ -318,6 +336,22 @@ def _check_language_and_formality(
318336
request_data["glossary_id"] = glossary.glossary_id
319337
elif glossary is not None:
320338
request_data["glossary_id"] = glossary
339+
if glossary_ids is not None:
340+
resolved_ids = [
341+
(
342+
entry.glossary_id
343+
if isinstance(
344+
entry, (GlossaryInfo, MultilingualGlossaryInfo)
345+
)
346+
else entry
347+
)
348+
for entry in glossary_ids
349+
]
350+
# The API expects glossary_ids as an array. For text translation
351+
# this is JSON-encoded as an array; for document translation
352+
# (form/multipart) translate_document_upload joins it into a
353+
# single comma-separated glossary_ids field.
354+
request_data["glossary_ids"] = resolved_ids
321355
if isinstance(style_rule, StyleRuleInfo):
322356
request_data["style_id"] = style_rule.style_id
323357
elif style_rule is not None:
@@ -397,6 +431,9 @@ def translate_text(
397431
glossary: Union[
398432
str, GlossaryInfo, MultilingualGlossaryInfo, None
399433
] = None,
434+
glossary_ids: Optional[
435+
List[Union[str, GlossaryInfo, MultilingualGlossaryInfo]]
436+
] = None,
400437
tag_handling: Optional[str] = None,
401438
tag_handling_version: Optional[str] = None,
402439
outline_detection: Optional[bool] = None,
@@ -435,6 +472,9 @@ def translate_text(
435472
"default".
436473
:param glossary: (Optional) glossary or glossary ID to use for
437474
translation. Must match specified source_lang and target_lang.
475+
:param glossary_ids: (Optional) list of up to 5 glossaries or glossary
476+
IDs to use for translation, applied in order. Requires source_lang
477+
to be set and cannot be combined with the glossary parameter.
438478
:param style_rule: (Optional) style rule or style rule ID to use for
439479
translation.
440480
:param translation_memory: (Optional) translation memory or translation
@@ -492,6 +532,7 @@ def translate_text(
492532
style_rule,
493533
translation_memory,
494534
translation_memory_threshold,
535+
glossary_ids,
495536
)
496537
request_data["text"] = text
497538

@@ -627,6 +668,12 @@ def translate_document_from_filepath(
627668
glossary: Union[
628669
str, GlossaryInfo, MultilingualGlossaryInfo, None
629670
] = None,
671+
glossary_ids: Optional[
672+
List[Union[str, GlossaryInfo, MultilingualGlossaryInfo]]
673+
] = None,
674+
style_rule: Union[str, StyleRuleInfo, None] = None,
675+
translation_memory: Union[str, TranslationMemoryInfo, None] = None,
676+
translation_memory_threshold: Optional[int] = None,
630677
timeout_s: Optional[int] = None,
631678
extra_body_parameters: Optional[dict] = None,
632679
) -> DocumentStatus:
@@ -644,6 +691,16 @@ def translate_document_from_filepath(
644691
Formality enum, "less", "more", "prefer_less", or "prefer_more".
645692
:param glossary: (Optional) glossary or glossary ID to use for
646693
translation. Must match specified source_lang and target_lang.
694+
:param glossary_ids: (Optional) list of up to 5 glossaries or glossary
695+
IDs to use for translation, applied in order. Requires source_lang
696+
to be set and cannot be combined with the glossary parameter.
697+
:param style_rule: (Optional) style rule or style rule ID to use for
698+
translation.
699+
:param translation_memory: (Optional) translation memory or translation
700+
memory ID to use for translation.
701+
:param translation_memory_threshold: (Optional) minimum matching
702+
percentage for fuzzy matches from the translation memory (0-100).
703+
Recommended minimum is 75%.
647704
:param timeout_s: (beta) (Optional) Maximum time to wait before
648705
the call raises an error. Note that this is not accurate to the
649706
second, but only polls every 5 seconds.
@@ -674,6 +731,12 @@ def translate_document_from_filepath(
674731
source_lang=source_lang,
675732
formality=formality,
676733
glossary=glossary,
734+
glossary_ids=glossary_ids,
735+
style_rule=style_rule,
736+
translation_memory=translation_memory,
737+
translation_memory_threshold=(
738+
translation_memory_threshold
739+
),
677740
output_format=output_format,
678741
timeout_s=timeout_s,
679742
extra_body_parameters=extra_body_parameters,
@@ -694,6 +757,12 @@ def translate_document(
694757
glossary: Union[
695758
str, GlossaryInfo, MultilingualGlossaryInfo, None
696759
] = None,
760+
glossary_ids: Optional[
761+
List[Union[str, GlossaryInfo, MultilingualGlossaryInfo]]
762+
] = None,
763+
style_rule: Union[str, StyleRuleInfo, None] = None,
764+
translation_memory: Union[str, TranslationMemoryInfo, None] = None,
765+
translation_memory_threshold: Optional[int] = None,
697766
filename: Optional[str] = None,
698767
output_format: Optional[str] = None,
699768
timeout_s: Optional[int] = None,
@@ -715,6 +784,16 @@ def translate_document(
715784
Formality enum, "less", "more", "prefer_less", or "prefer_more".
716785
:param glossary: (Optional) glossary or glossary ID to use for
717786
translation. Must match specified source_lang and target_lang.
787+
:param glossary_ids: (Optional) list of up to 5 glossaries or glossary
788+
IDs to use for translation, applied in order. Requires source_lang
789+
to be set and cannot be combined with the glossary parameter.
790+
:param style_rule: (Optional) style rule or style rule ID to use for
791+
translation.
792+
:param translation_memory: (Optional) translation memory or translation
793+
memory ID to use for translation.
794+
:param translation_memory_threshold: (Optional) minimum matching
795+
percentage for fuzzy matches from the translation memory (0-100).
796+
Recommended minimum is 75%.
718797
:param filename: (Optional) Filename including extension, only required
719798
if uploading string or bytes containing file content.
720799
:param output_format: (Optional) Desired output file extension, if
@@ -740,6 +819,10 @@ def translate_document(
740819
source_lang=source_lang,
741820
formality=formality,
742821
glossary=glossary,
822+
glossary_ids=glossary_ids,
823+
style_rule=style_rule,
824+
translation_memory=translation_memory,
825+
translation_memory_threshold=translation_memory_threshold,
743826
filename=filename,
744827
output_format=output_format,
745828
extra_body_parameters=extra_body_parameters,
@@ -770,6 +853,12 @@ def translate_document_upload(
770853
glossary: Union[
771854
str, GlossaryInfo, MultilingualGlossaryInfo, None
772855
] = None,
856+
glossary_ids: Optional[
857+
List[Union[str, GlossaryInfo, MultilingualGlossaryInfo]]
858+
] = None,
859+
style_rule: Union[str, StyleRuleInfo, None] = None,
860+
translation_memory: Union[str, TranslationMemoryInfo, None] = None,
861+
translation_memory_threshold: Optional[int] = None,
773862
filename: Optional[str] = None,
774863
output_format: Optional[str] = None,
775864
extra_body_parameters: Optional[dict] = None,
@@ -788,6 +877,16 @@ def translate_document_upload(
788877
Formality enum, "less", "more", "prefer_less", or "prefer_more".
789878
:param glossary: (Optional) glossary or glossary ID to use for
790879
translation. Must match specified source_lang and target_lang.
880+
:param glossary_ids: (Optional) list of up to 5 glossaries or glossary
881+
IDs to use for translation, applied in order. Requires source_lang
882+
to be set and cannot be combined with the glossary parameter.
883+
:param style_rule: (Optional) style rule or style rule ID to use for
884+
translation.
885+
:param translation_memory: (Optional) translation memory or translation
886+
memory ID to use for translation.
887+
:param translation_memory_threshold: (Optional) minimum matching
888+
percentage for fuzzy matches from the translation memory (0-100).
889+
Recommended minimum is 75%.
791890
:param filename: (Optional) Filename including extension, only required
792891
if uploading string or bytes containing file content.
793892
:param output_format: (Optional) Desired output file extension, if
@@ -801,11 +900,26 @@ def translate_document_upload(
801900
"""
802901

803902
request_data = self._check_language_and_formality(
804-
source_lang, target_lang, formality, glossary
903+
source_lang,
904+
target_lang,
905+
formality,
906+
glossary,
907+
style_rule,
908+
translation_memory,
909+
translation_memory_threshold,
910+
glossary_ids=glossary_ids,
805911
)
806912
if output_format:
807913
request_data["output_format"] = output_format
808914

915+
# The document endpoint uses multipart/form-data. Send glossary_ids as
916+
# a single comma-separated field (the form form of the array), matching
917+
# the other SDKs, instead of repeated multipart fields.
918+
if isinstance(request_data.get("glossary_ids"), list):
919+
request_data["glossary_ids"] = ",".join(
920+
request_data["glossary_ids"]
921+
)
922+
809923
files: Dict[str, Any] = {}
810924
if isinstance(input_document, (str, bytes)):
811925
if filename is None:

0 commit comments

Comments
 (0)