Skip to content

Issue/533 lang adapters#561

Open
armanist wants to merge 14 commits into
quantum-php:masterfrom
armanist:issue/533-lang-adapters
Open

Issue/533 lang adapters#561
armanist wants to merge 14 commits into
quantum-php:masterfrom
armanist:issue/533-lang-adapters

Conversation

@armanist

@armanist armanist commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Closes #533

Summary by CodeRabbit

  • New Features
    • Added adapter-based translation support for files, DeepL, and Google Translate.
    • Added shared caching and request handling for remote providers.
    • Enabled lazy loading for file-based translations.
  • Bug Fixes
    • Improved error handling for provider request failures and invalid responses.
  • Breaking Changes
    • Updated language configuration: lang.default now selects the adapter; locale fallback moved to lang.default_locale.
    • Removed the lang.enabled toggle and the public Lang::isEnabled() API.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@armanist, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 38 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 344b63f8-fb79-4fab-9ee5-6633b8c8266e

📥 Commits

Reviewing files that changed from the base of the PR and between 223e042 and bbe630c.

📒 Files selected for processing (9)
  • src/Lang/Adapters/DeepLAdapter.php
  • src/Lang/Adapters/GoogleTranslateAdapter.php
  • src/Lang/Enums/ExceptionMessages.php
  • src/Lang/Exceptions/LangException.php
  • src/Lang/Traits/RemoteAdapterTrait.php
  • tests/Unit/Lang/Adapters/DeepLAdapterTest.php
  • tests/Unit/Lang/Adapters/GoogleTranslateAdapterTest.php
  • tests/Unit/Lang/Exceptions/LangExceptionTest.php
  • tests/Unit/Storage/HttpClientTestCase.php
📝 Walkthrough

Walkthrough

Refactors the Lang package around configurable file and remote adapters, adding DeepL and Google Translate support, shared request/caching helpers, lazy file loading, and factory-based adapter resolution. Web request startup no longer performs automatic language loading.

Changes

Lang Adapter Architecture

Layer / File(s) Summary
Contracts, provider types, and configuration
src/Lang/Contracts/*, src/Lang/Enums/*, src/Lang/Exceptions/*, tests/_root/shared/config/lang.php, CHANGELOG.md
Defines adapter contracts, provider types, provider exceptions, expanded language configuration, and release documentation.
File adapter and Lang delegation
src/Lang/Adapters/FileAdapter.php, src/Lang/Lang.php, tests/Unit/Lang/Adapters/FileAdapterTest.php, tests/Unit/Lang/LangTest.php, tests/Unit/Lang/Helpers/LangHelperFunctionsTest.php
Moves local translation loading into FileAdapter, adds lazy loading, and delegates Lang operations to the configured adapter.
Remote adapters and shared caching
src/Lang/Traits/RemoteAdapterTrait.php, src/Lang/Adapters/DeepLAdapter.php, src/Lang/Adapters/GoogleTranslateAdapter.php, tests/Unit/Lang/Adapters/*, tests/Unit/Storage/HttpClientTestCase.php
Adds shared HTTP and cache behavior plus provider request, response validation, error, and caching tests.
Factory adapter resolution
src/Lang/Factories/LangFactory.php, tests/Unit/Lang/Factories/LangFactoryTest.php
Resolves configured adapters, creates and caches adapter-backed Lang instances, and rejects unsupported adapter names.
Web request language loading removal
src/App/Adapters/WebAppAdapter.php, src/App/Traits/WebAppTrait.php
Removes automatic language loading from web request startup.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LangFactory
  participant Lang
  participant GoogleTranslateAdapter
  participant Cache
  participant HttpClient
  LangFactory->>GoogleTranslateAdapter: create configured adapter
  LangFactory->>Lang: create adapter-backed Lang
  Lang->>GoogleTranslateAdapter: get translation
  GoogleTranslateAdapter->>Cache: check cached translation
  Cache-->>GoogleTranslateAdapter: cache hit or miss
  GoogleTranslateAdapter->>HttpClient: request provider translation
  HttpClient-->>GoogleTranslateAdapter: provider response
  GoogleTranslateAdapter->>Cache: cache translated text
  GoogleTranslateAdapter-->>Lang: return translated string
Loading

Possibly related PRs

Suggested labels: enhancement, refactoring, testing

Suggested reviewers: andrey-smaelov

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly points to the Lang adapter refactor.
Linked Issues check ✅ Passed The PR adds FileAdapter, DeepLAdapter, GoogleTranslateAdapter, factory/config resolution, caching, errors, docs, and tests as requested.
Out of Scope Changes check ✅ Passed The changes stay focused on the Lang adapter refactor, related config/docs, and test updates with no clear unrelated additions.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

codecov-commenter commented Jul 11, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 97.12919% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Lang/Traits/RemoteAdapterTrait.php 93.18% 3 Missing ⚠️
src/Lang/Adapters/FileAdapter.php 94.11% 1 Missing ⚠️
src/Lang/Enums/LangType.php 0.00% 1 Missing ⚠️
src/Lang/Factories/LangFactory.php 96.15% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5d2e64c17

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Lang/Adapters/GoogleTranslateAdapter.php Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/Lang/Lang.php (1)

61-64: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

getTranslation return type could be string instead of ?string.

The adapter's get() always returns string (either the translation or the key itself), so ?string is overly permissive. Tightening this to string would give callers a more precise contract.

🔧 Suggested refinement
-    public function getTranslation(string $key, array|string $params = null): ?string
+    public function getTranslation(string $key, array|string $params = null): string
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Lang/Lang.php` around lines 61 - 64, Update the return type of
Lang::getTranslation from ?string to string to match the adapter->get contract,
while preserving the existing delegation and parameters.
src/Lang/Adapters/FileAdapter.php (1)

88-100: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider using !== null instead of truthiness for $params check.

Line 96 uses return $params ? _message($message, $params) : $message;. A string param of '0' or an empty array [] would be falsy and skip interpolation. While [] correctly means "no params," the '0' edge case is surprising. Using $params !== null would be more precise and avoid the '0' pitfall.

♻️ Suggested refinement
-        return $params ? _message($message, $params) : $message;
+        return $params !== null ? _message($message, $params) : $message;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Lang/Adapters/FileAdapter.php` around lines 88 - 100, Update the
parameter check in FileAdapter::get to use an explicit null comparison, ensuring
a string value of "0" still reaches _message while null skips interpolation;
preserve the existing translation lookup and fallback behavior.
src/Lang/Adapters/GoogleTranslateAdapter.php (1)

65-81: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Move API key from URL query parameter to x-goog-api-key header.

The API key is currently embedded in the request URL via http_build_query($query), exposing it in proxy logs, access logs, and any HttpClient URL logging. Google Cloud APIs support the x-goog-api-key header as a more secure alternative.

🔒 Proposed fix
 $query = [
     'q' => $text,
     'target' => $this->lang,
     'format' => 'text',
-    'key' => $apiKey,
 ];
 
 if (!empty($this->params['source_locale'])) {
     $query['source'] = (string) $this->params['source_locale'];
 }
 
 $response = $this->sendRequest(
     (string) ($this->params['api_url'] ?? self::API_URL) . '?' . http_build_query($query, '', '&'),
     null,
-    [],
+    ['x-goog-api-key' => $apiKey],
     'POST'
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Lang/Adapters/GoogleTranslateAdapter.php` around lines 65 - 81, Update
the request construction in GoogleTranslateAdapter so the API key is removed
from the $query parameters and sent through the x-goog-api-key header passed to
sendRequest. Keep the remaining query parameters and POST behavior unchanged,
ensuring the key is no longer included in the URL generated by http_build_query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Lang/Exceptions/LangException.php`:
- Around line 46-54: Update LangException::providerRequestFailed so the
null-details branch does not add an extra period, while retaining the existing
colon-and-details formatting when details are provided. Ensure the
PROVIDER_REQUEST_FAILED template supplies the single final period in the
no-details message.
- Around line 46-54: Update the call to LangException::providerRequestFailed in
RemoteAdapterTrait::sendRequest to pass the adapter’s existing human-readable
provider label instead of static::class. Preserve the current details argument
and error behavior, matching the display names used by other language errors
such as DeepL and Google Translate.

In `@src/Lang/Factories/LangFactory.php`:
- Around line 61-79: Update LangFactory::resolve to validate the adapter after
applying the configured lang.default value, and throw a descriptive
LangException when it is missing or null before calling getAdapterClass or
indexing instances. Preserve the existing adapter resolution and instance
creation flow for valid adapter strings.

---

Nitpick comments:
In `@src/Lang/Adapters/FileAdapter.php`:
- Around line 88-100: Update the parameter check in FileAdapter::get to use an
explicit null comparison, ensuring a string value of "0" still reaches _message
while null skips interpolation; preserve the existing translation lookup and
fallback behavior.

In `@src/Lang/Adapters/GoogleTranslateAdapter.php`:
- Around line 65-81: Update the request construction in GoogleTranslateAdapter
so the API key is removed from the $query parameters and sent through the
x-goog-api-key header passed to sendRequest. Keep the remaining query parameters
and POST behavior unchanged, ensuring the key is no longer included in the URL
generated by http_build_query.

In `@src/Lang/Lang.php`:
- Around line 61-64: Update the return type of Lang::getTranslation from ?string
to string to match the adapter->get contract, while preserving the existing
delegation and parameters.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c94dd36-ca62-4aaa-bb26-d727f872ee03

📥 Commits

Reviewing files that changed from the base of the PR and between fc01492 and f5d2e64.

📒 Files selected for processing (21)
  • CHANGELOG.md
  • src/App/Adapters/WebAppAdapter.php
  • src/App/Traits/WebAppTrait.php
  • src/Lang/Adapters/DeepLAdapter.php
  • src/Lang/Adapters/FileAdapter.php
  • src/Lang/Adapters/GoogleTranslateAdapter.php
  • src/Lang/Contracts/LangAdapterInterface.php
  • src/Lang/Enums/ExceptionMessages.php
  • src/Lang/Enums/LangType.php
  • src/Lang/Exceptions/LangException.php
  • src/Lang/Factories/LangFactory.php
  • src/Lang/Lang.php
  • src/Lang/Traits/RemoteAdapterTrait.php
  • tests/Unit/Lang/Adapters/DeepLAdapterTest.php
  • tests/Unit/Lang/Adapters/FileAdapterTest.php
  • tests/Unit/Lang/Adapters/GoogleTranslateAdapterTest.php
  • tests/Unit/Lang/Factories/LangFactoryTest.php
  • tests/Unit/Lang/Helpers/LangHelperFunctionsTest.php
  • tests/Unit/Lang/LangTest.php
  • tests/Unit/Lang/TranslatorTest.php
  • tests/_root/shared/config/lang.php
💤 Files with no reviewable changes (4)
  • src/App/Adapters/WebAppAdapter.php
  • tests/Unit/Lang/TranslatorTest.php
  • tests/Unit/Lang/Helpers/LangHelperFunctionsTest.php
  • src/App/Traits/WebAppTrait.php

Comment thread src/Lang/Exceptions/LangException.php
Comment thread src/Lang/Factories/LangFactory.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Lang/Adapters/DeepLAdapter.php (1)

99-103: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Misleading exception for local json_encode failure.

buildPayload() throws LangException::invalidProviderResponse('DeepL') when json_encode fails, but this is a local payload encoding failure, not an invalid provider response. The resulting message ("The provider DeepL returned an invalid translation response") will mislead debugging. Consider a more accurate error such as a LangException with a message indicating payload encoding failure, or a generic RuntimeException.

The same pattern exists in GoogleTranslateAdapter::buildPayload() (line 103).

Proposed fix
         if ($payloadJson === false) {
-            throw LangException::invalidProviderResponse('DeepL');
+            throw new LangException('Failed to encode DeepL request payload: ' . json_last_error_msg());
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Lang/Adapters/DeepLAdapter.php` around lines 99 - 103, Update the
json_encode failure handling in buildPayload() for both DeepLAdapter and
GoogleTranslateAdapter so it throws an exception describing local payload
encoding failure instead of LangException::invalidProviderResponse('DeepL'). Use
an appropriate existing LangException factory or RuntimeException, and preserve
the current behavior for successful encoding.
🧹 Nitpick comments (1)
tests/Unit/Lang/LangTest.php (1)

54-61: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider renaming testLangFlushResetsTranslations to reflect actual behavior.

After flush(), FileAdapter::get() lazily reloads translations, so the assertion is identical before and after. The test would pass even if flush() were a no-op. A name like testLangFlushDoesNotBreakTranslations or adding an assertion that verifies the cache was actually cleared (e.g., via a spy or by checking reload count) would better communicate intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Unit/Lang/LangTest.php` around lines 54 - 61, The test name
testLangFlushResetsTranslations does not match its assertions, which only verify
translations remain available after flushing. Rename it to describe that flush
preserves translation access, such as testLangFlushDoesNotBreakTranslations,
without changing the test behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Lang/Adapters/DeepLAdapter.php`:
- Around line 69-76: Update DeepLAdapter’s sendRequest call to configure a
finite CURLOPT_TIMEOUT through the existing HttpClient setOpt() mechanism before
executing the request, using the adapter’s established timeout configuration or
constant if available. Ensure all DeepL requests have a bounded timeout instead
of hanging indefinitely.

In `@src/Lang/Adapters/GoogleTranslateAdapter.php`:
- Around line 100-104: Update the json_encode failure handling in
GoogleTranslateAdapter’s payload-building flow to throw the exception intended
for local payload encoding/serialization failures rather than
LangException::invalidProviderResponse('Google Translate'). Keep
provider-response validation errors separate and preserve the existing behavior
for successful encoding.

In `@tests/Unit/Storage/HttpClientTestCase.php`:
- Around line 18-19: Initialize the $data property in HttpClientTestCase to an
empty array instead of leaving it uninitialized, preserving getData() behavior
when setData() has not been called.

---

Outside diff comments:
In `@src/Lang/Adapters/DeepLAdapter.php`:
- Around line 99-103: Update the json_encode failure handling in buildPayload()
for both DeepLAdapter and GoogleTranslateAdapter so it throws an exception
describing local payload encoding failure instead of
LangException::invalidProviderResponse('DeepL'). Use an appropriate existing
LangException factory or RuntimeException, and preserve the current behavior for
successful encoding.

---

Nitpick comments:
In `@tests/Unit/Lang/LangTest.php`:
- Around line 54-61: The test name testLangFlushResetsTranslations does not
match its assertions, which only verify translations remain available after
flushing. Rename it to describe that flush preserves translation access, such as
testLangFlushDoesNotBreakTranslations, without changing the test behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6f54bc5a-bb45-45e8-93d7-59cf6aba566f

📥 Commits

Reviewing files that changed from the base of the PR and between f5d2e64 and 223e042.

📒 Files selected for processing (14)
  • src/Lang/Adapters/DeepLAdapter.php
  • src/Lang/Adapters/GoogleTranslateAdapter.php
  • src/Lang/Contracts/LangAdapterInterface.php
  • src/Lang/Enums/ExceptionMessages.php
  • src/Lang/Exceptions/LangException.php
  • src/Lang/Factories/LangFactory.php
  • src/Lang/Lang.php
  • tests/Unit/Lang/Adapters/DeepLAdapterTest.php
  • tests/Unit/Lang/Adapters/FileAdapterTest.php
  • tests/Unit/Lang/Adapters/GoogleTranslateAdapterTest.php
  • tests/Unit/Lang/Exceptions/LangExceptionTest.php
  • tests/Unit/Lang/Factories/LangFactoryTest.php
  • tests/Unit/Lang/LangTest.php
  • tests/Unit/Storage/HttpClientTestCase.php
💤 Files with no reviewable changes (2)
  • src/Lang/Contracts/LangAdapterInterface.php
  • src/Lang/Lang.php
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/Unit/Lang/Adapters/FileAdapterTest.php
  • tests/Unit/Lang/Adapters/GoogleTranslateAdapterTest.php
  • src/Lang/Factories/LangFactory.php
  • tests/Unit/Lang/Factories/LangFactoryTest.php
  • src/Lang/Enums/ExceptionMessages.php

Comment thread src/Lang/Adapters/DeepLAdapter.php
Comment thread src/Lang/Adapters/GoogleTranslateAdapter.php
Comment thread tests/Unit/Storage/HttpClientTestCase.php Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor Lang package to adapter-based architecture with FileAdapter, DeepL, and Google Translate support

2 participants