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
```