Skip to content

Customizing Language Resources

In a nutshell

Every skill ships small text files that say what phrases to listen for and what to say back. This page shows how to swap in your own versions of those files, to reword a reply, fix wording for your accent or dialect, or add a language a skill doesn't include, all without editing the skill's actual code. You drop your edited copy into a personal folder, and OVOS loads yours instead, falling back to the skill's original for anything you didn't change. See Language Support for the bigger picture, or the Glossary for terms.

OpenVoiceOS lets you override or extend a skill's locale resources, the plain-text files that tell the assistant what to listen for and what to say, without touching the skill's source code. This is how you localize responses, fix intent matching for your accent, reword a reply, or add a language a skill doesn't ship.

New here? A skill ships small text files grouped by language. You can drop your own copy of any one of those files into a user folder, and OVOS loads yours instead of the skill's. You only override the files you care about. Everything else falls back to the skill.

πŸ“ Formal specification

Locale resource layout and file formats are defined by OVOS-INTENT-2: Locale Resource Formats (companion to OVOS-INTENT-1, the sentence-template grammar). See the spec index. This page describes how OVOS implements that spec. The spec is the normative reference.


Resource Roles

Per OVOS-INTENT-2, every resource is identified by a (role, base name) pair, where the role is the file extension. There are five roles:

Role Extension Slots? Purpose
Intent .intent yes (slot-bearing) Templates matched against the user's speech (ASR input). Slots are filled by the engine at match time.
Dialog .dialog yes (slot-bearing) Phrases the assistant speaks back (TTS output). Slots are filled by the skill before speaking.
Entity .entity no (slot-free) Example values that can fill a named slot.
Vocabulary .voc no (slot-free) A named set of localized phrasings.
Blacklist .blacklist no (slot-free) Words that suppress an intent.

Two files may share a base name only if their roles differ (confirm.intent and confirm.dialog are distinct resources). Two files with the same extension must not share a base name anywhere in one language's directory tree.


Locale Folder Layout

All localized resources live under a single locale/ directory, with one subdirectory per language, named with a BCP-47 tag. This is case-insensitive: en-US and en-us are the same:

my-skill/
└── locale/
    β”œβ”€β”€ en-US/
    β”‚   β”œβ”€β”€ turn_on.intent
    β”‚   β”œβ”€β”€ confirm.dialog
    β”‚   β”œβ”€β”€ device.entity
    β”‚   β”œβ”€β”€ thing.voc
    β”‚   └── dialogs/            # subdirectories are allowed…
    β”‚       └── greeting.dialog # …and searched recursively
    └── pt-BR/
        └── …

A language directory may contain subdirectories. A loader resolves a resource by searching the language directory and all its subdirectories recursively. Subdirectory names are an authoring convenience and carry no meaning to the loader.

Legacy layouts

Older skills used vocab/<lang>/ and dialog/<lang>/ directories instead of locale/<lang>/. OVOS still searches these for backwards compatibility, but new skills and overrides should use locale/.


Resolution Precedence

The same resource, the same (role, base name) pair, may exist in three places. OVOS resolves it in this order (first match wins):

  1. User overrides: <xdg_data>/resources/<skill_id>/locale/<lang>/
  2. Skill resources: the skill's own bundled locale/<lang>/
  3. Core resources: fallback files shipped by the framework (e.g. ovos-workshop)

Overrides apply at whole-file granularity: an override file replaces the corresponding lower-precedence file entirely. You do not merge line-by-line, and you do not need to copy files you aren't changing.

.dialog files are honored by the user-override tier since ovos-workshop 9.5.3a1, the same as .intent, .voc, .entity, .rx (regex), and the other resource roles. The override only takes effect if the user directory already exists when the skill loads.

Where the user override folder lives

The user override base is <xdg_data>/resources/<skill_id>/, where <xdg_data> is the XDG data path, by default ~/.local/share/mycroft. A typical override file path is:

~/.local/share/mycroft/resources/<skill_id>/locale/<lang>/<file>

How to Override

  1. Find the skill ID, e.g. ovos-skill-weather.openvoiceos.
  2. Create the folders: ~/.local/share/mycroft/resources/<skill_id>/locale/<lang>/.
  3. Copy and edit: copy the .dialog, .intent, .voc, .entity, or .blacklist file you want to change from the skill's source into that folder and edit it.
  4. Restart ovos-core to pick up the change.

Partial overrides

Only place the specific files you want to change. The loader falls back to the skill (and then core) resources for everything you didn't override.

Language fallback

If the requested language has no directory, the loader prefers an exact match but may fall back to the nearest available language. OVOS resolves this through ovos-spec-tools' language-matching helpers (lang_matches/lang_distance, built on langcodes) and treats a distance of 10 or less as a usable regional match (the bound is inclusive β€” 10 is exactly the distance of a language against its macrolanguage tag), e.g. en-au resolving to en-us. Per the spec this fallback is an implementation choice, not a guarantee. Ship the exact language directory you need.


File Format Basics

All five roles are line-oriented UTF-8 text (OVOS-INTENT-2 Β§3):

  • one template per line;
  • blank lines and lines beginning with # (comments) are skipped;
  • both LF and CRLF line endings are accepted.

Slot-bearing files (.intent, .dialog) use the OVOS-INTENT-1 sentence-template grammar: expansion (a|b), optional [x], and named slots {name}. Slot-free files (.entity, .voc, .blacklist) use expansion only, with no {slots}.

# turn_on.intent  (slot-bearing)
turn on (the|) {device}
(switch|power) on {device}

Two slots must never sit next to each other with nothing between them: {r} {g} {b} raises MalformedTemplate at registration because there is no way to tell where one slot's match ends and the next begins. Put a literal word between them instead, for example {r} and {g} and {b}.

# thing.voc  (slot-free)
light
lamp

System-wide Resource Overrides

Some core, non-skill resources (sounds, common error/boot dialogs) are resolved by the framework outside the per-skill scheme above. Custom .wav sounds and core .dialog files placed in the framework's resource locations let you change the assistant's "personality". These paths are framework-defined. Only the locale/<lang>/ layout beneath a resource root is normative.


Customizing Number, Date, and Language-Name Parsers

The technical parsers for numbers, dates, and spoken language names are separate libraries, not skill resources:

  • Language names: ovos-lang-parser maps BCP-47 codes to spoken names.
  • Numbers: ovos-number-parser (e.g. if "22nd" doesn't parse in your language).
  • Dates: ovos-date-parser.

These are rule-driven per language. Contribute fixes upstream to the respective repository so every install benefits. Local edits to an installed package do not persist across upgrades. Each language gets its own module, named numbers_<code>.py in ovos-number-parser (for example numbers_pt.py) and dates_<code>.py in ovos-date-parser (for example dates_pt.py); adding one is how you give a new language cardinal/ordinal pronunciation, number extraction, or date/time parsing instead of falling back to the generic implementation. See Adding a New Language for the full path from a missing language to a released one.


Read next: Bidirectional Translation Related: Language Selection Β· Resource Files Β· Language Support Overview (incl. switching an install's language)