Skip to content

Repository files navigation

Made by the community

This is an unofficial Star Citizen fansite and fan localization tool. It is not affiliated with the Cloud Imperium group of companies. All content on this site not authored by its host or users are property of their respective owners.

verse-translator

Pipeline for translating Star Citizen global.ini localization files using local models via LM Studio. Automates what you'd otherwise do manually: split the file into batches, send each batch with a prompt to the model, collect responses, and assemble the translated file.

Translated files are meant to be published to sc-translations and served to users via jsDelivr CDN.

How it works

global.ini (EN)
  → parser       — split into key=value entries, skip comments and empty lines
  → filter       — skip untranslatable values (pure variables, empty strings)
  → cache lookup — skip already translated entries that haven't changed
  → batcher      — split remaining entries into chunks of N lines
  → backend      — send each batch as a JSON array to an AI tool, get JSON back
  → assembler    — merge translations back into global.ini preserving original structure
  → {output_dir}/{VERSION}/{lang}/global.ini

On subsequent runs only new or changed lines are sent to the model — everything else is taken from cache.

Backend

Translation runs through LM Studio (HTTP on localhost:1234, no auth — everything stays local). The pipeline loads the model via the LM Studio API automatically if it is not loaded yet.

Setup

# Install uv if needed
curl -Ls https://astral.sh/uv/install.sh | sh

# Install dependencies
uv sync

# Copy and edit config
cp verse-translator.example.toml verse-translator.toml

Make sure the LM Studio local server is running before starting (default port 1234). The model is loaded automatically if needed.

Tuning LM Studio for speed

Translation speed is dominated by token generation, so a misconfigured model load easily costs you a 10× slowdown. Symptom: single-digit tg = ... t/s in the LM Studio server logs — that means part of the model runs on the CPU or spilled into shared system memory.

All settings below live in My Models → gear icon on the model → Edit default load settings. Default load settings matter because the pipeline auto-loads the model through the LM Studio API — per-session tweaks on an already loaded instance are lost on the next load. Some options require Power User mode (selector at the bottom of the LM Studio window).

Recommended load settings

Reference setup: qwen/qwen3-14b Q4_K_M on an RTX 4070 12 GB — went from ~5 t/s to ~43 t/s with these settings (and ~60+ t/s with a draft model on top).

Setting Recommended Why
Context Length 8192 The pipeline reads the real context size via API and packs batches to fit — bigger is not required
GPU Offload (layers) maximum Any layer left on the CPU throttles the whole generation; if the max doesn't fit, use a smaller quant
Max Concurrent Predictions 1 The pipeline sends requests strictly one at a time; extra slots multiply KV-cache memory and cause prompt re-processing on slot switches
K Cache / V Cache Quantization q8_0 Halves KV-cache memory at negligible quality cost (requires Flash Attention)
Flash Attention on Faster attention, required for KV-cache quantization
Speculative Decoding same-family draft See below — ~1.5–2× extra on translation workloads

Fitting the model into VRAM is the whole game. Weights + KV cache + draft model + ~1 GB that Windows itself keeps on the GPU must stay under your VRAM total. If it doesn't fit, the NVIDIA driver silently spills into system RAM and generation crawls instead of failing. Rough guide: 12 GB → 14B Q4; 8 GB → 8B Q4; 6 GB → 4B Q4. A smaller model fully on the GPU always beats a bigger one that spills.

Draft model (speculative decoding)

LM Studio supports speculative decoding: a small "draft" model predicts tokens ahead and the main model only verifies them. Translation output is highly predictable, so acceptance rates are high — expect roughly 1.5–2× faster generation with identical output quality.

Setup (one-time, in the LM Studio UI):

  1. Download a draft model from the same family as the main one — for qwen/qwen3-14b use qwen3-0.6b (the draft must share the main model's vocabulary, so stick to the same model line).
  2. Switch LM Studio to Power User mode — otherwise the Speculative Decoding section is hidden.
  3. In the model's default load settings → Speculative Decoding → pick qwen3-0.6b as the draft model.

Note on VRAM: the draft model needs ~0.5–1 GB on top of the main model. Get the main model running fast first, then add the draft — if adding it pushes you over the VRAM budget, the gain turns into a loss.

Verifying the setup

Run a translation and watch two places:

  • LM Studio server logs: tg = ... t/s should be in the dozens, not single digits. With a draft model active, responses also report draft_model and accepted_draft_tokens_count.
  • nvidia-smi -l 1 during generation: GPU utilization should sit at 85–100% with power near its cap, and memory usage must stay below the total — a full-to-the-brim readout means you are already spilling into system RAM.

If generation is still slow with everything on the GPU, set CUDA – Sysmem Fallback Policy to Prefer No Sysmem Fallback in the NVIDIA Control Panel: overflow then fails loudly instead of silently degrading, which makes misconfiguration obvious.

Configuration

Settings are read from verse-translator.toml (gitignored — each contributor has their own). Copy the example and adjust paths:

cp verse-translator.example.toml verse-translator.toml
[output]
dir = "../sc-translations/translations"  # path to your local clone of sc-translations

[defaults]
model = "qwen/qwen3-14b"
version = "LIVE"
target_lang = "Russian"
target_lang_code = "ru"
batch_size = 50

CLI flags always override the config file.

Supported languages

--target-lang-code --target-lang Language
ru Russian Русский
zh Chinese Chinese (Simplified)
fr French French
de German German
it Italian Italian
ja Japanese Japanese
ko Korean 한국어 (Korean)
pl Polish Polish
pt Portuguese Portuguese
es Spanish Spanish

Translations are published to sc-translations and served via jsDelivr CDN:

https://cdn.jsdelivr.net/gh/sc-localization/sc-translations@main/translations/{VERSION}/{LANG}/global.ini

Usage

# Uses settings from verse-translator.toml
uv run python -m translator input/global.ini

# Override output dir (e.g. for local testing)
uv run python -m translator input/global.ini --output-dir output/

# Use a specific model (server must be running on port 1234)
uv run python -m translator input/global.ini --model qwen/qwen3-14b

# Translate to German
uv run python -m translator input/global.ini --target-lang German --target-lang-code de

# PTU version
uv run python -m translator input/global.ini --version PTU

Publishing translations

After translation, push the result to sc-translations:

cd ../sc-translations
git add translations/LIVE/ru/global.ini versions/versions.json
git commit -m "chore: update LIVE ru translation"
git push

Or use the helper script:

./translate-and-publish.sh

All options

positional:
  input                  Path to source global.ini (default: global.ini)

options:
  --model                Model name  (default from toml or qwen/qwen3-14b)
  --batch-size           Lines per AI call  (default from toml or 50)
  --version              Game version tag for output path  (default from toml or LIVE)
  --output-dir           Base output directory  (default from toml or output/translations)
  --target-lang          Target language name, e.g. German, French  (default from toml or Russian)
  --target-lang-code     Language code for output path, e.g. de, fr  (default from toml or ru)
  --source-lang          Source language name  (default: English)
  --max-retries          Retries per batch on failure  (default from toml or 3)
  --lmstudio-port        LM Studio server port  (default: 1234)
  -v, --verbose          Debug logging (shows prompts and responses)

Variable preservation

The pipeline instructs the model to leave game variables untouched:

Pattern Example Meaning
~func() ~mission(foo) Game function call
@tag @ui_label UI reference
%ls %ls String placeholder
{0} {1} Positional argument
\n \n Newline escape
<tag> <bold> Markup tag

Entries whose values consist entirely of variables are skipped and copied as-is.

Incremental translation

After each run a .translation_cache.jsonl file is saved next to the output global.ini. On the next run:

  • unchanged lines → taken from cache, no AI call
  • new or changed lines → translated and cache updated

Cache is per version and language, so LIVE/ru and PTU/ru have independent caches.

Development

uv run pytest tests/       # run tests
uv run mypy translator/    # type check

Linked projects

  • sc-translations — stores translated files, served via jsDelivr CDN
  • lingvo-injector — desktop app that downloads and installs translations into the game

About

Pipeline for translating Star Citizen global.ini localization files using local models via LM Studio

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages