A type-safe multilingual translation library powered by lingo.dev. Translate any JavaScript object into multiple languages in one call — with full TypeScript support.
Mango.dev follows a clear backend/frontend split:
| Backend | Frontend |
|---|---|
mg.translate() called here |
no translation at runtime |
| lingo.dev API called here | just reads field[lang] |
| API key stays safe ✅ | useMango() to switch lang |
| returns multilingual object | no API calls, instant switch |
Input →
{ title: "Hello World", slug: "hello-world" }Output →
{ title: { en: "Hello World", hi: "नमस्ते दुनिया", fr: "Bonjour le Monde" }, slug: "hello-world" }- One call, all languages — translate any nested object or array in a single
mg.translate()call - Type-safe —
excludepaths are autocompleted from your type; return type reflects exactly what changed - Smart skipping — URLs, emails, numbers, dates, slugs, and hex colors are never sent to the API
- Exclude paths — opt specific fields out of translation using dot-notation (
"author.email","tags[]") - React ready —
MangoProvider+useMango()hook for instant language switching on the client - No API key on client — translation happens on the server; frontend only reads the result
- Progress callback — track translation progress with an
onProgresshandler - Fast mode — trade quality for speed when needed
| Package | Description |
|---|---|
@mango.dev/core |
Core translation engine — Mango class, types, traversal logic |
@mango.dev/react |
React bindings — MangoProvider, useMango() hook, t() helper |
# npm
npm install @mango.dev/core @mango.dev/react
# pnpm
pnpm add @mango.dev/core @mango.dev/react// lib/constants.ts
export const LANGS = ["en", "hi", "fr"] as const
export type Lang = typeof LANGS[number] // "en" | "hi" | "fr"The same
LANGSmust be used in bothnew Mango()on the server and<MangoProvider>on the client.
import { Mango } from "@mango.dev/core"
import { LANGS } from "./lib/constants"
const mango = new Mango({
api_key: process.env.LINGODOTDEV_API_KEY!, // stays on the server ✅
langs: [...LANGS],
sourceLang: "en",
})
const post = {
id: "abc-123",
title: "Getting Started",
body: "Welcome to the guide.",
author: { name: "Jane", email: "jane@example.com" },
}
const translated = await mango.translate(post, {
exclude: ["id", "author.email"], // autocompleted from post's type ✅
})
// translated.title → { en: "Getting Started", hi: "...", fr: "..." }
// translated.id → "abc-123" (excluded)
// translated.author.email → "jane@example.com" (excluded)import { MangoProvider, useMango } from "@mango.dev/react"
import { LANGS } from "./lib/constants"
import type { Translated } from "@mango.dev/core"
type Post = { id: string; title: string; body: string; author: { name: string; email: string } }
type TranslatedPost = Translated<Post, "id" | "author.email", Lang>
export default function Page({ post }: { post: TranslatedPost }) {
return (
<MangoProvider langs={[...LANGS]} defaultLang="en">
<PostView post={post} />
</MangoProvider>
)
}
function PostView({ post }: { post: TranslatedPost }) {
const { t, lang, setLang, langs } = useMango()
return (
<article>
<h1>{t(post.title)}</h1>
<p>{t(post.body)}</p>
{langs.map((l) => (
<button key={l} onClick={() => setLang(l)} disabled={l === lang}>
{l}
</button>
))}
</article>
)
}See individual package docs for full configuration options:
Never use @mango.dev/core in client-side (browser) code — the api_key will be exposed in your bundle. Always call mango.translate() in a server action, API route, or build script. See the @mango.dev/core security guide for safe patterns.
Thanks to Lingo.dev for running the Multilingual Hackathon #2 - this project wouldn't exist without it. If you find Mango.dev useful or have feedback, feel free to reach out.