Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
openaec-foundation avatar

Frappe Core Translation

  • 25 installs
  • 159 repo stars
  • Updated July 8, 2026
  • openaec-foundation/frappe_claude_skill_package

Helps with ai & agent building tasks.

About

frappe-core-translation is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.

  • frappe-core-translation
  • AI & Agent Building
  • AI-coding skill

Frappe Core Translation by the numbers

  • 25 all-time installs (skills.sh)
  • +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #9,764 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/frappe_claude_skill_package --skill frappe-core-translation

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs25
repo stars159
Last updatedJuly 8, 2026
Repositoryopenaec-foundation/frappe_claude_skill_package

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

Frappe Translation / i18n

Deterministic patterns for translating Frappe apps across v14, v15, and v16.

---

Quick Reference

TaskPythonJavaScript
Translate string_("Hello")__("Hello")
With substitution_("Hello {0}").format(name)__("Hello {0}", [name])
With context_("Change", context="Coins")__("Change", null, "Coins")
Lazy (module-level)_lt("Pending") [v15+]N/A
Check RTLfrappe.utils.is_rtl()frappe.utils.is_rtl()

---

Decision Tree

Need to translate a string?
├── In Python (.py)?
│   ├── Inside a function/method → _("text {0}").format(val)
│   ├── Module-level constant [v15+] → _lt("text")
│   └── Module-level constant [v14] → define inside function or use lazy
├── In JavaScript (.js)?
│   └── ALWAYS → __("text {0}", [val])
├── In Jinja template (.html)?
│   └── {{ _("text") }}
├── In Vue (.vue)?
│   └── __("text") in <script>, {{ __("text") }} in <template>
└── DocType label/description/option?
    └── Auto-extracted — no _() needed

Where do translations live?
├── v14 → apps/{app}/{app}/translations/{lang}.csv
├── v15+ → apps/{app}/{app}/locale/{lang}/LC_MESSAGES/{app}.po
└── User overrides → Translation DocType (highest priority)

Need to extract untranslated strings?
├── v14 → bench --site {site} get-untranslated {lang} {output}
└── v15+ → bench generate-pot-file --app {app}

---

Translation Priority (Highest First)

PrioritySourceScope
1Translation DocType (user overrides)Per-site
2MO files (locale/{lang}/.../{app}.mo)Per-app [v15+]
3CSV files (translations/{lang}.csv)Per-app
4Parent language (e.g., pt for pt-BR)Fallback

---

Version Differences

Featurev14v15v16
_() / __()YesYesYes
_lt() lazy translationNoYesYes
CSV translationsYesYes (legacy)Yes (legacy)
PO/MO (gettext)NoYesYes
bench generate-pot-fileNoYesYes
Babel JS extractorNoYesYes
Type hints on _()NoNoYes

---

Auto-Extracted Strings (No _() Needed)

These are extracted automatically by the framework:

  • DocType labels and descriptions
  • Select field options (each option line)
  • Workflow states and actions
  • Print Format labels
  • Report column labels
  • Notification subjects (not body)
  • Dashboard chart labels

---

String Extraction Rules

File TypeExtractorWhat It Finds
.pyBabel (AST)_("..."), _lt("...") calls
.jsBabel tokenizer [v15+] / regex [v14]__("...") calls
.htmlRegex{{ _("...") }} in Jinja
.vueSame as JS__("...") in script/template
.jsonDocType parserLabels, descriptions, options

CRITICAL: Extractors work on the AST/tokens. They CANNOT extract dynamically constructed strings. See Anti-Patterns.

---

Anti-Patterns (NEVER Do These)

PatternWhy It BreaksCorrect Form
_(f"Hello {name}")f-string not extractable_("Hello {0}").format(name)
_("Hello " + name)Concatenation fragments_("Hello {0}").format(name)
_("Welcome %s") % nameOld-style not extractable_("Welcome {0}").format(name)
` __(Hello ${name}) `Template literal not extractable__("Hello {0}", [name])
_(" Hello ")Leading/trailing spaces trimmed_("Hello")
_("item" if x else "items")Ternary inside _()_("item") if x else _("items")
_(variable)Variable not extractable_("Known String")
Full anti-pattern catalog with code examples: references/anti-patterns.md

---

CSV Translation File Format

Location: apps/{app}/{app}/translations/{lang}.csv

"source","translation","context"
"Hello","Hallo",""
"Change","Wisselgeld","Coins"
"Change","Wijziging","Amendment"
  • ALWAYS use UTF-8 encoding (no BOM)
  • ALWAYS quote all fields with double quotes
  • Context column is optional but MUST be present (empty string if unused)
  • No hooks registration needed — auto-discovered from translations/ directory

---

PO/MO Files [v15+]

Location: apps/{app}/{app}/locale/{lang}/LC_MESSAGES/{app}.po

# Generate POT template
bench generate-pot-file --app {app}

# Migrate existing CSV to PO
bench migrate-csv-to-po --app {app}

# Compile PO to MO (required for runtime)
bench compile-po-to-mo --app {app}

PO files follow standard GNU gettext format. Use any PO editor (Poedit, Weblate, Transifex).

---

Bench Commands

CommandVersionPurpose
bench --site {site} get-untranslated {lang} {output.csv}AllExport untranslated strings
bench update-translations {lang} {untranslated.csv} {translated.csv}AllImport translations
bench generate-pot-file --app {app}v15+Generate .pot template
bench migrate-csv-to-po --app {app}v15+Convert CSV to PO format
bench compile-po-to-mo --app {app}v15+Compile PO to binary MO

---

RTL Support

Hardcoded RTL languages: ar (Arabic), he (Hebrew), fa (Persian/Farsi), ps (Pashto)

# Python
if frappe.utils.is_rtl():
    # Apply RTL-specific logic
// JavaScript
if (frappe.utils.is_rtl()) {
    // Apply RTL-specific logic
}
  • Frappe auto-applies dir="rtl" to the <html> element
  • ALWAYS use logical CSS properties (margin-inline-start not margin-left) for RTL compatibility
  • Bootstrap RTL stylesheet is auto-loaded when RTL language is active

---

Custom App Translation Workflow

Adding translations to your custom app:

1. Write translatable strings using _() / __() with positional placeholders 2. Extract untranslated strings:

  • v14: bench --site {site} get-untranslated {lang} untranslated.csv
  • v15+: bench generate-pot-file --app {app}

3. Translate the extracted strings (manually or via PO editor) 4. Place translations:

  • CSV: apps/{app}/{app}/translations/{lang}.csv
  • PO: apps/{app}/{app}/locale/{lang}/LC_MESSAGES/{app}.po

5. Compile (v15+ PO only): bench compile-po-to-mo --app {app} 6. Clear cache: bench --site {site} clear-cache

---

Reference Files

FileContents
references/api-reference.mdFull Python _() and JS __() API with all signatures and edge cases
references/csv-and-bench.mdCSV format spec, bench commands, PO/MO workflow, custom app setup
references/anti-patterns.mdComplete anti-pattern catalog with failing and corrected examples

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.