Most translation tools make you leave what you're doing: copy text, switch to a tab or app, paste, read, copy back. I wanted translation to sit inside whatever I was already using. That turned into Linguin, an AI translator with a native Mac app, an iPhone app, and a Chrome extension. Here's how I think about building the "same" product across three very different surfaces.
The product promise is identical everywhere: select text, get a fast, context-aware translation in 100+ languages. But the interaction has to be native to each platform, or it feels wrong:
Same core, three genuinely different UX shells.
The translation logic - language detection, prompt construction, tone handling, caching - is the part you never want to fork. If Mac and iOS drift, you get subtly different translations for the same input, which erodes trust fast.
So the model-facing logic lives behind one small service contract, and each client is a thin shell that owns only its platform UX. A translation request looks the same whether it comes from the menu bar, the share sheet, or a browser selection.
Classic MT is great at literal accuracy but blind to context. "Book" in a travel app and "book" in a library app should not translate the same way. Passing the surrounding context and a tone hint (formal, casual, technical) to an LLM produces translations that read like a human wrote them, not a dictionary.
The tradeoffs I had to design around:
If you want to try it, the Mac app, iOS app and Chrome extension are all at https://linguin.app Curious how others structure a shared core across native + web clients - do you go with a shared service, a shared package, or just accept some duplication?