or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-locale.mddate-time-formatting.mdindex.mdnumber-list-formatting.mdserver-support.mdstring-localization.md

server-support.mddocs/

0

# Server-Side Rendering Support

1

2

Components and utilities for server-side localization with client hydration support, enabling seamless internationalization in SSR applications.

3

4

## Capabilities

5

6

### PackageLocalizationProvider Component

7

8

Server-only component that injects localized strings into the initial HTML for client-side hydration.

9

10

```typescript { .api }

11

/**

12

* A PackageLocalizationProvider can be rendered on the server to inject the localized strings

13

* needed by the client into the initial HTML.

14

* @param props - Configuration for package localization

15

* @returns JSX.Element for server-side rendering or null on client

16

*/

17

function PackageLocalizationProvider(props: PackageLocalizationProviderProps): JSX.Element | null;

18

19

interface PackageLocalizationProviderProps {

20

/** The target locale for the injected strings */

21

locale: string;

22

/** Package localization strings organized by package name */

23

strings: PackageLocalizedStrings;

24

/** Optional CSP nonce for inline script security */

25

nonce?: string;

26

}

27

28

type PackageLocalizedStrings = {

29

[packageName: string]: Record<string, LocalizedString>;

30

};

31

```

32

33

**Usage Examples:**

34

35

```typescript

36

// Server-side usage (Next.js, Express, etc.)

37

import { PackageLocalizationProvider } from "@react-aria/i18n/server";

38

39

const localizationStrings = {

40

"@myapp/components": {

41

"welcome": "Welcome to our application",

42

"login": "Log in",

43

"logout": "Log out"

44

},

45

"@myapp/forms": {

46

"required": "This field is required",

47

"invalid_email": "Please enter a valid email"

48

}

49

};

50

51

function ServerApp({ locale, nonce }: { locale: string; nonce?: string }) {

52

return (

53

<html>

54

<head>

55

<PackageLocalizationProvider

56

locale={locale}

57

strings={localizationStrings}

58

nonce={nonce}

59

/>

60

</head>

61

<body>

62

<div id="root">

63

{/* Your app content */}

64

</div>

65

</body>

66

</html>

67

);

68

}

69

70

// Next.js integration example

71

import { GetServerSideProps } from "next";

72

73

export const getServerSideProps: GetServerSideProps = async (context) => {

74

const locale = context.locale || "en-US";

75

76

// Load localization strings for the specific locale

77

const strings = await loadLocalizationStrings(locale);

78

79

return {

80

props: {

81

locale,

82

strings

83

}

84

};

85

};

86

87

function MyPage({ locale, strings }: { locale: string; strings: PackageLocalizedStrings }) {

88

return (

89

<>

90

<Head>

91

<PackageLocalizationProvider

92

locale={locale}

93

strings={strings}

94

/>

95

</Head>

96

<main>

97

{/* Your page content */}

98

</main>

99

</>

100

);

101

}

102

103

// Express.js integration example

104

import express from "express";

105

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

106

107

app.get("*", (req, res) => {

108

const locale = req.headers["accept-language"]?.split(",")[0] || "en-US";

109

const strings = getLocalizationStrings(locale);

110

111

const html = renderToString(

112

<PackageLocalizationProvider

113

locale={locale}

114

strings={strings}

115

/>

116

);

117

118

res.send(`

119

<!DOCTYPE html>

120

<html>

121

<head>${html}</head>

122

<body>

123

<div id="root">${/* app content */}</div>

124

</body>

125

</html>

126

`);

127

});

128

```

129

130

### getPackageLocalizationScript Function

131

132

Utility function that generates the script content for injecting localized strings into HTML.

133

134

```typescript { .api }

135

/**

136

* Returns the content for an inline <script> tag to inject localized strings into initial HTML.

137

* @param locale - The target locale string

138

* @param strings - Package localization strings to inject

139

* @returns String content for inline script tag

140

*/

141

function getPackageLocalizationScript(locale: string, strings: PackageLocalizedStrings): string;

142

```

143

144

**Usage Examples:**

145

146

```typescript

147

import { getPackageLocalizationScript } from "@react-aria/i18n/server";

148

149

// Manual script injection

150

function manualScriptInjection() {

151

const locale = "es-ES";

152

const strings = {

153

"@myapp/ui": {

154

"save": "Guardar",

155

"cancel": "Cancelar",

156

"delete": "Eliminar"

157

}

158

};

159

160

const scriptContent = getPackageLocalizationScript(locale, strings);

161

162

// Use with template engines

163

const html = `

164

<!DOCTYPE html>

165

<html>

166

<head>

167

<script>${scriptContent}</script>

168

</head>

169

<body>

170

<!-- App content -->

171

</body>

172

</html>

173

`;

174

175

return html;

176

}

177

178

// Custom server rendering with security headers

179

function secureScriptInjection(nonce: string) {

180

const locale = "fr-FR";

181

const strings = {

182

"@myapp/dashboard": {

183

"overview": "Aperçu",

184

"settings": "Paramètres",

185

"profile": "Profil"

186

}

187

};

188

189

const scriptContent = getPackageLocalizationScript(locale, strings);

190

191

return `<script nonce="${nonce}">${scriptContent}</script>`;

192

}

193

194

// Integration with build-time optimization

195

function buildTimeOptimization() {

196

const supportedLocales = ["en-US", "es-ES", "fr-FR", "de-DE"];

197

const allStrings = loadAllLocalizationStrings();

198

199

// Pre-generate scripts for each locale

200

const precompiledScripts = supportedLocales.reduce((acc, locale) => {

201

const localeStrings = filterStringsByLocale(allStrings, locale);

202

acc[locale] = getPackageLocalizationScript(locale, localeStrings);

203

return acc;

204

}, {} as Record<string, string>);

205

206

// Save to build artifacts for runtime use

207

return precompiledScripts;

208

}

209

```

210

211

### Server-Side Locale Detection

212

213

Utilities for detecting and handling locales in server environments.

214

215

**Common Patterns:**

216

217

```typescript

218

// Express.js locale detection

219

function detectLocaleFromRequest(req: express.Request): string {

220

// Priority: URL param > Accept-Language header > default

221

const urlLocale = req.query.locale as string;

222

const headerLocale = req.headers["accept-language"]?.split(",")[0];

223

224

return urlLocale || headerLocale || "en-US";

225

}

226

227

// Next.js automatic locale detection

228

export const getServerSideProps: GetServerSideProps = async ({ locale, req }) => {

229

// Next.js automatically detects locale from routing or headers

230

const detectedLocale = locale || "en-US";

231

232

const strings = await loadStringsForLocale(detectedLocale);

233

234

return {

235

props: {

236

locale: detectedLocale,

237

strings

238

}

239

};

240

};

241

242

// Custom locale validation and fallback

243

function validateAndFallbackLocale(requestedLocale: string): string {

244

const supportedLocales = ["en-US", "es-ES", "fr-FR", "de-DE"];

245

const normalizedLocale = requestedLocale.toLowerCase();

246

247

// Exact match

248

if (supportedLocales.includes(requestedLocale)) {

249

return requestedLocale;

250

}

251

252

// Language-only fallback (e.g., "es" -> "es-ES")

253

const languageOnly = requestedLocale.split("-")[0];

254

const languageMatch = supportedLocales.find(locale =>

255

locale.startsWith(languageOnly)

256

);

257

258

return languageMatch || "en-US";

259

}

260

```

261

262

### Hydration Considerations

263

264

Important considerations for client-side hydration with server-injected localization.

265

266

**Best Practices:**

267

268

```typescript

269

// Client-side hydration handling

270

import { I18nProvider, useLocalizedStringFormatter } from "@react-aria/i18n";

271

272

function ClientApp({ serverLocale }: { serverLocale: string }) {

273

// Use server locale initially to prevent hydration mismatches

274

const [locale, setLocale] = useState(serverLocale);

275

276

useEffect(() => {

277

// After hydration, can update to browser preference if desired

278

const browserLocale = navigator.language;

279

if (browserLocale !== serverLocale) {

280

// Optionally update locale based on user preference

281

setLocale(browserLocale);

282

}

283

}, [serverLocale]);

284

285

return (

286

<I18nProvider locale={locale}>

287

<App />

288

</I18nProvider>

289

);

290

}

291

292

// Preventing hydration warnings with SSR-safe components

293

function SSRSafeLocaleDisplay() {

294

const [isClient, setIsClient] = useState(false);

295

const { locale } = useLocale();

296

297

useEffect(() => {

298

setIsClient(true);

299

}, []);

300

301

if (!isClient) {

302

// Return server-safe content

303

return <span>Loading locale...</span>;

304

}

305

306

return <span>Current locale: {locale}</span>;

307

}

308

309

// Error boundary for localization failures

310

class LocalizationErrorBoundary extends React.Component {

311

constructor(props) {

312

super(props);

313

this.state = { hasError: false };

314

}

315

316

static getDerivedStateFromError(error) {

317

return { hasError: true };

318

}

319

320

componentDidCatch(error, errorInfo) {

321

console.error("Localization error:", error, errorInfo);

322

}

323

324

render() {

325

if (this.state.hasError) {

326

return <div>Localization failed. Falling back to default content.</div>;

327

}

328

329

return this.props.children;

330

}

331

}

332

```

333

334

### Performance Optimization

335

336

Techniques for optimizing server-side localization performance.

337

338

```typescript

339

// String compression and caching

340

const localizationCache = new Map<string, PackageLocalizedStrings>();

341

342

function getCachedStrings(locale: string): PackageLocalizedStrings {

343

if (!localizationCache.has(locale)) {

344

const strings = loadLocalizationStrings(locale);

345

localizationCache.set(locale, strings);

346

}

347

348

return localizationCache.get(locale)!;

349

}

350

351

// Lazy loading of locale strings

352

async function lazyLoadStrings(locale: string, packages: string[]) {

353

const promises = packages.map(pkg =>

354

import(`./locales/${locale}/${pkg}.json`)

355

);

356

357

const results = await Promise.all(promises);

358

359

return packages.reduce((acc, pkg, index) => {

360

acc[pkg] = results[index].default;

361

return acc;

362

}, {} as PackageLocalizedStrings);

363

}

364

365

// Build-time string optimization

366

function optimizeStringsForProduction(strings: PackageLocalizedStrings) {

367

// Remove developer comments and descriptions

368

const optimized = {};

369

370

for (const [pkg, pkgStrings] of Object.entries(strings)) {

371

optimized[pkg] = {};

372

for (const [key, value] of Object.entries(pkgStrings)) {

373

if (typeof value === "string") {

374

optimized[pkg][key] = value;

375

} else {

376

// Remove description, keep only message

377

optimized[pkg][key] = value.message;

378

}

379

}

380

}

381

382

return optimized as PackageLocalizedStrings;

383

}

384

```