26 public function __construct() {
27 parent::__construct();
28 $this->addDescription(
'Script for comparing different plural implementations.' );
31 public function execute() {
32 $mwLanguages = $this->loadMediaWiki();
33 $gtLanguages = $this->loadGettext();
34 $clLanguages = $this->loadCLDR();
36 $all = MediaWikiServices::getInstance()
37 ->getLanguageNameUtils()
38 ->getLanguageNames(
null, LanguageNameUtils::ALL );
39 $allkeys = array_keys( $all + $mwLanguages + $gtLanguages + $clLanguages );
42 $this->output( sprintf(
"%12s %3s %3s %4s\n",
'Code',
'MW',
'Get',
'CLDR' ) );
43 foreach ( $allkeys as $code ) {
44 $mw = isset( $mwLanguages[$code] ) ?
'+' :
'';
45 $gt = isset( $gtLanguages[$code] ) ?
'+' :
'';
46 $cl = isset( $clLanguages[$code] ) ?
'+' :
'';
49 $fallbacks = Language::getFallbacksFor( $code );
50 foreach ( $fallbacks as $fcode ) {
51 if ( $fcode !==
'en' && isset( $mwLanguages[$fcode] ) ) {
58 if ( substr_count( sprintf(
'%s%s%s', $mw, $gt, $cl ),
'+' ) > 1 ) {
59 $error = $this->tryMatch( $code, $mw, $gtLanguages, $clLanguages );
62 $this->output( sprintf(
"%12s %-3s %-3s %-4s %s\n", $code, $mw, $gt, $cl, $error ) );
66 protected function tryMatch( $code, $mws, $gtLanguages, $clLanguages ) {
69 $lang = Language::factory( $code );
74 if ( isset( $gtLanguages[$code] ) ) {
75 $gtExp =
'return (int) ' . str_replace(
'n',
'$i', $gtLanguages[$code] ) .
';';
80 $cldrExp = $clLanguages[$code] ??
false;
82 for ( $i = 0; $i <= 250; $i++ ) {
83 $mw = $gt = $cl =
'?';
87 $exp = $lang->getCompiledPluralRules();
88 $mw = Evaluator::evaluateCompiled( $i, $exp );
96 $cl = Evaluator::evaluate( $i, $cldrExp );
99 if ( self::comp( $mw, $gt ) && self::comp( $gt, $cl ) && self::comp( $cl, $mw ) ) {
103 return "$i: $mw $gt $cl";
109 public static function comp( $a, $b ) {
110 return $a ===
'?' || $b ===
'?' || $a === $b;
113 protected function loadPluralFile( $fileName ) {
114 $doc =
new DOMDocument;
115 $doc->load( $fileName );
116 $rulesets = $doc->getElementsByTagName(
'pluralRules' );
118 foreach ( $rulesets as $ruleset ) {
119 $codes = $ruleset->getAttribute(
'locales' );
121 $ruleElements = $ruleset->getElementsByTagName(
'pluralRule' );
122 foreach ( $ruleElements as $elt ) {
123 $rules[] = $elt->nodeValue;
125 foreach ( explode(
' ', $codes ) as $code ) {
126 $plurals[$code] = $rules;
133 public function loadCLDR() {
136 return $this->loadPluralFile(
"$IP/languages/data/plurals.xml" );
139 public function loadMediaWiki() {
142 $rules = $this->loadPluralFile(
"$IP/languages/data/plurals.xml" );
143 $rulesMW = $this->loadPluralFile(
"$IP/languages/data/plurals-mediawiki.xml" );
145 return array_merge( $rules, $rulesMW );
148 public function loadGettext() {
149 $gtData = file_get_contents( __DIR__ .
'/../data/plural-gettext.txt' );
151 foreach ( preg_split(
'/\n|\r/', $gtData, -1, PREG_SPLIT_NO_EMPTY ) as $line ) {
152 list( $code, $rule ) = explode(
"\t", $line );
153 $rule = preg_replace(
'/^.*?plural=/',
'', $rule );
154 $gtLanguages[$code] = $rule;