Kotomot: a translation API I actually want to use
The hard part of i18n isn't translating the words. It's everything around them.
Every multi-locale app I've shipped has eventually broken on the same three things: keeping designers' edits in sync with the running app without a deploy, knowing exactly which version of "the strings" each environment sees, and writing a build script or CLI that doesn't feel like a hack. The existing services solve pieces of this — Lokalise has the editor, Phrase has the workflow, Crowdin has the community — but none of them ever felt like they were built FOR developers. An SDK was a sales bullet point, not a first-class API.
So I built Kotomot.
What it does
Kotomot is a hosted translation management platform: a web dashboard for your strings, a versioned API to read them, and SDKs for Node, React, React Native, and Flutter that turn that API into a one-liner.
The model is small on purpose. You have projects. Each project has locales. Each locale has a flat map of key paths to strings (home.hero.title, nav.cart.empty, errors.network). You edit in the dashboard, hit publish, and the API immediately serves the new published version to every environment pinned to it.
The SDKs handle the boring stuff: fetch + cache, version-based revalidation, retry with backoff, locale switching at runtime, and a fallback chain when a key is missing in the requested locale.
Two decisions I'm happy with
Reads come from the published set, not the live dashboard. It's tempting to expose "whatever's in the editor right now" — it makes demos feel magical. But it kills you in production: an unfinished edit gets shipped to real users at 11pm because someone pressed save. So getTranslations() returns only what you've explicitly published, and every environment can pin to a specific version. Your prod app reads prod-v42 until you choose to bump it. That single boundary turns the dashboard from a scary live system into a versioned content store.
The SDK design came first. Most of these services treat their SDKs as a marketing afterthought — wrapper code around a REST endpoint that was designed for the dashboard. Kotomot ran the other direction. The Node SDK shaped the API, not the reverse. A KotoClient takes one config, exposes four methods, and respects a single cache config that swaps between in-memory, Redis, and a custom storage you bring. The React Native SDK gives you a <KotoProvider> + useTranslation() hook with AsyncStorage cache and offline support — because you cannot rely on a network on mobile. The Flutter SDK has the same cache-first model in Dart. Three different host languages, the same conceptual API.
A small naming aside
Kotomot is koto (言, Japanese for "word") and mot (French for "word"). Words meeting words. That's translation in three syllables, and the domain (kotomot.app) was available, which is rarer than it sounds.
Try it
The hosted dashboard + API is live at kotomot.app. Generate an API key in the dashboard, pick a project, and install one of the SDKs:
# Node
npm install kotomot-node-sdk
# React
npm install kotomot-react
# React Native
npm install kotomot-react-native @react-native-async-storage/async-storage
# Flutter
flutter pub add kotomot_flutterThe SDK READMEs have copy-paste quickstarts that fit on one screen — that's deliberate. You should not need a tutorial for the first read.
What's next
A few things I want to ship soon: a CLI for export/import so translators can round-trip JSON or CSV without leaving their editor of choice, a webhook for "version published" so you can trigger a static rebuild automatically, and a "key usage" view in the dashboard so you can finally find the strings no app references anymore. If you try it and hit a rough edge — or have an opinion about a feature I haven't built yet — I genuinely want to hear it.
End of essay



