Auto-Translation
Lexis Pro includes integrated auto-translation support using industry-leading translation services. Translate your strings directly within the Unity Editor without leaving your workflow.
| Service | API | Best For |
|---|---|---|
| DeepL | DeepL API | High-quality European language translation |
| ChatGPT | OpenAI API | Context-aware translations, creative content |
| Google Translate | Cloud Translation API | Wide language coverage, fast processing |
| Gemini | Google Gemini API | Cost-effective AI translations |
| Claude | Anthropic API | Nuanced, context-aware translations |
DeepL Setup
- Go to DeepL API
- Sign up for a DeepL API account (Free or Pro)
- Navigate to your account settings → API Keys
- Copy your API key
- Free vs Pro: DeepL auto-detects based on your key
- Free keys end with
:fx - Free tier: 500,000 characters/month
- Pro tier: Pay-as-you-go pricing
- Free keys end with
Supported Languages: EN, DE, FR, ES, IT, NL, PL, PT, RU, JA, ZH, and more.
ChatGPT Setup
- Go to OpenAI Platform
- Create an account or sign in
- Navigate to API Keys section
- Click Create new secret key
- Copy the key (starts with
sk-) - Model Selection:
gpt-4o-mini(default): Fast, cost-effectivegpt-4o: Higher quality, more expensive
Note: OpenAI charges per token. Translation costs depend on text length and model.
Google Cloud Translation Setup
- Go to Google Cloud Console
- Create a new project or select existing
- Enable the Cloud Translation API:
- Go to APIs & Services → Library
- Search for "Cloud Translation API"
- Click Enable
- Create an API key:
- Go to APIs & Services → Credentials
- Click Create Credentials → API Key
- (Recommended) Restrict the key to Cloud Translation API only
- Copy the API key
Pricing: Google charges per character translated. See Cloud Translation pricing.
Gemini Setup
- Go to Google AI Studio
- Sign in with your Google account
- Click Get API Key → Create API key
- Copy the API key
Pricing: Gemini 2.0 Flash is very cost-effective. See Gemini API pricing.
Claude Setup
- Go to Anthropic Console
- Create an account or sign in
- Navigate to API Keys
- Click Create Key
- Copy the key (starts with
sk-ant-)
Pricing: Claude charges per token. See Anthropic pricing.
Lexis supports secure credential storage through environment variables (recommended) or EditorPrefs.
Environment Variables (Recommended)
Set environment variables before launching Unity:
| Service | Environment Variable |
|---|---|
| DeepL | LEXIS_DEEPL_API_KEY |
| ChatGPT | LEXIS_OPENAI_API_KEY |
LEXIS_GOOGLE_TRANSLATE_API_KEY | |
| Gemini | LEXIS_GEMINI_API_KEY |
| Claude | LEXIS_CLAUDE_API_KEY |
macOS/Linux:
export LEXIS_DEEPL_API_KEY="your-deepl-api-key"
export LEXIS_OPENAI_API_KEY="sk-your-openai-api-key"
export LEXIS_GOOGLE_TRANSLATE_API_KEY="your-google-api-key"
export LEXIS_GEMINI_API_KEY="your-gemini-api-key"
export LEXIS_CLAUDE_API_KEY="sk-ant-your-claude-api-key"Windows (PowerShell):
$env:LEXIS_DEEPL_API_KEY = "your-deepl-api-key"
$env:LEXIS_OPENAI_API_KEY = "sk-your-openai-api-key"
$env:LEXIS_GOOGLE_TRANSLATE_API_KEY = "your-google-api-key"
$env:LEXIS_GEMINI_API_KEY = "your-gemini-api-key"
$env:LEXIS_CLAUDE_API_KEY = "sk-ant-your-claude-api-key"EditorPrefs Storage
For convenience during development, you can store credentials in EditorPrefs via Auto-Translate:
- Open Tools → KitStack → Lexis → Auto-Translate...
- Go to the Settings tab
- Enter your API keys in the credential fields
- Click Validate All Credentials to verify each service shows "Verified" (green)
- Keys are stored in EditorPrefs (per-machine, not in version control)
Security Warning EditorPrefs storage is convenient but less secure than environment variables. Never commit API keys to version control.
CI/CD Configuration
For automated pipelines and CI/CD environments, configure credentials via environment variables before running Unity.
GitHub Actions:
jobs:
build:
runs-on: ubuntu-latest
env:
LEXIS_DEEPL_API_KEY: ${{ secrets.DEEPL_API_KEY }}
LEXIS_OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LEXIS_GOOGLE_TRANSLATE_API_KEY: ${{ secrets.GOOGLE_TRANSLATE_API_KEY }}
LEXIS_GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
LEXIS_CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
steps:
- uses: actions/checkout@v4
- name: Build Unity Project
uses: game-ci/unity-builder@v4
with:
projectPath: .
targetPlatform: StandaloneWindows64Credential Lookup Order:
- Environment variables (checked first)
- EditorPrefs (fallback for local development)
Menu: Tools → KitStack → Lexis → Auto-Translate...
The Auto-Translate window provides a unified interface for managing auto-translation.
Tabs
| Tab | Purpose |
|---|---|
| Translate | Translate individual strings with preview |
| Settings | Translation context, service credentials, and credential validation |
| Memory | View and manage translation cache with per-language-pair breakdown |
Translate Tab
- Service Selection: Choose DeepL, ChatGPT, Google Translate, Gemini, or Claude
- Service Status: Shows verification status next to the service dropdown — "Verified" (green), "Not Verified" (yellow), "Verification Failed" (red), or "Not Configured" (red)
- Language Selection: Source and target language codes
- Text Input: Enter text to translate
- Preview: See translation result before applying
Settings Tab
Translation Context: Assign or create a TranslationContext ScriptableObject that provides project-specific instructions to AI translators (tone, terminology, placeholders). Click Create to generate one automatically if none exists.
Service Credentials:
- DeepL: API key (Free or Pro), auto-detects endpoint
- ChatGPT: OpenAI API key
- Google: Cloud Translation API key
- Gemini: Google AI API key
- Claude: Anthropic API key
Validate All Credentials: Validates each configured service against its API. Status persists across sessions:
- Verified (green): API key confirmed working
- Verification Failed (red): API call failed
- Not Verified (yellow): Configured but not yet validated
- Not Configured (red): No API key set
Memory Tab
- Statistics: Total cached translations, total source characters, services used
- Language Pair Breakdown: Per-pair table (e.g., "en → de: 42 entries, 3,200 chars") with individual Clear buttons
- Clear All: Remove all cached entries
String Table Browser Integration
The String Table Browser includes two auto-translation features (Pro only):
Translate All Button:
- Located in the toolbar next to + Add Entry (only visible for String Tables)
- Translates all untranslated entries across all target languages in one click
- Shows a confirmation dialog with entry count, character count, and selected service
- Uses the Translation Context configured in the Settings tab
- Checks Translation Memory cache first to avoid redundant API calls
- Disabled (grayed out) when no translation service is configured
Per-Entry Translate Button (T):
- Appears next to the Edit button on each entry row
- Only visible when a specific target language column is selected (not "All Languages" or the default locale)
- Translates that single entry's default value into the selected language
- Result is written directly into the entry
- Uses Translation Memory cache and Translation Context
TranslationContext is a ScriptableObject that provides contextual information to improve translation quality. It's especially powerful with AI-based services like ChatGPT, Claude, and Gemini, which use the context to generate more accurate, consistent, and tonally appropriate translations.
Create: Via the Settings tab Create button, or right-click → Create → KitStack → Lexis → Translation Context
Why Use TranslationContext?
Without context, translation services treat each string in isolation. This leads to:
- Inconsistent terminology (translating "level" as "stage" sometimes and "tier" other times)
- Wrong tone (formal language in a casual mobile game)
- Incorrect domain assumptions (translating "tank" as a military vehicle instead of a game role)
With a well-configured TranslationContext, AI services understand your project and produce translations that:
- Match your game's tone and style
- Use consistent terminology throughout
- Respect domain-specific meanings
- Preserve brand names and untranslatable terms
Provider Support
| Feature | ChatGPT | Claude | Gemini | DeepL | Google Translate |
|---|---|---|---|---|---|
| Project Description | ✓ Full support | ✓ Full support | ✓ Full support | — | — |
| Genre/Audience | ✓ Full support | ✓ Full support | ✓ Full support | — | — |
| Formality | ✓ Full support | ✓ Full support | ✓ Full support | ✓ Partial* | — |
| DoNotTranslate | ✓ Full support | ✓ Full support | ✓ Full support | — | — |
| Glossary | ✓ Full support | ✓ Full support | ✓ Full support | ✓ Via API** | — |
*DeepL supports formality natively for some languages (DE, FR, IT, ES, NL, PL, PT, RU, JA). **DeepL glossaries require separate API setup; Lexis passes glossary terms via context for AI services.
Recommendation: For best translation quality, use ChatGPT or Claude with a well-configured TranslationContext. For cost-effective AI translations, use Gemini. For traditional translation without context needs, use DeepL or Google Translate.
Settings
| Property | Description |
|---|---|
ProjectDescription | Brief description of your project (see below for tips) |
Genre | Content genre (Game, App, Website, Documentation) |
TargetAudience | Target audience (Children, Teens, Adults, All Ages) |
Formality | Formality level (Default, Informal, Formal) |
DoNotTranslate | List of terms to preserve untranslated (brand names, etc.) |
Glossary | Term-to-translation mappings for consistent terminology |
Writing a Good Project Description
The ProjectDescription field is the most important setting for AI translation quality. Write 2-4 sentences that describe:
- What your project is - Game, app, website, etc.
- Genre and setting - Fantasy RPG, sci-fi shooter, casual puzzle, business app
- Tone and style - Serious, humorous, formal, casual, epic, lighthearted
- Target audience - Age group, player type
Good Examples:
"A dark fantasy action RPG set in a medieval world overrun by demons.
The tone is serious and dramatic, with occasional dark humor.
Target audience is mature gamers (18+).""A cheerful puzzle game for children ages 6-12 featuring colorful animals.
The tone is friendly, encouraging, and educational.
All text should be simple and easy to understand.""A competitive multiplayer FPS with a near-future military setting.
Communication is tactical and professional.
Target audience is teens and young adults who enjoy esports."Poor Examples:
"My game" // Too vague, provides no useful context"A game where you do stuff" // No genre, tone, or audience informationGlossary Entries
Define consistent translations for domain-specific terms. The Glossary is edited directly in the Unity Inspector:
How to Access:
- Create a TranslationContext asset: Right-click → Create → KitStack → Lexis → Translation Context
- Select the TranslationContext asset in the Project window
- In the Inspector, expand the Glossary section
- Click + to add entries, configure each with:
- Source Term: The English term to match
- Target Term: The desired translation
- Target Language: Language code (e.g., "de") or leave empty for all languages
Example Configuration (Inspector):
| Source Term | Target Term | Target Language |
|---|---|---|
| Health Points | Lebenspunkte | de |
| Health Points | Points de vie | fr |
| Mana | Mana | (empty - keep for all) |
| The Dark Lord | Der Dunkle Fürst | de |
You can also configure the Glossary via code:
var context = ScriptableObject.CreateInstance<TranslationContext>();
// Access glossary (read-only property, configure via Inspector or serialization)
foreach (var entry in context.Glossary)
{
Debug.Log($"{entry.SourceTerm} → {entry.TargetTerm} ({entry.TargetLanguage})");
}When to use Glossary:
- Character names that should be translated (not just transliterated)
- Game-specific terms with established translations
- Technical terms with specific meanings in your domain
- Terms that might be ambiguous without context
When to use DoNotTranslate:
- Brand names (your game title, company name)
- Character names that should stay in English
- Technical identifiers shown to users
- Proper nouns that shouldn't change
Before translation, Lexis can analyze source text for common issues that may affect translation quality.
Detected Issues
| Issue Type | Severity | Example |
|---|---|---|
| Unbalanced placeholders | Error | Hello {name (missing }) |
| Empty placeholders | Error | Hello {}! |
| Encoding issues | Error | Replacement character \uFFFD |
| Multiple spaces | Warning | Hello world |
| Leading/trailing whitespace | Warning | Hello |
| Hardcoded large numbers | Warning | You scored 10000 points |
| URLs in text | Info | Visit https://example.com |
Quality Levels
| Level | Meaning |
|---|---|
| Good | No issues detected |
| Fair | Warnings only |
| Poor | Contains errors |
Usage
using Lexis.Editor.Translation;
var checker = new SourceQualityChecker(() => openAiApiKey);
var result = checker.CheckBasicQuality("Hello {name}!");
if (result.HasIssues)
{
foreach (var issue in result.Issues)
{
Debug.LogWarning($"{issue.Type}: {issue.Description}");
}
}Translation Memory caches translations to reduce API calls and costs. Identical source strings return cached results instantly.
Features
- Automatic caching: All successful translations are cached
- Language-pair aware: Caches are specific to source/target language pairs
- Persistent: Cache survives Unity restarts (stored in Library folder)
- LRU eviction: Oldest entries removed when cache is full (10,000 max entries)
- Per-pair management: View and clear cache by individual language pair
Statistics
using Lexis.Editor.Translation;
var tm = TranslationMemoryManager.Instance;
var stats = tm.GetStats();
Debug.Log($"Entries: {stats.TotalEntries}");
Debug.Log($"Characters: {stats.TotalCharacters}");
Debug.Log($"Language pairs: {stats.LanguagePairs}");
Debug.Log($"Services: {string.Join(", ", stats.Services)}");
// Per language pair breakdown
foreach (var kvp in stats.LanguagePairBreakdown)
{
Debug.Log($"{kvp.Key}: {kvp.Value.EntryCount} entries, {kvp.Value.TotalCharacters} chars");
}Cache Management
// Check for cached translation
if (tm.TryGetCachedTranslation("Hello", "en", "de", out string cached))
{
Debug.Log($"Cached: {cached}");
}
// Store a translation
tm.StoreTranslation("Hello", "Hallo", "en", "de", "deepl");
// Clear specific language pair
int removed = tm.ClearForLanguagePair("en", "de");
// Clear all
tm.ClearAll();Single Translation
using Lexis.Editor.Translation;
using Lexis.Translation;
// Using the default configured service
var result = await TranslationIntegration.TranslateAsync(
"Hello, world!",
"en",
"de");
if (result.Success)
{
Debug.Log($"Translated: {result.TranslatedText}");
Debug.Log($"Characters: {result.CharacterCount}");
}
else
{
Debug.LogError($"Failed: {result.GetUserFriendlyMessage()}");
}Batch Translation
using Lexis.Editor.Translation;
using Lexis.Translation;
string[] texts = { "Hello", "World", "Welcome" };
var results = await TranslationIntegration.TranslateBatchAsync(
texts,
"en",
"de",
context: myTranslationContext,
progress: new Progress<TranslationProgress>(p =>
{
Debug.Log($"Progress: {p.Completed}/{p.Total}");
}));
for (int i = 0; i < results.Length; i++)
{
if (results[i].Success)
{
Debug.Log($"{texts[i]} → {results[i].TranslatedText}");
}
}Using Specific Services
using Lexis.Translation.Services;
// DeepL
var deepl = new DeepLService(() => Environment.GetEnvironmentVariable("LEXIS_DEEPL_API_KEY"));
var result = await deepl.TranslateAsync("Hello", "en", "de");
// ChatGPT with custom model
var chatgpt = new OpenAIService(() => Environment.GetEnvironmentVariable("LEXIS_OPENAI_API_KEY"));
chatgpt.Model = "gpt-4o"; // or "gpt-4o-mini" (default)
var result = await chatgpt.TranslateAsync("Hello", "en", "de", myContext);
// Google Translate
var google = new GoogleTranslateService(() => Environment.GetEnvironmentVariable("LEXIS_GOOGLE_TRANSLATE_API_KEY"));
var result = await google.TranslateAsync("Hello", "en", "de");
// Gemini
var gemini = new GeminiService(() => Environment.GetEnvironmentVariable("LEXIS_GEMINI_API_KEY"));
var result = await gemini.TranslateAsync("Hello", "en", "de", myContext);
// Claude
var claude = new ClaudeService(() => Environment.GetEnvironmentVariable("LEXIS_CLAUDE_API_KEY"));
var result = await claude.TranslateAsync("Hello", "en", "de", myContext);| Feature | DeepL | ChatGPT | Google Translate | Gemini | Claude |
|---|---|---|---|---|---|
| Languages | 30+ | All major | 100+ | All major | All major |
| Context-aware | Limited | Excellent | Limited | Good | Excellent |
| Formality control | Yes | Via prompt | No | Via prompt | Via prompt |
| Batch limit | 50 texts | 1 at a time | 128 texts | 1 at a time | 1 at a time |
| Cost | Per character | Per token | Per character | Per token | Per token |
| Best for | European languages | Creative content | Wide coverage | Cost-effective AI | Nuanced content |
- Use TranslationContext for AI services to improve quality
- Review translations before committing - machine translation isn't perfect
- Use glossaries for consistent terminology (character names, game terms)
- Check source quality before translating to avoid propagating errors
- Leverage caching - the Translation Memory reduces API costs significantly
- Use Translate All in the String Table Browser for bulk translation of untranslated entries
- Set DoNotTranslate for brand names, product names, and untranslatable terms
| Error | Cause | Solution |
|---|---|---|
| "Invalid API key" | Key is incorrect or expired | Verify key in service dashboard |
| "Rate limited" | Too many requests | Wait and retry, or upgrade API plan |
| "Quota exceeded" | Monthly limit reached | Check usage in service dashboard |
| "Unsupported language" | Service doesn't support language | Try a different service |
| "Network error" | Connection failed | Check internet connection |
