{"slug": "i-let-my-coding-agent-do-the-whole-localization-job-from-messy-keys-to-approved", "title": "I let my coding agent do the whole localization job, from messy keys to approved translations", "summary": "A developer built locli, an open-source CLI and MCP server that lets coding agents like Claude Code, Cursor and Codex localize apps end to end — consolidating duplicate string keys across iOS, Android, web and backend into one lower_snake_case identifier per text, translating via context-aware uploads, and validating placeholders, plural forms and glossary terms before a human approves each release. The developer reports running six apps with roughly 2,650 keys on it, with locli also localizing its own web app; the CLI and MCP server are MIT-licensed with no dependencies.", "body_md": "Every app I ship exists on iOS and Android, some on the web too. After a few releases the\n\nstrings were a mess:\n\n`Localizable.xcstrings` under keys like `\"Sign in\"`, `account.login` and\n`login_button`, all for the same button` R.string.login_btn`)` auth.signIn`)\nThree names for one text means three translations, three chances to drift, and nobody knows\n\nwhich one is right.\n\nSay \"localize this app\" to my coding agent, and get it done **properly**: not a quick\n\ntranslation that breaks a placeholder or puts a German sentence into a toolbar button.\n\nSo I built [locli](https://locli.dev), and now this is what my agent (Claude Code, but Cursor\n\nand Codex work the same) does on its own.\n\nHard-coded strings go into the app's own catalog: the String Catalog on iOS, `strings.xml` on\n\nAndroid, ICU JSON on the web or backend. The code switches to looking them up by key.\n\nEvery text gets one `lower_snake_case` identifier with a feature prefix:\n\n```\naccount_login\nsettings_language_title\ncart_checkout\n```\n\nThe **same identifier on iOS, Android and web**. So \"Sign in\" is one key, translated once,\n\nused everywhere. Where a platform really needs different wording, it gets a variant of that\n\nkey instead of a new one.\n\nThis is the part I used to dread. The agent finds keys that mean the same thing\n\n(`account.login` on iOS, `account_login` on Android), merges them into one, keeps every\n\ntranslation, and switches the code to the new name.\n\nIt only stops and asks me where two values really conflict, for example two different German\n\ntexts for the same button. It never just picks one.\n\n`locli push` uploads the keys and texts (it never overwrites what a translator changed). Then\n\nthe agent translates, using:\n\n`locli context` reads the code and knows that `cart_checkout` is a\ntoolbar item and `cart_title` a screen title\nEvery upload is checked: placeholders like `%lld` or `{count}` in every language, plural forms\n\nper language (Polish and Arabic need more than \"one\" and \"other\"), glossary terms.\n\nThe one thing the agent can't do is ship. I go through the changed texts in the locli web app,\n\neach with a diff, and approve the release. Only then does `locli pull` write exactly that\n\nrelease into the app. Builds stay reproducible, and a bad translation never reaches the store\n\njust because an agent was confident.\n\nI run six of my own apps on it, about 2,650 keys across iOS, Android, web and backend, and\n\nlocli localizes its own web app. Dogfooding found real bugs, and each got a fix and a test:\n\ncurrent Xcode saves String Catalogs as version 1.1, which the CLI refused at first.\n\nIn your app's repository:\n\n```\nnpx @locli/cli init\n```\n\nor tell your agent: *\"Set up locli for this app's texts.\"*\n\nFor Claude Code there's a plugin:\n\n```\n/plugin marketplace add mariohahn/locli\n/plugin install locli@locli\n```\n\nThe CLI and MCP server are MIT and have no dependencies:\n\n[github.com/mariohahn/locli](https://github.com/mariohahn/locli). One project is free.\n\nI'd love to hear how messy your keys are, and where this breaks on your project.", "url": "https://wpnews.pro/news/i-let-my-coding-agent-do-the-whole-localization-job-from-messy-keys-to-approved", "canonical_source": "https://dev.to/mario_hahn_69c72ae001e781/i-let-my-coding-agent-do-the-whole-localization-job-from-messy-keys-to-approved-translations-2adc", "published_at": "2026-10-30 21:05:19+00:00", "updated_at": "2026-10-30 21:20:41.121905+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "agent-protocols"], "entities": ["locli", "Claude Code", "Cursor", "Codex", "GitHub", "Mario Hahn"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-let-my-coding-agent-do-the-whole-localization-job-from-messy-keys-to-approved", "markdown": "https://wpnews.pro/news/i-let-my-coding-agent-do-the-whole-localization-job-from-messy-keys-to-approved.md", "text": "https://wpnews.pro/news/i-let-my-coding-agent-do-the-whole-localization-job-from-messy-keys-to-approved.txt", "jsonld": "https://wpnews.pro/news/i-let-my-coding-agent-do-the-whole-localization-job-from-messy-keys-to-approved.jsonld"}}