| name | mediawiki-translate-extension |
| description | Work with the Translate extension for multilingual wiki content — marking pages for translation, writing translatable templates, using |
| license | MIT |
| compatibility | opencode |
| depends_on | ["wikimedia-api-access","wikipedia-templates"] |
| skill_discovery_hints | [{"keywords":["Translate extension","page translation","translatable","<translate>","translation unit","language subpage"]},{"keywords":["Special:MyLanguage","#timef","translation memory","message group","fuzzy translation"]}] |
| last_verified | "2026-06-10T00:00:00.000Z" |
⚠️ User-Agent required: The API examples below hit Wikimedia endpoints. All requests must include a descriptive User-Agent header. See the wikimedia-api-access skill for the correct format.
📖 Prerequisites: For general template syntax and parser functions, see wikipedia-templates. For navigation patterns that use Special:MyLanguage/, see mediawiki-page-navigation. For styling translatable templates, see wikimedia-page-styling.
Table of Contents
- What the Translate Extension Is
- Two Translation Modes
- Page Translation: Marking Content for Translation
- Translation Units and
<translate> Tags
- The
<languages/> Bar
- Language Subpages (
/en, /fi, /ko, etc.)
- Translation Variables (
<tvar>)
Special:MyLanguage/ — Language-Aware Links
#timef — Locale-Aware Date Formatting
- Making Templates Translatable
- The
{{TRANSLATABLEPAGE}} Magic Word
- Page Translation Workflow
- Message Groups and Translation Memory
- Best Practices
- Troubleshooting
- Reference Links
What the Translate Extension Is
The Translate extension is MediaWiki's built-in system for creating multilingual content. It is installed on Meta, mediawiki.org, Commons, and many other Wikimedia wikis, but not on Wikipedia (which uses interlanguage links instead).
What It Solves
Without the Translate extension, multilingual wikis faced these problems:
| Problem | Without Translate | With Translate |
|---|
| How to display multiple languages | Manual copy-paste, hard to maintain | Automatic language subpages + <languages/> bar |
| How to track completion | No visibility | Colored progress indicators per language |
| What happens when source changes | Translations go out of sync silently | Marked as "outdated" (fuzzy) until reviewed |
| How to format dates per locale | Hard-coded formats | #timef — auto-formats to user's language |
| How to link to translated pages | Manual per-language links | Special:MyLanguage/ — follows user's preference |
Where It's Used
| Wiki | Translate Extension | Purpose |
|---|
| meta.wikimedia.org | ✅ Yes | Cross-project coordination docs, multilingual community pages |
| commons.wikimedia.org | ✅ Yes | Multilingual file descriptions |
| mediawiki.org | ✅ Yes | Software documentation in dozens of languages |
| en.wikipedia.org | ❌ No | Uses interlanguage links instead |
| translatewiki.net | ✅ Yes (primary) | Software interface translation (MediaWiki, extensions) |
| Toolforge | ✅ Yes | Tool documentation |
Two Translation Modes
The Translate extension has two distinct modes:
1. Page Translation
Content is written in one language (usually English) and marked for translation with <translate> tags. Translation administrators approve the page, and translators can translate each unit through the Special:Translate interface. This is what AvoinGLAM pages use.
Best for: Long-form content, documentation, community pages that need human-quality translation.
2. Unstructured Element Translation (Interface Messages)
Individual messages are defined as wiki pages in the MediaWiki namespace and translated via the same interface. Used for site UI and template messages.
Best for: Template labels, UI strings, small snippets.
This skill focuses on Page Translation, which is what the AvoinGLAM pages use.
Page Translation: Marking Content for Translation
The Basic Markup
To make a page translatable, wrap translatable content in <translate> tags:
<languages />
<translate>
== Introduction == <!--T:1-->
Welcome to the AvoinGLAM project.
== Mission == <!--T:2-->
Our goal is to promote Open Access to cultural heritage.
</translate>
Step-by-Step Process
-
Write the page in the base language (usually English), wrapping translatable content in <translate>... </translate>
-
Add <languages /> at the top (this shows the language selector bar)
-
Add translation unit markers — <!--T:1-->, <!--T:2-->, etc. — after each heading or paragraph. These can be auto-generated when the page is marked for translation.
-
Request translation marking — a translation administrator uses Special:PageTranslation to mark the page
-
Translators translate via Special:Translate — each unit gets translated independently
-
The system creates language subpages — /en, /fi, /fr, etc.
What Gets Wrapped in <translate>
Only the translatable content goes inside <translate> tags. Things that should NOT be translated:
- Template calls (but their labels should be translatable — see below)
- File names
- URLs and links (but link display text should be translatable)
- Numbers, dates in fixed formats
- Code examples
Omitting Content from Translation
Content outside <translate> tags is page-global — it appears on all language variants unchanged:
<languages />
{{Project/Navigation}}
<translate><!--T:1-->
Welcome to our project.
</translate>
[[:Category:Project]] ← Categories are page-global, outside translate
Translation Units and <translate> Tags
Translation Units
A translation unit is the smallest piece of content that can be translated independently. Each unit gets a unique identifier (<!--T:1-->).
<translate>
== Heading == <!--T:1-->
This is a paragraph. It is one translation unit. <!--T:2-->
This is another paragraph. It is a separate unit. <!--T:3-->
</translate>
Rules for translation units:
- Each paragraph, heading, or list item is typically one unit
- Units are separated by blank lines
- Every unit should have a
<!--T:N--> marker after it
- The markers are auto-generated when the page is first marked for translation
Headings
Headings inside <translate> become their own translation units:
<translate>
== Contact us == <!--T:10-->
Reach us at example@example.org. <!--T:11-->
</translate>
The heading is unit 10, the paragraph is unit 11.
Lists
List items can be individual units:
<translate>
Our activities include: <!--T:20-->
* Workshops <!--T:21-->
* Hackathons <!--T:22-->
* Online events <!--T:23-->
</translate>
Mixed Content
Content can be mixed inside and outside <translate> tags, but each section must be a complete block:
<translate><!--T:30-->
This paragraph is translatable.
</translate>
{{Some template that should not be translated}}
<translate><!--T:31-->
This paragraph is also translatable.
</translate>
The <languages/> Bar
Placement
Place <languages /> at the very top of the page, before any content:
<languages />
{{Project/Navigation}}
<translate>
...
</translate>
Appearance
The bar shows all available translations with colored progress indicators:
Languages: English ✅ Finnish ✅ French 🔵 Arabic 🟡 German 🔴
| Color | Meaning |
|---|
| ✅ Green | 100% translated and up-to-date |
| 🔵 Blue | 100% translated but some units are outdated (fuzzy) |
| 🟡 Yellow/Orange | Partially translated |
| 🔴 Red | Not translated at all |
No <languages/> at the Bottom
You only need one <languages /> tag at the top — do not add it to the bottom.
Language Bar for Templates
For templates that are translated (like navigation templates), place <languages /> inside <noinclude> so it only appears on the template page itself, not when transcluded:
<noinclude><languages /></noinclude>
<templatestyles src="Project/style.css" />
<translate>... translatable template content ...</translate>
Language Subpages (/en, /fi, /ko, etc.)
How They Are Created
When a page is marked for translation, the system automatically creates language subpages:
AvoinGLAM ← Base page (contains the translatable source)
AvoinGLAM/en ← English translation
AvoinGLAM/fi ← Finnish translation
AvoinGLAM/ko ← Korean translation
The Base Page vs. Translated Pages
- The base page (no language suffix) contains the source text with
<translate> tags
- Language subpages contain only the translated text for that language
- When you view the base page, you see the source language (usually English) by default
- When you view a variant like
/fi, you see the Finnish translation
- The
<languages /> bar on the base page links to all variants
Language Template Subpages
Language subpages work for templates too. The AvoinGLAM navigation template has:
Template:AvoinGLAM/Main navigation ← Source (with <translate> tags)
Template:AvoinGLAM/Main navigation/en ← English
Template:AvoinGLAM/Main navigation/fi ← Finnish
Template:AvoinGLAM/Main navigation/ko ← Korean
Template:AvoinGLAM/Main navigation/ar ← Arabic
Template:AvoinGLAM/Main navigation/zh ← Chinese
How the Translation System Decides Which Language to Show
- Check if a subpage matching the user's interface language exists
- If not, check the fallback language chain (e.g.,
fi → en)
- If no translation exists, show the source page
This is why Special:MyLanguage/ is important — it triggers this fallback chain.
Working with Language Subpages
Do NOT manually create language subpages. They are created and managed by the Translate extension's page translation system. Editing them directly is possible but will be overwritten the next time a translator updates through the interface.
Translation Variables (<tvar>)
<tvar> variables let you embed non-translatable content inside a translation unit while keeping the surrounding text translatable.
Basic Syntax
<translate><!--T:40-->
Welcome to <tvar name="project">{{SITENAME}}</tvar>.
Our website is at <tvar name="url">https://example.org</tvar>.
</translate>
In the translation interface, translators see:
Welcome to $project. Our website is at $url.
They translate the sentence but the $project and $url placeholders stay intact.
Common Uses for <tvar>
| Use | Example |
|---|
| Magic words | <tvar name="year">{{CURRENTYEAR}}</tvar> |
| Template calls | <tvar name="count">{{PAGESINCATEGORY:Events}}</tvar> |
| URLs | <tvar name="link">https://example.com</tvar> |
| Numbers/statistics | <tvar name="members">42</tvar> |
| Special characters | <tvar name="arrow">→</tvar> |
| Formulas | <tvar name="formula">E=mc²</tvar> |
In Templates
For template labels that include parameters:
<translate><!--T:50-->
Join the <tvar name="group">{{{groupname|}}}</tvar> community.
</translate>
Best Practices for <tvar>
- Use descriptive names —
name="project" not name="1" — so translators understand what they represent
- Wrap only the dynamic part — not the entire sentence
- Avoid
<tvar> inside links — use the link text approach instead (see below)
Special:MyLanguage/ — Language-Aware Links
Special:MyLanguage/ is a redirect page that follows the user's language preference.
How It Works
[[Special:MyLanguage/AvoinGLAM/Past activities|Past activities]]
- The user clicks the link
- Special:MyLanguage checks the user's interface language (e.g.,
fi)
- It redirects to
AvoinGLAM/Past activities/fi if that translation exists
- If not, it falls back to the base page (usually English)
Why It Matters
Without Special:MyLanguage/, a Finnish reader clicking "Past activities" would always go to the English page. With it, they land on the Finnish translation if available.
Where to Use It
- Every link in navigation menus — ensures navigation stays in the user's language
- Internal links on translatable pages — keeps users in their language context
- Links in templates — especially navigation, infoboxes, and banners
Using It in Templates
* [[Special:MyLanguage/AvoinGLAM|<translate><!--T:1--> AvoinGLAM</translate>]]
* [[Special:MyLanguage/AvoinGLAM/{{CURRENTYEAR}}|<translate><!--T:2--> This year</translate>]]
What NOT to Use It For
- Links to Wikipedia pages — use normal interwiki links like
[[w:en:Page|Page]]
- Links to files on Commons — files are not translated this way
- Category links —
Special:MyLanguage/ doesn't work with category syntax
#timef — Locale-Aware Date Formatting
#timef is a parser function provided by the Translate extension that formats dates according to the user's interface language.
Basic Syntax
{{#timef:2024-05-06|date}}
| User Language | Output |
|---|
| en (English) | 6 May 2024 |
| fi (Finnish) | 6. toukokuuta 2024 |
| fr (French) | 6 mai 2024 |
| de (German) | 6. Mai 2024 |
| ar (Arabic) | ٦ مايو ٢٠٢٤ |
| ko (Korean) | 2024년 5월 6일 |
Format Options
| Format | Example (English) | Example (Finnish) |
|---|
date | 6 May 2024 | 6. toukokuuta 2024 |
time | 14:30 | 14:30 |
both | 6 May 2024 14:30 | 6. toukokuuta 2024 14:30 |
dmy | 6 May 2024 | 6. toukokuuta 2024 |
mdy | May 6, 2024 | toukokuuta 6, 2024 |
ymd | 2024 May 6 | 2024 toukokuuta 6 |
iso | 2024-05-06 | 2024-05-06 (iso is always the same) |
Using #timef with Date Ranges
In the AvoinGLAM navigation template, #timef is used to display date ranges:
{{#timef:{{{startdate|}}}|date}}
{{#if: {{{enddate|}}}|–{{#timef:{{{enddate|}}}|date}}}}
This produces:
- English:
6 May 2024 – 7 May 2024
- Finnish:
6. toukokuuta 2024 – 7. toukokuuta 2024
Full Date-Time Display Pattern
{{{location|}}} {{#timef:{{{startdate|}}}|date}}
{{#if: {{{starttime|}}}|• {{{starttime|}}}
}}{{#if: {{{enddate|}}}|–
}}{{#if: {{{enddate|}}}|
{{#timef:{{{enddate|}}}|date}}
}}{{#if: {{{endtime|}}}|{{{endtime|}}}
}} {{{timezone|}}}
Important: #timef Only Works on Translatable Pages
#timef formats dates based on the language of the (translatable) page that contains it. On non-translatable pages, it falls back to #time behavior. This means:
- ✅ Works in templates that are transcluded on translatable pages
- ✅ Works in navigation templates that are part of a translatable project
- ❌ Does NOT work for raw
#timef calls on non-translatable pages
Related: #dateformat
#dateformat is another parser function from the Translate extension that formats dates according to the wiki's content language:
{{#dateformat:2024-05-06|dmy}}
This is less commonly used than #timef because it doesn't adapt to the user's language.
Related: {{#language:...}}
The #language parser function returns the language name in a given language:
{{#language:fi}} → "suomi" (in Finnish context)
{{#language:fi|en}} → "Finnish" (in English context)
{{#language:fr|en}} → "French"
Making Templates Translatable
Templates can be made translatable so that their labels, navigation text, and UI strings appear in the user's language.
Wrapping Labels in <translate>
<noinclude><languages /></noinclude>
<templatestyles src="Project/style.css" />
<div class="menu">
* [[Special:MyLanguage/AvoinGLAM|<translate><!--T:1--> AvoinGLAM</translate>]]
* [[Special:MyLanguage/AvoinGLAM/{{CURRENTYEAR}}|<translate><!--T:2--> This year</translate>]]
* [[Special:MyLanguage/AvoinGLAM/Past activities|<translate><!--T:4--> Past activities</translate>]]
</div>
Template Parameters with Translatable Labels
When a template parameter expects a label, you can provide it inline:
{{Project/Box
| title = <translate><!--T:5--> Join our community</translate>
| intro = <translate><!--T:6--> We invite you to participate.</translate>
}}
Or use parameters with defaults:
{{Project/Box
| title = <translate><!--T:5--> Join our community</translate>
| intro = {{{intro|<translate><!--T:6--> We invite you to participate.</translate>}}}
}}
Best Practice: Separate Label Templates
For complex projects, create a dedicated string template:
<!-- Template:Project/Labels -->
<translate>
<!--T:1--> AvoinGLAM
<!--T:2--> This year
<!--T:4--> Past activities
</translate>
And reference it in your navigation template:
{{#if: {{{show_join|}}}
| [[Special:MyLanguage/Project/Join|{{Project/Labels|join}}]]
}}
What NOT to Wrap in <translate>
<!-- ❌ WRONG: Wrapping the entire template call -->
<translate>{{Project/Navigation}}</translate>
<!-- ✅ RIGHT: Only wrap the labels inside the template -->
{{Project/Navigation|title=<translate><!--T:1--> Welcome</translate>}}
The {{TRANSLATABLEPAGE}} Magic Word
{{TRANSLATABLEPAGE}} returns the title of the translatable page that contains it. It is useful in templates that are transcluded on translatable pages.
Usage
{{fullurl:{{TRANSLATABLEPAGE}}|veaction=edit}}
This generates an edit link for the translatable page, regardless of whether the current view is /en, /fi, or the base page.
Common Pattern: Edit Button on Translatable Content
<span class="editbutton">
[[File:OOjs UI icon edit-ltr.svg|12px|link=
{{fullurl:{{TRANSLATABLEPAGE}}|veaction=edit}}
]]
</span>
This is used in the AvoinGLAM log entry template to ensure the edit button always targets the source page, not the translation variant.
Fallback
If {{TRANSLATABLEPAGE}} is used on a non-translatable page, it returns nothing. Always wrap in a conditional:
{{#if: {{TRANSLATABLEPAGE}}
| [[File:edit.svg|link={{fullurl:{{TRANSLATABLEPAGE}}|action=edit}}]]
}}
Page Translation Workflow
For Content Authors (Non-Administrators)
- Write the content in the base language, wrapping content in
<translate> tags
- Add
<languages /> at the top
- Add translation unit markers — either manually (
<!--T:1-->) or skip them (the system auto-generates when the page is marked)
- Request marking — add the page to a queue or ask a translation administrator
For Translation Administrators
- Mark the page at
Special:PageTranslation
- Review the translation units — the system parses
<translate> tags and shows each unit
- Approve the page for translation — this creates the unit structure
- Monitor translations — check for outdated (fuzzy) units
Main page: Help:Extension:Translate/Page translation administration
For Translators
- Go to
Special:Translate
- Select the page group (e.g., "AvoinGLAM")
- Choose your language (e.g., "Finnish")
- Translate each unit — the interface shows the source text and a text box
- Save — the translation is live immediately but marked as "up-to-date"
- Repeat for other units — progress is tracked automatically
When the Source Changes
- Author edits a translation unit on the base page
- That unit is automatically marked as outdated (fuzzy) for all translations
- Translators see the fuzzy unit highlighted in
Special:Translate
- They update the translation and save
- The unit is no longer fuzzy
Message Groups and Translation Memory
Message Groups
A message group is a collection of translation units. For page translation, one page = one message group. They can be organized into aggregate groups for larger projects:
AvoinGLAM (aggregate group)
├── AvoinGLAM (page group)
├── AvoinGLAM/Past activities (page group)
├── AvoinGLAM/Main navigation (page group)
└── AvoinGLAM/style.css (page group — CSS is NOT translatable)
Translation Memory
The Translate extension uses translation memory (TM) to suggest translations:
- When a translator translates a unit, it's stored in TM
- When similar text appears elsewhere, TM suggests the previous translation
- TM suggestions include a match percentage
Quality Assurance Features
| Feature | Description |
|---|
| Translation review | Translations can be marked as "reviewed" |
| Validation | Checks for missing variables, unbalanced tags |
| Pre-translation | Auto-fill from TM for high-match units |
| Consistency checks | Flags inconsistent translations of the same source text |
Best Practices
Writing for Translation
| Do | Don't |
|---|
| ✅ Write short, complete sentences | ❌ Write long paragraphs with multiple ideas |
✅ Use <!--T:N--> markers after each unit | ❌ Put everything in one giant <translate> block |
| ✅ Keep sentences self-contained | ❌ Use "As mentioned above" (direction is language-dependent) |
✅ Use <tvar> for numbers, URLs, magic words | ❌ Embed formatting in translated text |
✅ Use Special:MyLanguage/ for internal links | ❌ Hard-code language-specific links |
Template Design for Translation
| Pattern | Best Practice |
|---|
| Navigation | Wrap menu labels in <translate>, use Special:MyLanguage/ for links |
| Infoboxes | Make label parameters translatable with defaults |
| Buttons | Keep button text short, wrap in <translate> |
| Dates | Use {{#timef:...}} not {{#time:...}} |
| Banners | Use <tvar> for dynamic content like attendee counts |
Translation Completion Strategy
- Always maintain English as the source language
- Prioritize navigation templates — these affect user experience most
- Translate high-visibility pages first (main page, about page)
- Translate templates' UI strings independently from page content
- Use
#timef for all dates — it costs nothing and improves UX for all languages
Troubleshooting
| Problem | Likely Cause | Solution |
|---|
<languages /> bar not showing | Page hasn't been marked for translation | Request marking at Special:PageTranslation |
#timef not formatting dates | Page is not translatable or not in a translatable context | Ensure the page has <translate> tags and is marked |
Special:MyLanguage/ not working | No translation subpage exists for the target page | Create the translation or check the fallback |
| Template labels not translating | Labels not wrapped in <translate> | Add <translate> tags around labels |
| Translation units not updating | Source page was edited without updating the translation | Re-mark the page or ask an admin |
{{TRANSLATABLEPAGE}} returns nothing | Page is not translatable | Check that the page has been marked for translation |
Broken <tvar> in translation | Variable name doesn't match the source | Check for typos in name="..." |
| Language subpage shows source text | No translation exists yet | The system falls back to source when no translation is available |
Debugging Translation Status
curl -s "https://meta.wikimedia.org/w/api.php?action=query&prop=translationinfo&titles=AvoinGLAM/Past%20activities&format=json" \
-H "User-Agent: MyTool/1.0"
curl -s "https://meta.wikimedia.org/w/api.php?action=query&prop=langlinks&titles=AvoinGLAM/Past%20activities&format=json" \
-H "User-Agent: MyTool/1.0"
Reference Links
Tooling
This skill includes helper scripts, reference docs, and template code for working with translated pages.
🔧 Translation Status Checker (scripts/translation-status.sh)
Check the translation status of a translatable page — available languages, completion percentages, and fuzzy (outdated) units:
./scripts/translation-status.sh "AvoinGLAM/Past activities" --wiki meta
./scripts/translation-status.sh "AvoinGLAM" --languages
./scripts/translation-status.sh "Project/Page" --incomplete
🔧 Extract Translatable Strings (scripts/extract-translatable-strings.sh)
Extract all <translate> sections and their translation unit IDs from a page or template:
./scripts/extract-translatable-strings.sh "AvoinGLAM/Main navigation" --wiki meta
./scripts/extract-translatable-strings.sh "Template:Project/Navigation" --ids
./scripts/extract-translatable-strings.sh "Template:Project/Banner" --tvars
📚 Translate Parser Functions Reference (references/translate-parser-functions.md)
Complete reference for Translate extension parser functions:
#timef — locale-aware date formatting (all format options, examples across 10+ languages)
#dateformat — alternative date formatting
#language — language name in any language
#direction — text direction (ltr/rtl)
{{TRANSLATABLEPAGE}} — magic word for translatable page context
{{TRANSLATIONLANGUAGE}} — the language of the current translation
📚 Page Translation Workflow Guide (references/page-translation-workflow.md)
Step-by-step guide for the complete translation workflow:
- Writing content for translation (author)
- Marking a page for translation (admin)
- Translating units (translator)
- Reviewing translations (reviewer)
- Handling source updates (fuzzy matching)
- Managing translation memory
🐍 Translation Checker (assets/translation_checker.py)
Comprehensive translation analysis for a page — lists available languages, completion stats, fuzzy units, and identifies common issues:
python3 assets/translation_checker.py "AvoinGLAM/Past activities" --wiki meta
python3 assets/translation_checker.py "Project/Page" --fuzzy
python3 assets/translation_checker.py "Project/Page" --json
🐍 Template Translation Scanner (assets/template_translation_scanner.py)
Scan templates for translation compliance — checks that labels use <translate>, links use Special:MyLanguage/, and dates use #timef:
python3 assets/template_translation_scanner.py "Template:AvoinGLAM/Main navigation" --wiki meta
python3 assets/template_translation_scanner.py --project "AvoinGLAM" --wiki meta
python3 assets/template_translation_scanner.py "Template:Project/Box" --report
🧪 Test Suite (tests/)
Test scripts for verifying translation-related tooling:
python3 -m pytest tests/
python3 -m pytest tests/test_timef.py
python3 -m pytest tests/test_mylanguage.py
python3 -m pytest tests/test_extraction.py