diff --git a/CHANGELOG.md b/CHANGELOG.md index 017bee1..486d5c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed -- Nothing. +- Sort extracted messages descending by key, using a natural, case-insensitive sorting algorithm. ### Deprecated diff --git a/src/Format/Writer/ChromeWriter.php b/src/Format/Writer/ChromeWriter.php index 3e8ea7d..c0a0672 100644 --- a/src/Format/Writer/ChromeWriter.php +++ b/src/Format/Writer/ChromeWriter.php @@ -27,6 +27,11 @@ use FormatPHP\Format\WriterInterface; use FormatPHP\Format\WriterOptions; +use function ksort; + +use const SORT_FLAG_CASE; +use const SORT_NATURAL; + /** * Chrome formatter for FormatPHP * @@ -65,6 +70,8 @@ public function __invoke(DescriptorCollection $collection, WriterOptions $option $format[(string) $item->getId()] = $message; } + ksort($format, SORT_NATURAL | SORT_FLAG_CASE); + return $format; } } diff --git a/src/Format/Writer/FormatPHPWriter.php b/src/Format/Writer/FormatPHPWriter.php index 52b3f63..7d40f27 100644 --- a/src/Format/Writer/FormatPHPWriter.php +++ b/src/Format/Writer/FormatPHPWriter.php @@ -31,6 +31,9 @@ use function array_merge; use function ksort; +use const SORT_FLAG_CASE; +use const SORT_NATURAL; + /** * Default formatter for FormatPHP * @@ -96,6 +99,8 @@ public function __invoke(DescriptorCollection $collection, WriterOptions $option $format[(string) $item->getId()] = $message; } + ksort($format, SORT_NATURAL | SORT_FLAG_CASE); + return $format; } } diff --git a/src/Format/Writer/SimpleWriter.php b/src/Format/Writer/SimpleWriter.php index 2f1ca6a..1daf07b 100644 --- a/src/Format/Writer/SimpleWriter.php +++ b/src/Format/Writer/SimpleWriter.php @@ -27,6 +27,11 @@ use FormatPHP\Format\WriterInterface; use FormatPHP\Format\WriterOptions; +use function ksort; + +use const SORT_FLAG_CASE; +use const SORT_NATURAL; + /** * A simple formatter for FormatPHP, producing message key-value pairs * @@ -52,6 +57,8 @@ public function __invoke(DescriptorCollection $collection, WriterOptions $option $simple[(string) $item->getId()] = $item->getDefaultMessage(); } + ksort($simple, SORT_NATURAL | SORT_FLAG_CASE); + return $simple; } } diff --git a/tests/Console/Command/__snapshots__/ExtractCommandTest__testExecuteWithValidationHasNoErrors__1.txt b/tests/Console/Command/__snapshots__/ExtractCommandTest__testExecuteWithValidationHasNoErrors__1.txt index ce0160f..14f76c8 100644 --- a/tests/Console/Command/__snapshots__/ExtractCommandTest__testExecuteWithValidationHasNoErrors__1.txt +++ b/tests/Console/Command/__snapshots__/ExtractCommandTest__testExecuteWithValidationHasNoErrors__1.txt @@ -7,14 +7,14 @@ "defaultMessage": "You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }", "description": "A description with multiple lines and extra whitespace." }, + "Q+U0TW": { + "defaultMessage": "Welcome!" + }, "Soex4s": { "defaultMessage": "This is a default message", "description": "A simple description of a fixture for testing purposes." }, "xgMWoP": { "defaultMessage": "This is a default message" - }, - "Q+U0TW": { - "defaultMessage": "Welcome!" } } diff --git a/tests/Console/Command/__snapshots__/PseudoLocaleCommandTest__testExecute__1.txt b/tests/Console/Command/__snapshots__/PseudoLocaleCommandTest__testExecute__1.txt index afa3ce8..778a26a 100644 --- a/tests/Console/Command/__snapshots__/PseudoLocaleCommandTest__testExecute__1.txt +++ b/tests/Console/Command/__snapshots__/PseudoLocaleCommandTest__testExecute__1.txt @@ -5,12 +5,12 @@ "how.many.pets": { "defaultMessage": "Ļâśṭ ṭíṁè Ḭ ćḫèćǩèḋ, {gender, select, male{ḫè ḫâḋ} female{śḫè ḫâḋ} other{ṭḫèẏ ḫâḋ}} {petCount, plural, =0{ńŏ ṗèṭś} =1{â ṗèṭ} other{# ṗèṭś}}." }, - "start.with.tag": { - "defaultMessage": "{argument}" - }, "start.with.argument": { "defaultMessage": "{argument}" }, + "start.with.tag": { + "defaultMessage": "{argument}" + }, "value.with.non-ascii.characters": { "defaultMessage": "Ẅè’ḋ ńèèḋ ṭŏ ṭëśṭ śøṁè ńŏń-áśćíí ćḫâŕâćṭèŕś, ṭŏŏ…" } diff --git a/tests/Extractor/MessageExtractorTest.php b/tests/Extractor/MessageExtractorTest.php index 9b72c9d..b8a757c 100644 --- a/tests/Extractor/MessageExtractorTest.php +++ b/tests/Extractor/MessageExtractorTest.php @@ -79,6 +79,9 @@ public function testProcessBasic(): void 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], + 'goodbye' => [ + 'defaultMessage' => 'Goodbye!', + ], 'OpKKos' => [ 'defaultMessage' => 'Hello!', ], @@ -87,22 +90,19 @@ public function testProcessBasic(): void 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', 'description' => 'A description with multiple lines and extra whitespace.', ], - 'welcome' => [ + 'Q+U0TW' => [ 'defaultMessage' => 'Welcome!', ], - 'goodbye' => [ - 'defaultMessage' => 'Goodbye!', - ], 'Soex4s' => [ 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], + 'welcome' => [ + 'defaultMessage' => 'Welcome!', + ], 'xgMWoP' => [ 'defaultMessage' => 'This is a default message', ], - 'Q+U0TW' => [ - 'defaultMessage' => 'Welcome!', - ], ], $messages, ); @@ -140,6 +140,9 @@ public function testProcessWithFormatPhpFormatterName(): void 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', 'description' => 'A description with multiple lines and extra whitespace.', ], + 'Q+U0TW' => [ + 'defaultMessage' => 'Welcome!', + ], 'Soex4s' => [ 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', @@ -147,9 +150,6 @@ public function testProcessWithFormatPhpFormatterName(): void 'xgMWoP' => [ 'defaultMessage' => 'This is a default message', ], - 'Q+U0TW' => [ - 'defaultMessage' => 'Welcome!', - ], ], $messages, ); @@ -180,9 +180,9 @@ public function testProcessWithSimpleFormatterName(): void [ 'aTestId' => 'This is a default message', 'photos.count' => 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', + 'Q+U0TW' => 'Welcome!', 'Soex4s' => 'This is a default message', 'xgMWoP' => 'This is a default message', - 'Q+U0TW' => 'Welcome!', ], $messages, ); @@ -230,6 +230,9 @@ public function testProcessWithSmartlingFormatterName(): void 'description' => 'A description with multiple lines and extra whitespace.', 'message' => 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', ], + 'Q+U0TW' => [ + 'message' => 'Welcome!', + ], 'Soex4s' => [ 'description' => 'A simple description of a fixture for testing purposes.', 'message' => 'This is a default message', @@ -237,9 +240,6 @@ public function testProcessWithSmartlingFormatterName(): void 'xgMWoP' => [ 'message' => 'This is a default message', ], - 'Q+U0TW' => [ - 'message' => 'Welcome!', - ], ], $messages, ); @@ -276,6 +276,9 @@ public function testProcessWithCrowdinFormatterName(): void 'description' => 'A description with multiple lines and extra whitespace.', 'message' => 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', ], + 'Q+U0TW' => [ + 'message' => 'Welcome!', + ], 'Soex4s' => [ 'description' => 'A simple description of a fixture for testing purposes.', 'message' => 'This is a default message', @@ -283,9 +286,6 @@ public function testProcessWithCrowdinFormatterName(): void 'xgMWoP' => [ 'message' => 'This is a default message', ], - 'Q+U0TW' => [ - 'message' => 'Welcome!', - ], ], $messages, ); @@ -322,6 +322,9 @@ public function testProcessWithChromeFormatterName(): void 'description' => 'A description with multiple lines and extra whitespace.', 'message' => 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', ], + 'Q+U0TW' => [ + 'message' => 'Welcome!', + ], 'Soex4s' => [ 'description' => 'A simple description of a fixture for testing purposes.', 'message' => 'This is a default message', @@ -329,9 +332,6 @@ public function testProcessWithChromeFormatterName(): void 'xgMWoP' => [ 'message' => 'This is a default message', ], - 'Q+U0TW' => [ - 'message' => 'Welcome!', - ], ], $messages, ); @@ -623,32 +623,32 @@ public function testProcessWithCustomParser(): void 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], + 'customGoodbye' => [ + 'defaultMessage' => 'Custom Goodbye!', + ], + 'customWelcome' => [ + 'defaultMessage' => 'Custom Welcome!', + ], + 'goodbye' => [ + 'defaultMessage' => 'Goodbye!', + ], 'photos.count' => [ 'defaultMessage' => 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', 'description' => 'A description with multiple lines and extra whitespace.', ], - 'welcome' => [ + 'Q+U0TW' => [ 'defaultMessage' => 'Welcome!', ], - 'goodbye' => [ - 'defaultMessage' => 'Goodbye!', - ], 'Soex4s' => [ 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], - 'xgMWoP' => [ - 'defaultMessage' => 'This is a default message', - ], - 'Q+U0TW' => [ + 'welcome' => [ 'defaultMessage' => 'Welcome!', ], - 'customWelcome' => [ - 'defaultMessage' => 'Custom Welcome!', - ], - 'customGoodbye' => [ - 'defaultMessage' => 'Custom Goodbye!', + 'xgMWoP' => [ + 'defaultMessage' => 'This is a default message', ], ], $messages, @@ -715,32 +715,32 @@ public function testProcessWithCustomParserAsClosure(): void 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], + 'customGoodbye' => [ + 'defaultMessage' => 'Custom Goodbye!', + ], + 'customWelcome' => [ + 'defaultMessage' => 'Custom Welcome!', + ], + 'goodbye' => [ + 'defaultMessage' => 'Goodbye!', + ], 'photos.count' => [ 'defaultMessage' => 'You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.} }', 'description' => 'A description with multiple lines and extra whitespace.', ], - 'welcome' => [ + 'Q+U0TW' => [ 'defaultMessage' => 'Welcome!', ], - 'goodbye' => [ - 'defaultMessage' => 'Goodbye!', - ], 'Soex4s' => [ 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], - 'xgMWoP' => [ - 'defaultMessage' => 'This is a default message', - ], - 'Q+U0TW' => [ + 'welcome' => [ 'defaultMessage' => 'Welcome!', ], - 'customWelcome' => [ - 'defaultMessage' => 'Custom Welcome!', - ], - 'customGoodbye' => [ - 'defaultMessage' => 'Custom Goodbye!', + 'xgMWoP' => [ + 'defaultMessage' => 'This is a default message', ], ], $messages, @@ -810,6 +810,9 @@ public function testProcessFlatten(): void 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], + 'goodbye' => [ + 'defaultMessage' => 'Goodbye!', + ], 'OpKKos' => [ 'defaultMessage' => 'Hello!', ], @@ -818,22 +821,19 @@ public function testProcessFlatten(): void . '=1{You have one photo.} other{You have # photos.}}', 'description' => 'A description with multiple lines and extra whitespace.', ], - 'welcome' => [ + 'Q+U0TW' => [ 'defaultMessage' => 'Welcome!', ], - 'goodbye' => [ - 'defaultMessage' => 'Goodbye!', - ], 'Soex4s' => [ 'defaultMessage' => 'This is a default message', 'description' => 'A simple description of a fixture for testing purposes.', ], + 'welcome' => [ + 'defaultMessage' => 'Welcome!', + ], 'xgMWoP' => [ 'defaultMessage' => 'This is a default message', ], - 'Q+U0TW' => [ - 'defaultMessage' => 'Welcome!', - ], ], $messages, ); diff --git a/tests/Format/Writer/ChromeWriterTest.php b/tests/Format/Writer/ChromeWriterTest.php index 7596858..8030988 100644 --- a/tests/Format/Writer/ChromeWriterTest.php +++ b/tests/Format/Writer/ChromeWriterTest.php @@ -25,9 +25,9 @@ public function testFormatter(): void $this->assertSame( [ - 'foo' => ['message' => ''], 'bar' => ['message' => 'some message'], 'baz' => ['description' => 'a description', 'message' => 'another message'], + 'foo' => ['message' => ''], ], $formatter($collection, $options), ); diff --git a/tests/Format/Writer/CrowdinWriterTest.php b/tests/Format/Writer/CrowdinWriterTest.php index 941fcb3..425ce33 100644 --- a/tests/Format/Writer/CrowdinWriterTest.php +++ b/tests/Format/Writer/CrowdinWriterTest.php @@ -25,9 +25,9 @@ public function testFormatter(): void $this->assertSame( [ - 'foo' => ['message' => ''], 'bar' => ['message' => 'some message'], 'baz' => ['description' => 'a description', 'message' => 'another message'], + 'foo' => ['message' => ''], ], $formatter($collection, $options), ); diff --git a/tests/Format/Writer/FormatPHPWriterTest.php b/tests/Format/Writer/FormatPHPWriterTest.php index e55ea9c..001db25 100644 --- a/tests/Format/Writer/FormatPHPWriterTest.php +++ b/tests/Format/Writer/FormatPHPWriterTest.php @@ -25,9 +25,9 @@ public function testFormatterBasic(): void $this->assertSame( [ - 'foo' => ['defaultMessage' => ''], 'bar' => ['defaultMessage' => 'some message'], 'baz' => ['defaultMessage' => 'another message', 'description' => 'a description'], + 'foo' => ['defaultMessage' => ''], ], $formatter($collection, $options), ); diff --git a/tests/Format/Writer/SmartlingWriterTest.php b/tests/Format/Writer/SmartlingWriterTest.php index 20a82dd..aebb7e1 100644 --- a/tests/Format/Writer/SmartlingWriterTest.php +++ b/tests/Format/Writer/SmartlingWriterTest.php @@ -36,9 +36,9 @@ public function testFormatter(): void ], 'variants_enabled' => true, ], - 'foo' => ['message' => ''], 'bar' => ['message' => 'some message'], 'baz' => ['description' => 'a description', 'message' => 'another message'], + 'foo' => ['message' => ''], ], $formatter($collection, $options), ); diff --git a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XA__1.txt b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XA__1.txt index afa3ce8..778a26a 100644 --- a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XA__1.txt +++ b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XA__1.txt @@ -5,12 +5,12 @@ "how.many.pets": { "defaultMessage": "Ļâśṭ ṭíṁè Ḭ ćḫèćǩèḋ, {gender, select, male{ḫè ḫâḋ} female{śḫè ḫâḋ} other{ṭḫèẏ ḫâḋ}} {petCount, plural, =0{ńŏ ṗèṭś} =1{â ṗèṭ} other{# ṗèṭś}}." }, - "start.with.tag": { - "defaultMessage": "{argument}" - }, "start.with.argument": { "defaultMessage": "{argument}" }, + "start.with.tag": { + "defaultMessage": "{argument}" + }, "value.with.non-ascii.characters": { "defaultMessage": "Ẅè’ḋ ńèèḋ ṭŏ ṭëśṭ śøṁè ńŏń-áśćíí ćḫâŕâćṭèŕś, ṭŏŏ…" } diff --git a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XB__1.txt b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XB__1.txt index 07f8a09..a31f7b7 100644 --- a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XB__1.txt +++ b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-XB__1.txt @@ -5,12 +5,12 @@ "how.many.pets": { "defaultMessage": "[!! Ļâśśśṭ ṭṭṭíṁèèè Ḭ ćḫèèèćǩèèèḋ, !!]{gender, select, male{[!! ḫè !!][!! ḫâââḋ !!]} female{[!! śḫèèè !!][!! ḫâââḋ !!]} other{[!! ṭḫèèèẏ !!][!! ḫâââḋ !!]}}[!! !!]{petCount, plural, =0{[!! ńŏ !!][!! ṗèèèṭś !!]} =1{[!! â !!][!! ṗèèèṭ !!]} other{#[!! ṗèèèṭś !!]}}[!! . !!]" }, - "start.with.tag": { - "defaultMessage": "{argument}" - }, "start.with.argument": { "defaultMessage": "{argument}" }, + "start.with.tag": { + "defaultMessage": "{argument}" + }, "value.with.non-ascii.characters": { "defaultMessage": "[!! Ẅè’ḋ ńńńèèḋḋḋ ṭŏŏŏ ṭëśṭ śøṁṁṁè ńńńŏń-áśćććíí ćḫâââŕâćććṭèŕŕŕś, ṭŏŏŏŏ… !!]" } diff --git a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-xa with outFile__1.txt b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-xa with outFile__1.txt index afa3ce8..778a26a 100644 --- a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-xa with outFile__1.txt +++ b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale en-xa with outFile__1.txt @@ -5,12 +5,12 @@ "how.many.pets": { "defaultMessage": "Ļâśṭ ṭíṁè Ḭ ćḫèćǩèḋ, {gender, select, male{ḫè ḫâḋ} female{śḫè ḫâḋ} other{ṭḫèẏ ḫâḋ}} {petCount, plural, =0{ńŏ ṗèṭś} =1{â ṗèṭ} other{# ṗèṭś}}." }, - "start.with.tag": { - "defaultMessage": "{argument}" - }, "start.with.argument": { "defaultMessage": "{argument}" }, + "start.with.tag": { + "defaultMessage": "{argument}" + }, "value.with.non-ascii.characters": { "defaultMessage": "Ẅè’ḋ ńèèḋ ṭŏ ṭëśṭ śøṁè ńŏń-áśćíí ćḫâŕâćṭèŕś, ṭŏŏ…" } diff --git a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-AC__1.txt b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-AC__1.txt index 2afb72e..5bff2d2 100644 --- a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-AC__1.txt +++ b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-AC__1.txt @@ -5,12 +5,12 @@ "how.many.pets": { "defaultMessage": "LAST TIME I CHECKED, {gender, select, male{HE HAD} female{SHE HAD} other{THEY HAD}} {petCount, plural, =0{NO PETS} =1{A PET} other{# PETS}}." }, - "start.with.tag": { - "defaultMessage": "{argument}" - }, "start.with.argument": { "defaultMessage": "{argument}" }, + "start.with.tag": { + "defaultMessage": "{argument}" + }, "value.with.non-ascii.characters": { "defaultMessage": "WE’D NEED TO TËST SØME NON-ÁSCII CHARACTERS, TOO…" } diff --git a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-HA__1.txt b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-HA__1.txt index 24d1ef9..b27d5d5 100644 --- a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-HA__1.txt +++ b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-HA__1.txt @@ -5,12 +5,12 @@ "how.many.pets": { "defaultMessage": "[javascript]Last time I checked, {gender, select, male{he had} female{she had} other{they had}} {petCount, plural, =0{no pets} =1{a pet} other{# pets}}." }, - "start.with.tag": { - "defaultMessage": "[javascript]{argument}" - }, "start.with.argument": { "defaultMessage": "[javascript]{argument}" }, + "start.with.tag": { + "defaultMessage": "[javascript]{argument}" + }, "value.with.non-ascii.characters": { "defaultMessage": "[javascript]We’d need to tëst søme non-áscii characters, too…" } diff --git a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-LS__1.txt b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-LS__1.txt index 2cc9d8e..0375c92 100644 --- a/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-LS__1.txt +++ b/tests/PseudoLocale/__snapshots__/ConverterTest__testConvert with data set pseudo locale xx-LS__1.txt @@ -5,12 +5,12 @@ "how.many.pets": { "defaultMessage": "Last time I checked, {gender, select, male{he had} female{she had} other{they had}} {petCount, plural, =0{no pets} =1{a pet} other{# pets}}.SSSSSSSSSSSSSSSSSSSSSSSSS" }, - "start.with.tag": { - "defaultMessage": "{argument}SSSSSSSSSSSSSSSSSSSSSSSSS" - }, "start.with.argument": { "defaultMessage": "{argument}SSSSSSSSSSSSSSSSSSSSSSSSS" }, + "start.with.tag": { + "defaultMessage": "{argument}SSSSSSSSSSSSSSSSSSSSSSSSS" + }, "value.with.non-ascii.characters": { "defaultMessage": "We’d need to tëst søme non-áscii characters, too…SSSSSSSSSSSSSSSSSSSSSSSSS" }