88use Gettext \Translations ;
99
1010/**
11- * Class to load a PO file.
11+ * Class to load a PO file following the same rules of the GNU tools .
1212 */
1313final class StrictPoLoader extends Loader
1414{
1515 /** @var Translations */
1616 private $ translations ;
1717 /** @var Translation */
1818 private $ translation ;
19+ /** @var string */
1920 private $ data ;
21+ /** @var int */
2022 private $ position ;
23+ /** @var bool */
2124 private $ inPreviousComment ;
2225
26+ /**
27+ * Generates a Translations object from a .po based string
28+ */
2329 public function loadString (string $ string , Translations $ translations = null ): Translations
2430 {
2531 $ this ->data = $ string ;
@@ -40,27 +46,42 @@ public function loadString(string $string, Translations $translations = null): T
4046 return $ this ->translations ;
4147 }
4248
49+ /**
50+ * Prepares to parse a new translation
51+ */
4352 private function newEntry (): void
4453 {
4554 $ this ->inPreviousComment = false ;
4655 $ this ->translation = $ this ->createTranslation (null , '' );
4756 }
4857
58+ /**
59+ * Adds the current translation to the output list
60+ */
4961 private function saveEntry (): void
5062 {
5163 $ this ->translations ->add ($ this ->translation );
5264 }
5365
66+ /**
67+ * Attempts to read the prolog of a disabled comment
68+ */
5469 private function readDisabledComment (): bool
5570 {
5671 return $ this ->translation ->isDisabled () && $ this ->readString ('#~ ' );
5772 }
5873
74+ /**
75+ * Attempts to read the prolog of a previous translation comment
76+ */
5977 private function readPreviousTranslationComment (): bool
6078 {
6179 return $ this ->inPreviousComment && $ this ->readString ('#| ' );
6280 }
6381
82+ /**
83+ * Attempts to read whitespace characters, also might skip complex comment prologs when needed
84+ */
6485 private function readWhiteSpace (): bool
6586 {
6687 $ position = $ this ->position ;
@@ -70,20 +91,29 @@ private function readWhiteSpace(): bool
7091 return $ position !== $ this ->position ;
7192 }
7293
94+ /**
95+ * Attempts to read the exact informed string
96+ */
7397 private function readString (string $ word ): bool
7498 {
7599 return substr ($ this ->data , $ this ->position , strlen ($ word )) === $ word
76100 ? !!($ this ->position += strlen ($ word ))
77101 : false ;
78102 }
79103
104+ /**
105+ * Attempts to read the exact informed char
106+ */
80107 private function readChar (string $ char ): bool
81108 {
82109 return $ this ->getChar () === $ char
83110 ? !!++$ this ->position
84111 : false ;
85112 }
86113
114+ /**
115+ * Retrieves the current char and advances the internal pointer
116+ */
87117 private function nextChar (): ?string
88118 {
89119 $ char = $ this ->getChar ();
@@ -93,23 +123,35 @@ private function nextChar(): ?string
93123 return $ char ;
94124 }
95125
126+ /**
127+ * Retrieves the current char without advancing the internal pointer
128+ */
96129 private function getChar (): ?string
97130 {
98131 return $ this ->data [$ this ->position ] ?? null ;
99132 }
100133
134+ /**
135+ * Attempts to read a numeric sequence
136+ */
101137 private function readNumber (): string
102138 {
103139 for ($ data = '' ; ctype_digit ($ this ->getChar () ?? '' ); $ data .= $ this ->nextChar ());
104140 return $ data ;
105141 }
106142
143+ /**
144+ * Attempts to read a standard comment string which ends on \n
145+ */
107146 private function readCommentString (): string
108147 {
109148 for ($ data = '' ; ($ this ->getChar () ?? "\n" ) !== "\n" ; $ data .= $ this ->nextChar ());
110149 return $ data ;
111150 }
112151
152+ /**
153+ * Attempts to read a quoted string and unescape characters prefixed by \
154+ */
113155 private function readQuotedString (): string
114156 {
115157 static $ aliases = [
@@ -127,11 +169,13 @@ private function readQuotedString(): string
127169 $ hasData = false ;
128170 for ($ data = '' ;;) {
129171 if (!$ this ->readChar ('" ' )) {
172+ // Perhaps the data is over, let the next parser decide
130173 if ($ hasData ) {
131174 break ;
132175 }
133176 throw new Exception ("Expected an opening quote at byte {$ this ->position }" );
134177 }
178+ // Collects chars until the end of the data/file
135179 for (; ($ char = $ this ->getChar () ?? '" ' ) !== '" ' ; $ data .= $ char ) {
136180 $ this ->nextChar ();
137181 if ($ char === '\\' ) {
@@ -154,6 +198,9 @@ private function readQuotedString(): string
154198 return $ data ;
155199 }
156200
201+ /**
202+ * Attempts to read and interpret a comment
203+ */
157204 private function readComment (): bool
158205 {
159206 $ this ->readWhiteSpace ();
@@ -208,6 +255,9 @@ private function readComment(): bool
208255 return true ;
209256 }
210257
258+ /**
259+ * Attempts to read an identifier
260+ */
211261 private function readIdentifier (string $ identifier , bool $ isRequired = false ): ?string
212262 {
213263 $ this ->readWhiteSpace ();
@@ -221,6 +271,9 @@ private function readIdentifier(string $identifier, bool $isRequired = false): ?
221271 return $ this ->readQuotedString ();
222272 }
223273
274+ /**
275+ * Attempts to read the context
276+ */
224277 private function readContext (): bool
225278 {
226279 if (($ data = $ this ->readIdentifier ('msgctxt ' )) === null ) {
@@ -230,12 +283,18 @@ private function readContext(): bool
230283 return true ;
231284 }
232285
286+ /**
287+ * Reads the original message
288+ */
233289 private function readId (): void
234290 {
235291 $ data = $ this ->readIdentifier ('msgid ' , true );
236292 $ this ->translation = $ this ->translation ->withOriginal ($ data );
237293 }
238294
295+ /**
296+ * Attempts to read the plural message
297+ */
239298 private function readPlural (): bool
240299 {
241300 if (($ data = $ this ->readIdentifier ('msgid_plural ' )) === null ) {
@@ -245,6 +304,9 @@ private function readPlural(): bool
245304 return true ;
246305 }
247306
307+ /**
308+ * Reads the translation
309+ */
248310 private function readTranslation (): void
249311 {
250312 $ this ->readWhiteSpace ();
@@ -256,6 +318,9 @@ private function readTranslation(): void
256318 $ this ->translation ->translate ($ data );
257319 }
258320
321+ /**
322+ * Attempts to read the pluralized translation
323+ */
259324 private function readPluralTranslation (bool $ isRequired = false ): bool
260325 {
261326 $ this ->readWhiteSpace ();
@@ -267,14 +332,14 @@ private function readPluralTranslation(bool $isRequired = false): bool
267332 }
268333 $ this ->readWhiteSpace ();
269334 if (!$ this ->readChar ('[ ' )) {
270- throw new Exception ("Expected [ character at byte {$ this ->position }" );
335+ throw new Exception ("Expected character \" [ \" at byte {$ this ->position }" );
271336 }
272337 if (!strlen ($ index = $ this ->readNumber ())) {
273338 throw new Exception ("Expected msgstr index at byte {$ this ->position }" );
274339 }
275340 $ this ->readWhiteSpace ();
276341 if (!$ this ->readChar ('] ' )) {
277- throw new Exception ("Expected ] character at byte {$ this ->position }" );
342+ throw new Exception ("Expected character \" ] \" at byte {$ this ->position }" );
278343 }
279344 $ translations = $ this ->translation ->getPluralTranslations ();
280345 if (($ translation = $ this ->translation ->getTranslation ()) !== null ) {
@@ -291,6 +356,9 @@ private function readPluralTranslation(bool $isRequired = false): bool
291356 return true ;
292357 }
293358
359+ /**
360+ * Attempts to find and process the header translation
361+ */
294362 private function processHeader (): void
295363 {
296364 $ translations = $ this ->translations ;
@@ -318,6 +386,9 @@ private function processHeader(): void
318386 }
319387 }
320388
389+ /**
390+ * Parses the translation header data into an array
391+ */
321392 private function readHeaders (?string $ string ): array
322393 {
323394 if (empty ($ string )) {
0 commit comments