🥭 Get Started with Mango.dev

01

Install

Install the packages via npm, pnpm, or yarn.

bash
npm install @mango.dev/core @mango.dev/react
02

Add your API key

Get your key from lingo.dev — the free Hobby tier is enough. Add it to your .env.local file.

bash
# .env.local
LINGODOTDEV_API_KEY=your_api_key_here

💡 Get your API key at lingo.dev/en/app

03

Define your languages

Define LANGS once as a const. It flows to both backend and frontend — no repetition.

ts
// lib/constants.ts
export const LANGS = ["en", "hi", "fr"] as const
export type Lang = typeof LANGS[number] // "en" | "hi" | "fr"
04

Initialize Mango on the server

Create the Mango instance in a server-only file. The API key never leaves the server.

ts
// lib/mango.ts
import { Mango } from "@mango.dev/core"
import { LANGS } from "./constants"

export const mg = new Mango({
  api_key: process.env.LINGODOTDEV_API_KEY!,
  langs: [...LANGS],
  sourceLang: "en",
})
05

Wrap your app with MangoProvider

MangoProvider only needs langs — no API key. Completely safe for the frontend.

tsx
// app/layout.tsx
import { MangoProvider } from "@mango.dev/react"
import { LANGS } from "@/lib/constants"

export default function RootLayout({ children }) {
  return (
    <MangoProvider langs={[...LANGS]} defaultLang="en">
      <html><body>{children}</body></html>
    </MangoProvider>
  )
}
06

Translate your data on the server

Pass any object to mg.translate(). Mango traverses it recursively, translates every string field, and returns the same shape with multilingual maps.

ts
// app/api/posts/route.ts
import { mg } from "@/lib/mango"

export async function GET() {
  const res = await fetch("https://your-api.com/posts")
  const posts = await res.json()

  const { posts: translated } = await mg.translate(
    { posts },
    { exclude: ["posts[].id", "posts[].userId"] }
  )

  return NextResponse.json({ data: translated })
}

// output shape:
// {
//   id: 1,           <- excluded, original
//   title: {
//     en: "Hello",
//     hi: "\u0928\u092e\u0938\u094d\u0924\u0947",
//     fr: "Bonjour"
//   }
// }

💡 Wrap arrays in a named object before passing — gives proper TypeScript autocomplete on exclude paths.

07

Display on the frontend

useMango() gives you lang, setLang, and t(). t() resolves field[currentLang] with sourceLang as fallback.

tsx
// components/PostList.tsx
"use client"
import { useMango } from "@mango.dev/react"

export function PostList({ posts }) {
  const { t, setLang } = useMango()

  return (
    <>
      <button onClick={() => setLang("en")}>EN</button>
      <button onClick={() => setLang("hi")}>HI</button>
      <button onClick={() => setLang("fr")}>FR</button>

      {posts.map(post => (
        <div key={post.id}>
          <h2>{t(post.title)}</h2>
          <p>{t(post.body)}</p>
        </div>
      ))}
    </>
  )
}