domain: add AppLanguage model and AppLanguages registry#435
domain: add AppLanguage model and AppLanguages registry#435rainxchzed merged 12 commits intomainfrom
Conversation
- Introduce `AppLanguage` data class to represent user-selectable UI languages with IETF BCP 47 tags and native-script display names. - Create `AppLanguages` registry containing the list of currently supported languages (English, Arabic, Bengali, Spanish, French, Hindi, Italian, Japanese, Korean, Polish, Russian, Turkish, and Simplified Chinese). - Add `findByTag` utility to retrieve language metadata by its tag.
- Create a new `Language.kt` component in the tweaks presentation module. - Implement `languageSection` for `LazyListScope` to display language-related settings. - Add `LanguagePickerCard` and `LanguageDropdown` components to allow users to switch between supported app languages or follow the system default. - Use `AppLanguages` model to populate the dropdown with native-script labels and selection indicators.
- Add "LANGUAGE" section header. - Add strings for language picker title, description, and system default option. - Include introductory text explaining the immediate application of language overrides.
- Introduce a new "LANGUAGE" section and related strings to support in-app language switching. - Add strings for language picker title, description, and an option to follow the system settings. - Include an introductory note explaining that language changes apply immediately without a restart. - Clarify that language settings affect the UI but not content fetched from GitHub. - Provide translations for Turkish, Italian, Simplified Chinese, Bengali, French, Russian, Japanese, Hindi, Korean, Spanish, and Polish.
- Add `getAppLanguage` and `setAppLanguage` to `TweaksRepository` and its implementation using DataStore. - Update `TweaksState` to include `selectedAppLanguage` as a BCP 47 tag. - Implement `OnAppLanguageSelected` action in `TweaksViewModel` to persist user language choice. - Add `OnAppLanguageChangeRequiresRestart` event to handle platforms where in-place language switching is not supported. - Ensure empty or blank language tags are treated as "unset" to follow the system locale.
- Add `setActiveLanguageTag` to `LocalizationManager` to allow overriding the process-wide JVM `Locale.getDefault()`.
- Implement `setActiveLanguageTag` in `AndroidLocalizationManager` and `DesktopLocalizationManager`, including logic to restore the system default locale.
- Update `MainActivity` on Android to:
- Apply the persisted language setting via `runBlocking` before `super.onCreate` to prevent locale flickering on startup.
- Observe runtime language changes from `TweaksRepository` and trigger `recreate()` to ensure all strings and `rememberSaveable` state are correctly updated.
- Add a new `languageSection` to the `SettingsSection` UI component.
- Add `language_restart_required` and `language_restart_action` strings for language change notifications. - Handle `OnAppLanguageChangeRequiresRestart` event in `TweaksRoot` by showing a snackbar that triggers a JVM exit on desktop platforms. - Update `Language` picker UI to use a tinted `surface` background for better visibility against its container. - Set the language dropdown menu background to `surfaceContainerHigh` to provide better visual contrast against the parent card.
- Add `language_restart_required` and `language_restart_action` strings for language change notifications. - Handle `OnAppLanguageChangeRequiresRestart` event in `TweaksRoot` by showing a snackbar that triggers a JVM exit on desktop platforms. - Update `Language` picker UI to use a tinted `surface` background for better visibility against its container. - Set the language dropdown menu background to `surfaceContainerHigh` to provide better visual contrast against the parent card.
…on Desktop - Introduce `restartAppAfterLanguageChange` expect/actual function to handle platform-specific restart logic. - Implement JVM-specific logic using `ProcessHandle` and `ProcessBuilder` to attempt a fresh relaunch of the app with original arguments before exiting. - Add a no-op implementation for Android, where language changes are already handled via `Activity.recreate()`. - Update `TweaksRoot` to invoke the new restart logic when the user performs the snackbar action.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThis PR implements runtime app language selection and localization. Users can override the UI language in Tweaks settings, with platform-specific restart handling for Android and JVM. Language preferences persist via TweaksRepository, LocalizationManager implementations apply selected languages, and localized strings for language UI are added across 13 languages. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant UI as Language Picker UI
participant VM as TweaksViewModel
participant Repo as TweaksRepository
participant LM as LocalizationManager
participant App as MainActivity/DesktopApp
User->>UI: Select language
UI->>VM: OnAppLanguageSelected(tag)
VM->>Repo: setAppLanguage(tag)
Repo->>Repo: Persist to DataStore
VM->>VM: Update selectedAppLanguage state
VM->>VM: Emit OnAppLanguageChangeRequiresRestart (non-Android)
alt Desktop
VM->>App: Show restart snackbar
User->>App: Tap restart action
App->>App: restartAppAfterLanguageChange()
App->>App: ProcessBuilder relaunch + exitProcess
else Android
VM->>Repo: Observe getAppLanguage() changes
Repo->>LM: setActiveLanguageTag(tag)
LM->>LM: Locale.setDefault(newLocale)
App->>App: recreate()
App->>App: Recompose with new Locale
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (3)
feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt (1)
754-769: Consider short-circuiting when selected tag equals the current persisted value.If the user taps the already-active language,
setAppLanguagewill rewrite the same tag and (on Desktop)OnAppLanguageChangeRequiresRestartwill still fire, producing a spurious "restart to apply" snackbar for a no-op change. Minor UX nit — guard with a comparison against_state.value.selectedAppLanguagebefore persisting/emitting.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt` around lines 754 - 769, When handling TweaksAction.OnAppLanguageSelected inside the viewModelScope.launch, short-circuit if the tapped tag equals the current persisted selection to avoid rewriting the same value and emitting a spurious restart prompt: compare action.tag against _state.value.selectedAppLanguage and only call tweaksRepository.setAppLanguage(action.tag) and _events.send(TweaksEvent.OnAppLanguageChangeRequiresRestart) (when getPlatform() != Platform.ANDROID) if they differ; keep the existing platform check and use the same symbols (TweaksAction.OnAppLanguageSelected, tweaksRepository.setAppLanguage, _state.value.selectedAppLanguage, _events.send, TweaksEvent.OnAppLanguageChangeRequiresRestart, getPlatform, Platform.ANDROID, viewModelScope.launch).core/data/src/commonMain/kotlin/zed/rainxch/core/data/services/LocalizationManager.kt (1)
14-26: Interface extension looks clean.The KDoc clearly spells out the null/blank-restore semantics and the composition-side ordering requirement. Matches the platform actuals in
AndroidLocalizationManagerandDesktopLocalizationManager.Note: the existing guideline "Localization must support 11 languages" is now superseded in practice —
AppLanguagesregisters 13. Consider updating the CLAUDE.md guideline to match so future reviews aren't confused.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/data/src/commonMain/kotlin/zed/rainxch/core/data/services/LocalizationManager.kt` around lines 14 - 26, Review notes approve the interface but request updating the project guideline to match runtime reality: change the CLAUDE.md language-support note from "11 languages" to reflect the 13 languages registered by AppLanguages. Locate the AppLanguages registration to confirm the exact list, then update the CLAUDE.md text and any examples to reference the 13 supported languages and, if present, adjust any enumerations or counts that reference "11" so they match the AppLanguages contents; no code changes to setActiveLanguageTag are required.core/presentation/src/commonMain/composeResources/values-it/strings-it.xml (1)
116-122: Minor: inconsistent casing within the language section.Section headers in the Italian file are uppercase (
ASPETTO,INFORMAZIONI,RETE) andsection_languagecorrectly usesLINGUA. Howeverlanguage_picker_title("Lingua dell'app") andlanguage_introstart with lowercase "Sovrascrivi" — that's consistent with other locales here, just double-check that the picker title matches the sentence-case convention used by other picker titles in this file (e.g., compare withtheme_color= "Colore del Tema" which uses title case). Not a blocker.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/presentation/src/commonMain/composeResources/values-it/strings-it.xml` around lines 116 - 122, The Italian strings have inconsistent casing: update the values for language_picker_title and language_intro to match the existing title-case convention used by other picker labels (see theme_color / "Colore del Tema") and ensure section_language remains "LINGUA"; specifically change the first letter/casing in language_picker_title and the initial word of language_intro so both use title-case/initial-capitalization consistent with theme_color and other picker titles (referencing the string names language_picker_title, language_intro, theme_color, and section_language to locate the entries).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.kt`:
- Around line 43-52: Bound the startup preference read so a stalled or failing
DataStore doesn't block before super.onCreate(): wrap the call inside
runBlocking with a short timeout and safe fallback and handle exceptions; e.g.
call tweaksRepository.getAppLanguage().first() inside a
withTimeout/withTimeoutOrNull and/or try/catch, fall back to a default language
tag (e.g. system default or a configured default) if the read times out or
throws, then call localizationManager.setActiveLanguageTag(tag) with that safe
tag; ensure super.onCreate() still runs even when the preference read fails.
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.kt`:
- Around line 15-16: The startup blocks on runBlocking {
getAppLanguage().first() } which can hang if DataStore stalls; wrap the
preference read in a timeout using withTimeoutOrNull and fall back to a safe
default. Replace the direct runBlocking call that invokes
getAppLanguage().first() with runBlocking { withTimeoutOrNull(<timeoutMs>) {
getAppLanguage().first() } ?: <defaultLanguage> }, add the
kotlinx.coroutines.withTimeoutOrNull import, and ensure the code uses the same
timeout constant or value pattern used elsewhere (e.g.,
SearchRepositoryImpl/HomeRepositoryImpl) and a known default language symbol so
deep-linking and window creation proceed if the read fails.
In
`@core/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.kt`:
- Around line 214-230: The repository is currently treating only blank
app-language values as unset, but it should also reject unsupported tags; update
getAppLanguage() and setAppLanguage(tag: String?) to validate against the known
AppLanguages set (use the AppLanguages lookup/enum) so unsupported tags are not
emitted or persisted: in getAppLanguage() change the map to return
prefs[APP_LANGUAGE_KEY]?.takeIf { it.isNotBlank() &&
AppLanguages.containsTag(it.trim()) } (or equivalent lookup), and in
setAppLanguage() normalize the tag then remove APP_LANGUAGE_KEY when the
normalized value is empty or not a valid AppLanguages tag, otherwise persist the
normalized value.
In `@core/presentation/src/commonMain/composeResources/values-es/strings-es.xml`:
- Around line 99-103: The string language_intro currently promises "Se aplica al
instante — no requiere reinicio" which conflicts with language_restart_required
shown elsewhere; update language_intro to a platform-neutral phrase that does
not assert "no restart" (e.g., remove the "no requiere reinicio" clause or
replace it with a neutral "Los cambios pueden requerir reinicio según la
plataforma") so it no longer contradicts language_restart_required; edit the
resource identified by name="language_intro" and ensure consistency with
name="language_restart_required" and name="language_picker_description".
In
`@core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml`:
- Around line 100-106: The two strings conflict: language_intro currently
promises "即时生效,无需重启。" while language_restart_required asks the user to restart;
update language_intro (and equivalent keys in other locale files: values/,
values-ru, values-pl, values-fr, values-zh-rCN, etc.) to a platform-aware or
softer sentence such as "大多数设备会立即生效;桌面端可能需要重启。" or create platform-specific
variants and use them where appropriate so language_intro and
language_restart_required no longer contradict each other; ensure you edit the
string named language_intro (and its locale counterparts) and keep
language_restart_required unchanged unless making matching wording adjustments.
In `@core/presentation/src/commonMain/composeResources/values/strings.xml`:
- Around line 120-124: Update the intro string to avoid asserting “no restart
needed”: change the value of language_intro to neutral wording that does not
promise immediate application across platforms (e.g., mention that changes may
apply immediately or may require restart), ensure language_restart_required
remains accurate, and propagate equivalent neutral translations in all localized
resource files so the desktop restart flow and mobile immediate-apply flow are
consistent; check strings language_picker_title, language_picker_description and
language_follow_system for any locale-specific phrasing that might contradict
the neutral intro and update those localized copies as needed.
---
Nitpick comments:
In
`@core/data/src/commonMain/kotlin/zed/rainxch/core/data/services/LocalizationManager.kt`:
- Around line 14-26: Review notes approve the interface but request updating the
project guideline to match runtime reality: change the CLAUDE.md
language-support note from "11 languages" to reflect the 13 languages registered
by AppLanguages. Locate the AppLanguages registration to confirm the exact list,
then update the CLAUDE.md text and any examples to reference the 13 supported
languages and, if present, adjust any enumerations or counts that reference "11"
so they match the AppLanguages contents; no code changes to setActiveLanguageTag
are required.
In `@core/presentation/src/commonMain/composeResources/values-it/strings-it.xml`:
- Around line 116-122: The Italian strings have inconsistent casing: update the
values for language_picker_title and language_intro to match the existing
title-case convention used by other picker labels (see theme_color / "Colore del
Tema") and ensure section_language remains "LINGUA"; specifically change the
first letter/casing in language_picker_title and the initial word of
language_intro so both use title-case/initial-capitalization consistent with
theme_color and other picker titles (referencing the string names
language_picker_title, language_intro, theme_color, and section_language to
locate the entries).
In
`@feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt`:
- Around line 754-769: When handling TweaksAction.OnAppLanguageSelected inside
the viewModelScope.launch, short-circuit if the tapped tag equals the current
persisted selection to avoid rewriting the same value and emitting a spurious
restart prompt: compare action.tag against _state.value.selectedAppLanguage and
only call tweaksRepository.setAppLanguage(action.tag) and
_events.send(TweaksEvent.OnAppLanguageChangeRequiresRestart) (when getPlatform()
!= Platform.ANDROID) if they differ; keep the existing platform check and use
the same symbols (TweaksAction.OnAppLanguageSelected,
tweaksRepository.setAppLanguage, _state.value.selectedAppLanguage, _events.send,
TweaksEvent.OnAppLanguageChangeRequiresRestart, getPlatform, Platform.ANDROID,
viewModelScope.launch).
🪄 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: 874e6070-81a0-4768-be6f-c7e5f4b29ba1
📒 Files selected for processing (31)
composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.ktcomposeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.ktcore/data/src/androidMain/kotlin/zed/rainxch/core/data/services/AndroidLocalizationManager.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/services/LocalizationManager.ktcore/data/src/jvmMain/kotlin/zed/rainxch/core/data/services/DesktopLocalizationManager.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/AppLanguage.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/repository/TweaksRepository.ktcore/presentation/src/commonMain/composeResources/values-ar/strings-ar.xmlcore/presentation/src/commonMain/composeResources/values-bn/strings-bn.xmlcore/presentation/src/commonMain/composeResources/values-es/strings-es.xmlcore/presentation/src/commonMain/composeResources/values-fr/strings-fr.xmlcore/presentation/src/commonMain/composeResources/values-hi/strings-hi.xmlcore/presentation/src/commonMain/composeResources/values-it/strings-it.xmlcore/presentation/src/commonMain/composeResources/values-ja/strings-ja.xmlcore/presentation/src/commonMain/composeResources/values-ko/strings-ko.xmlcore/presentation/src/commonMain/composeResources/values-pl/strings-pl.xmlcore/presentation/src/commonMain/composeResources/values-ru/strings-ru.xmlcore/presentation/src/commonMain/composeResources/values-tr/strings-tr.xmlcore/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xmlcore/presentation/src/commonMain/composeResources/values/strings.xmlfeature/tweaks/presentation/src/androidMain/kotlin/zed/rainxch/tweaks/presentation/RestartApp.android.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/RestartApp.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksAction.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksEvent.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksRoot.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksState.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Language.ktfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/SettingsSection.ktfeature/tweaks/presentation/src/jvmMain/kotlin/zed/rainxch/tweaks/presentation/RestartApp.jvm.kt
…on Desktop - Introduce `restartAppAfterLanguageChange` expect/actual function to handle platform-specific restart logic. - Implement JVM-specific logic using `ProcessHandle` and `ProcessBuilder` to attempt a fresh relaunch of the app with original arguments before exiting. - Add a no-op implementation for Android, where language changes are already handled via `Activity.recreate()`. - Update `TweaksRoot` to invoke the new restart logic when the user performs the snackbar action.
- Implement `CrashReporter` for JVM to log stdout/stderr to a session file and write detailed crash dumps on uncaught exceptions. - Add OS-specific log directory resolution for Windows, macOS, and Linux. - Wrap the initial language preference read in `runBlocking` with a 2-second timeout to prevent potential DataStore stalls from blocking app launch. - Initialize `CrashReporter` at the entry point to capture early initialization errors.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/CrashReporter.kt`:
- Around line 16-24: The current install() sets System.setOut/Err to
TeePrintStream writing all stdout/stderr into session.log (via File(logDir,
"session.log") and rotateIfLarge), which persists arbitrary output; change
install() so teeing is opt-in and protected: add a boolean/config flag (e.g.,
enableSessionTee or CrashReporter.config.enableTee) checked before creating the
PrintStream and calling System.setOut/System.setErr so crash dumps remain active
but general teeing is disabled by default, and if enabled apply
redaction/retention controls (invoke rotateIfLarge, limit file age/size, and
filter sensitive patterns before writing using TeePrintStream or a wrapper) so
only approved/filtered output is persisted, leaving crash dump paths unchanged.
- Around line 67-72: The rotateIfLarge function currently calls rotated.delete()
and file.renameTo() which can fail silently; update rotateIfLarge to check their
boolean return values and handle failures: if rotated.delete() fails, attempt to
delete via Files.deleteIfExists(Path) or create a uniquely-named temp rotated
file and fall back to truncating the original (open FileOutputStream(file,
false) to truncate to zero) so session.log cannot grow past
MAX_SESSION_LOG_BYTES; if file.renameTo(rotated) fails, attempt an atomic move
via Files.move(Path, Path, StandardCopyOption.ATOMIC_MOVE/REPLACE_EXISTING) or
again truncate the original, and log the error using your logger so failures are
visible. Ensure references to rotated ("session.1.log"), file, rotateIfLarge,
and MAX_SESSION_LOG_BYTES are used to locate where to apply these checks and
fallbacks.
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.kt`:
- Around line 63-69: The try/catch around withTimeoutOrNull currently catches
Throwable (suppressing fatal JVM errors); change the catch to catch Exception so
only non-fatal exceptions are handled. Locate the try block that calls
withTimeoutOrNull(LANGUAGE_PREF_READ_TIMEOUT_MS) {
tweaksRepo.getAppLanguage().first() } (in DesktopApp.kt) and replace "catch (_:
Throwable)" with "catch (_: Exception)" or equivalent, leaving the timeout
behaviour unchanged.
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/AppLanguage.kt`:
- Around line 14-19: Add the kotlinx.serialization annotation to the AppLanguage
data class: annotate the data class AppLanguage with `@Serializable` and add the
corresponding import from kotlinx.serialization.Serializable so the model is
serializable by Kotlinx Serialization.
🪄 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: b4a57a30-465c-47ae-afaa-b2b1264e41ed
📒 Files selected for processing (20)
CLAUDE.mdcomposeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.ktcomposeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/CrashReporter.ktcomposeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.ktcore/data/src/commonMain/kotlin/zed/rainxch/core/data/repository/TweaksRepositoryImpl.ktcore/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/AppLanguage.ktcore/presentation/src/commonMain/composeResources/values-ar/strings-ar.xmlcore/presentation/src/commonMain/composeResources/values-bn/strings-bn.xmlcore/presentation/src/commonMain/composeResources/values-es/strings-es.xmlcore/presentation/src/commonMain/composeResources/values-fr/strings-fr.xmlcore/presentation/src/commonMain/composeResources/values-hi/strings-hi.xmlcore/presentation/src/commonMain/composeResources/values-it/strings-it.xmlcore/presentation/src/commonMain/composeResources/values-ja/strings-ja.xmlcore/presentation/src/commonMain/composeResources/values-ko/strings-ko.xmlcore/presentation/src/commonMain/composeResources/values-pl/strings-pl.xmlcore/presentation/src/commonMain/composeResources/values-ru/strings-ru.xmlcore/presentation/src/commonMain/composeResources/values-tr/strings-tr.xmlcore/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xmlcore/presentation/src/commonMain/composeResources/values/strings.xmlfeature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
✅ Files skipped from review due to trivial changes (9)
- CLAUDE.md
- core/presentation/src/commonMain/composeResources/values-es/strings-es.xml
- core/presentation/src/commonMain/composeResources/values/strings.xml
- core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml
- core/presentation/src/commonMain/composeResources/values-ko/strings-ko.xml
- core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml
- core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml
- core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml
- core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml
🚧 Files skipped from review as they are similar to previous changes (7)
- feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/TweaksViewModel.kt
- core/presentation/src/commonMain/composeResources/values-ar/strings-ar.xml
- core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml
- core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml
- core/presentation/src/commonMain/composeResources/values-it/strings-it.xml
- composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.kt
- core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml
| fun install() { | ||
| val teed = | ||
| runCatching { | ||
| val file = File(logDir, "session.log") | ||
| rotateIfLarge(file) | ||
| PrintStream(FileOutputStream(file, true), true, Charsets.UTF_8) | ||
| .also { stream -> | ||
| System.setOut(TeePrintStream(System.out, stream)) | ||
| System.setErr(TeePrintStream(System.err, stream)) |
There was a problem hiding this comment.
Avoid persisting unrestricted stdout/stderr by default.
Line 21–24 writes every process log line to disk, including anything accidentally printed by dependencies or debug code. Add redaction/retention controls or make session teeing explicitly opt-in while keeping crash dumps enabled.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/CrashReporter.kt`
around lines 16 - 24, The current install() sets System.setOut/Err to
TeePrintStream writing all stdout/stderr into session.log (via File(logDir,
"session.log") and rotateIfLarge), which persists arbitrary output; change
install() so teeing is opt-in and protected: add a boolean/config flag (e.g.,
enableSessionTee or CrashReporter.config.enableTee) checked before creating the
PrintStream and calling System.setOut/System.setErr so crash dumps remain active
but general teeing is disabled by default, and if enabled apply
redaction/retention controls (invoke rotateIfLarge, limit file age/size, and
filter sensitive patterns before writing using TeePrintStream or a wrapper) so
only approved/filtered output is persisted, leaving crash dump paths unchanged.
| private fun rotateIfLarge(file: File) { | ||
| if (!file.exists() || file.length() <= MAX_SESSION_LOG_BYTES) return | ||
| val rotated = File(file.parentFile, "session.1.log") | ||
| if (rotated.exists()) rotated.delete() | ||
| file.renameTo(rotated) | ||
| } |
There was a problem hiding this comment.
Handle failed rotation so session.log cannot grow unbounded.
delete() and renameTo() can fail silently. If rotation fails, the next FileOutputStream(..., true) keeps appending beyond MAX_SESSION_LOG_BYTES.
Proposed fallback
private fun rotateIfLarge(file: File) {
if (!file.exists() || file.length() <= MAX_SESSION_LOG_BYTES) return
val rotated = File(file.parentFile, "session.1.log")
- if (rotated.exists()) rotated.delete()
- file.renameTo(rotated)
+ if (rotated.exists() && !rotated.delete()) {
+ FileOutputStream(file, false).close()
+ return
+ }
+ if (!file.renameTo(rotated)) {
+ FileOutputStream(file, false).close()
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private fun rotateIfLarge(file: File) { | |
| if (!file.exists() || file.length() <= MAX_SESSION_LOG_BYTES) return | |
| val rotated = File(file.parentFile, "session.1.log") | |
| if (rotated.exists()) rotated.delete() | |
| file.renameTo(rotated) | |
| } | |
| private fun rotateIfLarge(file: File) { | |
| if (!file.exists() || file.length() <= MAX_SESSION_LOG_BYTES) return | |
| val rotated = File(file.parentFile, "session.1.log") | |
| if (rotated.exists() && !rotated.delete()) { | |
| FileOutputStream(file, false).close() | |
| return | |
| } | |
| if (!file.renameTo(rotated)) { | |
| FileOutputStream(file, false).close() | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/CrashReporter.kt`
around lines 67 - 72, The rotateIfLarge function currently calls
rotated.delete() and file.renameTo() which can fail silently; update
rotateIfLarge to check their boolean return values and handle failures: if
rotated.delete() fails, attempt to delete via Files.deleteIfExists(Path) or
create a uniquely-named temp rotated file and fall back to truncating the
original (open FileOutputStream(file, false) to truncate to zero) so session.log
cannot grow past MAX_SESSION_LOG_BYTES; if file.renameTo(rotated) fails, attempt
an atomic move via Files.move(Path, Path,
StandardCopyOption.ATOMIC_MOVE/REPLACE_EXISTING) or again truncate the original,
and log the error using your logger so failures are visible. Ensure references
to rotated ("session.1.log"), file, rotateIfLarge, and MAX_SESSION_LOG_BYTES are
used to locate where to apply these checks and fallbacks.
| data class AppLanguage( | ||
| /** IETF BCP 47 language tag (e.g. `en`, `zh-CN`, `pt-BR`). */ | ||
| val tag: String, | ||
| /** Native-script label, e.g. `简体中文`, `Español`. */ | ||
| val displayName: String, | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify Kotlinx Serialization is configured and inspect existing annotation patterns.
set -euo pipefail
fd -e kts 'build.gradle.kts' -x rg -n 'plugin\.serialization|kotlinx-serialization|kotlinx\.serialization|serialization' {}
rg -n --type=kt -C2 '@Serializable|data\s+class\s+AppLanguage\b'Repository: OpenHub-Store/GitHub-Store
Length of output: 176
Add the required serialization annotation to the data class.
AppLanguage is a domain model for UI language selection that should be serializable per the coding guidelines. Kotlinx Serialization is already configured in the build. Add the @Serializable annotation and import it from kotlinx.serialization.
Proposed update
package zed.rainxch.core.domain.model
+import kotlinx.serialization.Serializable
+
/**
* A user-selectable UI language for the app. Each entry corresponds to a
@@
* to escape.
*/
+@Serializable
data class AppLanguage(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/AppLanguage.kt`
around lines 14 - 19, Add the kotlinx.serialization annotation to the
AppLanguage data class: annotate the data class AppLanguage with `@Serializable`
and add the corresponding import from kotlinx.serialization.Serializable so the
model is serializable by Kotlinx Serialization.
- Change caught exception type from `Throwable` to `Exception` when reading the app language preference in both `DesktopApp.kt` and `MainActivity.kt`.
AppLanguagedata class to represent user-selectable UI languages with IETF BCP 47 tags and native-script display names.AppLanguagesregistry containing the list of currently supported languages (English, Arabic, Bengali, Spanish, French, Hindi, Italian, Japanese, Korean, Polish, Russian, Turkish, and Simplified Chinese).findByTagutility to retrieve language metadata by its tag.Summary by CodeRabbit
Release Notes
New Features
Chores