1212 */
1313final class StrictPoLoader extends Loader
1414{
15- /** @var string[] */
16- public $ warnings = [];
17-
1815 /** @var Translations */
1916 private $ translations ;
2017 /** @var Translation */
@@ -31,15 +28,26 @@ final class StrictPoLoader extends Loader
3128 private $ inPreviousComment ;
3229 /** @var bool */
3330 private $ throwOnWarning ;
31+ /** @var string[] */
32+ private $ warnings = [];
3433
3534 /**
3635 * Generates a Translations object from a .po based string
3736 */
38- public function loadString (
37+ public function loadString (string $ string , Translations $ translations = null ): Translations
38+ {
39+ return $ this ->loadStringExtended (...func_get_args ());
40+ }
41+
42+ /**
43+ * Generates a Translations object from a .po based string with extra options
44+ */
45+ public function loadStringExtended (
3946 string $ string ,
4047 Translations $ translations = null ,
4148 bool $ throwOnWarning = false
42- ): Translations {
49+ ): Translations
50+ {
4351 $ this ->data = $ string ;
4452 $ this ->position = 0 ;
4553 $ this ->translations = parent ::loadString ($ string , $ translations );
@@ -49,6 +57,9 @@ public function loadString(
4957 $ this ->warnings = [];
5058 for ($ this ->newEntry (); $ this ->getChar () !== null ; $ this ->newEntry ()) {
5159 while ($ this ->readComment ());
60+ if ($ this ->getChar () === null ) {
61+ $ this ->addWarning ("Comment ignored at the end of the string at byte {$ this ->position }" );
62+ }
5263 $ this ->readContext ();
5364 $ this ->readOriginal ();
5465 if ($ this ->readPlural () && $ this ->readPluralTranslation (true )) {
@@ -65,6 +76,15 @@ public function loadString(
6576 return $ this ->translations ;
6677 }
6778
79+ /**
80+ * Retrieves the collected warnings
81+ * @return string[]
82+ */
83+ public function getWarnings (): array
84+ {
85+ return $ this ->warnings ;
86+ }
87+
6888 /**
6989 * Prepares to parse a new translation
7090 */
@@ -88,9 +108,9 @@ private function saveEntry(): void
88108 throw new Exception ("Duplicated entry at byte {$ this ->position }" );
89109 }
90110 if ($ this ->pluralCount !== null && $ this ->translation ->getPlural () !== null
91- && count ($ this ->translation ->getPluralTranslations ()) < $ this ->pluralCount ) {
92- $ this ->addWarning ("The translation doesn't have all the { $ this -> pluralCount } "
93- . " plural forms at byte {$ this ->position }" );
111+ && ( $ translationCount = count ($ this ->translation ->getPluralTranslations ())) !== ( $ this ->pluralCount - 1 ) ) {
112+ $ this ->addWarning ("The translation has { $ translationCount } plural forms, "
113+ ." while the header expects { $ this -> pluralCount } at byte {$ this ->position }" );
94114 }
95115 $ this ->translations ->add ($ this ->translation );
96116 }
@@ -114,7 +134,7 @@ private function readPreviousTranslationComment(): bool
114134 /**
115135 * Attempts to read whitespace characters, also might skip complex comment prologs when needed
116136 */
117- private function readWhiteSpace (): bool
137+ private function readWhitespace (): bool
118138 {
119139 $ position = $ this ->position ;
120140 while ((ctype_space ($ this ->getChar () ?? '' ) && $ this ->nextChar ())
@@ -258,11 +278,11 @@ private function readQuotedString(): string
258278 }
259279 }
260280 if (!$ this ->readChar ('" ' )) {
261- throw new Exception ("Expected an ending quote at byte {$ this ->position }" );
281+ throw new Exception ("Expected a closing quote at byte {$ this ->position }" );
262282 }
263283 // Saves a checkpoint and attempts to read a new sequence
264284 $ checkpoint = $ this ->position ;
265- $ this ->readWhiteSpace ();
285+ $ this ->readWhitespace ();
266286 }
267287
268288 return $ data ;
@@ -273,7 +293,7 @@ private function readQuotedString(): string
273293 */
274294 private function readComment (): bool
275295 {
276- $ this ->readWhiteSpace ();
296+ $ this ->readWhitespace ();
277297 if (!$ this ->readChar ('# ' )) {
278298 return false ;
279299 }
@@ -336,7 +356,7 @@ private function readComment(): bool
336356 private function readIdentifier (string $ identifier , bool $ throwIfNotFound = false ): ?string
337357 {
338358 $ checkpoint = $ this ->position ;
339- $ this ->readWhiteSpace ();
359+ $ this ->readWhitespace ();
340360 if (!$ this ->readString ($ identifier )) {
341361 if ($ throwIfNotFound ) {
342362 throw new Exception ("Expected $ identifier at byte {$ this ->position }" );
@@ -345,7 +365,7 @@ private function readIdentifier(string $identifier, bool $throwIfNotFound = fals
345365
346366 return null ;
347367 }
348- $ this ->readWhiteSpace ();
368+ $ this ->readWhitespace ();
349369
350370 return $ this ->readQuotedString ();
351371 }
@@ -392,11 +412,11 @@ private function readPlural(): bool
392412 */
393413 private function readTranslation (): void
394414 {
395- $ this ->readWhiteSpace ();
415+ $ this ->readWhitespace ();
396416 if (!$ this ->readString ('msgstr ' )) {
397417 throw new Exception ("Expected msgstr at byte {$ this ->position }" );
398418 }
399- $ this ->readWhiteSpace ();
419+ $ this ->readWhitespace ();
400420 $ data = $ this ->readQuotedString ();
401421 // The header might be surrounded by newlines
402422 if ($ this ->translation ->getOriginal () !== '' ) {
@@ -410,22 +430,23 @@ private function readTranslation(): void
410430 */
411431 private function readPluralTranslation (bool $ throwIfNotFound = false ): bool
412432 {
413- $ this ->readWhiteSpace ();
433+ $ this ->readWhitespace ();
414434 if (!$ this ->readString ('msgstr ' )) {
415435 if ($ throwIfNotFound ) {
416436 throw new Exception ("Expected indexed msgstr at byte {$ this ->position }" );
417437 }
418438
419439 return false ;
420440 }
421- $ this ->readWhiteSpace ();
441+ $ this ->readWhitespace ();
422442 if (!$ this ->readChar ('[ ' )) {
423443 throw new Exception ("Expected character \"[ \" at byte {$ this ->position }" );
424444 }
445+ $ this ->readWhitespace ();
425446 if (!strlen ($ index = $ this ->readNumber ())) {
426447 throw new Exception ("Expected msgstr index at byte {$ this ->position }" );
427448 }
428- $ this ->readWhiteSpace ();
449+ $ this ->readWhitespace ();
429450 if (!$ this ->readChar ('] ' )) {
430451 throw new Exception ("Expected character \"] \" at byte {$ this ->position }" );
431452 }
@@ -436,7 +457,7 @@ private function readPluralTranslation(bool $throwIfNotFound = false): bool
436457 if (count ($ translations ) !== (int ) $ index ) {
437458 throw new Exception ("The msgstr has an invalid index at byte {$ this ->position }" );
438459 }
439- $ this ->readWhiteSpace ();
460+ $ this ->readWhitespace ();
440461 $ data = $ this ->readQuotedString ();
441462 $ translations [] = $ data ;
442463 $ this ->checkNewLine ($ data , 'msgstr ' );
0 commit comments