Translations
FS PBX's interface is translated by its community, directly through GitHub. Interface text and email content have separate translation workflows. This page explains how to contribute translations. To change the language used by your system, see Language Settings and Sounds in the Getting Started Guide.
Translating interface text
There's no separate translation website. Interface translations live in the
FS PBX GitHub repository, in
resources/lang/{locale}.json. Each file is a flat list of
"English text": "Translated text" pairs. To contribute:
- Open the file for your language, e.g.
resources/lang/es-es.jsonfor Spanish. Every string the app knows how to translate is already listed there, one"English text": "..."pair per line -- new strings are added to every language file automatically the moment they're added in English, so you never have to go hunting for what's new or add a key yourself. - An empty value (
"") means nobody has translated that string yet -- it currently falls back to showing the English text. Search the file for": ""to jump straight to what's left, and fill in your translation:{
"Save": "Guardar",
"Extensions": "Extensiones"
} - If a source string contains a
:placeholder(e.g.":count items"), keep the same placeholder token in your translation, just move it to wherever it reads naturally in your language -- CI checks that the token survives translation, not its position. - Open a pull request with your changes. A CI check validates the JSON and the placeholder tokens automatically; someone will review and merge it. You don't need to finish a whole language in one PR -- leaving the rest blank is completely normal, and each string you fill in is used as soon as it's merged.
If your language doesn't have a file yet, don't create one by hand -- open
an issue or PR asking for it to be added to config/locales.php, which
generates the file for you (fully populated, ready to fill in) the next
time lang:sync runs.
A note on regional variants: some languages are listed more than once --
for example, Spanish, plus Spanish (Mexico) and Spanish (Latin America). Each
one is a fully independent file with no connection to the others -- so if
you're translating Spanish (Mexico), you're translating every string in
resources/lang/es-mx.json yourself, not just the handful that differ from
es-es.json. That's a deliberate choice: having one variant borrow from
another was more confusing than helpful.
Translating shipped email templates
Email subjects and bodies are maintained separately from the interface JSON catalogs. Each language needs its own complete template. FS PBX selects an existing language version when sending email, fills in its variables, and falls back to English when that version is unavailable. It does not translate the message at send time.
Source format
The shipped sources use Blade files (.blade.php), not Markdown (.md).
Each email purpose has an HTML file and a required plain-text companion under
resources/views/emails/{locale}/. For example, the English password-reset
template consists of:
resources/views/emails/en-us/authentication/reset-password.blade.php
resources/views/emails/en-us/authentication/reset-password-text.blade.php
The HTML file begins with an email-template metadata comment. It owns the
pair's version, language, category, subcategory, subject, description, and HTML
layout. The plain-text companion carries only format: text and layout: none.
Translate the subject, visible HTML text, and plain-text text together. Keep
variable names, links, and Blade conditions intact. Do not add translation
helpers around the email text or put whole email bodies into JSON catalogs.
A subject such as {{ $email_subject }} inserts the subject supplied by the
sending workflow; write a translated subject with the appropriate variables
instead of leaving an English generated subject. Keep this variable when the
subject is intentionally supplied by a user, as in AI Agent follow-up emails.
Adding another shipped language
The shipped folders are en-us, ru, fr, es-419, and pt-br. Folder names
must match a locale code in config/locales.php and the HTML file's language
metadata. Use en-us for English, not en.
- Copy the English HTML and text pair into the corresponding category in the
target locale folder. For example, a German password-reset translation uses
resources/views/emails/de/authentication/reset-password.blade.phpandreset-password-text.blade.php. Preserve the English files. - Set
language: deandversion: 1.0.0in the new HTML file. Keep the same category and subcategory. Translate its subject, description, HTML body, and the companion's plain-text body. The text companion must contain onlyformat: textandlayout: nonemetadata. - For templates with
layout: standard, copyen-us/email_layout.blade.phpto the new locale folder if it does not exist. Translate the visible footer and set the HTMLlangattribute. Extendemails.de.email_layoutfrom the German HTML template. Templates withlayout: noneremain self-contained. - Check both formats with representative data. Preserve variables, links,
attachments, and all conditional branches. Template text is written directly
in Blade; do not add calls to
__()or other runtime translation helpers. - On a development installation, run
php artisan email:templates:seed --dry-runto validate sources and see the import summary. Add-vto see every template and language. Then runphp artisan email:templates:seedto import the files and use Email Templates → Preview to review them without sending email.
Each email purpose can be contributed independently. If a purpose is missing
in the requested language, the sender falls back to en-us. Regional variants
are matched exactly; es-419 does not borrow templates from es-es.
Updating an existing shipped template
When changing a shipped subject, HTML body, plain-text body, or layout, increase
the version in the HTML file's metadata, for example from 1.0.0 to 1.0.1.
Bump it once for the pair; do not add version metadata to the text companion.
Include both formats in the pull request and check that they convey the same message. Review variables and links carefully, especially verification codes and password-reset URLs. Use the editor's Preview to inspect sample output without sending email.
The email:templates:seed command discovers all locale folders and installs or
updates shipped defaults in the database. Normal application updates run this
command automatically. Its normal output is a summary; -v enables per-template
details, and failures are always reported. It requires a newer version when
template content changes and leaves custom templates unchanged. Existing
database templates are used for sending, so changing a source file alone does
not update an installed default. When changing a shared locale layout, bump the
versions of that locale's affected HTML templates as well.
For administrators: switching the language
The administrator instructions are now in Language Settings and Sounds. That guide covers system and account interface languages, menu assignments, separate email templates per language, installing call audio packs, voicemail configuration, and troubleshooting.