Skip to content

feat: add LibreTranslate + DeepL translation providers#649

Merged
rainxchzed merged 4 commits into
mainfrom
feat/644-libretranslate-deepl
May 20, 2026
Merged

feat: add LibreTranslate + DeepL translation providers#649
rainxchzed merged 4 commits into
mainfrom
feat/644-libretranslate-deepl

Conversation

@rainxchzed
Copy link
Copy Markdown
Member

@rainxchzed rainxchzed commented May 20, 2026

Summary

Adds two privacy-respecting translation providers per #644:

  • LibreTranslate — user supplies instance URL (self-host = best privacy). Optional API key. Public mirrors come and go, so no defaults baked in.
  • DeepL — user supplies auth key. Free tier (:fx suffix) routes to api-free.deepl.com; Pro routes to api.deepl.com. Free tier may use submitted text to train models — disclaimer surfaced in UI.

Architecture

Follows the existing Google/Youdao pattern:

  • TranslationProvider enum gains LIBRE_TRANSLATE + DEEPL
  • LibreTranslator + DeeplTranslator implement Translator
  • TweaksRepository gains KSafe-encrypted prefs (libre_translate_base_url, libre_translate_api_key, deepl_auth_key)
  • TranslationRepositoryImpl.resolveTranslator() routes to new providers
  • Tweaks UI gains 2 credential forms with privacy disclaimers

Test plan

  • Tweaks → Translation → tap LibreTranslate chip → form expands → paste URL → Save → translate a README → verify hit lands on user's instance
  • Tweaks → Translation → tap DeepL chip → form expands → paste :fx key → Save → translate → verify free endpoint hit
  • Paste non-:fx key → verify pro endpoint hit
  • Empty creds → translation triggers TranslationProviderNotConfiguredException surfaced in UI

Closes #644

Summary by CodeRabbit

  • New Features

    • Added LibreTranslate, DeepL, and Microsoft translation providers with persistent credentials, provider selection, and LibreTranslate default fallback when URL is blank.
    • LibreTranslate supports a configurable base URL and optional API key; DeepL uses an auth key; Microsoft uses key + region. Deepl selection only activates when a key is present.
  • UI Changes

    • New settings forms to enter/save credentials, key show/hide toggles, and provider-specific save confirmations.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

Adds LibreTranslate, DeepL, and Microsoft translators; extends domain enum and TweaksRepository contract; persists Libre/DeepL credentials in KSafe; wires translators in TranslationRepositoryImpl with a default Libre URL; and adds ViewModel, UI forms, events, and strings to manage credentials and provider selection.

Changes

Translation Provider Integration

Layer / File(s) Summary
Domain model and repository contracts
core/domain/src/commonMain/kotlin/.../TranslationProvider.kt, core/domain/src/commonMain/kotlin/.../TweaksRepository.kt
TranslationProvider gains LIBRE_TRANSLATE and DEEPL; TweaksRepository adds Flow getters and suspend setters for LibreTranslate base URL/API key, DeepL auth key, and Microsoft key/region.
Data persistence implementation
core/data/src/commonMain/kotlin/.../TweaksRepositoryImpl.kt
Implements persistence for LibreTranslate base URL, LibreTranslate API key, and DeepL auth key in KSafe; getters wait for migration, setters trim input and delete when empty; adds companion key constants.
Translator implementations and wiring
feature/details/data/src/commonMain/kotlin/.../LibreTranslator.kt, .../DeeplTranslator.kt, .../MicrosoftTranslator.kt, feature/details/data/.../TranslationRepositoryImpl.kt
Adds LibreTranslator, DeeplTranslator, and MicrosoftTranslator with language-code mapping, HTTP requests, JSON parsing and error handling; TranslationRepositoryImpl.resolveTranslator() constructs translators using persisted credentials and a default Libre URL fallback.
Presentation: state, ViewModel, UI and strings
feature/tweaks/presentation/src/commonMain/kotlin/.../TweaksAction.kt, .../TweaksEvent.kt, .../TweaksState.kt, .../TweaksViewModel.kt, feature/tweaks/presentation/.../Translation.kt, core/presentation/.../strings.xml, .../TweaksRoot.kt
Adds actions/events/state for Libre/DeepL/Microsoft credentials and visibility; ViewModel hydrates and persists values, updates provider-selection/save logic, emits saved events; adds LibreTranslate credentials form and localized strings; snackbars show on save.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰
I nibble keys and URLs with care,
Libre hops in and DeepL joins the lair.
Settings tucked away where secrets sleep,
Translators hum translations deep.
A little rabbit guards what you keep.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.86% 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 accurately and concisely describes the primary feature added: LibreTranslate and DeepL translation providers.
Linked Issues check ✅ Passed The PR implements two privacy-respecting translation providers (LibreTranslate and DeepL) from the suggestions in #644, providing user-controlled alternatives to existing privacy-concerning options.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing LibreTranslate and DeepL providers, including MicrosoftTranslator support that extends the translation framework consistently.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/644-libretranslate-deepl

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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)
core/presentation/src/commonMain/composeResources/values/strings.xml (1)

904-905: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the provider description to reflect all available providers.

Line 904 still describes only Google/Youdao, which is now outdated after adding LibreTranslate and DeepL.

Suggested text update
-    <string name="translation_provider_description">Google works globally without configuration. Youdao works from mainland China but requires API credentials from Youdao's developer portal.</string>
+    <string name="translation_provider_description">Google works globally without configuration. Youdao requires API credentials from Youdao's developer portal. LibreTranslate supports self-hosted instances for stronger privacy control. DeepL requires an auth key (Free and Pro tiers use different endpoints automatically).</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 `@core/presentation/src/commonMain/composeResources/values/strings.xml` around
lines 904 - 905, The string resource translation_provider_description is
outdated (mentions only Google and Youdao); update its text to include all
current providers (Google, Youdao, LibreTranslate, DeepL) and brief notes about
availability/requirements (e.g., Google — global, Youdao — mainland China with
API credentials, LibreTranslate — self-hostable/public instances, DeepL —
requires API key and may have regional limitations) so the new description
accurately reflects all providers; locate and edit the value of
translation_provider_description (and adjust translation_provider_google if
needed) in the strings.xml entry.
🤖 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
`@feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/DeeplTranslator.kt`:
- Line 65: The DeeplTranslator translation extraction currently uses
first["text"]?.jsonPrimitive?.content.orEmpty() which silently returns an empty
string when the required "text" field is missing; change this to treat a missing
or non-primitive "text" as an API error by validating the presence and type of
first["text"] and throwing the same kind of exception used elsewhere in this
class (e.g., the existing API error handling at the checks around lines 59 and
64) instead of returning an empty string—update the code that reads translation
(the variable named translation and the access first["text"]) to throw a
descriptive exception when the field is absent or invalid so failures fail fast.

In
`@feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/LibreTranslator.kt`:
- Line 53: The assignment to translation in LibreTranslator currently uses
root["translatedText"]?.jsonPrimitive?.content.orEmpty() which silently returns
an empty string when the field is missing; change this to fail-fast by checking
root["translatedText"] and throwing an exception (similar to the existing error
handling for "error" responses) if the field is absent or not a primitive
string. Locate the LibreTranslator function where translation is computed
(reference symbol: translation and root["translatedText"]) and replace the
orEmpty() usage with a null-check that throws a descriptive exception (e.g.,
IllegalStateException or a custom error) so missing translatedText is surfaced
immediately.

In
`@feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Translation.kt`:
- Line 467: The placeholder string in Translation.kt is hardcoded as
Text("https://translate.example.com"); replace this with a localized resource by
adding a string resource named translation_libre_base_url_placeholder (value
"https://translate.example.com") and use stringResource(...) inside the
placeholder lambda (i.e., change Text("...") to
Text(stringResource(R.string.translation_libre_base_url_placeholder))) and add
the necessary import for stringResource; this ensures the LibreTranslate URL
placeholder is translatable.

---

Outside diff comments:
In `@core/presentation/src/commonMain/composeResources/values/strings.xml`:
- Around line 904-905: The string resource translation_provider_description is
outdated (mentions only Google and Youdao); update its text to include all
current providers (Google, Youdao, LibreTranslate, DeepL) and brief notes about
availability/requirements (e.g., Google — global, Youdao — mainland China with
API credentials, LibreTranslate — self-hostable/public instances, DeepL —
requires API key and may have regional limitations) so the new description
accurately reflects all providers; locate and edit the value of
translation_provider_description (and adjust translation_provider_google if
needed) in the strings.xml entry.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4d724702-e12a-4e14-b4b6-6e561b6abb68

📥 Commits

Reviewing files that changed from the base of the PR and between 6bc9a91 and 08798d6.

📒 Files selected for processing (13)
  • core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt
  • core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/TranslationProvider.kt
  • core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/TweaksRepository.kt
  • core/presentation/src/commonMain/composeResources/values/strings.xml
  • feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/TranslationRepositoryImpl.kt
  • feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/DeeplTranslator.kt
  • feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/LibreTranslator.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksAction.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksEvent.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksRoot.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksState.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Translation.kt

value = state.libreTranslateBaseUrl,
onValueChange = { onAction(TweaksAction.OnLibreTranslateBaseUrlChanged(it)) },
label = { Text(stringResource(Res.string.translation_libre_base_url)) },
placeholder = { Text("https://translate.example.com") },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize the LibreTranslate URL placeholder.

This placeholder is hardcoded and won’t be translatable.

Suggested fix
-            placeholder = { Text("https://translate.example.com") },
+            placeholder = { Text(stringResource(Res.string.translation_libre_base_url_placeholder)) },

Add a string resource:

<string name="translation_libre_base_url_placeholder">https://translate.example.com</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
`@feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Translation.kt`
at line 467, The placeholder string in Translation.kt is hardcoded as
Text("https://translate.example.com"); replace this with a localized resource by
adding a string resource named translation_libre_base_url_placeholder (value
"https://translate.example.com") and use stringResource(...) inside the
placeholder lambda (i.e., change Text("...") to
Text(stringResource(R.string.translation_libre_base_url_placeholder))) and add
the necessary import for stringResource; this ensures the LibreTranslate URL
placeholder is translatable.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 20, 2026

Greptile Summary

Adds LibreTranslate, DeepL, and Microsoft Translator as new translation providers, following the existing Google/Youdao architecture (enum entry → Translator implementation → resolveTranslator() routing → Tweaks credential form). All three providers address the issues raised in a previous round: HTTP status is checked before JSON parsing, DeepL's empty-translations case surfaces the error message, and LibreTranslate uses separate source/target mappers.

  • Three new Translator implementations with per-provider language-code normalisation and defensive error paths; TranslationRepositoryImpl routes to them and supplies a Disroot fallback for blank LibreTranslate URLs.
  • TweaksRepository (interface + impl) gains five new KSafe-backed prefs; TweaksViewModel adds observation coroutines and save handlers that auto-activate the provider when credentials are first committed.
  • Tweaks UI adds AnimatedVisibility-gated credential forms with key-visibility toggles and provider-specific privacy disclaimers.

Confidence Score: 5/5

Safe to merge; all three translators are well-guarded and the credential storage follows the existing KSafe pattern

The previous round's response-parsing and language-mapping bugs have all been addressed. The two remaining findings are non-blocking: one is a dead condition in the LibreTranslate shouldActivate expression that never causes wrong behavior, and the other is a language-mapping default that may surprise non-American English users but does not break functionality.

DeeplTranslator.kt (en → EN-US mapping) and TweaksViewModel.kt (dead branch in shouldActivate)

Important Files Changed

Filename Overview
feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/DeeplTranslator.kt New DeepL translator with correct HTTP status guard, empty-translations check, and tier routing; en unconditionally maps to EN-US instead of EN-GB
feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/LibreTranslator.kt New LibreTranslate translator with correct HTTP status guard, separate target/source language mappers, and graceful JSON error handling
feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/MicrosoftTranslator.kt New Microsoft Translator implementation using global endpoint + region header pattern; handles JSON error envelopes and malformed responses correctly
feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt Adds credential observation, provider selection gating, and save handlers for 3 new providers; LibreTranslate shouldActivate contains a dead branch because the chip never enters draft state
feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/TranslationRepositoryImpl.kt Routes three new providers in resolveTranslator(); applies Disroot default for blank LibreTranslate URL following the existing lazy-resolver pattern
core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt Adds five new KSafe-backed credential getters/setters following the established trim-then-delete-or-put pattern
feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Translation.kt Adds AnimatedVisibility-gated credential forms for LibreTranslate, DeepL, and Microsoft; privacy disclaimers and key-visibility toggles match the existing Youdao pattern
core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/TranslationProvider.kt Adds LIBRE_TRANSLATE, DEEPL, and MICROSOFT enum entries; no logic changes
core/presentation/src/commonMain/composeResources/values/strings.xml Adds 15 new string resources for all three providers including help text, field labels, save confirmations, and external link labels

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[resolveTranslator] --> B{TranslationProvider}
    B --> C[GOOGLE → GoogleTranslator]
    B --> D[YOUDAO → YoudaoTranslator]
    B --> E[LIBRE_TRANSLATE]
    B --> F[DEEPL → DeeplTranslator]
    B --> G[MICROSOFT → MicrosoftTranslator]

    E --> E1{baseUrl blank?}
    E1 -- yes --> E2[use LIBRE_TRANSLATE_DEFAULT_URL]
    E1 -- no --> E3[use user-configured URL]
    E2 --> E4[LibreTranslator]
    E3 --> E4

    F --> F1{authKey ends with :fx?}
    F1 -- yes --> F2[api-free.deepl.com]
    F1 -- no --> F3[api.deepl.com]
    F2 --> F4[translate]
    F3 --> F4

    G --> G1{subscriptionRegion blank or global?}
    G1 -- yes --> G2[No region header]
    G1 -- no --> G3[Add Ocp-Apim-Subscription-Region header]
    G2 --> G4[api.cognitive.microsofttranslator.com]
    G3 --> G4
Loading

Fix All in Claude Code

Reviews (4): Last reviewed commit: "cr: guard HTTP status + surface error me..." | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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
`@feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt`:
- Around line 969-978: The code currently commits
TranslationProvider.LIBRE_TRANSLATE immediately; change it to require either a
non-empty user URL (draftTranslationProvider) or an explicit user confirmation
before calling tweaksRepository.setTranslationProvider. Instead of directly
clearing draft and launching the repository update in the
TranslationProvider.LIBRE_TRANSLATE branch, update the draft state to preserve
any user-entered URL via _state.update { it.copy(draftTranslationProvider = /*
keep or set value */) }, send an event (e.g.,
TweaksEvent.RequestLibreTranslateConfirmation) with _events.send to trigger a
confirmation dialog, and only perform
tweaksRepository.setTranslationProvider(...) and send
TweaksEvent.OnTranslationProviderSaved from the confirmation handler (not here)
once the user either confirms “use public mirror” or provides a non-empty URL.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a63ba7b3-dda8-44b2-9dea-60810d706d0f

📥 Commits

Reviewing files that changed from the base of the PR and between 08798d6 and 3ea4b91.

📒 Files selected for processing (4)
  • core/presentation/src/commonMain/composeResources/values/strings.xml
  • feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/TranslationRepositoryImpl.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Translation.kt
✅ Files skipped from review due to trivial changes (1)
  • core/presentation/src/commonMain/composeResources/values/strings.xml

Comment on lines +969 to +978
TranslationProvider.LIBRE_TRANSLATE -> {
// No gating — repository falls back to the
// public Disroot mirror when no URL configured,
// so first-tap "just works" without going
// through a config dialog.
_state.update { it.copy(draftTranslationProvider = null) }
viewModelScope.launch {
tweaksRepository.setTranslationProvider(action.provider)
_events.send(TweaksEvent.OnTranslationProviderSaved)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Require explicit consent/config before activating LibreTranslate.

This branch commits LIBRE_TRANSLATE immediately, which can route user text to the public mirror without explicit confirmation of endpoint choice. Please gate activation behind either a non-empty user-provided URL or an explicit “use public mirror” confirmation step.

🤖 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
`@feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt`
around lines 969 - 978, The code currently commits
TranslationProvider.LIBRE_TRANSLATE immediately; change it to require either a
non-empty user URL (draftTranslationProvider) or an explicit user confirmation
before calling tweaksRepository.setTranslationProvider. Instead of directly
clearing draft and launching the repository update in the
TranslationProvider.LIBRE_TRANSLATE branch, update the draft state to preserve
any user-entered URL via _state.update { it.copy(draftTranslationProvider = /*
keep or set value */) }, send an event (e.g.,
TweaksEvent.RequestLibreTranslateConfirmation) with _events.send to trigger a
confirmation dialog, and only perform
tweaksRepository.setTranslationProvider(...) and send
TweaksEvent.OnTranslationProviderSaved from the confirmation handler (not here)
once the user either confirms “use public mirror” or provides a non-empty URL.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/TranslationRepositoryImpl.kt (1)

220-223: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove implicit LibreTranslate public-mirror fallback.

Line 222 falls back to a public endpoint (Line 323) when URL is unset, which can send user text to a third party without explicit opt-in. For this flow, missing URL should be treated as not configured.

Suggested fix
+import zed.rainxch.details.data.translation.TranslationProviderNotConfiguredException
@@
             TranslationProvider.LIBRE_TRANSLATE -> {
                 val configured = tweaksRepository.getLibreTranslateBaseUrl().first()
-                val baseUrl = configured.takeIf { it.isNotBlank() } ?: LIBRE_TRANSLATE_DEFAULT_URL
+                val baseUrl = configured.trim().takeIf { it.isNotEmpty() }
+                    ?: throw TranslationProviderNotConfiguredException(
+                        "LibreTranslate instance URL not configured",
+                    )
                 val apiKey = tweaksRepository.getLibreTranslateApiKey().first().takeIf { it.isNotBlank() }
                 LibreTranslator(
                     httpClient = { httpClient },
                     json = json,
                     baseUrl = baseUrl,
                     apiKey = apiKey,
                 )
             }
@@
-        private const val LIBRE_TRANSLATE_DEFAULT_URL = "https://translate.disroot.org"

Also applies to: 319-324

🤖 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
`@feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/TranslationRepositoryImpl.kt`
around lines 220 - 223, The code currently falls back to
LIBRE_TRANSLATE_DEFAULT_URL when tweaksRepository.getLibreTranslateBaseUrl() is
blank (in TranslationRepositoryImpl where TranslationProvider.LIBRE_TRANSLATE is
handled), which sends text to a public mirror; remove that implicit fallback by
making baseUrl = configured.takeIf { it.isNotBlank() } (i.e. null when unset)
and update the downstream logic (the LibreTranslate request path in
TranslationRepositoryImpl) to treat a null/blank baseUrl as "not configured"
(return an error/skip provider) rather than using LIBRE_TRANSLATE_DEFAULT_URL;
apply the same change to the other LibreTranslate handling block that uses
LIBRE_TRANSLATE_DEFAULT_URL.
🤖 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
`@feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/MicrosoftTranslator.kt`:
- Around line 72-79: The code in MicrosoftTranslator that builds the
`translation` value currently uses `.orEmpty()` which masks missing or malformed
responses; change it to fail-fast by replacing the `.orEmpty()` with a
null-check that throws a clear exception (e.g., IllegalStateException or a
domain-specific exception) when the chain from
`first["translations"]?.jsonArray?.firstOrNull()?.jsonObject?.get("text")?.jsonPrimitive?.content`
is null or blank; update the assignment to `translation` in MicrosoftTranslator
so missing translation text throws with a descriptive message instead of
returning an empty string.

---

Outside diff comments:
In
`@feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/TranslationRepositoryImpl.kt`:
- Around line 220-223: The code currently falls back to
LIBRE_TRANSLATE_DEFAULT_URL when tweaksRepository.getLibreTranslateBaseUrl() is
blank (in TranslationRepositoryImpl where TranslationProvider.LIBRE_TRANSLATE is
handled), which sends text to a public mirror; remove that implicit fallback by
making baseUrl = configured.takeIf { it.isNotBlank() } (i.e. null when unset)
and update the downstream logic (the LibreTranslate request path in
TranslationRepositoryImpl) to treat a null/blank baseUrl as "not configured"
(return an error/skip provider) rather than using LIBRE_TRANSLATE_DEFAULT_URL;
apply the same change to the other LibreTranslate handling block that uses
LIBRE_TRANSLATE_DEFAULT_URL.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac0ba816-9f60-446c-a203-5180b912bcf5

📥 Commits

Reviewing files that changed from the base of the PR and between 3ea4b91 and 57d862f.

📒 Files selected for processing (12)
  • core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt
  • core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/TranslationProvider.kt
  • core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/TweaksRepository.kt
  • core/presentation/src/commonMain/composeResources/values/strings.xml
  • feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/TranslationRepositoryImpl.kt
  • feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/translation/MicrosoftTranslator.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksAction.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksEvent.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksRoot.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksState.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
  • feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Translation.kt
✅ Files skipped from review due to trivial changes (1)
  • core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/TranslationProvider.kt

@rainxchzed rainxchzed merged commit cfaddcc into main May 20, 2026
1 check was pending
@rainxchzed rainxchzed deleted the feat/644-libretranslate-deepl branch May 20, 2026 05:24
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.

More privacy respecting translation options

1 participant