summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'MLEB/Translate/src/MessageValidator/Validators/EscapeCharacterValidator.php')
-rw-r--r--MLEB/Translate/src/MessageValidator/Validators/EscapeCharacterValidator.php89
1 files changed, 89 insertions, 0 deletions
diff --git a/MLEB/Translate/src/MessageValidator/Validators/EscapeCharacterValidator.php b/MLEB/Translate/src/MessageValidator/Validators/EscapeCharacterValidator.php
new file mode 100644
index 00000000..05d79827
--- /dev/null
+++ b/MLEB/Translate/src/MessageValidator/Validators/EscapeCharacterValidator.php
@@ -0,0 +1,89 @@
+<?php
+declare( strict_types = 1 );
+
+namespace MediaWiki\Extensions\Translate\MessageValidator\Validators;
+
+use MediaWiki\Extensions\Translate\Validation\MessageValidator;
+use MediaWiki\Extensions\Translate\Validation\ValidationIssue;
+use MediaWiki\Extensions\Translate\Validation\ValidationIssues;
+use TMessage;
+
+/**
+ * Ensures that only the specified escape characters are present.
+ * @license GPL-2.0-or-later
+ * @since 2020.01
+ */
+class EscapeCharacterValidator implements MessageValidator {
+ /** @var string[] */
+ protected $allowedCharacters;
+
+ /** @var string */
+ protected $regex;
+
+ /** List of valid escape characters recognized. */
+ private const VALID_CHARS = [ '\t', '\n', '\\\'', '\"', '\f', '\r', '\a', '\b', '\\\\' ];
+
+ public function __construct( array $params ) {
+ $this->allowedCharacters = $params['values'] ?? [];
+
+ if ( $this->allowedCharacters === [] || !is_array( $this->allowedCharacters ) ) {
+ throw new \InvalidArgumentException(
+ 'No values provided for EscapeCharacter validator.'
+ );
+ }
+
+ $this->regex = $this->buildRegex( $this->allowedCharacters );
+ }
+
+ public function getIssues( TMessage $message, string $targetLanguage ): ValidationIssues {
+ $issues = new ValidationIssues();
+ $translation = $message->translation();
+ preg_match_all( "/$this->regex/U", $translation, $transVars );
+
+ // Check for missing variables in the translation
+ $params = $transVars[0];
+ if ( count( $params ) ) {
+ $messageParams = [
+ [ 'PARAMS', $params ],
+ [ 'COUNT', count( $params ) ],
+ [ 'PARAMS', $this->allowedCharacters ],
+ [ 'COUNT', count( $this->allowedCharacters ) ]
+ ];
+
+ $issue =
+ new ValidationIssue(
+ 'escape', 'invalid', 'translate-checks-escape', $messageParams
+ );
+ $issues->add( $issue );
+ }
+
+ return $issues;
+ }
+
+ private function buildRegex( array $allowedCharacters ): string {
+ $regex = '\\\\[^';
+ $prefix = '';
+ foreach ( $allowedCharacters as $character ) {
+ if ( !in_array( $character, self::VALID_CHARS ) ) {
+ throw new \InvalidArgumentException(
+ "Invalid escape character encountered: $character during configuration." .
+ 'Valid escape characters include: ' . implode( ', ', self::VALID_CHARS )
+ );
+ }
+
+ if ( $character !== '\\' ) {
+ $character = stripslashes( $character );
+ // negative look ahead, to avoid "\\ " being treated as an accidental escape
+ $prefix = '(?<!\\\\)';
+ }
+
+ // This is done because in the regex we need slashes for some characters such as
+ // \", \', but not for others such as \n, \t etc
+ $normalizedChar = addslashes( $character );
+ $regex .= $normalizedChar;
+ }
+ $regex .= ']';
+
+ return $prefix . $regex;
+ }
+}