# gt-next: General Translation Next.js SDK: Pages Router Quickstart URL: https://generaltranslation.com/en-GB/docs/next/tutorials/quickstart-pages-router.mdx --- title: Pages Router Quickstart description: Add multiple languages to your Next.js Pages Router app in under 10 minutes --- By the end of this guide, your Next.js Pages Router app will display content in multiple languages, with a language switcher your users can interact with. In the Pages Router, `gt-next` works through `getServerSideProps`: on each request, the server resolves the user's locale, loads a translations snapshot, and passes both to a `` in `_app.tsx` so the first render is already translated. **Prerequisites:** * A Next.js app using the **Pages Router** * Node.js 18+ **Using the App Router?** Follow the [Next.js Quickstart](/docs/next) instead — it uses server components and needs no `getServerSideProps` configuration. *** ## Step 1: Install the packages `gt-next` is the library that powers translations in your app. `gt` is the CLI tool that prepares translations for production. ```bash npm i gt-next npm i -D gt ``` ```bash yarn add gt-next yarn add --dev gt ``` ```bash bun add gt-next bun add --dev gt ``` ```bash pnpm add gt-next pnpm add --save-dev gt ``` *** ## Step 2: Configure your Next.js config `gt-next` uses a Next.js plugin called **`withGTConfig`** to set up internationalisation at build time. Wrap your existing Next.js config with it: ```ts title="next.config.ts" import { withGTConfig } from 'gt-next/config'; const nextConfig = {}; export default withGTConfig(nextConfig); ``` This plugin reads your translation settings and hooks everything up behind the scenes. The config is identical for the App Router and the Pages Router — no router-specific flags are needed. *** ## Step 3: Create a translation config file Create a **`gt.config.json`** file in your project root. This tells the library which languages you support: ```json title="gt.config.json" { "defaultLocale": "en", "locales": ["es", "fr", "ja"], "files": { "gt": { "output": "public/_gt/[locale].json" } } } ``` * **`defaultLocale`** — the language your app is written in (your source language). * **`locales`** — the languages you want to translate into. Choose any from the [supported locales list](/docs/platform/supported-locales). * **`files.gt.output`** — where the CLI saves translation files. `[locale]` is replaced with each language code (e.g. `public/_gt/es.json`). Add `public/_gt/` to your **`.gitignore`** — these files are generated, not written by hand: ```txt title=".gitignore" public/_gt/ ``` *** ## Step 4: Add a load function for local translations Create a **`loadTranslations`** file in your project root (or `src/` directory). This tells `gt-next` how to load the translation files generated by the CLI: ```ts title="loadTranslations.ts" export default async function loadTranslations(locale: string) { try { const translations = await import(`./public/_gt/${locale}.json`); return translations.default; } catch { return {}; } } ``` `withGTConfig` automatically detects a `loadTranslations.[js|ts]` file in your project root or `src/` directory — no additional configuration required. **Why local translations?** Local translations are bundled with your app, so they load instantly with no reliance on external services. See the [Local Translation Storage guide](/docs/next/guides/local-tx) for more details and trade-offs. *** ## Step 5: Wrap getServerSideProps on your pages Wrap each page's `getServerSideProps` with **`withGTServerSideProps`**. On every request, it resolves the user's locale — from the `generaltranslation.locale` cookie if set, otherwise from the `Accept-Language` header — loads a translations snapshot for that locale, and injects both into your page props: ```tsx title="pages/index.tsx" import type { GetServerSideProps } from 'next'; import { withGTServerSideProps } from 'gt-next'; export const getServerSideProps: GetServerSideProps = withGTServerSideProps( async (context) => { return { props: { // your own props }, }; } ); ``` If a page doesn't need server-side props of its own, call it with no arguments: ```tsx title="pages/about.tsx" import { withGTServerSideProps } from 'gt-next'; export const getServerSideProps = withGTServerSideProps(); ``` `withGTServerSideProps` adds `locale` and `translations` to your props (plus an internal `enableI18n` flag). If your inner function returns a `redirect` or `notFound`, it passes the result through unchanged without loading translations. *** ## Step 6: Add the GTProvider to your app The **`GTProvider`** component gives your entire app access to translations. In `_app.tsx`, pull the injected props out of `pageProps` and pass them to the provider. The **`WithGTServerSideProps`** type describes the injected shape: ```tsx title="pages/_app.tsx" import type { AppProps } from 'next/app'; import { GTProvider, WithGTServerSideProps } from 'gt-next'; export default function App({ Component, pageProps, }: AppProps) { const { locale, translations, ...restPageProps } = pageProps; return ( ); } ``` Because the locale and translations arrive with the server response, the first render is already in the user's language — no client-side loading state. *** ## Step 7: Mark content for translation Now, wrap any text you want translated with the **``** component. `` stands for "translate": ```tsx title="pages/index.tsx" import { T } from 'gt-next'; export default function Home() { return (

Welcome to my app

This content will be translated automatically.

); } ``` You can wrap as much or as little JSX as you like inside ``. Everything inside it — text, nested elements, even formatting — is translated as a unit. *** ## Step 8: Add a language switcher Add a **``** so users can change languages: ```tsx title="pages/index.tsx" import { T, LocaleSelector } from 'gt-next'; export default function Home() { return (

Welcome to my app

This content will be translated automatically.

); } ``` `LocaleSelector` renders a dropdown populated with the languages from your `gt.config.json`. When the user picks a language, `gt-next` saves the choice to the `generaltranslation.locale` cookie and reloads the page, so the server re-renders everything in the new locale. *** ## Step 9: Set up environment variables (optional) To see translations in development, you need API keys from General Translation. These enable **on-demand translation** — your app translates content in real time as you develop. Create a **`.env.local`** file: ```bash title=".env.local" GT_API_KEY="your-api-key" GT_PROJECT_ID="your-project-id" ``` Get your free keys at [dash.generaltranslation.com](https://dash.generaltranslation.com/signup) or by running: ```bash npx gt auth ``` For development, use a key starting with `gtx-dev-`. Production keys (`gtx-api-`) are for CI/CD only. Never expose `GT_API_KEY` to the browser or commit it to source control. *** ## Step 10: See it working Start your dev server: ```bash npm run dev ``` ```bash yarn dev ``` ```bash bun dev ``` ```bash pnpm dev ``` Open [http://localhost:3000](http://localhost:3000) and use the language dropdown to switch languages. You should see your content translated. In development, translations happen on-demand — you may see a brief loading state the first time you switch to a new language. In production, translations are pre-generated and load instantly. *** ## Step 11: Translate strings (not just JSX) For plain strings — like `placeholder` attributes, `aria-label` values, or `alt` text — use the **`useGT`** hook: ```tsx title="pages/contact.tsx" import { useGT } from 'gt-next'; export default function ContactPage() { const gt = useGT(); return (
); } ``` *** ## Step 12: Deploy to production In production, translations are pre-generated at build time (no real-time API calls). Add the translate command to your build script: ```json title="package.json" { "scripts": { "build": "npx gt translate && next build" } } ``` Set your **production** environment variables in your hosting provider (Vercel, Netlify, etc.): ```bash GT_PROJECT_ID=your-project-id GT_API_KEY=gtx-api-your-production-key ``` Production keys start with `gtx-api-` (not `gtx-dev-`). Get one from [dash.generaltranslation.com](https://dash.generaltranslation.com). Never prefix it with `NEXT_PUBLIC_`. That's it — your app is now multilingual. 🎉 *** ## Troubleshooting Yes — `` requires the `locale` and `translations` props, and they only exist on pages whose `getServerSideProps` is wrapped. For pages that don't fetch their own data, export the no-argument form: ```tsx export const getServerSideProps = withGTServerSideProps(); ``` No. Resolving the `locale` requires per-request data (the locale cookie and `Accept-Language` header), which isn't available during static generation. `gt-next` provides no `getStaticProps` helper for the Pages Router. `gt-next` stores the user's language preference in a cookie called `generaltranslation.locale`. If you previously tested with a different language, this cookie may override your selection. Clear your cookies and try again. * [Chrome](https://support.google.com/chrome/answer/95647) * [Firefox](https://support.mozilla.org/en-US/kb/delete-cookies-remove-info-websites-stored) * [Safari](https://support.apple.com/en-mn/guide/safari/sfri11471/16.0/mac/11.0) This is expected. In development, translations happen on-demand (your content is translated in real time via the API). This delay **does not exist in production** — all translations are pre-generated by `npx gt translate`. *** ## Next steps * [**`` Component Guide**](/docs/next/guides/t) — Learn about variables, plurals, and advanced translation patterns * [**String Translation Guide**](/docs/next/guides/strings) — Deep dive into `useGT` * [**Variable Components**](/docs/next/guides/variables) — Handle dynamic content with ``, ``, ``, and `` * [**Pluralisation**](/docs/next/api/components/plural) — Handle plural forms with the `` component * [**Deploying to Production**](/docs/next/tutorials/quickdeploy) — CI/CD setup, caching, and performance optimisation * [**Shared Strings**](/docs/next/guides/shared-strings) — Translate text in arrays, config objects, and shared data with `msg()`