Delivery Tongue (@pptt)A VS Code Copilot Chat extension for translating PowerPoint presentations. Supports full-file translation, resume from interruption, and single-page translation — while preserving original layout, images, and themes. Table of Contents
Prerequisites
UsageOpen a workspace containing Command Overview
|
| Prompt Example | Detected Language | Output Filename |
|---|---|---|
translate to Traditional Chinese |
zh-TW | _zh-TW.pptx |
translate to Simplified Chinese |
zh-CN | _zh-CN.pptx |
translate to Japanese |
ja | _ja.pptx |
Translate to English |
en | _en.pptx |
translate to Korean |
ko | _ko.pptx |
Terminology Preservation
Specify non-translatable terms in your prompt:
@pptt /all translate to Traditional Chinese, keep DevOps, CI/CD, Kubernetes in English
File Input/Output
| File | Description |
|---|---|
[filename].pptx |
The source presentation you provide (not modified) |
[filename]_progress.json |
Translation progress draft (editable for manual corrections) |
[filename]_{language-code}.pptx |
The translated output file |
Manual Draft Correction
_progress.json is a human-readable JSON file. You can open it directly in VS Code to modify translations:
- Find the page to edit (by
index, 0-based page number) - Modify the
textvalues in thetranslatedTextsarray - Save the file
- Run
@pptt /resumeto regenerate the.pptx(your edits will be preserved)
AI Model Settings
By default, the model selected in the Copilot Chat interface (e.g., GPT-4o) is used. To use a specific model, override it in VS Code settings:
- Open Settings:
Ctrl+, - Search for
ppt-translator.modelFamily - Enter the model family name
| Setting Value | Description |
|---|---|
| (empty, default) | Follows the model selected in Chat |
gpt-4o |
OpenAI GPT-4o |
gpt-4.1 |
OpenAI GPT-4.1 |
claude-sonnet-4 |
Anthropic Claude Sonnet 4 |
o3-mini |
OpenAI o3-mini |
If the specified model is unavailable, the system automatically falls back to the Chat-selected model and displays a warning.
Translation Settings
All translation settings are optional and can be configured in VS Code user settings or workspace settings (.vscode/settings.json). Workspace settings take precedence over user settings.
Default Target Language
After setting a default target language, you can use @pptt /all or @pptt /page 3 without entering translation instructions:
{
"ppt-translator.defaultTargetLanguage": "zh-TW"
}
- With this set,
@pptt /all(without additional text) translates the entire presentation - If an explicit language instruction is provided in Chat, the Chat input takes precedence
- Supports any BCP 47 language code:
zh-TW,zh-CN,ja,en,ko, etc.
Custom Locale Style Guides
Override the translation style specification for a specific locale. The setting value completely replaces the built-in style guide for that locale:
{
"ppt-translator.localeStyleGuides": {
"zh-TW": "Target locale: Taiwan Traditional Chinese\n- Use Taiwan terminology\n- Use bilingual annotation for technical terms: Chinese (English)\n- Do not translate proper nouns",
"ja": "Target locale: Japanese\n- Use desu/masu form\n- Use katakana for technical terms"
}
}
Built-in zh-TW Style Guide (click to expand)
Target locale: Taiwan Traditional Chinese (zh-TW)
Style guidelines:
- Use Taiwan Traditional Chinese vocabulary and phrasing, NOT Simplified Chinese or mainland Chinese expressions.
- For technical/professional terms, use BILINGUAL ANNOTATION format: "Chinese (English)" on first occurrence within each slide.
- Terms universally used in English in Taiwan's IT industry should be kept as-is WITHOUT Chinese annotation: Git, CI/CD, BDD, TDD, SRE, DevOps, etc.
- Do NOT translate proper nouns, product names, well-known abbreviations, author names, book titles, company names, or organization names.
- Use natural, fluent Taiwan-style phrasing. Avoid stiff literal translations.
- Prefer active voice over passive voice.
- Eliminate redundancy — Chinese translations should be MORE concise than English.
- For bulleted/listed items, maintain PARALLEL STRUCTURE.
Override Guidance Prompts
Each LLM call in the system consists of a "guidance prompt (overridable)" and an "enforced response format (not overridable)". You can override the guidance portion to adjust the AI's translation behavior; the system automatically appends enforced format rules.
All prompts support {{placeholder}} variables that are replaced at runtime with actual values.
{
"ppt-translator.prompts": {
"domainAnalysis": "...", // Override domain analysis guidance prompt
"preAnalysis": "...", // Override per-slide pre-analysis guidance prompt
"translation": "..." // Override translation guidance prompt
}
}
Domain Analysis (domainAnalysis)
Analyzes the professional domain of the entire presentation to ensure ambiguous terms are translated correctly.
Supported Variables: {{userPrompt}}, {{sampledContent}}, {{slideCount}}
Built-in Domain Analysis Guidance Prompt (click to expand)
Role: You are a domain expert analyst for presentation decks.
Task: Determine the primary professional domain of this presentation and provide terminology guidance for translation.
User context: {{userPrompt}}
IMPORTANT: Focus on identifying the domain so that ambiguous terms can be translated correctly.
For example:
- In DevOps/Software: "master" = Git branch name (keep as-is), "pipeline" = CI/CD pipeline
- In Music: "master" = master recording, "pipeline" = production pipeline
- In Education: "master" = master's degree, "pipeline" = talent pipeline
- In Finance: "hedge" = hedging strategy, "leverage" = financial leverage
Sampled content from {{slideCount}}-slide presentation:
{{sampledContent}}
Per-Slide Pre-Analysis (preAnalysis)
Analyzes each slide's content type and translation strategy before translation.
Supported Variables: {{userPrompt}}, {{slideContent}}
Built-in Pre-Analysis Guidance Prompt (click to expand)
Role: You are a content analyst for presentation slides.
Task: Analyze the following slide content and provide translation guidance.
User translation context: {{userPrompt}}
Slide content:
{{slideContent}}
Translation (translation)
Controls the core behavior rules for AI translation.
Supported Variables: {{targetLanguage}}, {{slideTitle}}, {{domainContext}}, {{contentAnalysis}}, {{styleGuide}}, {{userPrompt}}, {{inputText}}
Built-in Translation Guidance Prompt — With Pre-Analysis (click to expand)
You are an expert translator specializing in technical presentations. Translate the following slide content.
Slide context: This slide is titled "{{slideTitle}}".
{{domainContext}}
{{contentAnalysis}}
{{styleGuide}}
User instructions: {{userPrompt}}
Input:
{{inputText}}
Built-in Translation Guidance Prompt — Without Pre-Analysis (click to expand)
You are an expert translator specializing in technical presentations. Translate the following slide content.
Slide context: This slide is titled "{{slideTitle}}".
{{domainContext}}{{styleGuide}}
User instructions: {{userPrompt}}
QUALITY RULES:
5. For short labels (e.g., flowchart labels like "AUTO", "CODE DONE"), translate them concisely while keeping them meaningful in context.
6. When a segment contains a long sentence that was split across visual lines, translate the ENTIRE semantic meaning.
8. Do NOT translate proper nouns, author names, book titles, citation sources, or attribution blocks.
9. Maintain a natural, FLUENT tone in the target language.
...
Input:
{{inputText}}
Combined Settings Example
You can set only the parts you need; all settings are independent. Here is a complete example with all available settings:
{
// ═══════════════════════════════════════════════════════════
// Basic Settings
// ═══════════════════════════════════════════════════════════
// Default target language (BCP 47). After setting, @pptt /all works without a prompt
"ppt-translator.defaultTargetLanguage": "zh-TW",
// AI model family (leave empty to follow Chat interface selection)
"ppt-translator.modelFamily": "",
// LLM concurrent call limit (Pre-Analysis + Translation phases)
"ppt-translator.concurrencyLimit": 5,
// ═══════════════════════════════════════════════════════════
// Locale Style Guides (completely replaces built-in for that locale)
// ═══════════════════════════════════════════════════════════
"ppt-translator.localeStyleGuides": {
"zh-TW": "Target locale: Taiwan Traditional Chinese\n- Use Taiwan terminology\n- Use bilingual annotation for technical terms: Chinese (English), on first occurrence\n- Keep Git, CI/CD, DevOps, Kubernetes and other industry-standard English terms as-is\n- Do not translate proper nouns, personal names, or company names\n- Avoid stiff literal translations; use natural, fluent Taiwan Chinese\n- Prefer active voice; minimize use of particle words; Chinese should be more concise than English",
"ja": "Target locale: Japanese\n- Use desu/masu form\n- Use katakana or keep English for technical terms\n- Use natural Japanese expressions"
},
// ═══════════════════════════════════════════════════════════
// Guidance Prompt Overrides (only replaces guidance, enforced format appended by system)
// Supports {{placeholder}} variables, replaced at runtime
// ═══════════════════════════════════════════════════════════
"ppt-translator.prompts": {
// Domain analysis: determine presentation domain, resolve ambiguous term translations
// Variables: {{userPrompt}}, {{sampledContent}}, {{slideCount}}
"domainAnalysis": "Role: You are a domain expert analyst for presentation decks.\nTask: Determine the primary professional domain of this presentation and provide terminology guidance for translation.\n\nUser context: {{userPrompt}}\n\nSampled content from {{slideCount}}-slide presentation:\n{{sampledContent}}",
// Per-slide pre-analysis: analyze content type and translation strategy before translating
// Variables: {{userPrompt}}, {{slideContent}}
"preAnalysis": "Role: You are a content analyst for presentation slides.\nTask: Analyze the following slide content and provide translation guidance.\n\nUser translation context: {{userPrompt}}\n\nSlide content:\n{{slideContent}}",
// Translation: core AI translation behavior rules
// Variables: {{targetLanguage}}, {{slideTitle}}, {{domainContext}}, {{contentAnalysis}}, {{styleGuide}}, {{userPrompt}}, {{inputText}}
"translation": "You are an expert translator specializing in technical presentations. Translate the following slide content.\n\nSlide context: This slide is titled \"{{slideTitle}}\".\n\n{{domainContext}}\n{{contentAnalysis}}\n\n{{styleGuide}}\n\nUser instructions: {{userPrompt}}\n\nInput:\n{{inputText}}"
}
}
Tip: The
promptscontent above represents the built-in default values. You can remove any fields you don't need to override; the system will use the built-in values automatically.
Translation Quality Mechanisms
This extension does more than just "send text to AI for translation." Multiple built-in mechanisms ensure translation quality:
| Mechanism | Description |
|---|---|
| Domain Detection | Analyzes the entire presentation's professional domain before translation, ensuring ambiguous terms like master and pipeline are translated correctly across DevOps / music / education contexts |
| Per-Slide Pre-Analysis | Determines content type (flowchart, narrative, list, etc.) before translating each page, generating a page-specific translation strategy instead of one-size-fits-all rules |
| Format Preservation | Directly manipulates PowerPoint Run objects, preserving color, bold, size, and other formatting differences for each text segment |
| Translation Cache | Shares cache across slides; identical source text is not sent to AI again, ensuring consistent terminology throughout the presentation |
| Draft System | Translation results are written to _progress.json in real time; you can interrupt, manually correct, and resume at any time |
For detailed technical information, see Appendix: How Pre-Analysis Improves Translation Quality.
FAQ
Q: Why does @pptt not respond in Copilot Chat?
A: Ensure the GitHub Copilot extension is installed and signed in. Chat Participants require Copilot to function.
Q: What if translation is interrupted midway?
A: Simply enter @pptt /resume. The system resumes from the interruption point without re-translating completed pages.
Q: How do I fix incorrect translations?
A: Open the _progress.json draft file, find the corresponding page, modify the text values in translatedTexts, save, then run @pptt /resume to regenerate the file.
Q: Can I translate to languages not listed in the prompt examples? A: Yes. Describe the target language in your prompt; the system uses AI to detect it automatically.
Q: Will images and layout be affected? A: No. The system only replaces text content. All images, charts, themes, and animations are fully preserved.
Known Limitations
| Item | Description |
|---|---|
| Operating System | Windows only (relies on PowerPoint COM automation) |
| Office Version | Requires Office 2016 or later (version 16.0+) |
| File Format | Only .pptx (OpenXML); legacy .ppt is not supported |
| Protected Files | Encrypted/protected presentations require entering a password in the PowerPoint popup window |
| File Locking | The source .pptx must not be open in another program during translation (avoids COM lock conflicts) |
| Text in Images | Text embedded in images/SmartArt cannot be translated |
| Speaker Notes | Currently only translates slide text; speaker notes are not included |
Troubleshooting
PowerPoint component connection failed
This warning at extension startup means a PowerPoint COM connection could not be established.
- Verify Microsoft Office is installed (not Office Online)
- Verify PowerPoint is not in a "repairing" or "updating" state
- Try opening VS Code as Administrator
COM Error During Translation
- Check if PowerPoint has opened automatically and is stuck on a dialog (e.g., password input, macro security prompt)
- Close all PowerPoint windows and retry
- If it recurs, use
@pptt /resumeto continue from the interruption
Abnormal Output File Format
- Verify the source file itself opens normally
- Output filenames include a language code suffix (e.g.,
_zh-TW.pptx) and never overwrite the original - If a file with the same name already exists, a sequential number is added (e.g.,
_zh-TW_2.pptx)
Model Unavailable or Slow Response
- Verify your GitHub Copilot subscription is active and signed in
- Try switching to a different model in the Chat interface
- Large presentations (>50 pages) take longer to translate — this is expected
License
MIT License
Appendix: How Pre-Analysis Improves Translation Quality
Each slide undergoes an LLM Pre-Analysis before translation. This is not redundant — it is a key design decision that significantly improves translation quality.
Problem: Without Pre-Analysis
The typical approach is to send text to the LLM with a set of "universal rules." But presentation content types vary enormously:
- Flowchart pages: Each Shape is an independent label requiring extremely short translations (≤4 characters)
- Narrative/quote pages: Contain names, book titles, and citation sources that must be preserved as-is
- Taxonomy/list pages: Many short labels requiring parallel structure, no bilingual annotations
- Long-form explanation pages: Require natural, fluent paragraph translation with bilingual term annotations
Using a single set of 13 universal rules for all pages causes the LLM to frequently:
- Add unnecessary bilingual annotations to flowchart labels, causing text overflow
- Translate citation sources, destroying original attributions
- Apply inconsistent styles to list items (some as nouns, some as verbs)
Solution: Analyze Before Translating
Pre-analysis lets the LLM "understand" the page before translating:
| Pre-Analysis Output | Purpose | Example |
|---|---|---|
contentType |
Determine content type | "flowchart with deployment pipeline" |
strategy |
Generate page-specific translation strategy | "Keep labels ≤4 chars; preserve branch names" |
summary |
Provide contextual summary | "CI/CD pipeline showing build→test→deploy" |
preserveBlocks |
Mark blocks that should not be translated | ["Source: Forrester Research", "Boeing 737"] |
These analysis results are injected into the translation prompt, replacing the 13 universal rules, enabling the LLM to translate precisely based on each page's characteristics.
Comparison of Results
| Scenario | Without Pre-Analysis | With Pre-Analysis |
|---|---|---|
Flowchart label CODE DONE |
Too long with bilingual annotation (overflow) | Concise (≤4 chars) |
Citation Source: Forrester... |
Translated (should not be) | Preserved as-is |
List Short-lived feature branches |
Verbose with bilingual annotation | Concise translation |
Narrative Continuous Integration first occurrence |
May miss or duplicate annotation | Annotated only on first occurrence |
Presentation-Level Domain Detection
Before per-slide analysis, the system performs a Domain Detection on the entire presentation to resolve ambiguous term translation:
| Ambiguous Term | DevOps Presentation | Music Presentation | Education Presentation |
|---|---|---|---|
master |
Git branch name (keep as-is) | Master recording | Master's degree |
pipeline |
CI/CD pipeline | Production pipeline | Talent pipeline |
build |
Build/compile | Sound shaping | Build/construct |
release |
Release version | Album release | Publish/release |
Domain detection uniformly samples from the entire presentation (≤8 pages), producing domain, terminology, and disambiguations results that are injected into every slide's translation prompt. This ensures that even a page with just a single "from Master" label gets the correct translation as a Git branch rather than another meaning.
Performance Overhead
- Domain detection: Only 1 LLM call per presentation (lightweight sampled input)
- Per-slide pre-analysis: 1 LLM call per slide (text summary input)
Negligible compared to the translation token consumption itself. In return, each page gets a tailored translation strategy plus presentation-level domain context.
Appendix: Translation Pipeline Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ VS Code Copilot Chat │
│ User input: @pptt /all translate to Traditional Chinese │
└──────────────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Command Router │
│ Parse command → /all, /page, /resume │
│ Detect target language → zh-TW │
│ Search workspace for .pptx files │
└──────────────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 1: Open Presentation │
│ ┌───────────────┐ stdin/stdout ┌──────────────────────────┐ │
│ │ Office Bridge │◄══ JSON Lines ════►│ PowerShell COM Layer │ │
│ │ (TypeScript) │ │ PowerPoint.Application │ │
│ └───────────────┘ └──────────────────────────┘ │
│ Extract text from each slide: Shape → Paragraph → Run │
│ Output: TextSegment[] = { xmlPath, text } │
└──────────────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 2: Domain Detection (1 LLM call per presentation) │
│ │
│ Uniformly sample slides (≤8 pages) → identify domain │
│ → Output: domain, terminology, disambiguations │
│ → Injected into every subsequent translation prompt │
└──────────────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 3: Per-Slide Pre-Analysis (1 LLM call per slide) │
│ │
│ Classify content type (flowchart / narrative / list) │
│ → Output: contentType, strategy, summary, preserveBlocks │
└──────────────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 4: Per-Slide Translation (1–N LLM calls per slide) │
│ │
│ ┌──────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Group by Shape│────►│ Build Prompt │────►│ Copilot LLM │ │
│ │ + Smart Merge │ │ + Style Guide│ │ (gpt-4o, etc.) │ │
│ └──────────────┘ └─────────────┘ └────────┬────────────┘ │
│ │ │
│ ┌──────────────┐ ┌─────────────┐ │ │
│ │ Translation │◄────│ Parse [idx] │◄─────────────┘ │
│ │ Cache │ │ Response │ │
│ │ (cross-slide)│ │ │ │
│ └──────────────┘ └─────────────┘ │
│ │
│ • Identical text hits cache — no duplicate LLM calls │
│ • Soft-break markers (\u000b ↔ <br>) round-trip preserved │
│ • >40 segments auto-batched at Shape boundaries │
└──────────────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Draft Management │
│ │
│ After each slide → write to _progress.json immediately │
│ ┌─────────────────────────────────────┐ │
│ │ _progress.json │ │
│ │ { slides: [ │◄── Editable by user │
│ │ { originalTexts, translatedTexts│ then /resume to rebuild │
│ │ status, preAnalysis } │ │
│ │ ] } │ │
│ └─────────────────────────────────────┘ │
└──────────────┬──────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 5: Assembly │
│ │
│ Write translations back via COM, slide by slide │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Format-Preserving Write │ │
│ │ │ │
│ │ 1. Read Run structure (color, size, bold per Run) │ │
│ │ 2. Locate anchor tokens in translated text │ │
│ │ 3. Set Run.Text directly → formatting fully preserved │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ SaveAs → [filename]_zh-TW.pptx (never overwrites original) │
└─────────────────────────────────────────────────────────────────────┘
Component Interaction
VS Code Extension Host (TypeScript) PowerShell Child Process (COM)
════════════════════════════════════ ══════════════════════════════
┌────────────┐ ┌──────────────────┐
│ Command │─► /all (full translate) │ office-bridge.ps1│
│ Router │─► /page (single page) │ │
│ │─► /resume (draft resume) │ PowerPoint COM │
│ │ stdin (JSON Lines) │ │
│ Services ──┼─────────══════════════════════►│ Read / Write / │
│ │ stdout (JSON Lines) │ Save │
│ │◄═══════════════════════════════│ │
│ │ └──────────────────┘
│ │
│ ┌──────────┴────────────────────────────┐
│ │ PPTX Parser — Extract text via COM │
│ │ Pre-Analyzer — Domain + per-slide │
│ │ Translator — LLM + cache + batch │
│ │ Draft Manager — _progress.json CRUD │
│ │ PPTX Assembler — Write back via COM │
│ │ Progress Reporter — Chat UI output │
│ └──────────────────────────────────────┘
└────────────┘