CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jupyterlab--rendermime-interfaces

TypeScript interfaces for implementing MIME renderer extensions in JupyterLab

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

translation-system.mddocs/

Translation System

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

Capabilities

ITranslator Interface

Central interface for accessing translation services and language information.

/**
 * Translation provider interface
 */
interface ITranslator {
  /** The code of the language in use */
  readonly languageCode: string;
  /**
   * Load translation bundles for a given domain
   * @param domain The translation domain to use for translations
   * @returns The translation bundle if found, or the English bundle
   */
  load(domain: string): TranslationBundle;
}

Usage Example:

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

class InternationalizedRenderer implements IRenderMime.IRenderer {
  private translator?: IRenderMime.ITranslator;
  
  constructor(options: IRenderMime.IRendererOptions) {
    this.translator = options.translator;
  }

  async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
    if (this.translator) {
      // Load translation bundle for this extension
      const bundle = this.translator.load('my-renderer-extension');
      
      // Get current language
      const lang = this.translator.languageCode;
      console.log(`Rendering in language: ${lang}`);
      
      // Create localized UI elements
      const title = bundle.__('Data Visualization');
      const loadingText = bundle.__('Loading data...');
      const errorText = bundle.__('Failed to load data');
      
      // Use translations in UI
      this.node.innerHTML = `
        <div class="renderer-header">
          <h3>${title}</h3>
        </div>
        <div class="renderer-content">
          <p>${loadingText}</p>
        </div>
      `;
    }
  }
}

TranslationBundle Type

Comprehensive set of translation functions supporting various gettext patterns.

/**
 * Bundle of gettext-based translation functions for a specific domain
 */
type TranslationBundle = {
  /**
   * Alias for `gettext` (translate strings without number inflection)
   * @param msgid message (text to translate)
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  __(msgid: string, ...args: any[]): string;
  
  /**
   * Alias for `ngettext` (translate accounting for plural forms)
   * @param msgid message for singular
   * @param msgid_plural message for plural
   * @param n determines which plural form to use
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  _n(msgid: string, msgid_plural: string, n: number, ...args: any[]): string;
  
  /**
   * Alias for `pgettext` (translate in given context)
   * @param msgctxt context
   * @param msgid message (text to translate)
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  _p(msgctxt: string, msgid: string, ...args: any[]): string;
  
  /**
   * Alias for `npgettext` (translate accounting for plural forms in given context)
   * @param msgctxt context
   * @param msgid message for singular
   * @param msgid_plural message for plural
   * @param n number used to determine which plural form to use
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  _np(msgctxt: string, msgid: string, msgid_plural: string, n: number, ...args: any[]): string;
  
  /**
   * Look up the message id in the catalog and return the corresponding message string.
   * Otherwise, the message id is returned.
   * @param msgid message (text to translate)
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  gettext(msgid: string, ...args: any[]): string;
  
  /**
   * Do a plural-forms lookup of a message id. msgid is used as the message id for
   * purposes of lookup in the catalog, while n is used to determine which plural form
   * to use. Otherwise, when n is 1 msgid is returned, and msgid_plural is returned in
   * all other cases.
   * @param msgid message for singular
   * @param msgid_plural message for plural
   * @param n determines which plural form to use
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  ngettext(msgid: string, msgid_plural: string, n: number, ...args: any[]): string;
  
  /**
   * Look up the context and message id in the catalog and return the corresponding
   * message string. Otherwise, the message id is returned.
   * @param msgctxt context
   * @param msgid message (text to translate)
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  pgettext(msgctxt: string, msgid: string, ...args: any[]): string;
  
  /**
   * Do a plural-forms lookup of a message id. msgid is used as the message id for
   * purposes of lookup in the catalog, while n is used to determine which plural
   * form to use. Otherwise, when n is 1 msgid is returned, and msgid_plural is
   * returned in all other cases.
   * @param msgctxt context
   * @param msgid message for singular
   * @param msgid_plural message for plural
   * @param n number used to determine which plural form to use
   * @param args additional values for interpolation
   * @returns A translated string if found, or the original string
   */
  npgettext(msgctxt: string, msgid: string, msgid_plural: string, n: number, ...args: any[]): string;
  
  /**
   * Do a plural-forms lookup of a message id with domain and context support.
   * @param domain - The translations domain
   * @param msgctxt - The message context
   * @param msgid - The singular string to translate
   * @param msgid_plural - The plural string to translate
   * @param n - The number for pluralization
   * @param args - Any additional values to use with interpolation
   * @returns A translated string if found, or the original string
   */
  dcnpgettext(domain: string, msgctxt: string, msgid: string, msgid_plural: string, n: number, ...args: any[]): string;
};

Translation Usage Patterns

Basic Translation

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

function createLocalizedRenderer(translator?: IRenderMime.ITranslator): IRenderMime.IRenderer {
  return {
    async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
      if (translator) {
        const bundle = translator.load('my-extension');
        
        // Simple string translation
        const title = bundle.__('Data Viewer');
        const subtitle = bundle.__('Showing %s items', model.data.length);
        
        this.node.innerHTML = `
          <h2>${title}</h2>
          <p>${subtitle}</p>
        `;
      }
    }
  } as IRenderMime.IRenderer;
}

Plural Forms

function createItemCounter(translator?: IRenderMime.ITranslator): string {
  if (!translator) return 'Items';
  
  const bundle = translator.load('my-extension');
  
  return (count: number) => {
    // Handle plural forms
    return bundle._n(
      '%d item found',      // singular
      '%d items found',     // plural
      count,               // count for pluralization
      count                // value for substitution
    );
  };
}

// Usage
const counter = createItemCounter(translator);
console.log(counter(1));  // "1 item found"
console.log(counter(5));  // "5 items found"

Contextual Translation

function createStatusMessages(translator?: IRenderMime.ITranslator) {
  if (!translator) return { processing: 'Processing', complete: 'Complete' };
  
  const bundle = translator.load('my-extension');
  
  return {
    // Same word, different contexts
    processing: bundle._p('status', 'Processing'),
    complete: bundle._p('status', 'Complete'),
    
    // Buttons might have different translations
    processingButton: bundle._p('button', 'Processing'),
    completeButton: bundle._p('button', 'Complete')
  };
}

Complex Pluralization with Context

function createFileMessages(translator?: IRenderMime.ITranslator) {
  if (!translator) return (count: number) => `${count} files`;
  
  const bundle = translator.load('my-extension');
  
  return {
    selected: (count: number) => bundle._np(
      'file-selection',     // context
      '%d file selected',   // singular
      '%d files selected',  // plural
      count,               // count for pluralization
      count                // value for substitution
    ),
    
    processed: (count: number) => bundle._np(
      'file-processing',
      '%d file processed',
      '%d files processed',
      count,
      count
    )
  };
}

Full Document Widget Factory with Translation

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

function createInternationalizedExtension(
  rendererFactory: IRenderMime.IRendererFactory,
  translator?: IRenderMime.ITranslator
): IRenderMime.IExtension {
  
  let bundle: IRenderMime.TranslationBundle | undefined;
  if (translator) {
    bundle = translator.load('my-data-renderer');
  }
  
  // Helper function for translations
  const __ = (msgid: string, ...args: any[]) => 
    bundle ? bundle.__(msgid, ...args) : msgid;
  
  return {
    id: 'my-org:data-renderer',
    description: __('Advanced data visualization renderer'),
    rendererFactory,
    
    documentWidgetFactoryOptions: {
      name: __('Data Visualizer'),
      label: __('Data Viz'),
      primaryFileType: 'data-viz',
      fileTypes: ['data-viz'],
      translator,
      
      toolbarFactory: (widget) => [
        {
          name: 'refresh',
          widget: createButton(__('Refresh'), () => {
            console.log(__('Refreshing data...'));
          })
        },
        {
          name: 'export',
          widget: createButton(__('Export'), () => {
            console.log(__('Exporting data...'));
          })
        }
      ]
    },
    
    fileTypes: [
      {
        name: 'data-viz',
        mimeTypes: ['application/data-viz'],
        extensions: ['.dviz'],
        displayName: __('Data Visualization')
      }
    ]
  };
}

function createButton(label: string, onClick: () => void) {
  // Create a simple button widget
  const button = document.createElement('button');
  button.textContent = label;
  button.onclick = onClick;
  
  // Return as Widget-like object
  return { node: button } as any;
}

Language Detection and Adaptation

class AdaptiveRenderer implements IRenderMime.IRenderer {
  constructor(private options: IRenderMime.IRendererOptions) {}

  async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
    const translator = this.options.translator;
    
    if (translator) {
      const bundle = translator.load('my-renderer');
      const lang = translator.languageCode;
      
      // Adapt rendering based on language
      const isRTL = ['ar', 'he', 'fa'].includes(lang);
      
      if (isRTL) {
        this.node.style.direction = 'rtl';
        this.node.style.textAlign = 'right';
      }
      
      // Use appropriate number formatting
      const formatter = new Intl.NumberFormat(lang);
      const data = model.data as { count: number };
      
      this.node.innerHTML = `
        <div class="data-display">
          <h3>${bundle.__('Data Summary')}</h3>
          <p>${bundle.__('Count: %s', formatter.format(data.count))}</p>
        </div>
      `;
    }
  }
}

docs

data-models.md

document-system.md

extension-system.md

icon-system.md

index.md

renderer-system.md

translation-system.md

utility-services.md

tile.json