Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
UnicodePlural.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Extension\Translate\Utilities;
8
9use RuntimeException;
11
14 private const PRE = '{{PLURAL|';
15 private const POST = '}}';
16
23 public static function getPluralKeywords( $code ) {
24 $filePath = __DIR__ . '/../../data/plural-cldr.json';
25 $ruleData = json_decode( file_get_contents( $filePath ), true );
26
27 $ruleSet = $ruleData[ 'supplemental' ][ 'plurals-type-cardinal' ][ $code ] ?? null;
28 if ( $ruleSet === null ) {
29 return null;
30 }
31
32 $keywords = [];
33 foreach ( array_keys( $ruleSet ) as $name ) {
34 $keywords[] = str_replace( 'pluralRule-count-', '', $name );
35 }
36
37 return $keywords;
38 }
39
46 public static function hasPlural( $text ) {
47 return strpos( $text, self::PRE ) !== false;
48 }
49
57 public static function flattenMap( array $forms ) {
58 $list = [];
59 foreach ( $forms as $keyword => $value ) {
60 $list[] = [ $keyword, $value ];
61 }
62
63 return self::flattenList( $list );
64 }
65
73 public static function flattenList( array $formList ) {
74 $formatted = [];
75 foreach ( $formList as list( $keyword, $value ) ) {
76 $formatted[] = self::formatForm( $keyword, $value );
77 }
78
79 return self::PRE . implode( '|', $formatted ) . self::POST;
80 }
81
82 private static function formatForm( $keyword, $value ) {
83 $prefix = $keyword === 'other' ? '' : "$keyword=";
84 return $prefix . $value;
85 }
86
98 public static function unflatten( $text, $expectedKeywords ) {
99 list( $template, $instanceMap ) = self::parsePluralForms( $text );
100 return self::expandTemplate( $template, $instanceMap, $expectedKeywords );
101 }
102
109 public static function parsePluralForms( $text ) {
110 $m = [];
111 $pre = preg_quote( self::PRE, '/' );
112 $post = preg_quote( self::POST, '/' );
113
114 $ok = preg_match_all( "/$pre(.*)$post/Us", $text, $m );
115 if ( $ok === false ) {
116 throw new RuntimeException( "Plural regular expression failed for text: $text" );
117 }
118
119 $template = $text;
120 $instanceMap = [];
121
122 foreach ( $m[0] as $instanceIndex => $instanceText ) {
123 $ph = TranslateUtils::getPlaceholder();
124
125 // Using preg_replace instead of str_replace because of the limit parameter
126 $pattern = '/' . preg_quote( $instanceText, '/' ) . '/';
127 $template = preg_replace( $pattern, $ph, $template, 1 );
128
129 $instanceForms = [];
130 foreach ( explode( '|', $m[ 1 ][ $instanceIndex ] ) as $form ) {
131 $m2 = [];
132 $ok = preg_match( "~\s*([a-z]+)\s*=(.+)~s", $form, $m2 );
133 $keyword = $ok ? $m2[ 1 ] : 'other';
134 $value = $ok ? trim( $m2[ 2 ] ) : $form;
135 $instanceForms[] = [ $keyword, $value ];
136 }
137
138 $instanceMap[$ph] = $instanceForms;
139 }
140
141 return [ $template, $instanceMap ];
142 }
143
152 public static function expandTemplate( $template, array $instanceMap, $expectedKeywords ) {
153 $formArray = [];
154
155 // Convert from list of forms to map of forms for easier processing
156 foreach ( $instanceMap as $ph => $list ) {
157 $instanceMap[ $ph ] = self::convertFormListToFormMap( $list, $expectedKeywords );
158 }
159
160 foreach ( $expectedKeywords as $keyword ) {
161 // Start with the whole string
162 $form = $template;
163
164 // Loop over each plural markup instance and replace it with the plural form belonging
165 // to the current index
166 foreach ( $instanceMap as $ph => $instanceFormMap ) {
167 // For missing forms, fall back to empty text.
168 $replacement = $instanceFormMap[ $keyword ] ?? '';
169 $form = str_replace( $ph, $replacement, $form );
170 }
171
172 $formArray[ $keyword ] = $form;
173 }
174
175 return $formArray;
176 }
177
178 public static function convertFormListToFormMap( array $formList, array $expectedKeywords ) {
179 $formMap = [];
180 foreach ( $formList as list( $keyword, $value ) ) {
181 $formMap[ $keyword ] = $value;
182 }
183
184 $sortedFormMap = [];
185 foreach ( $expectedKeywords as $keyword ) {
186 $sortedFormMap[ $keyword ] = $formMap[ $keyword ] ?? null;
187 }
188
189 return $sortedFormMap;
190 }
191}
static parsePluralForms( $text)
Parses plural markup into a structure form.
static expandTemplate( $template, array $instanceMap, $expectedKeywords)
Gives fully expanded forms given a template and parsed plural markup instances.
static unflatten( $text, $expectedKeywords)
Format translation with plural forms as array of forms.
static flattenList(array $formList)
Format plural forms list as single string.
static getPluralKeywords( $code)
Returns CLDR plural rule for given language.
static hasPlural( $text)
Quick way to check if the text contains plural syntax.
static flattenMap(array $forms)
Format plural forms map as single string suitable for translation.
Essentially random collection of helper functions, similar to GlobalFunctions.php.