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

string-localization.mddocs/

0

# String Localization and Search

1

2

Advanced string handling including localization with interpolation, collation, and locale-aware text filtering capabilities.

3

4

## Capabilities

5

6

### useLocalizedStringFormatter Hook

7

8

Provides localized string formatting with support for interpolation, pluralization, and variable substitution.

9

10

```typescript { .api }

11

/**

12

* Provides localized string formatting for the current locale. Supports interpolating variables,

13

* selecting the correct pluralization, and formatting numbers. Automatically updates when the locale changes.

14

* @param strings - A mapping of languages to localized strings by key

15

* @param packageName - Optional package name for global dictionary lookup

16

* @returns LocalizedStringFormatter instance

17

*/

18

function useLocalizedStringFormatter<K extends string = string, T extends LocalizedString = string>(

19

strings: LocalizedStrings<K, T>,

20

packageName?: string

21

): LocalizedStringFormatter<K, T>;

22

23

type LocalizedStrings<K extends string = string, T extends LocalizedString = string> = Record<string, Record<K, T>>;

24

25

type LocalizedString = string | LocalizedStringParams;

26

27

interface LocalizedStringParams {

28

/** The default string value */

29

message: string;

30

/** Optional description for translators */

31

description?: string;

32

}

33

```

34

35

**Usage Examples:**

36

37

```typescript

38

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

39

40

// Define localized strings

41

const strings = {

42

"en-US": {

43

greeting: "Hello, {name}!",

44

itemCount: {

45

message: "{count, plural, =0 {No items} =1 {One item} other {# items}}",

46

description: "Number of items in the list"

47

},

48

welcome: "Welcome to our application"

49

},

50

"es-ES": {

51

greeting: "¡Hola, {name}!",

52

itemCount: {

53

message: "{count, plural, =0 {Sin elementos} =1 {Un elemento} other {# elementos}}",

54

description: "Número de elementos en la lista"

55

},

56

welcome: "Bienvenido a nuestra aplicación"

57

},

58

"fr-FR": {

59

greeting: "Bonjour, {name} !",

60

itemCount: {

61

message: "{count, plural, =0 {Aucun élément} =1 {Un élément} other {# éléments}}",

62

description: "Nombre d'éléments dans la liste"

63

},

64

welcome: "Bienvenue dans notre application"

65

}

66

};

67

68

// Basic string localization

69

function LocalizedGreeting() {

70

const formatter = useLocalizedStringFormatter(strings);

71

72

return (

73

<div>

74

<p>{formatter.format("welcome")}</p>

75

<p>{formatter.format("greeting", { name: "Maria" })}</p>

76

</div>

77

);

78

}

79

80

// Pluralization example

81

function ItemCounter({ count }: { count: number }) {

82

const formatter = useLocalizedStringFormatter(strings);

83

84

return (

85

<p>{formatter.format("itemCount", { count })}</p>

86

);

87

}

88

89

// Using with different locales

90

function MultiLocaleExample() {

91

return (

92

<div>

93

<I18nProvider locale="en-US">

94

<LocalizedContent />

95

</I18nProvider>

96

<I18nProvider locale="es-ES">

97

<LocalizedContent />

98

</I18nProvider>

99

<I18nProvider locale="fr-FR">

100

<LocalizedContent />

101

</I18nProvider>

102

</div>

103

);

104

}

105

106

function LocalizedContent() {

107

const formatter = useLocalizedStringFormatter(strings);

108

109

return (

110

<div>

111

<h2>{formatter.format("welcome")}</h2>

112

<p>{formatter.format("greeting", { name: "Alex" })}</p>

113

<p>{formatter.format("itemCount", { count: 3 })}</p>

114

</div>

115

);

116

}

117

```

118

119

### useLocalizedStringDictionary Hook

120

121

Returns a cached LocalizedStringDictionary for reuse across components.

122

123

```typescript { .api }

124

/**

125

* Returns a cached LocalizedStringDictionary for the given strings.

126

* @param strings - A mapping of languages to localized strings by key

127

* @param packageName - Optional package name for global dictionary lookup

128

* @returns LocalizedStringDictionary instance

129

*/

130

function useLocalizedStringDictionary<K extends string = string, T extends LocalizedString = string>(

131

strings: LocalizedStrings<K, T>,

132

packageName?: string

133

): LocalizedStringDictionary<K, T>;

134

```

135

136

### useMessageFormatter Hook (Deprecated)

137

138

Legacy hook for ICU message formatting. Use `useLocalizedStringFormatter` instead.

139

140

```typescript { .api }

141

/**

142

* Handles formatting ICU Message strings to create localized strings for the current locale.

143

* @deprecated - use useLocalizedStringFormatter instead

144

* @param strings - A mapping of languages to strings by key

145

* @returns FormatMessage function

146

*/

147

function useMessageFormatter(strings: LocalizedStrings): FormatMessage;

148

149

type FormatMessage = (key: string, variables?: {[key: string]: any}) => string;

150

```

151

152

### useCollator Hook

153

154

Provides locale-aware string collation for sorting and comparison operations.

155

156

```typescript { .api }

157

/**

158

* Provides localized string collation for the current locale. Automatically updates when the locale changes,

159

* and handles caching of the collator for performance.

160

* @param options - Collator options for comparison behavior

161

* @returns Intl.Collator instance

162

*/

163

function useCollator(options?: Intl.CollatorOptions): Intl.Collator;

164

165

interface Intl.CollatorOptions {

166

/** The locale matching algorithm to use */

167

localeMatcher?: "best fit" | "lookup";

168

/** Whether to use numeric collation */

169

numeric?: boolean;

170

/** Case sensitivity */

171

caseFirst?: "upper" | "lower" | "false";

172

/** Sensitivity level */

173

sensitivity?: "base" | "accent" | "case" | "variant";

174

/** Whether to ignore punctuation */

175

ignorePunctuation?: boolean;

176

/** Usage hint */

177

usage?: "sort" | "search";

178

}

179

```

180

181

**Usage Examples:**

182

183

```typescript

184

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

185

186

// Basic string comparison and sorting

187

function StringComparison() {

188

const collator = useCollator();

189

190

const compare = (a: string, b: string) => collator.compare(a, b);

191

192

const items = ["zebra", "apple", "banana"];

193

const sortedItems = items.sort(compare);

194

195

return (

196

<ul>

197

{sortedItems.map(item => (

198

<li key={item}>{item}</li>

199

))}

200

</ul>

201

);

202

}

203

204

// Case-insensitive comparison

205

function CaseInsensitiveSort() {

206

const collator = useCollator({

207

sensitivity: "base" // ignore case and accents

208

});

209

210

const items = ["Apple", "banana", "Cherry"];

211

const sorted = items.sort(collator.compare);

212

213

return <p>Sorted: {sorted.join(", ")}</p>;

214

}

215

216

// Numeric sorting

217

function NumericSort() {

218

const collator = useCollator({

219

numeric: true

220

});

221

222

const files = ["file1.txt", "file10.txt", "file2.txt"];

223

const sorted = files.sort(collator.compare);

224

225

return <p>Files: {sorted.join(", ")}</p>;

226

// Result: "file1.txt, file2.txt, file10.txt"

227

}

228

229

// Accent-sensitive comparison

230

function AccentComparison() {

231

const collator = useCollator({

232

sensitivity: "accent"

233

});

234

235

const words = ["café", "cafe", "naïve", "naive"];

236

const grouped = words.reduce((acc, word) => {

237

const group = acc.find(g => collator.compare(g[0], word) === 0);

238

if (group) {

239

group.push(word);

240

} else {

241

acc.push([word]);

242

}

243

return acc;

244

}, [] as string[][]);

245

246

return (

247

<div>

248

{grouped.map((group, i) => (

249

<p key={i}>Group {i + 1}: {group.join(", ")}</p>

250

))}

251

</div>

252

);

253

}

254

```

255

256

### useFilter Hook

257

258

Provides locale-aware string filtering and search functionality.

259

260

```typescript { .api }

261

/**

262

* Provides localized string search functionality that is useful for filtering or matching items

263

* in a list. Options can be provided to adjust the sensitivity to case, diacritics, and other parameters.

264

* @param options - Collator options affecting search behavior

265

* @returns Filter object with search methods

266

*/

267

function useFilter(options?: Intl.CollatorOptions): Filter;

268

269

interface Filter {

270

/** Returns whether a string starts with a given substring */

271

startsWith(string: string, substring: string): boolean;

272

/** Returns whether a string ends with a given substring */

273

endsWith(string: string, substring: string): boolean;

274

/** Returns whether a string contains a given substring */

275

contains(string: string, substring: string): boolean;

276

}

277

```

278

279

**Usage Examples:**

280

281

```typescript

282

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

283

284

// Basic filtering

285

function SearchableList() {

286

const filter = useFilter();

287

const [query, setQuery] = useState("");

288

289

const items = ["Apple", "Banana", "Cherry", "Date", "Elderberry"];

290

291

const filteredItems = items.filter(item =>

292

filter.contains(item.toLowerCase(), query.toLowerCase())

293

);

294

295

return (

296

<div>

297

<input

298

value={query}

299

onChange={(e) => setQuery(e.target.value)}

300

placeholder="Search items..."

301

/>

302

<ul>

303

{filteredItems.map(item => (

304

<li key={item}>{item}</li>

305

))}

306

</ul>

307

</div>

308

);

309

}

310

311

// Case-insensitive filtering

312

function CaseInsensitiveFilter() {

313

const filter = useFilter({

314

sensitivity: "base" // ignore case and accents

315

});

316

317

const names = ["André", "Anna", "Björn", "Café"];

318

const query = "an";

319

320

const matches = names.filter(name => filter.contains(name, query));

321

322

return <p>Matches for "{query}": {matches.join(", ")}</p>;

323

}

324

325

// Prefix filtering

326

function PrefixFilter() {

327

const filter = useFilter();

328

const [prefix, setPrefix] = useState("");

329

330

const words = ["react", "redux", "router", "component", "context"];

331

332

const prefixMatches = words.filter(word =>

333

filter.startsWith(word, prefix)

334

);

335

336

return (

337

<div>

338

<input

339

value={prefix}

340

onChange={(e) => setPrefix(e.target.value)}

341

placeholder="Type prefix..."

342

/>

343

<p>Words starting with "{prefix}": {prefixMatches.join(", ")}</p>

344

</div>

345

);

346

}

347

348

// Suffix filtering

349

function SuffixFilter() {

350

const filter = useFilter();

351

352

const files = ["document.pdf", "image.png", "script.js", "style.css"];

353

const extension = ".js";

354

355

const jsFiles = files.filter(file =>

356

filter.endsWith(file, extension)

357

);

358

359

return <p>JavaScript files: {jsFiles.join(", ")}</p>;

360

}

361

362

// Advanced search with multiple criteria

363

function AdvancedSearch() {

364

const filter = useFilter({

365

sensitivity: "base",

366

ignorePunctuation: true

367

});

368

369

const products = [

370

"iPhone 14 Pro",

371

"Samsung Galaxy S23",

372

"Google Pixel 7",

373

"OnePlus 11"

374

];

375

376

const [searchTerm, setSearchTerm] = useState("");

377

378

const results = products.filter(product => {

379

const terms = searchTerm.split(" ");

380

return terms.every(term =>

381

filter.contains(product, term)

382

);

383

});

384

385

return (

386

<div>

387

<input

388

value={searchTerm}

389

onChange={(e) => setSearchTerm(e.target.value)}

390

placeholder="Search products..."

391

/>

392

<ul>

393

{results.map(product => (

394

<li key={product}>{product}</li>

395

))}

396

</ul>

397

</div>

398

);

399

}

400

```