# General Translation Knowledge Base: How do I translate a Node.js app?
URL: https://generaltranslation.com/en-US/kb/translate-node-app.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Detect each request's language, usually from its Accept-Language header, and return every string in that language. General Translation's gt-node binds the locale per request with withGT and translates strings with getGT, from translations that npx gt translate --publish generates before you deploy.
Category: Internationalization
Last updated: 2026-10-21
Authors: Kevin Liu, Kevin Wu
Published: 2026-10-21

Translating a Node.js app means detecting each request's language, usually from its `Accept-Language` header, and returning every string in that language. It's hard because one server handles many users at once, so the language can't be a global setting: each request carries its own, and every function that builds the response needs it. Strings with values also need grammar rules per language: a count takes one of 2 plural forms in English and one of 6 in Arabic.

## Video

The video is narrated in English, with English captions.

[How do I translate a Node.js app?](https://caxecubb9c64cezv.public.blob.vercel-storage.com/films/kb-translate-node-app.mp4) (48 sec)

General Translation lets you translate strings into each request's locale with `gt-node`. Call `initializeGT` once, wrap each request in `withGT`, await `getGT` in a handler, list `server.js` in `gt.config.json`, sign in, and run `npx gt translate`.

## Ways to translate a Node.js app

| Approach | What it does well | Locale for each request | What it leaves to you |
| --- | --- | --- | --- |
| An internationalization (i18n) library alone ([`i18next`](/kb/general-translation-vs-i18next)) | Mature runtime for rendering translations and formatting values | A middleware plugin detects it | Extracting strings into one JSON key file per language, writing each translation, and updating every file when copy changes |
| [`nestjs-i18n`](/kb/general-translation-vs-nestjs-i18n) (NestJS) | Renders messages from per-language JSON or YAML catalogs, over HTTP, GraphQL, gRPC, and WebSockets | Resolvers read the query string, a header, a cookie, or `Accept-Language`, in the order you list them | Writing every language's catalog and keeping each one current |
| A machine translation API at request time (DeepL, Google Cloud Translation) | Translates any text, including content that only exists at run time | You pass the target language on each call | Latency and cost on every request unless you cache results, consistent terms, plurals, and review |
| General Translation (`gt-node` and the `gt` CLI) | Strings stay inline in handlers, in `gt()` calls, and [`npx gt translate --publish`](/docs/cli/reference/commands/translate) translates them before you deploy | [`withGT`](/docs/node/reference/functions/with-gt) binds it | A project ID and `gt.config.json` from [`npx gt init`](/docs/cli/reference/commands/init), [`gt login`](/docs/cli/reference/commands/login) or an API key, and the CLI in your build or deploy step |

Use `i18next` or `nestjs-i18n` alone when your team already maintains translated catalogs. Call a machine translation API at request time only for content that exists just at run time, such as user posts. Use `gt-node` when the strings live in your handlers and change with every release. If your API returns only data and error codes, and a web or mobile client renders every message, a simpler setup is enough: translate in the client.

## Translate a Node.js app with gt-node

1. Call [`initializeGT`](/docs/node/reference/functions/initialize-gt) once at startup with your locales.
2. Wrap each request in [`withGT`](/docs/node/reference/functions/with-gt). It binds the locale with `AsyncLocalStorage`, so concurrent requests keep their own, and [`getRequestLocale`](/docs/node/reference/functions/get-request-locale) reads it from `Accept-Language`.
3. In a handler, call [`getGT`](/docs/node/reference/functions/get-gt) for a `gt()` function that takes ICU messages, plurals included, and a `$context` option for ambiguous words:

   ```js title="server.js"
   import express from 'express';
   import { initializeGT, withGT, getRequestLocale, getGT } from 'gt-node';

   initializeGT({ defaultLocale: 'en', locales: ['en', 'es', 'fr'] });
   const app = express();
   app.use((req, res, next) => withGT(getRequestLocale(req), () => next()));

   app.get('/api/greeting', async (req, res) => {
     const gt = await getGT();
     res.json({ message: gt('Hello, {name}!', { name: 'Alice' }) });
   });
   app.listen(3000, () => console.log('Listening on http://localhost:3000'));
   ```

4. Before you deploy, enable the CDN in your project settings and run [`npx gt translate --publish`](/docs/cli/reference/commands/translate).

In production, `gt-node` fetches those translations from the General Translation CDN for the project ID in `GT_PROJECT_ID`, and a missing translation falls back to the source string.

## Share terms with your client app

If your web or mobile client also uses General Translation, assign its Context Group (Glossary and Custom Prompts) to the server's project from **Project > Context** in the Dashboard, so new translations in API responses use the same terms. The [Node.js Quickstart](/docs/node/quickstart) has the full steps.

## Related questions

- [How do I translate a React app?](https://generaltranslation.com/en-US/kb/translate-react-app.mdx): Translating a React app means internationalizing its components so they render in the user's language, then translating every string into each language you support. General Translation's gt-react translates JSX in place in the `<T>` component, and npx gt translate writes one file per language.
- [How do I translate a Vue app?](https://generaltranslation.com/en-US/kb/translate-vue-app.mdx): Translating a Vue app means putting each template string behind a lookup for the active language and translating it into every target language. General Translation's gt-vue plugin translates content wrapped in the `<T>` component, and npx gt translate writes one catalog per target language.
- [How do I add i18n to a Next.js App Router app?](https://generaltranslation.com/en-US/kb/add-i18n-to-nextjs.mdx): Start with gt init to configure General Translation in a supported App Router project, then mark source content, generate translations, and verify language switching. gt-next keeps copy in JSX with translation context; the CLI, Dashboard editor, and Locadex handle generation, review, and ongoing updates. This guide also shows the explicit local-file setup.
- [How do I keep translations up to date on every deploy?](https://generaltranslation.com/en-US/kb/translations-in-ci.mdx): Run translation as a pipeline step before each production build, so new copy ships translated with the deploy that adds it. General Translation's gt CLI does this with npx gt translate, using a project API key and project ID stored as CI secrets.

## Previous and next questions

- Previous question: [How do I translate a Mintlify docs site?](https://generaltranslation.com/en-US/kb/translate-mintlify-docs.mdx)
- Next question: [How do I translate a React app?](https://generaltranslation.com/en-US/kb/translate-react-app.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/en-US/kb/sitemap.md) for every article.
