Stop hand-editing
strings.xml. Extract hardcoded literals, kill duplicates, and find dead resources — all from the editor.
IntelliJ IDEA / Android Studio plugin for managing Android strings.xml resources: extract hardcoded literals with context-aware replacement, detect duplicate values, and flag unused entries — without leaving the editor.
- Context-aware replacement
- Inside
@Composable→stringResource(R.string.key) - Inside composable entry-point lambdas (
setContent,composable,navigation,dialog,bottomSheet,composed) and nested layout lambdas →stringResource(R.string.key) - Inside
Activity/Fragment/View→getString(R.string.key) - Other Kotlin code →
R.string.key - XML layout attribute →
@string/key
- Inside
- Kotlin Multiplatform / Compose Multiplatform — targets under
composeResources/values/produce CMP references with auto-imported generatedRes:@Composable→stringResource(Res.string.key)- Other Kotlin code →
Res.string.key Respackage auto-detected (gradlepackageOfResClass→ existing imports → derived), with a manual override in settings
- Auto-import for Compose
stringResource(sorted with existing imports) - Duplicate value detection during extract — reuse existing key
- Multi-locale propagation across
values-*folders - Kotlin template expressions extracted as
%1$sformat args (e.g."Hello $name"→stringResource(R.string.hello_s, name)) - Quick-fix intention on hardcoded literals (Alt+Enter)
- Quick extract: skip dialog when target is unambiguous (inline hint confirms the chosen key)
- Batch extract: extract all strings in a file in one pass — colour-coded per-row status with per-status counts, a one-click Fix collisions action, and status/summary updating live while you edit keys
@Previewcomposables excluded by default (configurable)- Key suggestions romanize Greek and Cyrillic and strip Latin accents (
Καλημέρα→kalimera,Café→cafe)
- Copy an existing string resource to a new key across
res/values/strings.xmland everyvalues-*locale in one undoable step (Ctrl+Alt+Dor Alt+Enter) - Works on any reference:
R.string.key,Res.string.key,@string/key, or a<string>entry - Reuses each locale's existing translation; locales that don't translate the source key are skipped (shown in the dialog) instead of being filled with the default value
- Optionally redirects the reference under the caret to the new key (Compose Multiplatform imports updated automatically)
- Redirecting the reference shows an inline hint with the new key
- Rename an existing string key and edit its default and per-locale values in one undoable step (
Ctrl+Alt+Eor Alt+Enter) - Renames every
R.string.key,Res.string.key, and@string/keyreference to the renamed key, scoped to the declaring module and its dependents - Reports how many references were updated (and warns when none were found, e.g. a dynamically-built key)
- Works on any reference or a
<string>entry, in Android and Compose Multiplatform projects
- Hardcoded string highlight in editor (opt-in) — Android resource XML (
res/<type>/) and Kotlin only - Duplicate value in
strings.xml(same text, different keys) - Unused string resource (no
R.string.key,Res.string.key, or@string/keyreferences)
Configurable prefix, naming convention, replacement style per context, locale propagation defaults, format-arg detection, inspection toggles, exclusion patterns, and custom composable wrapper names. A live key preview reflects your settings as you type a sample string. Compose Multiplatform projects can set a generated Res package override under Kotlin Multiplatform.
Custom wrappers: if your project wraps content in a helper whose trailing lambda is a @Composable scope (e.g. screenViewComposable { … }), add its name under Settings → Tools → StringSmith → Custom Composable Wrappers so strings inside it use stringResource.
Extract to strings.xml right on the hardcoded literal, with a context-aware replacement table and a Before/After preview.
Pick key, target module, and per-locale values — with live duplicate-key reuse and a context-aware replacement preview.
Extract every string in a file in one pass — per-row keys, inclusion toggles, colour-coded status (New / Reuse existing / Duplicate / Collision / Invalid) that updates live as you edit keys, shared locale propagation, single undoable write.
Copy an existing string resource to a new key across res/values/strings.xml and every locale in one undoable step — with a live preview and the option to redirect the reference under the caret. Works in Android and Compose Multiplatform (Res.string.key) projects alike.
Duplicate and unused strings.xml entries are flagged inline.
Configure key generation, replacement style, locale defaults, format-arg detection, inspections, and strings.xml behavior.
Or: Settings → Plugins → Marketplace, search StringSmith, install.
git clone https://github.com/SeijinD/stringsmith.git
cd stringsmith
./gradlew buildPlugin
Output: build/distributions/stringsmith-<version>.zip
Install via Settings → Plugins → ⚙ → Install Plugin from Disk.
./gradlew runIde # default IntelliJ Platform sandbox
./gradlew runAndroidStudio # Android Studio sandbox
Android Studio path is auto-detected per OS. Override via the androidStudioPath
Gradle property (e.g. in ~/.gradle/gradle.properties) if installed elsewhere
(such as a JetBrains Toolbox location).
- Place caret inside a hardcoded string literal or XML attribute value.
Ctrl+Alt+Xor right-click → Extract to strings.xml.- Pick key, module, locale rows in the dialog.
- Entry written to
res/values/strings.xml; literal replaced with context-appropriate reference.
Ctrl+Alt+Shift+X — extracts immediately when the target is unambiguous (single module, no key collision, no locale variants, no existing key for the value). Falls back to the regular dialog otherwise.
Ctrl+Alt+Shift+B or Refactor → Batch Extract Strings in File — opens a table of all extractable strings in the current file. Edit per-row keys, toggle inclusion, pick locale propagation, write all in one undoable step.
- Place caret on a string reference (
R.string.key,Res.string.key,@string/key) or a<string>entry instrings.xml. Ctrl+Alt+Dor right-click → Duplicate String Resource (also Alt+Enter).- Pick the new key. The dialog lists which locales receive the copy. Optionally redirect the reference under the caret to the new key.
- Place caret on a string reference (
R.string.key,Res.string.key,@string/key) or a<string>entry instrings.xml. Ctrl+Alt+Eor right-click → Edit String Resource (also Alt+Enter).- Change the key and/or the default and per-locale values. On rename, every reference is updated and the dialog reports how many.
Strings inside @Preview composables are skipped by default (typically dummy data). Toggle in Settings → Tools → StringSmith → Compose Previews.
| Action | Shortcut |
|---|---|
| Extract to strings.xml | Ctrl+Alt+X |
| Quick Extract (skip dialog when unambiguous) | Ctrl+Alt+Shift+X |
| Batch Extract Strings in File | Ctrl+Alt+Shift+B |
| Duplicate String Resource | Ctrl+Alt+D |
| Edit String Resource | Ctrl+Alt+E |
- IntelliJ IDEA 2024.2+
- Android Studio (compatible IntelliJ 242+ platform, i.e. Ladybug 2024.2 and newer)
- Kotlin plugin K1 and K2 modes
- Android
res/values/and Compose MultiplatformcomposeResources/values/resource layouts
Nothing happens when I run Extract / the action is greyed out.
The caret must be inside a hardcoded string literal (Kotlin) or an XML attribute value. It won't trigger on an
already-extracted reference such as R.string.key. For Duplicate/Edit, place the caret on a string reference or a
<string> entry instead.
Extract can't find strings.xml / writes to the wrong module.
The target is the resource folder of the module owning the file. Multi-module projects pick the module in the dialog.
Make sure the module has a res/values/strings.xml (Android) or composeResources/values/ (CMP) source set.
Compose Multiplatform: it generates R.string instead of Res.string.
CMP references are produced only for files under a composeResources/values/ layout. If the generated Res package
is mis-detected, set an override under Settings → Tools → StringSmith → Kotlin Multiplatform.
Edit reports "0 references updated". The key is referenced only dynamically (e.g. built by string concatenation or resource-name lookup), which can't be resolved statically. The rename and value edits still apply — only the auto-update of references is skipped.
Strings inside a custom Composable wrapper get getString instead of stringResource.
Add the wrapper's name under Settings → Tools → StringSmith → Custom Composable Wrappers so StringSmith treats
its trailing lambda as a @Composable scope.
My @Preview strings aren't extracted.
That's intentional — @Preview composables are skipped by default (usually dummy data). Toggle it under
Settings → Tools → StringSmith → Compose Previews.
./gradlew runIde # launch sandbox IDE
./gradlew verifyPlugin # plugin verifier against recommended IDEs
./gradlew buildPlugin # produce distributable zip
./gradlew test # run the test suite
Apache License 2.0 — see LICENSE.






