i18n Strings Editor for IntelliJ/Android Studio banner

i18n Strings Editor for IntelliJ/Android Studio

6 devlogs
9h 31m 56s

An IntelliJ IDEA and Android Studio plugin for editing Lyricist-based Kotlin localization files through a live table UI. Supports nested string groups, lambda keys, multiple locales, and in-place editing. Changes are written back to the source fil…

An IntelliJ IDEA and Android Studio plugin for editing Lyricist-based Kotlin localization files through a live table UI. Supports nested string groups, lambda keys, multiple locales, and in-place editing. Changes are written back to the source file instantly.

This project uses AI

Used Perplexity to help work through IntelliJ’s PSI and APIs, fix a handful of tricky compiler errors, set up the GitHub Actions release workflow, and as help to write the README. Also used GitHub Copilot for code completion.

Demo Repository

Loading README...

schwenoldnoah

Wrapped everything up to get the plugin ready to ship.

Set up a GitHub Actions workflow that builds the plugin and automatically publishes a release when I push a version tag. The release ships two things: the plugin JAR you install directly from disk, and the KotlinProject zip so people can try it out without setting up their own Lyricist project first.

Also wrote a proper README with installation steps, feature overview, known limitations, and credits. Added a pluginIcon.svg so it actually shows up with a logo in the plugin settings instead of a blank square.

Attachment
0
schwenoldnoah

You can now drag keys and groups around in the tree, reorder within the same group, move to a different group, nest into a child. I encountered a couple of bugs during the implementation: The drop zone landing in the wrong group when releasing between two groups, group moves defaulting to root when they shouldn’t. Got there eventually.

Also had to completely rethink how drag starts, the default drag-enabled was blocking cell editing, so I switched to manual drag detection that only kicks in after 8px of movement.

Fixed navigation on click stealing focus in Android Studio. Ctrl+click now navigates to source, plain click just edits.

Attachment
0
schwenoldnoah

Fixed the group header text getting cut off. Headers now span the full table width instead of being clipped to the first column. Took a bit of effort, but it works nicely now.

Added a lock feature. You can lock any key or group from the toolbar. Locked rows can’t be edited through the plugin anymore, the icon shows up in the row, and it persists across restarts. Useful for keys with custom lambda logic You don’t want accidentally overwritten.

Also fixed lambda creation. You can now actually specify types like (Int, Int) -> String instead of being stuck with String. The dialog now has a params field with ‘name: Type’ syntax and a separate return type field.

Attachment
0
schwenoldnoah

I fixed a few things in the IntelliJ plugin.

The biggest one was click-to-navigate. When you click a cell in the table, it now jumps to the right place in the Kotlin file. The tricky part was that the string groups can be nested so I had to walk the whole tree recursively instead of just checking the top level.

I also fixed the column order in the table. Keys were showing up in the wrong order because nested groups were collected after the parent’s own keys. I fixed it by first emitting the current group’s keys, then going deeper.

Attachment
0
schwenoldnoah

I’ve been working on Unspeakable, a KMP word game for a while now, and managing translations has always been annoying. The Lyricist strings file is massive: nested data classes, lambda keys, maps of game mode strings. Editing it by hand across multiple locales just sucks.

So about a month ago I started building an IntelliJ plugin that turns the whole thing into an editable table. Rows are keys, columns are locales, you click a cell and type. It writes back directly to the Kotlin source file.

The annoying part was lambda keys — things like { teamName -> “No players in $teamName” }.

IntelliJ’s threading rules also bit me hard. Opening a rename dialog directly from the table caused a crash because the dialog constructor internally touches the workspace index, which isn’t allowed on the main thread anymore in IDEA 2024.3. Took a while to figure out the right way to route it through the platform’s own rename action instead.

Today’s the last day of Flavortown and I need those cookies for a 3D printer, so here we are.

Attachment
0