# General Translation React SDKs (gt-react, gt-next, gt-react-native): Developing with SPA translations
URL: https://generaltranslation.com/en-US/docs/react/guides/developing-spa-translations.mdx
---
title: Developing with SPA translations
description: How to preview General Translation translations while developing a single-page React app.
related:
links:
- /docs/react/guides/storing-translations
- /docs/react/guides/configuring
- /docs/react/guides/translating-jsx
- /docs/react/guides/managing-locales
---
Development translations let you preview translated content as you edit your SPA. They require the GT compiler and a development API key.
**Prerequisites:**
- A single-page React app configured with the [SPA Quickstart](/docs/react/react-spa-quickstart)
- A development API key that starts with `gtx-dev-`
**CommonJS limitation:** Development hot reloading requires ESM because the compiler injects top-level `await`. It does not work in applications compiled as CommonJS. Production translations still work with the CommonJS startup pattern in the [SPA Quickstart](/docs/react/react-spa-quickstart).
## Setup [#setup]
### 1. Install the compiler
Install `@generaltranslation/compiler` as a development dependency:
```bash
npm i -D @generaltranslation/compiler
```
```bash
yarn add --dev @generaltranslation/compiler
```
```bash
bun add --dev @generaltranslation/compiler
```
```bash
pnpm add --save-dev @generaltranslation/compiler
```
### 2. Add the compiler plugin
Enable development hot reload in the config shared by the CLI and compiler:
```json title="gt.config.json"
{
"files": {
"gt": {
"output": "src/_gt/[locale].json",
"parsingFlags": {
"devHotReload": true
}
}
}
}
```
Then add the plugin for your bundler.
```ts title="vite.config.ts"
import react from '@vitejs/plugin-react';
import { vite as gtCompiler } from '@generaltranslation/compiler'; // [!code highlight]
import { defineConfig } from 'vite';
import gtConfig from './gt.config.json'; // [!code highlight]
export default defineConfig({
plugins: [react(), gtCompiler({ ...gtConfig })], // [!code highlight]
});
```
Install `dotenv` as a development dependency so webpack can read `.env` and `.env.local`, then add the compiler before the rest of your plugins. Use `DefinePlugin` to expose only development credentials to browser code:
```js title="webpack.config.mjs"
import { webpack as gtCompiler } from '@generaltranslation/compiler';
import dotenv from 'dotenv';
import webpack from 'webpack';
import gtConfig from './gt.config.json' with { type: 'json' };
dotenv.config({ path: '.env' });
dotenv.config({ path: '.env.local', override: true });
export default (_env, argv) => {
const isProduction = (argv.mode ?? 'production') === 'production';
return {
// Keep your existing webpack settings.
plugins: [
gtCompiler({ ...gtConfig }),
new webpack.DefinePlugin({
'process.env.GT_PROJECT_ID': JSON.stringify(
isProduction ? '' : (process.env.GT_PROJECT_ID ?? '')
),
'process.env.GT_DEV_API_KEY': JSON.stringify(
isProduction ? '' : (process.env.GT_DEV_API_KEY ?? '')
),
}),
],
};
};
```
See the complete [`gt-react` webpack example](https://github.com/generaltranslation/gt/tree/main/examples/webpack-spa) for loaders, local translation files, and development server settings.
Register the compiler before your other Rollup plugins:
```js title="rollup.config.mjs"
import { rollup as gtCompiler } from '@generaltranslation/compiler';
export default {
input: 'src/index.ts',
plugins: [
gtCompiler(),
// Your other Rollup plugins
],
};
```
Rollup cannot analyze a fully dynamic translation import. List each locale with a static import specifier:
```ts title="src/loadTranslations.ts"
const translationLoaders = {
es: () => import('./_gt/es.json'),
fr: () => import('./_gt/fr.json'),
};
export default async function loadTranslations(locale: string) {
const loader =
translationLoaders[locale as keyof typeof translationLoaders];
return loader ? (await loader()).default : {};
}
```
Plain Rollup does not provide the development credential integration shown for Vite and webpack. Regenerate local translation files when source content changes. See the complete [`gt-react` Rollup example](https://github.com/generaltranslation/gt/tree/main/examples/rollup-spa).
Add the Rspack adapter to your plugins:
```js title="rspack.config.mjs"
import { rspack as gtCompiler } from '@generaltranslation/compiler';
export default {
plugins: [gtCompiler()],
};
```
Development translation also requires exposing `GT_PROJECT_ID` and `GT_DEV_API_KEY` to browser code without including either value in production bundles.
Add the esbuild adapter to the `plugins` array:
```js title="build.mjs"
import { build } from 'esbuild';
import { esbuild as gtCompiler } from '@generaltranslation/compiler';
await build({
entryPoints: ['src/index.tsx'],
bundle: true,
outdir: 'dist',
plugins: [gtCompiler()],
});
```
*Note: The esbuild adapter does not support automatic JSX injection. Wrap translatable JSX explicitly or use another adapter when `enableAutoJsxInjection` is required.*
See the complete [`gt-react` Vite example](https://github.com/generaltranslation/gt/tree/main/examples/vite-spa) for a full Vite setup.
### 3. Add development credentials
Get a development API key at [dash.generaltranslation.com](https://dash.generaltranslation.com/en-US/signin) or by running:
```bash
npx gt auth
```
Then add your project ID and development API key to `.env.local` and pass them to your initialization function:
```bash title=".env.local"
VITE_GT_PROJECT_ID="your-project-id"
VITE_GT_DEV_API_KEY="your-dev-api-key"
```
```ts
await initializeGTSPA({
...gtConfig,
projectId: import.meta.env.VITE_GT_PROJECT_ID,
devApiKey: import.meta.env.VITE_GT_DEV_API_KEY,
loadTranslations,
});
```
```bash title=".env.local"
GT_PROJECT_ID="your-project-id"
GT_DEV_API_KEY="your-dev-api-key"
```
```ts
await initializeGTSPA({
...gtConfig,
projectId: process.env.GT_PROJECT_ID,
devApiKey: process.env.GT_DEV_API_KEY,
loadTranslations,
});
```
The webpack config above replaces both values with empty strings in production builds, so development credentials are not included in the production bundle.
**Development only:** Use a key starting with `gtx-dev-`. Never expose a production key that starts with `gtx-api-` in browser code.
### 4. Start developing
Start your development server and switch to a non-default locale. When you edit translatable content, the compiler registers the change and `gt-react` requests an updated development translation.
## Next steps
- /docs/react/guides/storing-translations
- /docs/react/guides/configuring
- /docs/react/guides/translating-jsx
- /docs/react/guides/managing-locales