npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ts-obsidian-i18n

v1.0.2

Published

Unified i18n for obsidian plugins

Readme

npm version License: MIT jsdoc Build & Test codecov

BOTTOM CHANGELOG LICENSE ROADMAP

Obsidian I18N Utility

A small, self-contained i18n utility designed for use inside Obsidian plugins.

This module provides a type-safe I18NService singleton and related types to unify translation access across multiple plugin files, while respecting configurable fallback languages and compile-time key checking.

The primary design goal is safe integration into Obsidian plugins via bundling. The module is not intended to be loaded dynamically at runtime.


Motivation

Obsidian plugins run in a constrained environment:

  • External runtime dependencies are discouraged
  • node_modules are typically not shipped with plugins
  • All code should be bundled into the final plugin file

This module is therefore designed to:

  • Provide type-safe translations with compile-time key checking
  • Integrate cleanly with Obsidian’s plugin environment
  • Be bundled (e.g. via Rollup) directly into the plugin output
  • Provide consistent translation and fallback behavior across multiple plugin files

Features

  • Type-safe translation keys using I18NKeyMap
  • Compile-time checking of translation resources
  • Singleton service with init() and stable translation function
  • Automatic fallback to build-time or default language
  • Works seamlessly in multi-file plugin setups

Installation

npm install ts-obsidian-i18n

Peer dependency:

obsidian >= 1.5.0

Basic Usage

1. Define translation keys

Create or augment the key map using TypeScript module augmentation:

// src/lib/types.ts
import "ts-obsidian-i18n";

/**
 * Define all translation keys here.
 * Each key must map to `true`.
 */
export const I18NKeys = {
  "settings.header": true;
  "settings.table.header.prefix": true;
  "settings.control.tooltip.delete": true;
} as const;

/**
 * Type representing all valid translation keys.
 * This enables type-safe key checking in the translation function.
 */
export type I18NKeyMap = typeof I18NKeys;

/**
 * Augment the module to include our key map.
 * This ensures unique keys across the plugin.
 */
declare module "ts-obsidian-i18n" {
  // may look redundant, but necessary for augmentation
  type I18NKeyMap = typeof I18NKeys;
}

This ensures type-safety: any call to the translation function with a key not defined here will fail at compile time.


2. Create translation resources

Define translations for each language you want to support:

// src/lib/lang.ts
import type { I18NResourcesByLang } from "ts-obsidian-i18n";

export const resources: I18NResourcesByLang = {
  en: {
    "settings.header": "Settings",
    "settings.table.header.prefix": "Prefix",
    "settings.control.tooltip.delete": "Delete mapping"
  },
  de: {
    "settings.header": "Einstellungen",
    "settings.table.header.prefix": "Präfix",
    "settings.control.tooltip.delete": "Mapping löschen"
  }
};

alternatively, you can import resources from separate files:

// src/lib/de.ts
import type { I18NResource } from "ts-obsidian-i18n";
import type { I18NKeyMap   } from "./types";

export const de: I18NResource<I18NKeyMap> = {
  "settings.header": "Einstellungen",
  "settings.table.header.prefix": "Präfix",
  "settings.control.tooltip.delete": "Mapping löschen"
};

and then:

// src/lib/lang.ts
import type { I18NResourcesByLang } from "ts-obsidian-i18n";
import      { en                  } from "./en";
import      { de                  } from "./de";
import type { I18NKeyMap          } from "./types";

export const RESOURCES: I18NResourcesByLang<I18NKeyMap> = { en, de };

Every key from I18NKeyMap must exist in each resource.


3. Initialize the I18N service

// src/lib/bootstrap.ts
import { I18NService } from "ts-obsidian-i18n";
import { RESOURCES   } from "./lang";

export { I18NService } from "ts-obsidian-i18n";
export const I18N = I18NService.init({resources: RESOURCES, fallbackLanguage: "en"});
// src/lib/plugin.ts
import { I18NService } from "ts-obsidian-i18n";

export class DailyNoteStructurePlugin extends Plugin {
  public constructor(app: App, manifest: PluginManifest) {
    super(app, manifest);
    // Provide 'app' to I18NService for Obsidian integration
    I18NService.init({ app });
  }
  // ...
}
  • i18n is a translation function: (key: I18NKey) => string
  • Safe to call from any file after initialization
  • Singleton ensures the same function reference everywhere

4. Use the translation function

import { I18N } from "./bootstrap";
console.log(I18N("settings.header")); // "Settings" or localized value
console.log(I18N("settings.table.header.prefix")); // "Prefix" or localized value
  • Automatically uses language from window.localStorage.getItem("language")
  • Falls back to fallbackLanguage if missing
  • Falls back to default "en" if neither is present

Build-time Fallback Language with Rollup

ts-obsidian-i18n supports a compile-time fallback language via Rollup replacement:

declare const __PLUGIN_FALLBACK_LANGUAGE__: string | undefined;

You can replace this during the Rollup build using the @rollup/plugin-replace plugin:

// .config/rollup.config.mjs
import replace from "@rollup/plugin-replace";

export default {
  input: "src/index.ts",
  output: {
    file: "index.js",
    format: "esm",
  },
  plugins: [
    replace({
      preventAssignment: true,
      values: {
        __PLUGIN_FALLBACK_LANGUAGE__: JSON.stringify("en") // your desired fallback
      }
    })
  ]
};
  • If __PLUGIN_FALLBACK_LANGUAGE__ is defined and present in your resources, it will be used automatically as the fallback.
  • If missing, DEFAULT_FALLBACK_LANGUAGE = "en" is used.

Advanced Usage

Dynamic language switching

window.localStorage.setItem("language", "de");
console.log(i18n("settings.header")); 

Multi-file plugin

// file1.ts
import { I18N } from "./bootstrap";
console.log(I18N("fiel.1.header"));

// file2.ts
import { I18N } from "./bootstrap";
console.log(I18N("file.2.header")); // same reference, same behavior

API Reference

I18NService

| Method | Description | | ----------------------- | -------------------------------------------------------------------------------------------- | | static init(settings) | Initializes the singleton service and returns the translation function. Must be called once. | | i18n(key: I18NKey) | Translation function returned by init(). |

Types

  • I18NKeyMap: Augmentable interface defining all translation keys
  • I18NKey: keyof I18NKeyMap
  • I18NResource: { [key in I18NKey]: string }
  • I18NResourcesByLang: { [lang: string]: I18NResource }

TOP CHANGELOG LICENSE ROADMAP