or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

components.mdhocs.mdhooks.mdicu-macro.mdindex.mdssr.md

ssr.mddocs/

0

# Server-Side Rendering

1

2

React i18next provides comprehensive server-side rendering (SSR) support for Next.js, Remix, and other SSR frameworks, including initial data hydration and SSR-safe component rendering.

3

4

## Capabilities

5

6

### useSSR Hook

7

8

Hook for initializing i18next with pre-loaded translations and language settings from the server.

9

10

```typescript { .api }

11

/**

12

* Hook for SSR initialization with pre-loaded translation data

13

* @param initialI18nStore - Translation resources loaded on server

14

* @param initialLanguage - Language detected/set on server

15

* @param props - Optional configuration with custom i18next instance

16

*/

17

function useSSR(

18

initialI18nStore: Resource,

19

initialLanguage: string,

20

props?: { i18n?: i18n }

21

): void;

22

23

interface Resource {

24

[language: string]: {

25

[namespace: string]: any;

26

};

27

}

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

import { useSSR, useTranslation } from "react-i18next";

34

35

// Next.js page component

36

function HomePage({ initialI18nStore, initialLanguage }) {

37

useSSR(initialI18nStore, initialLanguage);

38

const { t } = useTranslation();

39

40

return (

41

<div>

42

<h1>{t('welcome')}</h1>

43

<p>{t('description')}</p>

44

</div>

45

);

46

}

47

48

export async function getServerSideProps(context) {

49

// Get initial props on server

50

const { initialI18nStore, initialLanguage } = getInitialProps();

51

52

return {

53

props: {

54

initialI18nStore,

55

initialLanguage

56

}

57

};

58

}

59

60

// With custom i18next instance

61

function CustomSSRPage({ ssrData, customI18n }) {

62

useSSR(ssrData.store, ssrData.language, { i18n: customI18n });

63

const { t } = useTranslation();

64

65

return <div>{t('content')}</div>;

66

}

67

68

// Remix loader example

69

export async function loader({ request }) {

70

const { initialI18nStore, initialLanguage } = getInitialProps();

71

72

return json({

73

initialI18nStore,

74

initialLanguage

75

});

76

}

77

78

export default function RemixPage() {

79

const { initialI18nStore, initialLanguage } = useLoaderData();

80

useSSR(initialI18nStore, initialLanguage);

81

82

const { t } = useTranslation();

83

return <h1>{t('title')}</h1>;

84

}

85

```

86

87

### Initial Props Generation

88

89

Functions for generating initial translation data on the server.

90

91

```typescript { .api }

92

/**

93

* Generates initial props for SSR with translation data

94

* @returns Object with translation store and current language

95

*/

96

function getInitialProps(): {

97

initialI18nStore: { [ns: string]: {} };

98

initialLanguage: string;

99

};

100

101

/**

102

* Composes initial props from component and translation data

103

* @param ForComponent - Component with potential getInitialProps method

104

* @returns Async function that combines component and i18n initial props

105

*/

106

function composeInitialProps(ForComponent: any): (ctx: unknown) => Promise<{

107

[key: string]: any;

108

initialI18nStore: { [ns: string]: {} };

109

initialLanguage: string;

110

}>;

111

```

112

113

**Usage Examples:**

114

115

```typescript

116

import { getInitialProps, composeInitialProps } from "react-i18next";

117

118

// Basic initial props generation

119

export async function getServerSideProps() {

120

const i18nProps = getInitialProps();

121

122

return {

123

props: {

124

...i18nProps,

125

// Additional server-side data

126

serverTime: new Date().toISOString()

127

}

128

};

129

}

130

131

// Composing with component initial props

132

class ProductPage extends React.Component {

133

static async getInitialProps(ctx) {

134

const productId = ctx.query.id;

135

const product = await fetchProduct(productId);

136

137

return { product };

138

}

139

140

render() {

141

const { t, product } = this.props;

142

return (

143

<div>

144

<h1>{t('product.title', { name: product.name })}</h1>

145

<p>{t('product.price', { price: product.price })}</p>

146

</div>

147

);

148

}

149

}

150

151

// Combine component and i18n initial props

152

ProductPage.getInitialProps = composeInitialProps(ProductPage);

153

154

// Manual composition

155

export async function getServerSideProps(context) {

156

// Get component-specific data

157

const productId = context.query.id;

158

const product = await fetchProduct(productId);

159

160

// Get i18n data

161

const { initialI18nStore, initialLanguage } = getInitialProps();

162

163

return {

164

props: {

165

product,

166

initialI18nStore,

167

initialLanguage

168

}

169

};

170

}

171

```

172

173

### withSSR HOC

174

175

Higher-order component that automatically adds SSR support to components.

176

177

```typescript { .api }

178

/**

179

* HOC that adds SSR support with automatic getInitialProps generation

180

* @returns HOC function that wraps components with SSR capabilities

181

*/

182

function withSSR(): <Props>(

183

WrappedComponent: React.ComponentType<Props>

184

) => {

185

(props: {

186

initialI18nStore: Resource;

187

initialLanguage: string;

188

} & Props): React.FunctionComponentElement<Props>;

189

getInitialProps: (ctx: unknown) => Promise<any>;

190

};

191

```

192

193

**Usage Examples:**

194

195

```typescript

196

import { withSSR, withTranslation } from "react-i18next";

197

198

// Component with automatic SSR support

199

class BlogPost extends React.Component {

200

static async getInitialProps(ctx) {

201

const postId = ctx.query.id;

202

const post = await fetchBlogPost(postId);

203

return { post };

204

}

205

206

render() {

207

const { t, post } = this.props;

208

return (

209

<article>

210

<h1>{t('blog.title', { title: post.title })}</h1>

211

<div>{post.content}</div>

212

</article>

213

);

214

}

215

}

216

217

// Apply both translation and SSR HOCs

218

export default withSSR()(withTranslation('blog')(BlogPost));

219

220

// Functional component with SSR

221

function NewsPage({ articles, t }) {

222

return (

223

<div>

224

<h1>{t('news.headline')}</h1>

225

{articles.map(article => (

226

<div key={article.id}>

227

<h2>{article.title}</h2>

228

<p>{article.summary}</p>

229

</div>

230

))}

231

</div>

232

);

233

}

234

235

NewsPage.getInitialProps = async () => {

236

const articles = await fetchLatestNews();

237

return { articles };

238

};

239

240

export default withSSR()(withTranslation('news')(NewsPage));

241

```

242

243

## Framework Integration

244

245

### Next.js Integration

246

247

Complete Next.js setup with SSR support:

248

249

```typescript

250

// pages/_app.js

251

import { appWithTranslation } from 'next-i18next';

252

import { I18nextProvider } from 'react-i18next';

253

import i18n from '../i18n/config';

254

255

function MyApp({ Component, pageProps }) {

256

return (

257

<I18nextProvider i18n={i18n}>

258

<Component {...pageProps} />

259

</I18nextProvider>

260

);

261

}

262

263

export default appWithTranslation(MyApp);

264

265

// pages/index.js

266

import { useSSR, useTranslation } from 'react-i18next';

267

import { getInitialProps } from 'react-i18next';

268

269

function HomePage(props) {

270

useSSR(props.initialI18nStore, props.initialLanguage);

271

const { t } = useTranslation();

272

273

return <h1>{t('welcome')}</h1>;

274

}

275

276

export async function getServerSideProps() {

277

return {

278

props: getInitialProps()

279

};

280

}

281

282

export default HomePage;

283

284

// Alternative with getStaticProps

285

export async function getStaticProps({ locale }) {

286

return {

287

props: {

288

...getInitialProps(),

289

// Additional static props

290

}

291

};

292

}

293

```

294

295

### Remix Integration

296

297

```typescript

298

// app/root.tsx

299

import { useSSR } from 'react-i18next';

300

import { useLoaderData } from '@remix-run/react';

301

302

export async function loader() {

303

const { initialI18nStore, initialLanguage } = getInitialProps();

304

return json({ initialI18nStore, initialLanguage });

305

}

306

307

export default function App() {

308

const { initialI18nStore, initialLanguage } = useLoaderData();

309

useSSR(initialI18nStore, initialLanguage);

310

311

return (

312

<html>

313

<head />

314

<body>

315

<Outlet />

316

</body>

317

</html>

318

);

319

}

320

321

// app/routes/index.tsx

322

export default function Index() {

323

const { t } = useTranslation();

324

return <h1>{t('welcome')}</h1>;

325

}

326

```

327

328

### Custom SSR Setup

329

330

```typescript

331

// server.js (Express example)

332

import express from 'express';

333

import React from 'react';

334

import { renderToString } from 'react-dom/server';

335

import { I18nextProvider } from 'react-i18next';

336

import { getInitialProps } from 'react-i18next';

337

import App from './App';

338

import i18n from './i18n/config';

339

340

const server = express();

341

342

server.get('*', async (req, res) => {

343

// Initialize i18n for this request

344

const { initialI18nStore, initialLanguage } = getInitialProps();

345

346

// Render React app to string

347

const html = renderToString(

348

<I18nextProvider i18n={i18n}>

349

<App

350

initialI18nStore={initialI18nStore}

351

initialLanguage={initialLanguage}

352

/>

353

</I18nextProvider>

354

);

355

356

res.send(`

357

<!DOCTYPE html>

358

<html>

359

<body>

360

<div id="root">${html}</div>

361

<script>

362

window.__INITIAL_I18N_STORE__ = ${JSON.stringify(initialI18nStore)};

363

window.__INITIAL_LANGUAGE__ = "${initialLanguage}";

364

</script>

365

</body>

366

</html>

367

`);

368

});

369

```

370

371

## Namespace Reporting

372

373

React i18next automatically tracks used namespaces for SSR optimization:

374

375

```typescript { .api }

376

/**

377

* Namespace usage tracking for SSR optimization

378

*/

379

interface ReportNamespaces {

380

/** Add namespaces to the used list */

381

addUsedNamespaces(namespaces: Namespace): void;

382

/** Get list of namespaces used during rendering */

383

getUsedNamespaces(): string[];

384

}

385

```

386

387

**Usage Examples:**

388

389

```typescript

390

// Automatic namespace tracking

391

function Component() {

392

const { t } = useTranslation(['common', 'user']); // Automatically tracked

393

return <div>{t('common:welcome')}</div>;

394

}

395

396

// Manual namespace reporting

397

import { getI18n } from 'react-i18next';

398

399

const i18n = getI18n();

400

if (i18n.reportNamespaces) {

401

i18n.reportNamespaces.addUsedNamespaces(['admin', 'dashboard']);

402

}

403

404

// Server-side namespace collection

405

export async function getServerSideProps() {

406

const i18n = getI18n();

407

408

// Render app to collect used namespaces

409

renderToString(<App />);

410

411

// Get only the namespaces that were actually used

412

const usedNamespaces = i18n.reportNamespaces?.getUsedNamespaces() || [];

413

414

return {

415

props: {

416

...getInitialProps(),

417

usedNamespaces

418

}

419

};

420

}

421

```

422

423

## SSR Best Practices

424

425

### Hydration Safety

426

427

Ensure client and server render the same content:

428

429

```typescript

430

// Avoid hydration mismatches

431

function SafeComponent({ initialI18nStore, initialLanguage }) {

432

useSSR(initialI18nStore, initialLanguage);

433

const { t, ready } = useTranslation();

434

435

// Wait for client-side hydration

436

if (!ready) {

437

return <div>Loading...</div>; // Same as server

438

}

439

440

return <div>{t('content')}</div>;

441

}

442

```

443

444

### Performance Optimization

445

446

```typescript

447

// Load only required namespaces

448

export async function getServerSideProps() {

449

const requiredNamespaces = ['common', 'home'];

450

451

const i18n = getI18n();

452

await Promise.all(

453

requiredNamespaces.map(ns => i18n.loadNamespaces(ns))

454

);

455

456

return {

457

props: getInitialProps()

458

};

459

}

460

```

461

462

### Error Handling

463

464

```typescript

465

function SSRErrorBoundary({ children, initialI18nStore, initialLanguage }) {

466

try {

467

useSSR(initialI18nStore, initialLanguage);

468

return children;

469

} catch (error) {

470

console.error('SSR initialization failed:', error);

471

// Fallback to client-side initialization

472

return <div>Loading...</div>;

473

}

474

}

475

```