From 8bffaf6f57ccd8da7023192268e511af378f6d59 Mon Sep 17 00:00:00 2001 From: stromek Date: Fri, 14 Aug 2026 15:04:31 +0200 Subject: [PATCH] Add language option to ConfOptions The widget UI language could only be set through the snippet() parameter, which lands on the loader script as data-lang and is therefore fixed for the lifetime of the page. Theme, the other presentation setting, has always been a conf key. Language now works the same way, so integrators can switch it at runtime instead of re-rendering the page. The snippet() parameter stays supported as the initial value; the conf value wins when both are given. The constructor argument is appended last so positional callers keep working. --- CHANGELOG.md | 4 ++++ README.md | 7 ++++++- src/Options/ConfOptions.php | 11 +++++++++++ src/SnippetClient.php | 2 ++ tests/Options/ConfOptionsTest.php | 14 ++++++++++++++ tests/SnippetClientTest.php | 6 ++++++ 6 files changed, 43 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb29d56..171622a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [0.5.0] - 2026-08-14 +### Added +- `language` option on `ConfOptions` — sets the widget UI language through `conf()`, mirroring `theme`. Values: `null` (follows the browser, falling back to English), `en`, `cs`, `sk`. Unlike the `snippet()` parameter it can be changed at runtime; when both are given, the conf value wins + ## [0.4.0] - 2026-08-07 ### Added - `entityResolve` callback option on `ConfOptions` — resolves business-entity detail for the message editor's chip hover-card diff --git a/README.md b/README.md index ef55b2d..08f598b 100644 --- a/README.md +++ b/README.md @@ -284,11 +284,16 @@ See the full list of parameters in [`src/Options/ConfOptions.php`](src/Options/C | `pageCSSPath` | `?string` | CSS file URL injected into the snippet iframe. | | `notificationElementTargetElement` | `?string` | JS expression returning the target DOM element. | | `notificationElementPosition` | `?int` | Icon position: 1=top-left, 2=top-right, 3=bottom-right, 4=bottom-left. | +| `language` | `?string` | UI language of the app. Values: `null` (follows the browser, falling back to English), `en`, `cs`, `sk`. | | `theme` | `?string` | Light/dark mode for the app. Values: `null` (follows browser preference), `stromcom-light`, `stromcom-dark`. | | `entityResolve` | `?string` | JS callback resolving business-entity detail (order, ticket…) for the message editor's chip hover-card. Receives `{type, id}`, returns (or resolves to) `{title, url?, fields: [{label, value}]}`. | ### UI language -Pass a language code to `snippet()` to force the widget UI language (`cs`, `en`, `sk`…). When omitted, the widget detects it from the browser, falling back to English. +Set the language on `ConfOptions`, the same way as the theme. When omitted, the widget detects it from the browser, falling back to English. +```php +echo $client->conf(new ConfOptions(language: 'cs'))->getHTML(); +``` +`snippet()` also takes a language code, which sets the initial value before `conf()` runs. Use it when the language is known at page render and you want the widget to boot into it without waiting for `conf()`; `ConfOptions::$language` wins whenever both are given. ```php echo $client->snippet('cs')->getHTML(); ``` diff --git a/src/Options/ConfOptions.php b/src/Options/ConfOptions.php index 27a141a..0ecdb54 100644 --- a/src/Options/ConfOptions.php +++ b/src/Options/ConfOptions.php @@ -45,6 +45,9 @@ class ConfOptions extends SnippetOptions { #[Docs('Callback invoked after the notification element is rendered', null, true, 'Function|null')] private ?string $notificationElementAfterRender = null; + #[Docs('UI language of the app. Null follows the browser, falling back to English. Available: en, cs, sk', 'cs', true)] + private ?string $language = null; + #[Docs('Theme name applied to the host page via data-theme on . Available: stromcom-default, stromcom-dark', 'stromcom-dark', true)] private ?string $theme = null; @@ -67,6 +70,9 @@ public function __construct( ?string $homeBeforeRender = null, ?string $theme = null, ?string $entityResolve = null, + // Appended last on purpose — inserting it next to $theme would shift the + // positional arguments of existing callers. + ?string $language = null, ) { $this->notificationRenderer = $notificationRenderer; $this->onNotification = $onNotification; @@ -80,6 +86,7 @@ public function __construct( $this->notificationElementBeforeRender = $notificationElementBeforeRender; $this->notificationElementAfterRender = $notificationElementAfterRender; $this->homeBeforeRender = $homeBeforeRender; + $this->language = $language; $this->theme = $theme; $this->entityResolve = $entityResolve; } @@ -157,6 +164,10 @@ public function renderNotificationElementAfterRender(): ?JsValue { return $this->wrapJsValue($this->notificationElementAfterRender); } + public function getLanguage(): ?string { + return $this->language; + } + public function getTheme(): ?string { return $this->theme; } diff --git a/src/SnippetClient.php b/src/SnippetClient.php index 1541f75..a8af7d1 100644 --- a/src/SnippetClient.php +++ b/src/SnippetClient.php @@ -61,6 +61,8 @@ public function csp(): CspPolicy { * * @param string|null $language UI language (e.g. "cs", "en", "sk"). Null (default) lets the * widget detect it from the browser, falling back to English. + * This is the initial value only — `ConfOptions::$language` + * overrides it and can be changed later at runtime. * * @throws SnippetGenerationException */ diff --git a/tests/Options/ConfOptionsTest.php b/tests/Options/ConfOptionsTest.php index ed9f7fc..7c685b4 100644 --- a/tests/Options/ConfOptionsTest.php +++ b/tests/Options/ConfOptionsTest.php @@ -104,6 +104,20 @@ public function entity_resolve_null_renders_as_null(): void { $this->assertNull($options->renderEntityResolve()); } + #[Test] + public function language_is_included_when_set(): void { + $options = new ConfOptions(language: 'cs'); + $result = $options->getOptions(); + + $this->assertArrayHasKey('language', $result); + $this->assertSame('cs', $result['language']); + } + + #[Test] + public function language_is_not_included_when_null(): void { + $this->assertArrayNotHasKey('language', (new ConfOptions())->getOptions()); + } + #[Test] public function get_options_with_docs_returns_all_property_schemas(): void { $schema = ConfOptions::getOptionsWithDocs(); diff --git a/tests/SnippetClientTest.php b/tests/SnippetClientTest.php index d5b1785..9ea1a98 100644 --- a/tests/SnippetClientTest.php +++ b/tests/SnippetClientTest.php @@ -80,6 +80,12 @@ public function conf_output_contains_conf_call(): void { $this->assertStringContainsString('stromCom.conf(', $code); } + #[Test] + public function conf_output_contains_language(): void { + $code = $this->client->conf(new ConfOptions(language: 'cs'))->getCode(); + $this->assertStringContainsString('"language": "cs"', $code); + } + #[Test] public function conf_output_with_docs_contains_on_load(): void { $code = $this->client->conf(new ConfOptions(), true)->getCode();