Joomla's core client-side form validation reads a field's data-validation-text HTML attribute and uses its value verbatim as the "invalid" message:
media/system/js/fields/validate.es6.js, markInvalid():
const message = element.getAttribute('data-validation-text');
It only falls back to a translated string, Joomla.Text._('JLIB_FORM_FIELD_INVALID_VALUE'), when the attribute is absent entirely.
data-validation-text can be set per field directly from form XML, because
FormField::setup() copies every data-* XML attribute into $dataAttributes verbatim:
foreach ($this->element->attributes() as $key => $value) {
if (str_starts_with($key, 'data-')) {
$this->dataAttributes[$key] = $value;
}
}
At no point in this chain (XML attribute → FormField::$dataAttributes → field layout → HTML attribute → validate.es6.js) does the value pass through Text::() / Joomla.Text.(). So an extension or template developer who — reasonably, given how label, description and hint behave elsewhere in form XML — sets data-validation-text="MYEXT_FIELD_INVALID_MESSAGE" will see the raw, untranslated language constant shown to end users as the validation error, in every language.
data-validation-text="SOME_LANG_KEY" to any form field in a component's XML (e.g. a calendar or text field), where SOME_LANG_KEY is a defined language string in the extension's language file.pattern mismatch or a required violation).SOME_LANG_KEY, not the translated text.Either:
data-validation-text must contain literal, pre-resolved text (not a language key), so developers don't assume it behaves like label/description/hint; ordata-validation-text (and similarly end-user-facing data-* attributes) throughText::_() when building dataAttributes, consistent with how label/description/hint are already translated in form XML.Verified against the current source on both active branches:
Same element.getAttribute('data-validation-text') / no Text._() call in both.
5.4
No response
No response
No response
No response
| Labels |
Added:
No Code Attached Yet
bug
|
||
sounds like a good idea to me
| Status | New | ⇒ | Closed |
| Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2026-09-08 11:31:53 |
| Closed_By | ⇒ | hans2103 |
Update — root cause narrowed down further
After tracing this deeper against the actual Joomla 6.1.3 source (not just the JS layer):
FormField::getLayoutData()already exposes$validationtextto every field layout (it's inlibraries/src/Form/FormField.php, populated from the XMLvalidationtextattribute). Butacross all 36 files in
layouts/joomla/form/field/, onlytext.phpactually turns$validationtextinto thedata-validation-textattribute thatvalidate.es6.jsreads:checkbox.phpdocuments$validationtextin its docblock but never uses it. Every other fieldtype — including several that already build their own
patternattribute for HTML5 validation(
tel.php,date.php,datetime.php,email.php,url.php,number.php, ...) — has noreference to it at all. So
calendaris not a special case; it's one of ~34 field types missinga feature that exists, half-finished, in exactly one layout.
Proposed fix
Rather than duplicating that one line across every layout (and finishing the half-done
checkbox.phpreference), move it intoFormField::renderDataAttributes(), which alreadybuilds
$dataAttributeand is echoed by essentially every field layout:This makes
validationtextwork for every field type in one place, with consistent escaping(current
text.phpescapes via$this->escape();ArrayHelper::toString(), used by severalother layouts such as
calendar.php, does not escape at all — centralizing this avoids thatinconsistency too).
text.php's own line becomes redundant and can be removed, which alsoresolves the
@TODO add a proper string here!!!left on it.Happy to turn this into a PR if that's useful.