Skip to main content
shipi18n logo|Documentation

Custom Providers

A provider is any object with a complete(prompt) method. That is the entire interface, so a local model, an internal gateway or a proxy takes about ten lines.

The interface

const myAdapter = {
  name: 'my-llm',
  async complete(prompt, options = {}) {
    // Call your model however you like and return its text response.
    const res = await fetch('https://llm.internal/v1/complete', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ prompt, max_tokens: options.maxTokens ?? 4096 }),
    })
    const data = await res.json()
    return data.text
  },
}

Using it

import { translateJSON } from '@shipi18n/core'

const { result } = await translateJSON({
  content: source,
  from: 'en',
  to: 'de',
  provider: myAdapter,
})

What the engine expects back

  • A string. Anything else is treated as an error.
  • The prompt asks for JSON, and the engine parses it. If your model wraps output in a code fence, strip it in the adapter before returning.
  • Throw on failure rather than returning an empty string — the engine falls back to per-string retries when a batch fails, and a thrown error is what triggers that.

Why this matters

Because the provider boundary is one method, nothing about Shipi18n ties you to a vendor. If a cheaper or better model appears next quarter, you swap the adapter and keep every other guarantee — structure preservation, placeholder validation and incremental translation are all provider-agnostic.