Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MediaWikiPluralValidator.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\Validation\Validators;
5
10use MediaWiki\Languages\LanguageFactory;
11use MediaWiki\User\UserFactory;
12use Parser;
13use ParserFactory;
14use ParserOptions;
15use PPFrame;
16
25 private $languageFactory;
27 private $parserFactory;
29 private $userFactory;
30
31 public function __construct(
32 LanguageFactory $languageFactory,
33 ParserFactory $parserFactory,
34 UserFactory $userFactory
35 ) {
36 $this->languageFactory = $languageFactory;
37 $this->parserFactory = $parserFactory;
38 $this->userFactory = $userFactory;
39 }
40
41 public function getIssues( Message $message, string $targetLanguage ): ValidationIssues {
42 $issues = new ValidationIssues();
43 $this->pluralCheck( $message, $issues );
44 $this->pluralFormsCheck( $message, $targetLanguage, $issues );
45
46 return $issues;
47 }
48
49 private function pluralCheck( Message $message, ValidationIssues $issues ): void {
50 $definition = $message->definition();
51 $translation = $message->translation();
52
53 if (
54 stripos( $definition, '{{plural:' ) !== false &&
55 stripos( $translation, '{{plural:' ) === false
56 ) {
57 $issue = new ValidationIssue( 'plural', 'missing', 'translate-checks-plural' );
58 $issues->add( $issue );
59 }
60 }
61
62 protected function pluralFormsCheck(
63 Message $message, string $code, ValidationIssues $issues
64 ): void {
65 $translation = $message->translation();
66 // Are there any plural forms for this language in this message?
67 if ( stripos( $translation, '{{plural:' ) === false ) {
68 return;
69 }
70
71 $plurals = $this->getPluralForms( $translation );
72 $allowed = $this->getPluralFormCount( $code );
73
74 foreach ( $plurals as $forms ) {
75 $forms = self::removeExplicitPluralForms( $forms );
76 $provided = count( $forms );
77
78 if ( $provided > $allowed ) {
79 $issue = new ValidationIssue(
80 'plural',
81 'forms',
82 'translate-checks-plural-forms',
83 [
84 [ 'COUNT', $provided ],
85 [ 'COUNT', $allowed ],
86 ]
87 );
88
89 $issues->add( $issue );
90 }
91
92 // Are the last two forms identical?
93 if ( $provided > 1 && $forms[$provided - 1] === $forms[$provided - 2] ) {
94 $issue = new ValidationIssue( 'plural', 'dupe', 'translate-checks-plural-dupe' );
95 $issues->add( $issue );
96 }
97 }
98 }
99
101 public function getPluralFormCount( string $code ): int {
102 $forms = $this->languageFactory->getLanguage( $code )->getPluralRules();
103
104 // +1 for the 'other' form
105 return count( $forms ) + 1;
106 }
107
114 public function getPluralForms( string $translation ): array {
115 // Stores the forms from plural invocations
116 $plurals = [];
117
118 $cb = static function ( $parser, $frame, $args ) use ( &$plurals ) {
119 $forms = [];
120
121 foreach ( $args as $index => $form ) {
122 // The first arg is the number, we skip it
123 if ( $index !== 0 ) {
124 // Collect the raw text
125 $forms[] = $frame->expand( $form, PPFrame::RECOVER_ORIG );
126 // Expand the text to process embedded plurals
127 $frame->expand( $form );
128 }
129 }
130 $plurals[] = $forms;
131
132 return '';
133 };
134
135 // Setup parser
136 $parser = $this->parserFactory->create();
137 $parser->setFunctionHook( 'plural', $cb, Parser::SFH_NO_HASH | Parser::SFH_OBJECT_ARGS );
138
139 // Setup things needed for preprocess
140 $title = null;
141 $options = ParserOptions::newFromUserAndLang(
142 $this->userFactory->newAnonymous(),
143 $this->languageFactory->getLanguage( 'en' )
144 );
145
146 $parser->preprocess( $translation, $title, $options );
147
148 return $plurals;
149 }
150
152 public static function removeExplicitPluralForms( array $forms ): array {
153 // Handle explicit 0= and 1= forms
154 foreach ( $forms as $index => $form ) {
155 if ( preg_match( '/^[0-9]+=/', $form ) ) {
156 unset( $forms[$index] );
157 }
158 }
159
160 return array_values( $forms );
161 }
162}
Interface for message objects used by MessageCollection.
Definition Message.php:13
add(ValidationIssue $issue)
Add a new validation issue to the collection.
Handles plural validation for MediaWiki inline plural syntax.
getPluralFormCount(string $code)
Returns the number of plural forms MediaWiki supports for a language.
getPluralForms(string $translation)
Ugly home made probably awfully slow looping parser that parses {{PLURAL}} instances from a message a...
static removeExplicitPluralForms(array $forms)
Remove forms that start with an explicit number.