Help:Extension:Translate/Validators
Translators (main help page )
- How to translate
- Best practices
- Statistics and reporting
- Quality assurance
- Message group states
- Offline translation
- Glossary
Translation administrators
- How to prepare a page for translation
- Page translation administration
- Unstructured element translation
- Group management
- Move translatable page
- Import translations via CSV
- Working with message bundles
Sysadmins and developers
Translatable strings often contain markup that should be retained as-is in the translation. Typing that markup can be slow and difficult because special characters are common. Translate extension can provide translators a button clicking on which inserts the piece of markup into the translation to the current cursor position. In addition, if a translation is missing that specific markup, the Translate extension can either warn the translator or simply reject the translation, since such markup is usually mandatory to display the messages properly to the end user.
For example in the string,
Adapted by %{name} from a work by %{original}
there are two insertables - %{name}
and %{original}
.
If the translator does not add them to their translation, the end user using the software will not see a proper message.
The MessageValidator
framework has been added with the intent of helping with validating translations.
Validators run on the translated message and based on the configuration, a warning or error message is shown to the translator.
Translations with warnings can still be saved, but ones that have error cannot.
Only a user with translate-manage
permission can save translations that have errors.
When configuring a validator, a regex is defined to identify markup that is mandatory. The validator can also be marked as insertable, in which case a button will be displayed to the translator to add that markup into the translation.
Adding a custom validators is still possible and will be needed for more specialized validations.
Configuration
[edit]Following is a summarized validator configuration,
VALIDATORS:
# Example 1
- id: InsertableRegex
enforce: true
insertable: true
params: /\$[a-z0-9]+/
keymatch:
- 'untranslated' # Matches key untranslated directly
-
type: 'wildcard'
pattern: '*translated*' # Matches any key that has the translated in it
# Example 2
- id: InsertableRegex
insertable: true
params:
regex: /(?<pre>\[)[^]]+(?<post>\]\([^)]+\))/
display: $pre $post
pre: $pre
post: $post
# Example 3
- class: MathJaxMessageValidator
enforce: true
# Example 4
- id: BraceBalance
In the example above,
InsertableRegex
is a bundled validator that can accept a custom regex and run validations.MathJaxMessageValidator
is a custom validator class.BraceBalance
is another bundled validator.
VALIDATORS
uses an array format.
Lets look at the various parameters being used here in each array item,
Parameters
[edit]Property | Type | Description |
---|---|---|
id | string | Incase a bundled / pre-provided validator is being used, the ID of the validator. Required if class is not specified.
|
class | string | If a custom validator is being used, then use this option instead of id . Specifies the name of the validator class. See example #3 in the above config. The AUTOLOAD option can be used to load the class. Required if id is not specified.
|
enforce | boolean | Whether the validator should be enforced. If set to true, and a translation fails validation, an error will be displayed which must be fixed in order to save the translation. |
insertable | boolean | Whether the validator should also be an insertable. |
keymatch | array | With this option it is possible to limit certain validations to certain messages. Keymatch is an array with each option being either a string or a prototype. If it is a string, a direct comparison with the message key is done. See example #1 in the above config. |
keymatch[i].type | string | Type is either regex or wildcard. This is the approach that will be used to check if the message key matches a given pattern. |
keymatch[i].pattern | string | Pattern is a string that will be used for matching. |
params | string / associative array | If params is specified as a string, it is used as the regex. See example #1
In this case if insertable is true,
If params is specified as an associative array (see example #2), see below for further details. |
params.regex | string | The regex to be used for validator. Must use named captures. When specifying named captures, do not use the $ symbol in the name.
In example #2, two named captures are used - |
params.display | string | Mandatory value. The display value for the insertable. Named captures prefixed with $ are used here. See example #2. |
params.pre | string | The pre value for the insertable. Value inserted before the cursor position. Named captures prefixed with $ are used here. If not specified, is set to the display value. See example #2. |
params.post | string | The post value for the insertable. Value inserted after the cursor position. Named captures prefixed with $ are used here. See example #2. If not specified, defaults to an empty string. |
Pre-provided / Bundled validators
[edit]Following is a list of bundled validators,
BraceBalance
[edit]ID: BraceBalance
Ensures that the number of open braces / brackets, matches the number of closed braces / brackets in the translation.
For example, the following translations would pass,
{{ }}
[ ]
whereas, the following would fail,
[ ]]
{{ }
This validator cannot be marked as insertable.
EscapeCharacter
[edit]ID: EscapeCharacter
The validator ensures that only the specified escape character are present in a translation.
The allowed escape characters can be specified when adding the validator, and can only include,
\t
\n
\'
\"
\f
\r
\a
\b
\\
This validator is not insertable.
GettextNewline
[edit]ID: GettextNewline
This works specifically for GetText based message groups.
Ensures that the translation has the same number of newlines as the source message at the beginning and end of the string.
GettextPlural
[edit]ID: GettextPlural
This works specifically on GetText based message groups.
Ensures that if the source / definition contains a plural in the format - foo {{PLURAL:GETTEXT|one|many}} bar
, the translation must contain it as well.
Based on the language this also checks if the translation has the correct number of plural forms.
For example, English has two, but Hebrew has four.
InsertableRegex
[edit]ID: InsertableRegex
A generic reusable validator that can be used to specify custom validations and insertables.
For example, take the following configuration where the validator is marked as insertable and enforced,
- id: InsertableRegex
enforce: true
insertable: true
params: "/\$[a-zA-Z0-9]+/"
Given the following source message - Hello $name. My name is $myName. that is being translated, the translation must have the parameters - $name and $myName. They will also be displayed as insertables to make it easier for translators to use them in the translation. An absence of these parameters will cause an error to be displayed to the translator.
InsertableRubyVariable
[edit]ID: InsertableRubyVariable
This is a validator that matches ruby variables in the translations.
Internally it extends InsertableRegexValidator
and uses the following regex - %{[a-zA-Z_]+}
.
This validator is insertable.
Example:
%{abc}
IosVariable
[edit]ID: IosVariable
An insertable variable validator for Ios. Regex is used from this Rubustrings source. This validator is insertable.
Example:
%@
MatchSet
[edit]ID: MatchSet
Ensures that the translation is present in the list of values.
Also takes a parameter - caseSensitive
that can be either true (default) or false.
For example the following configuration, the validator will validate the message with key - html.dir
and ensure that the values for it can either be ltr or rtl.
Note that LTR or RTL will not be valid values, since caseSensitive
is true by default.
- id: MatchSet
enforce: true
keymatch:
- html.dir
params:
values:
- ltr
- rtl
MediaWikiLink
[edit]ID: MediaWikiLink
Checks if the translation uses links that are discouraged.
Valid links are those that link to Special: pages, {{ns:special}}:
or project pages trough MediaWiki messages like {{MediaWiki:helppage-url}}:
.
Also links in the definition are allowed.
MediaWikiPageName
[edit]ID: MediaWikiPageName
Ensures that if the source / definition contains a namespace such as {{ns:project}}:hello
the translations made do not try to translate the namespaces itself.
MediaWikiParameter
[edit]ID: MediaWikiParameter
This is a validator that matches wiki parameters in the translations.
Internally it extends InsertableRegexValidator
and uses the following regex - /\$[1-9]/
.
This validator is insertable.
Example:
$1
, $2
.
MediaWikiPlural
[edit]ID: MediaWikiPlural
Ensures that if the source / definition contains a {{PLURAL:$1|message|messages}}
, the translation should also have it.
It can also be used as an insertable.
Based on the language this also checks if the translation has the correct number of plural forms.
For example, English has two, but Hebrew has three.
MediaWikiTimeList
[edit]ID: MediaWikiTimeList
Provides validations for expiry options and IP block options specified in the MediaWiki core. These are usually in the format,
indefinite:indefinite,3 hours:3 hours,12 hours:12 hours,24 hours:24 hours,31 hours:31 hours,36 hours:36 hours,48 hours:48 hours,60 hours:60 hours,72 hours:72 hours,1 week:1 week,2 weeks:2 weeks,1 month:1 month,3 months:3 months,6 months:6 months,1 year:1 year,2 years:2 years,3 years:3 years,infinite:indefinite
The validations ensure that the translations have the exact same number of key-value pairs. These validations are run only on messages with keys,
- protect-expiry-options
- ipboptions
Newline
[edit]ID: Newline
Ensures that the translation has the same number of newlines as the source / definition message at the beginning of the string. This validator is not insertable.
NotEmpty
[edit]ID: NotEmpty
Ensures that the translation has some content, and that content is not just whitespace. This validator is not insertable.
NumericalParameter
[edit]ID: NumericalParameter
This validator matches numerical parameters by using the following regex: /\$\d+/
.
This validator is insertable.
Example:
$33
, $1
etc.
Printf
[edit]ID: Printf
This validator checks for missing and unknown printf formatting characters in translations. This validator is insertable.
Example:
%2$f
, %d
etc.
PythonInterpolation
[edit]ID: PythonInterpolation
This validator matches python string interpolation variables by using the following regex: /\%(?:\([a-zA-Z0-9]*?\))?[diouxXeEfFgGcrs]/U
.
This validator is insertable.
Example:
%s
, %(name)s
Replacement
[edit]ID: Replacement
Checks if a translation is using the search
string, and instead suggests the translator to use the string mentioned under replacement
.
This validator is not insertable.
- id: Replacement
enforce: true
params:
search: '{{PLURAL:'
replace: '{PLURAL:'
SmartFormatPlural
[edit]ID: SmartFormatPlural
This works specifically on SmartFormat based message groups.
Ensures that if the source / definition contains a plural in the format - {1:test|tests}{0:message|messages}
, the translation must contain it as well.
Based on the language this also checks if the translation has the correct number of plural forms.
For example, English has two, but Hebrew has four.
UnicodePlural
[edit]ID: UnicodePlural
Ensures that if the source / definition contains a plural in the format - foo {{PLURAL|one=one|many}} bar
, the translation must contain it as well.
Based on the language this also checks if the translation has the correct number of plural forms.
For example, English has two, but Hebrew has three.
User interface
[edit]The user interface has been updated to differentiate between errors and warnings.
During translation, if an error is noticed with the translation, the Save translation button is disabled unless the user who is translating has translate-manage
permission.
Additionally validation is also done on the server when the user is saving the translation.
This will still allow users who have the translate-manage
permission to save the translation even if it has errors.
Custom validators
[edit]Certain complicated validations might still require a custom validator to be written.
Custom validators must implement the MediaWiki\Extensions\Translate\Validation\MessageValidator
interface [1].
Below is an example of a custom validator,
<?php
// Filename: Validator.php
use MediaWiki\Extensions\Translate\Validation\MessageValidator;
use MediaWiki\Extensions\Translate\Validation\ValidationIssue;
use MediaWiki\Extensions\Translate\Validation\ValidationIssues;
/**
* My Custom Validator
*/
class MyCustomValidator implements MessageValidator {
public function getIssues( TMessage $message, string $targetLanguage ): ValidationIssues {
$issues = new ValidationIssues();
// Validation code goes here. Push ValidationIssue into the ValidationIssues. E.g.:
$issue = new ValidationIssue(
'value-not-present', // type
'invalid', // sub-type
'translate-checks-value-not-present', // message key
[ // message params
[ 'PLAIN-PARAMS', $this->possibleValues ],
[ 'COUNT', count( $this->possibleValues ) ]
]
);
$issues->add( $issue );
return $issues;
}
}
Also see the following classes,
ValidationIssues
- https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/extensions/Translate/+/master/src/Validation/ValidationIssues.phpValidationIssue
- https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/extensions/Translate/+/master/src/Validation/ValidationIssue.php
The add the custom validator in the configuration file,
VALIDATORS:
- class: MyCustomValidator
enforce: true
AUTOLOAD:
MyCustomValidator: Validator.php