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

@molecule/api-ai-translation-llm

v1.1.2

Published

Language-model translation provider for molecule.dev — translates through any @molecule/api-ai model, hosted or self-hosted

Downloads

424

Readme

@molecule/api-ai-translation-llm

Language-model translation provider for molecule.dev.

Implements the @molecule/api-ai-translation contract with any @molecule/api-ai provider, so translation can run on whichever model is cheapest or best for the job — a hosted model (DeepSeek, Qwen, GPT, Claude, …) or a self-hosted one through @molecule/api-ai-local (vLLM, Ollama, llama.cpp), with no translation-vendor account at all.

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Quick Start

import { setProvider as setAi } from '@molecule/api-ai'
import { provider as deepseek } from '@molecule/api-ai-deepseek'
import { setProvider, requireProvider } from '@molecule/api-ai-translation'
import { createProvider } from '@molecule/api-ai-translation-llm'

setAi(deepseek) // the app's AI provider
setProvider(createProvider()) // translate with it — or createProvider({ ai, model }) for another

const { translations } = await requireProvider().translate({
  text: ['{{count}} items in your cart', 'Checkout'],
  targetLang: 'de',
  protect: ['{{count}}'],
  context: 'Labels in an online store',
})

Type

provider

Installation

npm install @molecule/api-ai-translation-llm @molecule/api-ai @molecule/api-ai-translation

API

Interfaces

MaskedText

A text prepared for the model, plus what is needed to restore it.

interface MaskedText {
  /** The text with each protected substring replaced by `⟦N⟧`. */
  masked: string
  /** The protected substrings, in order of occurrence. */
  originals: string[]
}

LlmTranslationConfig

Configuration for the language-model translation provider.

interface LlmTranslationConfig {
  /**
   * The `@molecule/api-ai` provider to translate with. Defaults to the provider
   * bonded as `ai` (`requireProvider()` from `@molecule/api-ai`) at first use —
   * pass one explicitly to translate with a different model than the app chats
   * with (e.g. a cheap model, or a self-hosted one via `@molecule/api-ai-local`).
   */
  ai?: AIProvider
  /** Model id passed to the AI provider. Defaults to the provider's own default model. */
  model?: string
  /** Texts per model request. Defaults to 40 — larger batches are cheaper but fail more often. */
  batchSize?: number
  /** Sampling temperature. Defaults to 0 (translation should be deterministic). */
  temperature?: number
  /**
   * Extra instructions appended to the system prompt — a style guide, a glossary
   * ("translate 'workspace' as 'Arbeitsbereich'"), or product context.
   */
  instructions?: string
}

Functions

languageName(code)

English name of a language code, falling back to the code itself. Accepts provider-flavored codes in any case (de, DE, PT-BR, zh-TW, ZH-HANT).

function languageName(code: string): string
  • code — A BCP-47-style language code.

Returns: The language's English name, e.g. 'German' or 'Chinese (Taiwan)'.

systemPrompt(targetLang, sourceLang, context, instructions)

Builds the system prompt for one target language.

function systemPrompt(
  targetLang: string,
  sourceLang: string | undefined,
  context: string | undefined,
  instructions: string | undefined,
): string
  • targetLang — Target language code.
  • sourceLang — Source language code, if known.
  • context — Caller-supplied context about the texts (not translated).
  • instructions — Extra standing instructions from the provider config.

Returns: The system prompt.

parseTranslations(answer, expected)

Parses the model's answer into an array of strings.

function parseTranslations(answer: string, expected: number): string[] | null
  • answer — The model's full text output.
  • expected — How many translations the request carried.

Returns: The translations, or null when the answer is not a same-length string array.

maskText(text, protect)

Replaces each protected substring (longest first) with a numbered token.

function maskText(text: string, protect: string[]): MaskedText
  • text — The caller's text.
  • protect — Literal substrings to protect.

Returns: The masked text and its protected substrings.

tokensIntact(translated, originals)

Whether a translation carries every token of its source exactly once and no others.

function tokensIntact(translated: string, originals: string[]): boolean
  • translated — The model's output for one text.
  • originals — The substrings maskText protected for that text.

Returns: True when every ⟦N⟧ is present once and none is extra.

unmaskText(translated, originals)

Restores protected substrings by index.

function unmaskText(translated: string, originals: string[]): string
  • translated — The model's output for one text.
  • originals — The substrings maskText protected for that text.

Returns: The restored text.

createProvider(config)

Creates a language-model translation provider.

function createProvider(config?: LlmTranslationConfig): AITranslationProvider
  • config — Which AI provider/model to use and how to batch.

Returns: An AITranslationProvider backed by a language model.

Constants

provider

The provider implementation.

const provider: AITranslationProvider

Core Interface

Implements @molecule/api-ai-translation interface.

Bond Wiring

Setup function to register this provider with the core interface:

import { setProvider } from '@molecule/api-ai-translation'
import { provider } from '@molecule/api-ai-translation-llm'

export function setupAiTranslationLlm(): void {
  setProvider(provider)
}

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-ai >=1.0.0
  • @molecule/api-ai-translation >=1.1.0

Runtime Dependencies

  • @molecule/api-ai

  • @molecule/api-ai-translation

  • Uses the AI provider bonded as ai unless you pass one. To translate with a cheaper model than the app chats with, pass createProvider({ ai, model }). Spend is the AI provider's token spend — getUsage() only counts characters in this process (characterLimit is Infinity).

  • protect placeholders travel as numbered tokens (⟦0⟧) and are restored by index; the model may move them for word order. A batch whose answer is not a same-length JSON array, or that loses a token, is retried in halves down to one text. A text that still fails comes back WITHOUT its placeholders intact — so check every result holds its placeholders before storing it; never store the English source as a "translation" instead.

  • Language codes are free-form (de, DE, PT-BR, zh-TW): they are turned into English language names for the model. getSupportedLanguages() lists ~80 common languages for pickers; the model can do more.

  • context (e.g. "button labels in a banking app") and the config's instructions (a glossary or style guide) go into the prompt — use them: one-word UI strings are ambiguous ("Close" as a verb or an adjective), and context is the only fix.

  • formality, glossaryId, modelType, preserveFormatting and tagHandling have no model equivalent and are ignored.

  • Output quality depends on the model. Small models are weaker on low-resource languages (Yoruba, Lao, Zulu…); spot-check those.

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip. The sandbox has a live AI provider, so translations run for real; output is non-deterministic, so assert on the resulting LANGUAGE/meaning, never an exact string:

  • [ ] Translating real text to a target language through the UI returns text ACTUALLY in that language — English→Spanish produces recognizably Spanish, not the original echoed back or left in English.
  • [ ] Switching the target language (from the picker populated by getSupportedLanguages('target')) changes the output language for the same input — the same source re-translates into the newly chosen language.
  • [ ] With sourceLang omitted the provider auto-detects: a known-language input comes back with the correct detectedSourceLang, and if the UI shows a detected-language label it names the right one.
  • [ ] Text already in the target language is left sensible — unchanged or a valid paraphrase, never mangled, doubled, or emptied.
  • [ ] Empty or untranslatable input (whitespace, emoji, a bare code snippet) is handled gracefully — a clear UI state, nothing crashes.
  • [ ] A provider failure (bad key, quota exhausted, network drop) surfaces a visible error in the UI, not an unhandled 500 or a silently blank result.
  • [ ] The translate call runs server-side only — the provider key never reaches the browser (check the network panel: no key in any request).