Skip to content

Commit c8370da

Browse files
feat: Add support for style_id and get all style rules endpoint
1 parent a7b1b8f commit c8370da

File tree

8 files changed

+444
-0
lines changed

8 files changed

+444
-0
lines changed

README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ using the following keys:
137137
See the [API documentation][api-docs-context-param] for more information and
138138
example usage.
139139
- `glossary`: glossary ID of glossary to use for translation.
140+
- `style_id`: specifies a style rule to use with translation, either as a string
141+
containing the ID of the style rule, or a `StyleRuleInfo` object.
140142
- `model_type`: specifies the type of translation model to use, options are:
141143
- `'quality_optimized'`: use a translation model that maximizes translation quality, at
142144
the cost of response time. This option may be unavailable for
@@ -615,6 +617,66 @@ Note that glossaries work for all target regional-variants: a glossary for the
615617
target language English (`'en'`) supports translations to both American English
616618
(`'en-US'`) and British English (`'en-GB'`).
617619

620+
### Style Rules
621+
622+
Style rules allow you to customize your translations using a managed, shared list
623+
of rules for style, formatting, and more. Multiple style rules can be stored with
624+
your account, each with a user-specified name and a uniquely-assigned ID.
625+
626+
#### Creating and managing style rules
627+
628+
Currently style rules must be created and managed in the DeepL UI via
629+
https://www.deepl.com/en/custom-rules. Full CRUD functionality via the APIs will
630+
come shortly.
631+
632+
#### Listing all style rules
633+
634+
`getAllStyleRules()` returns a list of `StyleRuleInfo` objects
635+
corresponding to all of your stored style rules. The method accepts optional
636+
parameters: `page` (page number for pagination, 0-indexed), `pageSize` (number
637+
of items per page), and `detailed` (whether to include detailed configuration
638+
rules in the `configuredRules` property).
639+
640+
```php
641+
// Get all style rules
642+
$styleRules = $deeplClient->getAllStyleRules();
643+
foreach ($styleRules as $rule) {
644+
echo "{$rule->name} ({$rule->styleId})\n";
645+
}
646+
647+
// Get style rules with detailed configuration
648+
$styleRulesDetailed = $deeplClient->getAllStyleRules(detailed: true);
649+
foreach ($styleRulesDetailed as $rule) {
650+
if ($rule->configuredRules && $rule->configuredRules->numbers) {
651+
echo " Number formatting: " . implode(", ", array_keys($rule->configuredRules->numbers)) . "\n";
652+
}
653+
}
654+
```
655+
656+
#### Using a stored style rule
657+
658+
You can use a stored style rule for text translation by setting the `style_id`
659+
option to either the style rule ID or a `StyleRuleInfo` object:
660+
661+
```php
662+
// Using a style rule ID
663+
$result = $deeplClient->translateText(
664+
'Hello, world!',
665+
'en',
666+
'de',
667+
['style_id' => 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4']
668+
);
669+
670+
// Using a StyleRuleInfo object
671+
$styleRules = $deeplClient->getAllStyleRules();
672+
$result = $deeplClient->translateText(
673+
'Hello, world!',
674+
'en',
675+
'de',
676+
['style_id' => $styleRules[0]]
677+
);
678+
```
679+
618680
### Writing a Plugin
619681

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

src/ConfiguredRules.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
// Copyright 2025 DeepL SE (https://www.deepl.com)
4+
// Use of this source code is governed by an MIT
5+
// license that can be found in the LICENSE file.
6+
7+
namespace DeepL;
8+
9+
/**
10+
* Configuration rules for a style rule list.
11+
*/
12+
class ConfiguredRules
13+
{
14+
/** @var array<string, string>|null Date and time formatting rules. */
15+
public $datesAndTimes;
16+
17+
/** @var array<string, string>|null Text formatting rules. */
18+
public $formatting;
19+
20+
/** @var array<string, string>|null Number formatting rules. */
21+
public $numbers;
22+
23+
/** @var array<string, string>|null Punctuation rules. */
24+
public $punctuation;
25+
26+
/** @var array<string, string>|null Spelling and grammar rules. */
27+
public $spellingAndGrammar;
28+
29+
/** @var array<string, string>|null Style and tone rules. */
30+
public $styleAndTone;
31+
32+
/** @var array<string, string>|null Vocabulary rules. */
33+
public $vocabulary;
34+
35+
public function __construct(
36+
?array $datesAndTimes = null,
37+
?array $formatting = null,
38+
?array $numbers = null,
39+
?array $punctuation = null,
40+
?array $spellingAndGrammar = null,
41+
?array $styleAndTone = null,
42+
?array $vocabulary = null
43+
) {
44+
$this->datesAndTimes = $datesAndTimes;
45+
$this->formatting = $formatting;
46+
$this->numbers = $numbers;
47+
$this->punctuation = $punctuation;
48+
$this->spellingAndGrammar = $spellingAndGrammar;
49+
$this->styleAndTone = $styleAndTone;
50+
$this->vocabulary = $vocabulary;
51+
}
52+
53+
/**
54+
* @throws InvalidContentException
55+
*/
56+
public static function fromJson(?array $json): ?ConfiguredRules
57+
{
58+
if ($json === null) {
59+
return null;
60+
}
61+
62+
return new ConfiguredRules(
63+
$json['dates_and_times'] ?? null,
64+
$json['formatting'] ?? null,
65+
$json['numbers'] ?? null,
66+
$json['punctuation'] ?? null,
67+
$json['spelling_and_grammar'] ?? null,
68+
$json['style_and_tone'] ?? null,
69+
$json['vocabulary'] ?? null
70+
);
71+
}
72+
}

src/CustomInstruction.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
// Copyright 2025 DeepL SE (https://www.deepl.com)
4+
// Use of this source code is governed by an MIT
5+
// license that can be found in the LICENSE file.
6+
7+
namespace DeepL;
8+
9+
/**
10+
* Custom instruction for a style rule.
11+
*/
12+
class CustomInstruction
13+
{
14+
/** @var string Label for the custom instruction. */
15+
public $label;
16+
17+
/** @var string Prompt text for the custom instruction. */
18+
public $prompt;
19+
20+
/** @var string|null Optional source language code for the custom instruction. */
21+
public $sourceLanguage;
22+
23+
public function __construct(
24+
string $label,
25+
string $prompt,
26+
?string $sourceLanguage = null
27+
) {
28+
$this->label = $label;
29+
$this->prompt = $prompt;
30+
$this->sourceLanguage = $sourceLanguage;
31+
}
32+
33+
/**
34+
* @throws InvalidContentException
35+
*/
36+
public static function fromJson(array $json): CustomInstruction
37+
{
38+
return new CustomInstruction(
39+
$json['label'],
40+
$json['prompt'],
41+
$json['source_language'] ?? null
42+
);
43+
}
44+
}

src/DeepLClient.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,4 +331,40 @@ public function buildRephraseBodyParams(
331331

332332
return $params;
333333
}
334+
335+
/**
336+
* Retrieves a list of StyleRuleInfo for all available style rules.
337+
* @param int|null $page Page number for pagination, 0-indexed (optional).
338+
* @param int|null $pageSize Number of items per page (optional).
339+
* @param bool|null $detailed Whether to include detailed configuration rules (optional).
340+
* @return StyleRuleInfo[] List of StyleRuleInfo objects for all available style rules.
341+
* @throws DeepLException
342+
*/
343+
public function getAllStyleRules(
344+
?int $page = null,
345+
?int $pageSize = null,
346+
?bool $detailed = null
347+
): array {
348+
$params = [];
349+
if ($page !== null) {
350+
$params['page'] = (string)$page;
351+
}
352+
if ($pageSize !== null) {
353+
$params['page_size'] = (string)$pageSize;
354+
}
355+
if ($detailed !== null) {
356+
$params['detailed'] = $detailed ? 'true' : 'false';
357+
}
358+
359+
$queryString = '';
360+
if (!empty($params)) {
361+
$queryString = '?' . http_build_query($params);
362+
}
363+
364+
$response = $this->client->sendRequestWithBackoff('GET', "/v3/style_rules$queryString");
365+
$this->checkStatusCode($response);
366+
list(, $content) = $response;
367+
368+
return StyleRuleInfo::parseList($content);
369+
}
334370
}

src/StyleRuleInfo.php

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
// Copyright 2025 DeepL SE (https://www.deepl.com)
4+
// Use of this source code is governed by an MIT
5+
// license that can be found in the LICENSE file.
6+
7+
namespace DeepL;
8+
9+
use DateTime;
10+
use JsonException;
11+
12+
/**
13+
* Information about a style rule list.
14+
*/
15+
class StyleRuleInfo
16+
{
17+
/** @var string Unique ID assigned to the style rule list. */
18+
public $styleId;
19+
20+
/** @var string User-defined name assigned to the style rule list. */
21+
public $name;
22+
23+
/** @var DateTime Timestamp when the style rule list was created. */
24+
public $creationTime;
25+
26+
/** @var DateTime Timestamp when the style rule list was last updated. */
27+
public $updatedTime;
28+
29+
/** @var string Language code for the style rule list. */
30+
public $language;
31+
32+
/** @var int Version number of the style rule list. */
33+
public $version;
34+
35+
/** @var ConfiguredRules|null The predefined rules that have been enabled. */
36+
public $configuredRules;
37+
38+
/** @var CustomInstruction[]|null Optional list of custom instructions. */
39+
public $customInstructions;
40+
41+
public function __construct(
42+
string $styleId,
43+
string $name,
44+
DateTime $creationTime,
45+
DateTime $updatedTime,
46+
string $language,
47+
int $version,
48+
?ConfiguredRules $configuredRules = null,
49+
?array $customInstructions = null
50+
) {
51+
$this->styleId = $styleId;
52+
$this->name = $name;
53+
$this->creationTime = $creationTime;
54+
$this->updatedTime = $updatedTime;
55+
$this->language = $language;
56+
$this->version = $version;
57+
$this->configuredRules = $configuredRules;
58+
$this->customInstructions = $customInstructions;
59+
}
60+
61+
/**
62+
* @param string|StyleRuleInfo $styleRule Style rule ID or StyleRuleInfo of style rule.
63+
*/
64+
public static function getStyleId($styleRule): string
65+
{
66+
return is_string($styleRule) ? $styleRule : $styleRule->styleId;
67+
}
68+
69+
/**
70+
* @throws InvalidContentException
71+
*/
72+
public static function fromJson(array $json): StyleRuleInfo
73+
{
74+
$configuredRules = null;
75+
if (isset($json['configured_rules'])) {
76+
$configuredRules = ConfiguredRules::fromJson($json['configured_rules']);
77+
}
78+
79+
$customInstructions = null;
80+
if (isset($json['custom_instructions']) && is_array($json['custom_instructions'])) {
81+
$customInstructions = [];
82+
foreach ($json['custom_instructions'] as $instruction) {
83+
$customInstructions[] = CustomInstruction::fromJson($instruction);
84+
}
85+
}
86+
87+
return new StyleRuleInfo(
88+
$json['style_id'],
89+
$json['name'],
90+
new DateTime($json['creation_time']),
91+
new DateTime($json['updated_time']),
92+
$json['language'],
93+
$json['version'],
94+
$configuredRules,
95+
$customInstructions
96+
);
97+
}
98+
99+
/**
100+
* @throws InvalidContentException
101+
*/
102+
public static function parseList(string $content): array
103+
{
104+
try {
105+
$decoded = json_decode($content, true, 512, \JSON_THROW_ON_ERROR);
106+
} catch (JsonException $exception) {
107+
throw new InvalidContentException($exception);
108+
}
109+
110+
$result = [];
111+
$styleRules = $decoded['style_rules'] ?? [];
112+
foreach ($styleRules as $object) {
113+
$result[] = self::fromJson($object);
114+
}
115+
return $result;
116+
}
117+
118+
public function __toString(): string
119+
{
120+
return "StyleRule \"{$this->name}\" ({$this->styleId})";
121+
}
122+
}

src/TranslateTextOptions.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,10 @@ class TranslateTextOptions
8686
* Values must be of string type.
8787
*/
8888
public const EXTRA_BODY_PARAMETERS = 'extra_body_parameters';
89+
90+
/** Set to string containing a style rule ID to use the style rule for translation.
91+
* Can also be set to a StyleRuleInfo as returned by getAllStyleRules.
92+
* @see \DeepL\DeepLClient::getAllStyleRules()
93+
*/
94+
public const STYLE_ID = 'style_id';
8995
}

src/Translator.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,16 @@ private function validateAndAppendTextOptions(array &$params, ?array $options):
693693
$params[TranslateTextOptions::IGNORE_TAGS] =
694694
$this->joinTagList($options[TranslateTextOptions::IGNORE_TAGS]);
695695
}
696+
if (isset($options[TranslateTextOptions::STYLE_ID])) {
697+
$styleRule = $options[TranslateTextOptions::STYLE_ID];
698+
if (is_string($styleRule)) {
699+
$params['style_id'] = $styleRule;
700+
} elseif ($styleRule instanceof StyleRuleInfo) {
701+
$params['style_id'] = $styleRule->styleId;
702+
} else {
703+
throw new DeepLException('style_id must be a string or StyleRuleInfo object');
704+
}
705+
}
696706
$this->applyExtraBodyParameters(
697707
$params,
698708
$options[TranslateTextOptions::EXTRA_BODY_PARAMETERS] ?? null

0 commit comments

Comments
 (0)