# XliffAI

[![npm version](https://img.shields.io/npm/v/xliffai)](https://www.npmjs.com/package/xliffai)
[![npm license](https://img.shields.io/npm/l/xliffai)](LICENSE)
[![TypeScript](https://img.shields.io/badge/implementation-native%20TypeScript-3178c6)](https://www.typescriptlang.org/)

XliffAI translates XLIFF 2.x files with AI, sending a **group of segments per request** instead of one segment at a time. Each batch carries the glossary terms and existing translation matches already present in the file, plus a couple of segments of surrounding context duplicated from the neighboring batches, so the model has real context and stays consistent across a batch instead of translating isolated strings.

AI-proposed translations are never written straight into a segment's `<target>`. Each one is added as a new `<mtc:match type="mt" origin="<engine>">` candidate on the segment's unit - the same spec Translation Candidates module (from [TypesXLIFF](https://github.com/rmraya/TypesXLIFF)) that already holds any pre-existing TM matches - so it can be reviewed and accepted like any other suggested match. A segment's `<target>` and `@state` are never modified by XliffAI.

## Highlights

- Batches segments per request instead of translating one at a time, carrying glossary terms, existing TM matches, and a few segments of context duplicated from neighboring batches so terminology and register stay consistent across a batch
- Supports seven AI engines through the same `AIEngine` interface: **ChatGPT** (OpenAI), **Claude** (Anthropic), **Gemini** (Google), **Ollama** (local), **Mistral**, **Qwen** (Alibaba DashScope), **Z.ai** (Zhipu)
- Never modifies a segment's `<target>` or `@state` - proposals are added as `<mtc:match>` candidates for review, leaving the input file untouched
- Ships an `xliffai` command-line tool for translating files and for listing/curating the models available from each engine
- Usable as a library too - `XliffAI.translateFile()` parses, batches, translates, and writes the result in one call

## Requirements

- Node.js 24 LTS or later

## Installation

```bash
npm install xliffai
```

## Quick start

```typescript
import { XliffAI, ChatGPTEngine } from 'xliffai';

const engine = new ChatGPTEngine(apiKey, 'gpt-5');
const xliffAI = new XliffAI();

// optional - both default sensibly (batch size 20, context overlap 2)
xliffAI.setBatchSize(20);
xliffAI.setContextOverlap(2);

const results = await xliffAI.translateFile('input.xlf', 'output.xlf', engine);
```

`translateFile` parses the XLIFF, batches segments, calls the engine once per batch, writes each result back into the document as an `<mtc:match>`, and saves `output.xlf`. `generatePrompts(inputFile)` and `translateBatches(inputFile, engine)` are available for inspecting prompts or driving translation without writing a file. Every engine listed above (`ChatGPTEngine`, `ClaudeEngine`, `GeminiEngine`, `OllamaEngine`, `MistralEngine`, `QwenEngine`, `ZaiEngine`) implements the same `AIEngine` interface, so any can be passed in.

## Command-line interface

Installing XliffAI globally also adds an `xliffai` command:

```bash
npm install -g xliffai

xliffai translate -i input.xlf -o output.xlf -e chatgpt -k $OPENAI_API_KEY -m gpt-5
xliffai models -e claude -k $ANTHROPIC_API_KEY --curate
xliffai models-json -o models.json
```

`translate` never touches `<target>` - it adds `<mtc:match type="mt" origin="<engine>">` candidates to a **new** output file, leaving the input untouched. Run `xliffai <command> --help` for the full flag list of any command.

### translate

```text
Required:
  -i, --input <file>        XLIFF file to read
  -o, --output <file>       XLIFF file to write (original is not modified)
  -e, --engine <name>       chatgpt | claude | gemini | ollama | mistral | qwen | zai

Engine auth (one of -k, or the matching environment variable):
  -k, --key <apiKey>        OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY / MISTRAL_API_KEY / QWEN_API_KEY / ZAI_API_KEY
      --ollama-url <url>    default http://localhost:11434 (or OLLAMA_URL)

Options:
  -m, --model <name>        required for chatgpt/claude/ollama/mistral/qwen/zai (gemini defaults to gemini-2.5-flash)
      --region <name>       qwen: Singapore | Virginia | Beijing (default Singapore)
      --batch-size <n>      max segments per request (default 20)
  -p, --prompt <file>       plain-text prompt template replacing the default; placeholders:
                            {SOURCE_DESCRIPTION} {TARGET_DESCRIPTION} {SEGMENTS} {TO_TRANSLATE_COUNT}
```

### models

Without `--curate`, prints the raw model list exactly as the engine's API returns it - this can include image, audio, embedding, coding, and other models with no bearing on text translation. With `--curate`, that raw list is sent to a model of the same engine (its default curation model, or the one given with `--curate-model`) with a prompt asking it to keep only the models fit for translating natural-language text, and only that filtered list is printed.

### models-json

Fetches the model list for chatgpt, claude, mistral, gemini, qwen, and zai, curates each one with that engine's default curation model, and writes them to `<file>` as `{ "ChatGPT": [...], "Claude": [...], "Mistral": [...], "Gemini": [...], "Qwen": [...], "Z.ai": [...] }`. An engine whose API key env var isn't set is skipped with a warning, as is one whose curation call fails; the rest are still written. `ollama` is not included - its models are local to each machine, not a stable list to ship in a config file.

## Dependencies

- [TypesXLIFF](https://github.com/maxprograms-com/TypesXLIFF) - XLIFF 2.x object model, parsing, and serialization
- [TypesXML](https://github.com/maxprograms-com/TypesXML) - XML object model used by TypesXLIFF
- [TypesBCP47](https://github.com/maxprograms-com/TypesBCP47) - BCP 47 language tag utilities
- [TypesMatch](https://github.com/maxprograms-com/TypesMatch) - Translation Candidates match model shared with TypesXLIFF

## Building from Source

```bash
npm install
npm run build
```

## License

Eclipse Public License 1.0 - see [LICENSE](LICENSE) for details.
