or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdinstance-management.mdlanguage-management.mdplugin-system.mdresource-management.mdtranslation.md
tile.json

plugin-system.mddocs/

Plugin System

Extensible module system supporting backends, language detectors, formatters, post-processors, and third-party integrations for i18next.

Capabilities

Use Modules

Load and register modules with i18next instances.

/**
 * Load a module/plugin into i18next
 * @param module - Module instance, class, or constructor
 * @returns i18next instance for chaining
 */
function use<T extends Module>(module: T | NewableModule<T> | Newable<T>): i18n;

interface Module {
  type: ModuleType;
}

type ModuleType = 
  | 'backend' 
  | 'logger' 
  | 'languageDetector' 
  | 'postProcessor' 
  | 'i18nFormat' 
  | 'formatter' 
  | '3rdParty';

interface Newable<T> {
  new (...args: any[]): T;
}

interface NewableModule<T extends Module> extends Newable<T> {
  type: T['type'];
}

Usage Examples:

import i18next from "i18next";
import Backend from "i18next-http-backend";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";

// Use multiple modules
i18next
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    // configuration
  });

// Use with custom module
class CustomLogger {
  type = "logger";
  
  log(...args) { console.log("[i18next]", ...args); }
  warn(...args) { console.warn("[i18next]", ...args); }
  error(...args) { console.error("[i18next]", ...args); }
}

i18next.use(new CustomLogger());

Backend Modules

Modules for loading translation resources from various sources.

Backend Module Interface

interface BackendModule<Options = object> extends Module {
  type: 'backend';
  /** Initialize the backend */
  init(services: Services, backendOptions: Options, i18nextOptions: InitOptions): void;
  /** Read translation resource */
  read(language: string, namespace: string, callback: ReadCallback): void;
  /** Save missing translation (optional) */
  create?(
    languages: readonly string[],
    namespace: string,
    key: string,
    fallbackValue: string
  ): void;
  /** Load multiple resources (optional) */
  readMulti?(
    languages: readonly string[],
    namespaces: readonly string[],
    callback: MultiReadCallback
  ): void;
  /** Store translation resource (optional) */
  save?(language: string, namespace: string, data: ResourceLanguage): void;
}

type ReadCallback = (
  err: CallbackError,
  data: ResourceKey | boolean | null | undefined
) => void;

type MultiReadCallback = (
  err: CallbackError,
  data: Resource | null | undefined
) => void;

type CallbackError = Error | string | null | undefined;

Backend Implementation Example:

class CustomBackend {
  type = "backend";
  
  init(services, backendOptions, i18nextOptions) {
    this.services = services;
    this.options = backendOptions;
  }
  
  read(language, namespace, callback) {
    // Load from custom source (API, file system, etc.)
    fetch(`/api/translations/${language}/${namespace}`)
      .then(response => response.json())
      .then(data => callback(null, data))
      .catch(error => callback(error, null));
  }
  
  create(languages, namespace, key, fallbackValue) {
    // Save missing key to backend
    const payload = { languages, namespace, key, fallbackValue };
    fetch("/api/missing-keys", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload)
    });
  }
}

// Usage
i18next.use(new CustomBackend()).init({
  backend: {
    // backend-specific options
    apiUrl: "/api/translations"
  }
});

Language Detector Modules

Modules for automatic language detection from various sources.

Language Detector Interface

interface LanguageDetectorModule extends Module {
  type: 'languageDetector';
  /** Initialize detector (optional) */
  init?(services: Services, detectorOptions: object, i18nextOptions: InitOptions): void;
  /** Detect user language */
  detect(): string | readonly string[] | undefined;
  /** Cache detected language (optional) */
  cacheUserLanguage?(lng: string): void;
}

interface LanguageDetectorAsyncModule extends Module {
  type: 'languageDetector';
  /** Enable async detection */
  async: true;
  /** Initialize detector (optional) */
  init?(services: Services, detectorOptions: object, i18nextOptions: InitOptions): void;
  /** Detect user language asynchronously */
  detect(
    callback: (lng: string | readonly string[] | undefined) => void | undefined
  ): void | Promise<string | readonly string[] | undefined>;
  /** Cache detected language (optional) */
  cacheUserLanguage?(lng: string): void | Promise<void>;
}

Language Detector Implementation Example:

class CustomLanguageDetector {
  type = "languageDetector";
  
  init(services, detectorOptions, i18nextOptions) {
    this.options = detectorOptions;
  }
  
  detect() {
    // Detect from multiple sources
    const sources = [
      () => localStorage.getItem("i18nextLng"),
      () => navigator.language,
      () => document.documentElement.lang,
      () => "en" // fallback
    ];
    
    for (const source of sources) {
      const lng = source();
      if (lng) return lng;
    }
  }
  
  cacheUserLanguage(lng) {
    localStorage.setItem("i18nextLng", lng);
  }
}

// Async detector example
class AsyncLanguageDetector {
  type = "languageDetector";
  async = true;
  
  async detect(callback) {
    try {
      const response = await fetch("/api/user/language");
      const data = await response.json();
      callback(data.language);
    } catch (error) {
      callback("en"); // fallback
    }
  }
  
  async cacheUserLanguage(lng) {
    await fetch("/api/user/language", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ language: lng })
    });
  }
}

Post-Processor Modules

Modules for processing translation values after retrieval.

Post-Processor Interface

interface PostProcessorModule extends Module {
  type: 'postProcessor';
  /** Unique processor name */
  name: string;
  /** Process translation value */
  process(value: string, key: string | string[], options: TOptions, translator: any): string;
}

Post-Processor Implementation Example:

class MarkdownProcessor {
  type = "postProcessor";
  name = "markdown";
  
  process(value, key, options, translator) {
    // Simple markdown processing
    return value
      .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
      .replace(/\*(.*?)\*/g, "<em>$1</em>")
      .replace(/`(.*?)`/g, "<code>$1</code>");
  }
}

// Usage
i18next.use(new MarkdownProcessor()).init({
  postProcess: ["markdown"] // Apply markdown processing
});

// In translation resource:
// "description": "This is **bold** and *italic* text with `code`"
// Result: "This is <strong>bold</strong> and <em>italic</em> text with <code>code</code>"

Formatter Modules

Modules for custom value formatting in interpolation.

Formatter Interface

interface FormatterModule extends Module, Formatter {
  type: 'formatter';
}

interface Formatter {
  /** Initialize formatter */
  init(services: Services, i18nextOptions: InitOptions): void;
  /** Add formatter function */
  add(name: string, fc: (value: any, lng: string | undefined, options: any) => string): void;
  /** Add cached formatter function */
  addCached(
    name: string,
    fc: (lng: string | undefined, options: any) => (value: any) => string
  ): void;
  /** Main format function */
  format: FormatFunction;
}

type FormatFunction = (value: any, format: string, lng: string, options: any) => string;

Formatter Implementation Example:

class CustomFormatter {
  type = "formatter";
  
  init(services, options) {
    this.services = services;
    
    // Add custom formatters
    this.add("currency", (value, lng, options) => {
      const currency = options.currency || "USD";
      return new Intl.NumberFormat(lng, {
        style: "currency",
        currency: currency
      }).format(value);
    });
    
    this.add("datetime", (value, lng, options) => {
      const date = new Date(value);
      return new Intl.DateTimeFormat(lng, options).format(date);
    });
  }
  
  add(name, formatter) {
    this.formatters = this.formatters || {};
    this.formatters[name] = formatter;
  }
  
  format(value, format, lng, options) {
    const formatter = this.formatters[format];
    if (formatter) {
      return formatter(value, lng, options.formatParams || {});
    }
    return value;
  }
}

// Usage
i18next.use(new CustomFormatter()).init({
  interpolation: {
    format: (value, format, lng, options) => {
      // Custom formatting is handled by the formatter module
      return i18next.services.formatter.format(value, format, lng, options);
    }
  }
});

// In translation resource:
// "price": "Price: {{amount, currency}}"
// "date": "Date: {{timestamp, datetime}}"

// Usage:
// i18next.t("price", { amount: 29.99, formatParams: { currency: "EUR" } })
// i18next.t("date", { timestamp: Date.now() })

Logger Modules

Custom logging modules for i18next operations.

Logger Interface

interface LoggerModule extends Module {
  type: 'logger';
  /** Log regular messages */
  log(...args: any[]): void;
  /** Log warnings */
  warn(...args: any[]): void;
  /** Log errors */
  error(...args: any[]): void;
}

Logger Implementation Example:

class CustomLogger {
  type = "logger";
  
  log(...args) {
    console.log(`[i18next:${new Date().toISOString()}]`, ...args);
  }
  
  warn(...args) {
    console.warn(`[i18next:WARNING:${new Date().toISOString()}]`, ...args);
  }
  
  error(...args) {
    console.error(`[i18next:ERROR:${new Date().toISOString()}]`, ...args);
    // Could also send to error reporting service
    this.sendToErrorService(args);
  }
  
  sendToErrorService(args) {
    // Send errors to monitoring service
    fetch("/api/errors", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ error: args.join(" "), timestamp: Date.now() })
    });
  }
}

Third-Party Modules

Generic modules for third-party integrations.

Third-Party Interface

interface ThirdPartyModule extends Module {
  type: '3rdParty';
  /** Initialize with i18next instance */
  init(i18next: i18n): void;
}

Third-Party Implementation Example:

class ReactIntegration {
  type = "3rdParty";
  
  init(i18next) {
    // Set up React-specific integrations
    this.i18next = i18next;
    
    // Listen for language changes to trigger React re-renders
    i18next.on("languageChanged", (lng) => {
      this.updateReactComponents(lng);
    });
    
    // Add React-specific translation helpers
    this.setupReactHelpers();
  }
  
  updateReactComponents(lng) {
    // Trigger React component updates
    window.dispatchEvent(new CustomEvent("i18nextLanguageChanged", { detail: lng }));
  }
  
  setupReactHelpers() {
    // Add React-specific functionality
  }
}

Module Container

Access to loaded modules through the modules container.

interface Modules {
  /** Backend module */
  backend?: BackendModule;
  /** Logger module */
  logger?: LoggerModule;
  /** Language detector module */
  languageDetector?: LanguageDetectorModule | LanguageDetectorAsyncModule;
  /** I18n format module */
  i18nFormat?: I18nFormatModule;
  /** Formatter module */
  formatter?: FormatterModule;
  /** Third-party modules */
  external: ThirdPartyModule[];
}

Usage Examples:

// Access loaded modules
console.log("Loaded modules:", i18next.modules);

// Check if specific module type is loaded
if (i18next.modules.backend) {
  console.log("Backend module is loaded");
}

if (i18next.modules.languageDetector) {
  console.log("Language detector is available");
}

// Access third-party modules
i18next.modules.external.forEach(module => {
  console.log("Third-party module:", module.constructor.name);
});

Popular Modules

Common modules in the i18next ecosystem:

// Backend modules
import HttpBackend from "i18next-http-backend";
import FsBackend from "i18next-fs-backend";
import ChainedBackend from "i18next-chained-backend";

// Language detectors
import LanguageDetector from "i18next-browser-languagedetector";
import NodeLanguageDetector from "i18next-node-fs-backend";

// Post-processors
import SprintfPostProcessor from "i18next-sprintf-postprocessor";
import IntervalPlural from "i18next-intervalplural-postprocessor";

// Framework integrations
import { initReactI18next } from "react-i18next";
import { initAngularI18next } from "angular-i18next";
import { initVueI18next } from "vue-i18next";

// Usage example with popular modules
i18next
  .use(HttpBackend)
  .use(LanguageDetector)
  .use(SprintfPostProcessor)
  .use(initReactI18next)
  .init({
    backend: {
      loadPath: "/locales/{{lng}}/{{ns}}.json"
    },
    detection: {
      order: ["localStorage", "navigator"],
      caches: ["localStorage"]
    },
    postProcess: ["sprintf"]
  });