@weglot/translate-react
Translate your
React,
Next.js or
Vite app
No t() wrappers, no JSON files. Add a build plugin and a Weglot API key: the text in your JSX is translated when your app builds, and your team edits translations in Weglot without touching code.
Copy the prompt for · · · read the docs · view on npm
111,368+ global brands rely on Weglot to translate their websites
// what your users see
The JSX you wrote, in every language
Write the text once. Weglot translates it at build time.
Same button, five languages. Widths measured live.
export default function Settings() { return ( <button>Save changes</button> ); } // no key, no t(), no en.json
No keys, no t(). Write the text in JSX, that is it.
// how it works
Four steps. Your components stay as they are.
Source and target languages come from your Weglot project, not from your code. The plugin reads the text in your JSX at build time and fetches its translations.
-
Install the package and add your API key
Create a Weglot 2.0 project, then copy its API key from the project settings. It starts with
pk_. Keep.envout of version control.terminal · .env$ npm install @weglot/translate-react # .env WEGLOT_API_KEY=pk_your_weglot_api_key
-
Add the plugin
Wrap your Next.js config with
withWeglot. PointsourceRootto the folder that holds your pages and components.Add
weglotPluginto your Vite config. With Webpack, import it from@weglot/translate-react/webpackinstead.next.config.tsimport type { NextConfig } from "next"; import { withWeglot } from "@weglot/translate-react/next"; const nextConfig: NextConfig = {}; export default async function (): Promise<NextConfig> { return await withWeglot(nextConfig, { sourceRoot: "./app" }); }
vite.config.tsimport { defineConfig } from "vite"; import { weglotPlugin } from "@weglot/translate-react/vite"; export default defineConfig({ plugins: [weglotPlugin({ sourceRoot: "src" })], });
-
Add the provider
Wrap your root layout with
WeglotProviderfrom the Next.js entry point, so that changing language refreshes your server components.Wrap your app with
WeglotProvider, as early as possible.app/layout.tsximport { WeglotProvider } from "@weglot/translate-react/react/next"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <WeglotProvider>{children}</WeglotProvider> </body> </html> ); }
src/main.tsximport { WeglotProvider } from "@weglot/translate-react/react"; root.render( <WeglotProvider> <App /> </WeglotProvider>, );
-
Build, and ship in every language of your project
Each build fetches missing translations from Weglot and writes
public/translations/<locale>.json. Ignore that folder. Add a language switcher withLocaleSwitcheroruseWeglotContext..gitignorepublic/translations/
// under the hood
What happens when you build
- 01Reads your JSX
- 02Sends new text
- 03Weglot translates
- 04Writes one file per language
// every language of your project
One build, every language you add
Pick languages in Weglot. The next build ships them.
enAdd a language in Weglot, then build. Translation files deploy with your app.
// built for coding agents
Your agent sets it up
No strings to rewrite, so the change is small and easy to review.






Any coding agent. Paste one prompt in the agent you already use.
Docs agents can read. An llms.txt index and Markdown for every page.
package.jsonnext.config.tslayout.tsx.gitignore.envA diff you can review. No strings rewritten.
Paste in Claude Code
Paste in Cursor (Agent mode)
Paste in Codex$ npm install @weglot/translate-react
Copy the prompt. Same steps as the getting-started guide.
// what gets translated
The plugin knows text from code
export default function Pricing() { return ( <section className="pricing"> <h2>Choose your plan</h2> <input placeholder="Email address" /> <a href="/signup">{"Start free trial"}</a> <span translate="no">Weglot</span> </section> ); }
Text is translated. JSX text, literals, constants, alt, title, placeholder, aria-label.
Code is left alone. Class names, URLs, logic.
Your call. Keep any element as is, or use data-weglot-skip.
// for your team
Edit and review without touching code
Review in Weglot. Product, marketing and translators edit the wording.
No pull request to fix a word.
Track what is reviewed. See progress for each language.
// fit
When to use Weglot, and when not to
The package is in preview. Here is where it fits today.
Next.js App Router
SupportedNext.js 15 or 16.0.4+, React 19.
Vite
SupportedReact 19, Node 20.9+. Webpack works too.
React Server Components
SupportedChanging language refreshes your server components.
CMS and API content
SupportedWith tDynamic in Next.js server components.
Non-developers editing
SupportedReview and edit in the Weglot dashboard.
One URL per language
Not yetThe language is stored in a cookie today. Need indexed URLs per language now: use next-intl or Paraglide JS.
Translations as repo files
Translate ActionWeglot translates your JSON locale files in GitHub Actions and opens a pull request. See the docs →
React 18, Pages Router
Not supportedAlso Next.js 14 or older.
CMS or website builder
Not this packageYour site isn't built in React: use Weglot's CMS integrations.
// compare
Why not a classic i18n library?
i18n libraries ask you to replace every string with a key and keep one file per language. Weglot reads the strings you already wrote. Here is how the options compare.
| Criteria | Weglot@weglot/translate-react |
next-intl / i18next | Paraglide JS | CMS native localization |
|---|---|---|---|---|
| Wrap strings in t() or message functions | NoText in JSX is detected at build time. | Yest("key") for every string. |
Yesm.key() message functions. |
Content onlyStrings in your code still need a library. |
| Translation files per language | None to maintainGenerated at build, git-ignored. | YesTypically one JSON file per locale. | YesOne message file per locale. | NoStored in the CMS. |
| Multilingual routing and SEO (URL per language, hreflang) | Not yetLanguage stored in a cookie. Same URLs for all languages, source language indexed. | next-intl: yesLocale routing built in. i18next: through your framework setup. | YesLocalized URLs built in: locale prefixes, translated paths or domains. Add hreflang tags yourself. | Front endA headless CMS stores content per locale. URLs and hreflang come from your front end. |
| Translations generated for you | YesWeglot translates with an LLM during the build. | NoBring your own translations or a TMS. | With toolinginlang CLI machine translation, or your coding agent. | Paid add-onAI translation on paid plans: Contentful AI Actions, Sanity AI Assist, Strapi AI Translations. |
| Edit translations without a developer | YesReview and edit in the Weglot dashboard. | NoEdit JSON files, or add a separate TMS. | With Finkinlang's web editor, with a GitHub account. | YesIn the CMS editor. |
| Set up by a coding agent in one prompt | YesOne install, two config edits. Copyable prompt below. | Long taskThe agent rewrites every string into keys and files. | Long taskinit runs without prompts for agents, then every string becomes an m.key() message. |
n/aConfigured in the CMS. |
FAQ
Does it handle SEO: one URL per language and hreflang?
Not today. The visitor's language is stored in a cookie and every language is served on the same URLs, so search engines index the source language only.
You can translate page titles and descriptions with tDynamicAll in generateMetadata. If you need indexed URLs per language now, use a library with locale routing, such as next-intl or Paraglide JS.
How do I translate dynamic content from a CMS, an API or users?
The plugin only translates text written in your code. For content your code never sees, call tDynamic, tDynamicAll or tDynamicHtml from @weglot/translate-react/dynamic in Next.js server components.
If the API takes longer than 500 ms, or a text is requested for the first time, they return the source text. The translation is ready on a later request. If you cache data yourself, make the cache depend on the visitor's language.
Next.js or Vite: what changes?
Next.js uses withWeglot from @weglot/translate-react/next and WeglotProvider from @weglot/translate-react/react/next. Vite uses weglotPlugin from @weglot/translate-react/vite and WeglotProvider from @weglot/translate-react/react. Webpack uses weglotPlugin from @weglot/translate-react/webpack.
The dynamic content functions only run in Next.js server components.
Does it work with React Server Components?
Yes, with the Next.js App Router. Import WeglotProvider from @weglot/translate-react/react/next so that changing language refreshes your server components. tDynamic, tDynamicAll and tDynamicHtml run server-side, in server components.
What happens when I build?
The plugin finds the text in the JSX under sourceRoot and asks the Weglot API for the translations it lacks. Weglot generates them with an LLM, and the build waits up to translationTimeout (300 seconds by default). It then writes public/translations/<locale>.json.
If translation fails, the build fails and keeps what it received in the local cache: build again to continue. With buildMode: "cache-only", the build makes no network calls.
Where are the translations stored?
In your Weglot project, where you review and edit them. Each build also keeps the translations it received in <sourceRoot>/weglot/cache/<locale>.json. Commit that folder to build without calling the API, or ignore it. public/translations/ is generated and goes in .gitignore.
What gets translated, and how do I exclude something?
Text in JSX, string literals inside JSX expressions, strings read from constants, and attributes such as title, alt, placeholder and aria-label. Code, URLs, class names and strings outside JSX are left alone. Add translate="no" or data-weglot-skip to keep an element in the original language. Declare your own text props with translatableAttributes.
Make your React app multilingual without rewriting it
Install the package, add your API key, build.
$ npm install @weglot/translate-react
Prefer to do it yourself? Read the docs or view the package on npm