Language Overrides (changing displayed text)
- Version
- 3.x
- Updated
How to change the wording of CBX's interface text — relabel a field, reword a tooltip, retitle a
button — without editing core language files. This is the language_overrides/ mechanism: a single
overrides.ini per language whose entries are loaded last, so they win over the shipped strings.
It is a small mechanism, but it comes with one essential distinction: CBX has two text systems,
and overrides.ini only touches one of them. §1 sorts that out; get it right and the rest is a one-file
edit.
Read com_configbox_customization_overview.md first. All paths are relative to the component root
docroot/components/com_configbox/. Source references are point-in-time (component 3.4.1) — verify
against the code.
1. Which text system are you changing? (read this first)
| If the text is… | It comes from… | Change it via… |
|---|---|---|
Static UI text — field labels, tooltips, buttons, messages, headings (keyed strings like FIELD_LABEL_COMPONENT_SKU) | the INI language files (language/<tag>/frontend.ini / backend.ini), resolved by KText::_() | language_overrides/<tag>/overrides.ini — this guide |
| Admin-authored content — a product's name, a page's description, an option's label, country names | the EAV #__configbox_strings table, edited per-language in the admin (via the translatable property type) | the admin UI (edit the record in that language), not overrides.ini |
overrides.ini overrides static UI strings only. Content strings live in the database and are
translated by editing the record in each active language — there is no file override for them. (This is the
EAV i18n system the project notes refer to; it is separate from the INI files this guide covers.)
Quick test: if the text has an ALL_CAPS key and is the same for every product (a label, a button, an error), it's an INI string →
overrides.ini. If it's specific to one product/option/page and an admin typed it, it's a content string → edit it in the admin.
2. How the override is resolved
KText::getLanguageFiles() (external/kenedo/classes/KText.php:173-207) builds the list of INI files to
load for the active language, in this order:
language/en-GB/frontend.ini ← en-GB is the built-in fallback (loaded first)
language/<tag>/frontend.ini ← the active language
language/en-GB/backend.ini ┐ (admin pages only)
language/<tag>/backend.ini ┘
data/customization/language_overrides/<tag>/overrides.ini ← YOUR overrides (loaded LAST)
Each file is parsed and merged into one map, later files overwriting earlier keys (load(),
:214-234):
foreach ($strings as $key => $string) {
self::$strings[$languageTag][$key] = $string; // last write wins
}
Because overrides.ini is loaded last (:195), any key you set there beats the shipped value — for
both frontend and backend strings of that language. Missing files are skipped silently (:199-203), so you
only ship the overrides.ini for languages you actually customize.
Per language tag. The override file is keyed by the active language tag (
<tag>, e.g.en-US,de-DE). To override the same string in two languages, add anoverrides.iniunder each tag's folder. The active tag is the platform language if it's an active CB language, else the CB default (determineLanguage(),:151-165).
3. Finding the key to override
Keys are looked up upper-cased (_() does strtoupper($key), :261), so override keys are by
convention ALL_CAPS and match case-insensitively. To find the key for a piece of text:
- Grep the shipped INI files for the visible text:
grep -ri "SKU/Code Segment" language/→ gives you the key (e.g.FIELD_LABEL_COMPONENT_SKU). - Or grep templates/code for the
KText::_('SOME_KEY')call that emits it.
Then copy that key into your overrides.ini with your new value.
Two lookup quirks worth knowing (rarely needed, but they explain odd keys):
- Trailing colon —
KText::_('Name:')will match a keyNAMEand re-append the colon (:258-266). So overrideNAME, notNAME:.- Parentheses in keys are encoded to
__POPEN__/__PCLOSE__(:255-256). You'll see these in the shipped files; match them if you override such a key.
4. Writing overrides.ini
Standard PHP INI syntax (parse_ini_file, :221): KEY="value", one per line; quote the value and
keep it on one line. From the shipped en-US/overrides.ini (real example):
; data/customization/language_overrides/en-US/overrides.ini
FIELD_LABEL_COMPONENT_SKU="SKU/Code Segment"
TOOLTIP_COMPONENT_SKU="This code will be included in the configuration code. Enter (none) if you don't want this answer to add to the code."
FIELD_LABEL_QUESTION_HEADING="Heading (generic for both metric and imperial)"
TOOLTIP_QUESTION_HEADING="Tell what should show in the heading above the question"
Each line replaces the shipped string for that key in that language. INI gotchas:
- Always quote values (
KEY="…"). Unquoted values with spaces/special characters break parsing or get truncated. - Escape inner double quotes or use single quotes inside, and avoid raw
"mid-value. - No multi-line values. Keep each string on one line.
- A parse error logs and the whole override file is skipped (
:223-226) — if your overrides "don't apply", check the INI syntax first.
5. Deployment checklist
data/customization/
language_overrides/
<tag>/ ← one folder per language tag you customize (e.g. en-US, de-DE)
overrides.ini ← KEY="new value" lines; loaded LAST, wins over shipped strings
- Confirm it's a UI/INI string, not admin content (§1). Content → edit in the admin instead.
- Find the key by grepping
language/for the current text (§3). - Add
KEY="new value"todata/customization/language_overrides/<tag>/overrides.ini, quoted, one line (§4). - Repeat per language — one
overrides.iniper tag. - Verify manually — reload the screen in that language and confirm the new text (and that you didn't break the INI: a syntax error silently drops all your overrides). CBX has zero automated tests.
6. Conventions & gotchas
overrides.iniis for INI/UI strings only. Admin-authored content lives in#__configbox_stringsand is translated in the admin, not here (§1).- Loaded last → wins. Your keys override shipped frontend and backend strings for that language
(
:195). - Keys are upper-cased on lookup — write ALL_CAPS keys; matching is case-insensitive (§3).
- Per language tag — add an
overrides.iniunder each<tag>/you want to change. - Quote values, single line, valid INI — a parse error drops the whole file silently (§4).
- Find keys by grepping
language/for the visible text, or for theKText::_('KEY')call. - Override
NAME, notNAME:— trailing colons are handled automatically (§3).
See also
com_configbox_customization_overview.md— the extension-point map (this is a merge/append mechanism: your file is combined with the shipped INI files, loaded last).external/kenedo/classes/KText.php—getLanguageFiles()(:173, the load order),load()(:214, last-write-wins),_()(:241, the lookup + quirks).language/<tag>/— the shipped INI files to grep for keys and copy from.external/kenedo/properties/translatable.php— thetranslatableproperty type that stores admin-authored content strings in#__configbox_strings(the other i18n system, not overridable here).