or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-models.mddocument-system.mdextension-system.mdicon-system.mdindex.mdrenderer-system.mdtranslation-system.mdutility-services.md
tile.json

translation-system.mddocs/

0

# Translation System

1

2

Internationalization interfaces providing gettext-based translation support for JupyterLab extensions.

3

4

## Capabilities

5

6

### ITranslator Interface

7

8

Central interface for accessing translation services and language information.

9

10

```typescript { .api }

11

/**

12

* Translation provider interface

13

*/

14

interface ITranslator {

15

/** The code of the language in use */

16

readonly languageCode: string;

17

/**

18

* Load translation bundles for a given domain

19

* @param domain The translation domain to use for translations

20

* @returns The translation bundle if found, or the English bundle

21

*/

22

load(domain: string): TranslationBundle;

23

}

24

```

25

26

**Usage Example:**

27

28

```typescript

29

import { IRenderMime } from "@jupyterlab/rendermime-interfaces";

30

31

class InternationalizedRenderer implements IRenderMime.IRenderer {

32

private translator?: IRenderMime.ITranslator;

33

34

constructor(options: IRenderMime.IRendererOptions) {

35

this.translator = options.translator;

36

}

37

38

async renderModel(model: IRenderMime.IMimeModel): Promise<void> {

39

if (this.translator) {

40

// Load translation bundle for this extension

41

const bundle = this.translator.load('my-renderer-extension');

42

43

// Get current language

44

const lang = this.translator.languageCode;

45

console.log(`Rendering in language: ${lang}`);

46

47

// Create localized UI elements

48

const title = bundle.__('Data Visualization');

49

const loadingText = bundle.__('Loading data...');

50

const errorText = bundle.__('Failed to load data');

51

52

// Use translations in UI

53

this.node.innerHTML = `

54

<div class="renderer-header">

55

<h3>${title}</h3>

56

</div>

57

<div class="renderer-content">

58

<p>${loadingText}</p>

59

</div>

60

`;

61

}

62

}

63

}

64

```

65

66

### TranslationBundle Type

67

68

Comprehensive set of translation functions supporting various gettext patterns.

69

70

```typescript { .api }

71

/**

72

* Bundle of gettext-based translation functions for a specific domain

73

*/

74

type TranslationBundle = {

75

/**

76

* Alias for `gettext` (translate strings without number inflection)

77

* @param msgid message (text to translate)

78

* @param args additional values for interpolation

79

* @returns A translated string if found, or the original string

80

*/

81

__(msgid: string, ...args: any[]): string;

82

83

/**

84

* Alias for `ngettext` (translate accounting for plural forms)

85

* @param msgid message for singular

86

* @param msgid_plural message for plural

87

* @param n determines which plural form to use

88

* @param args additional values for interpolation

89

* @returns A translated string if found, or the original string

90

*/

91

_n(msgid: string, msgid_plural: string, n: number, ...args: any[]): string;

92

93

/**

94

* Alias for `pgettext` (translate in given context)

95

* @param msgctxt context

96

* @param msgid message (text to translate)

97

* @param args additional values for interpolation

98

* @returns A translated string if found, or the original string

99

*/

100

_p(msgctxt: string, msgid: string, ...args: any[]): string;

101

102

/**

103

* Alias for `npgettext` (translate accounting for plural forms in given context)

104

* @param msgctxt context

105

* @param msgid message for singular

106

* @param msgid_plural message for plural

107

* @param n number used to determine which plural form to use

108

* @param args additional values for interpolation

109

* @returns A translated string if found, or the original string

110

*/

111

_np(msgctxt: string, msgid: string, msgid_plural: string, n: number, ...args: any[]): string;

112

113

/**

114

* Look up the message id in the catalog and return the corresponding message string.

115

* Otherwise, the message id is returned.

116

* @param msgid message (text to translate)

117

* @param args additional values for interpolation

118

* @returns A translated string if found, or the original string

119

*/

120

gettext(msgid: string, ...args: any[]): string;

121

122

/**

123

* Do a plural-forms lookup of a message id. msgid is used as the message id for

124

* purposes of lookup in the catalog, while n is used to determine which plural form

125

* to use. Otherwise, when n is 1 msgid is returned, and msgid_plural is returned in

126

* all other cases.

127

* @param msgid message for singular

128

* @param msgid_plural message for plural

129

* @param n determines which plural form to use

130

* @param args additional values for interpolation

131

* @returns A translated string if found, or the original string

132

*/

133

ngettext(msgid: string, msgid_plural: string, n: number, ...args: any[]): string;

134

135

/**

136

* Look up the context and message id in the catalog and return the corresponding

137

* message string. Otherwise, the message id is returned.

138

* @param msgctxt context

139

* @param msgid message (text to translate)

140

* @param args additional values for interpolation

141

* @returns A translated string if found, or the original string

142

*/

143

pgettext(msgctxt: string, msgid: string, ...args: any[]): string;

144

145

/**

146

* Do a plural-forms lookup of a message id. msgid is used as the message id for

147

* purposes of lookup in the catalog, while n is used to determine which plural

148

* form to use. Otherwise, when n is 1 msgid is returned, and msgid_plural is

149

* returned in all other cases.

150

* @param msgctxt context

151

* @param msgid message for singular

152

* @param msgid_plural message for plural

153

* @param n number used to determine which plural form to use

154

* @param args additional values for interpolation

155

* @returns A translated string if found, or the original string

156

*/

157

npgettext(msgctxt: string, msgid: string, msgid_plural: string, n: number, ...args: any[]): string;

158

159

/**

160

* Do a plural-forms lookup of a message id with domain and context support.

161

* @param domain - The translations domain

162

* @param msgctxt - The message context

163

* @param msgid - The singular string to translate

164

* @param msgid_plural - The plural string to translate

165

* @param n - The number for pluralization

166

* @param args - Any additional values to use with interpolation

167

* @returns A translated string if found, or the original string

168

*/

169

dcnpgettext(domain: string, msgctxt: string, msgid: string, msgid_plural: string, n: number, ...args: any[]): string;

170

};

171

```

172

173

## Translation Usage Patterns

174

175

### Basic Translation

176

177

```typescript

178

import { IRenderMime } from "@jupyterlab/rendermime-interfaces";

179

180

function createLocalizedRenderer(translator?: IRenderMime.ITranslator): IRenderMime.IRenderer {

181

return {

182

async renderModel(model: IRenderMime.IMimeModel): Promise<void> {

183

if (translator) {

184

const bundle = translator.load('my-extension');

185

186

// Simple string translation

187

const title = bundle.__('Data Viewer');

188

const subtitle = bundle.__('Showing %s items', model.data.length);

189

190

this.node.innerHTML = `

191

<h2>${title}</h2>

192

<p>${subtitle}</p>

193

`;

194

}

195

}

196

} as IRenderMime.IRenderer;

197

}

198

```

199

200

### Plural Forms

201

202

```typescript

203

function createItemCounter(translator?: IRenderMime.ITranslator): string {

204

if (!translator) return 'Items';

205

206

const bundle = translator.load('my-extension');

207

208

return (count: number) => {

209

// Handle plural forms

210

return bundle._n(

211

'%d item found', // singular

212

'%d items found', // plural

213

count, // count for pluralization

214

count // value for substitution

215

);

216

};

217

}

218

219

// Usage

220

const counter = createItemCounter(translator);

221

console.log(counter(1)); // "1 item found"

222

console.log(counter(5)); // "5 items found"

223

```

224

225

### Contextual Translation

226

227

```typescript

228

function createStatusMessages(translator?: IRenderMime.ITranslator) {

229

if (!translator) return { processing: 'Processing', complete: 'Complete' };

230

231

const bundle = translator.load('my-extension');

232

233

return {

234

// Same word, different contexts

235

processing: bundle._p('status', 'Processing'),

236

complete: bundle._p('status', 'Complete'),

237

238

// Buttons might have different translations

239

processingButton: bundle._p('button', 'Processing'),

240

completeButton: bundle._p('button', 'Complete')

241

};

242

}

243

```

244

245

### Complex Pluralization with Context

246

247

```typescript

248

function createFileMessages(translator?: IRenderMime.ITranslator) {

249

if (!translator) return (count: number) => `${count} files`;

250

251

const bundle = translator.load('my-extension');

252

253

return {

254

selected: (count: number) => bundle._np(

255

'file-selection', // context

256

'%d file selected', // singular

257

'%d files selected', // plural

258

count, // count for pluralization

259

count // value for substitution

260

),

261

262

processed: (count: number) => bundle._np(

263

'file-processing',

264

'%d file processed',

265

'%d files processed',

266

count,

267

count

268

)

269

};

270

}

271

```

272

273

### Full Document Widget Factory with Translation

274

275

```typescript

276

import { IRenderMime } from "@jupyterlab/rendermime-interfaces";

277

278

function createInternationalizedExtension(

279

rendererFactory: IRenderMime.IRendererFactory,

280

translator?: IRenderMime.ITranslator

281

): IRenderMime.IExtension {

282

283

let bundle: IRenderMime.TranslationBundle | undefined;

284

if (translator) {

285

bundle = translator.load('my-data-renderer');

286

}

287

288

// Helper function for translations

289

const __ = (msgid: string, ...args: any[]) =>

290

bundle ? bundle.__(msgid, ...args) : msgid;

291

292

return {

293

id: 'my-org:data-renderer',

294

description: __('Advanced data visualization renderer'),

295

rendererFactory,

296

297

documentWidgetFactoryOptions: {

298

name: __('Data Visualizer'),

299

label: __('Data Viz'),

300

primaryFileType: 'data-viz',

301

fileTypes: ['data-viz'],

302

translator,

303

304

toolbarFactory: (widget) => [

305

{

306

name: 'refresh',

307

widget: createButton(__('Refresh'), () => {

308

console.log(__('Refreshing data...'));

309

})

310

},

311

{

312

name: 'export',

313

widget: createButton(__('Export'), () => {

314

console.log(__('Exporting data...'));

315

})

316

}

317

]

318

},

319

320

fileTypes: [

321

{

322

name: 'data-viz',

323

mimeTypes: ['application/data-viz'],

324

extensions: ['.dviz'],

325

displayName: __('Data Visualization')

326

}

327

]

328

};

329

}

330

331

function createButton(label: string, onClick: () => void) {

332

// Create a simple button widget

333

const button = document.createElement('button');

334

button.textContent = label;

335

button.onclick = onClick;

336

337

// Return as Widget-like object

338

return { node: button } as any;

339

}

340

```

341

342

### Language Detection and Adaptation

343

344

```typescript

345

class AdaptiveRenderer implements IRenderMime.IRenderer {

346

constructor(private options: IRenderMime.IRendererOptions) {}

347

348

async renderModel(model: IRenderMime.IMimeModel): Promise<void> {

349

const translator = this.options.translator;

350

351

if (translator) {

352

const bundle = translator.load('my-renderer');

353

const lang = translator.languageCode;

354

355

// Adapt rendering based on language

356

const isRTL = ['ar', 'he', 'fa'].includes(lang);

357

358

if (isRTL) {

359

this.node.style.direction = 'rtl';

360

this.node.style.textAlign = 'right';

361

}

362

363

// Use appropriate number formatting

364

const formatter = new Intl.NumberFormat(lang);

365

const data = model.data as { count: number };

366

367

this.node.innerHTML = `

368

<div class="data-display">

369

<h3>${bundle.__('Data Summary')}</h3>

370

<p>${bundle.__('Count: %s', formatter.format(data.count))}</p>

371

</div>

372

`;

373

}

374

}

375

}

376

```