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.
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.
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.
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.
# 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.tomlMake sure the LM Studio local server is running before starting (default port 1234). The model is loaded automatically if needed.
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).
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.
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):
- Download a draft model from the same family as the main one — for
qwen/qwen3-14buseqwen3-0.6b(the draft must share the main model's vocabulary, so stick to the same model line). - Switch LM Studio to Power User mode — otherwise the Speculative Decoding section is hidden.
- In the model's default load settings → Speculative Decoding → pick
qwen3-0.6bas 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.
Run a translation and watch two places:
- LM Studio server logs:
tg = ... t/sshould be in the dozens, not single digits. With a draft model active, responses also reportdraft_modelandaccepted_draft_tokens_count. nvidia-smi -l 1during 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.
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 = 50CLI flags always override the config file.
--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
# 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 PTUAfter 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 pushOr use the helper script:
./translate-and-publish.shpositional:
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)
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.
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.
uv run pytest tests/ # run tests
uv run mypy translator/ # type check- sc-translations — stores translated files, served via jsDelivr CDN
- lingvo-injector — desktop app that downloads and installs translations into the game
