Repository: briannesbitt/Carbon (php)

Issue:
[Translation tool] es_ES
## Additional fixes
First => primer
Second => segundo
Third => tercer
Fourth => cuarto
Last => último



----
Currently there is no translation for Ordinal Numbers format.

Example:
`[EN_US] First Sunday of november`
`[ES_ES] Primer domingo de noviembre`

---- 
I would like to contribute to this but i don´t know where to start.

Pull request:
Translate ordinal word when parsing string
Fix #2692

Patch:
diff --git a/src/Carbon/Lang/de.php b/src/Carbon/Lang/de.php
index ff00c974..3b70750e 100644
--- a/src/Carbon/Lang/de.php
+++ b/src/Carbon/Lang/de.php
@@ -105,4 +105,13 @@ return [
     'first_day_of_week' => 1,
     'day_of_first_week_of_year' => 4,
     'list' => [', ', ' und '],
+    'ordinal_words' => [
+        'of' => 'im',
+        'first' => 'erster',
+        'second' => 'zweiter',
+        'third' => 'dritter',
+        'fourth' => 'vierten',
+        'fifth' => 'fünfter',
+        'last' => 'letzten',
+    ],
 ];
diff --git a/src/Carbon/Lang/es.php b/src/Carbon/Lang/es.php
index f77ec39c..1c4fcfd0 100644
--- a/src/Carbon/Lang/es.php
+++ b/src/Carbon/Lang/es.php
@@ -26,6 +26,7 @@
  * - quinterocesar
  * - Daniel Commesse Liévanos (danielcommesse)
  * - Pete Scopes (pdscopes)
+ * - gam04
  */
 
 use Carbon\CarbonInterface;
@@ -108,4 +109,13 @@ return [
     'day_of_first_week_of_year' => 4,
     'list' => [', ', ' y '],
     'meridiem' => ['a. m.', 'p. m.'],
+    'ordinal_words' => [
+        'of' => 'de',
+        'first' => 'primer',
+        'second' => 'segundo',
+        'third' => 'tercer',
+        'fourth' => 'cuarto',
+        'fifth' => 'quinto',
+        'last' => 'último',
+    ],
 ];
diff --git a/src/Carbon/Lang/fr.php b/src/Carbon/Lang/fr.php
index 8c81ec65..f4c7247b 100644
--- a/src/Carbon/Lang/fr.php
+++ b/src/Carbon/Lang/fr.php
@@ -111,4 +111,13 @@ return [
     'first_day_of_week' => 1,
     'day_of_first_week_of_year' => 4,
     'list' => [', ', ' et '],
+    'ordinal_words' => [
+        'of' => 'de',
+        'first' => 'premier',
+        'second' => 'deuxième',
+        'third' => 'troisième',
+        'fourth' => 'quatrième',
+        'fifth' => 'cinquième',
+        'last' => 'dernier',
+    ],
 ];
diff --git a/src/Carbon/Lang/it.php b/src/Carbon/Lang/it.php
index 30c0ffd5..49875d7e 100644
--- a/src/Carbon/Lang/it.php
+++ b/src/Carbon/Lang/it.php
@@ -103,4 +103,13 @@ return [
     'first_day_of_week' => 1,
     'day_of_first_week_of_year' => 4,
     'list' => [', ', ' e '],
+    'ordinal_words' => [
+        'of' => 'di',
+        'first' => 'primo',
+        'second' => 'secondo',
+        'third' => 'terzo',
+        'fourth' => 'quarto',
+        'fifth' => 'quinto',
+        'last' => 'ultimo',
+    ],
 ];
diff --git a/src/Carbon/Lang/pt.php b/src/Carbon/Lang/pt.php
index 0af89499..bb6359b1 100644
--- a/src/Carbon/Lang/pt.php
+++ b/src/Carbon/Lang/pt.php
@@ -104,4 +104,13 @@ return [
     'first_day_of_week' => 1,
     'day_of_first_week_of_year' => 4,
     'list' => [', ', ' e '],
+    'ordinal_words' => [
+        'of' => 'de',
+        'first' => 'primeira',
+        'second' => 'segunda',
+        'third' => 'terceira',
+        'fourth' => 'quarta',
+        'fifth' => 'quinta',
+        'last' => 'última',
+    ],
 ];
diff --git a/src/Carbon/Lang/sl.php b/src/Carbon/Lang/sl.php
index b000e30e..2e197212 100644
--- a/src/Carbon/Lang/sl.php
+++ b/src/Carbon/Lang/sl.php
@@ -49,8 +49,8 @@ return [
     'a_second' => '{1}nekaj sekund|:count sekunda|:count sekundi|:count sekunde|:count sekund',
     's' => ':count s',
 
-    'year_ago' => ':count letom|:count letoma|:count leti|:count leti',
-    'y_ago' => ':count letom|:count letoma|:count leti|:count leti',
+    'year_ago' => ':count letom|:count leti|:count leti|:count leti',
+    'y_ago' => ':count letom|:count leti|:count leti|:count leti',
     'month_ago' => ':count mesecem|:count meseci|:count meseci|:count meseci',
     'week_ago' => ':count tednom|:count tednoma|:count tedni|:count tedni',
     'day_ago' => ':count dnem|:count dnevoma|:count dnevi|:count dnevi',
diff --git a/src/Carbon/Traits/Localization.php b/src/Carbon/Traits/Localization.php
index bd641743..ff249566 100644
--- a/src/Carbon/Traits/Localization.php
+++ b/src/Carbon/Traits/Localization.php
@@ -357,6 +357,13 @@ trait Localization
             $weekdays = $messages['weekdays'] ?? [];
             $meridiem = $messages['meridiem'] ?? ['AM', 'PM'];
 
+            if (isset($messages['ordinal_words'])) {
+                $timeString = self::replaceOrdinalWords(
+                    $timeString,
+                    $key === 'from' ? array_flip($messages['ordinal_words']) : $messages['ordinal_words']
+                );
+            }
+
             if ($key === 'from') {
                 foreach (['months', 'weekdays'] as $variable) {
                     $list = $messages[$variable.'_standalone'] ?? null;
@@ -821,4 +828,11 @@ trait Localization
 
         return $list;
     }
+
+    private static function replaceOrdinalWords(string $timeString, array $ordinalWords): string
+    {
+        return preg_replace_callback('/(?<![a-z])[a-z]+(?![a-z])/i', function (array $match) use ($ordinalWords) {
+            return $ordinalWords[mb_strtolower($match[0])] ?? $match[0];
+        }, $timeString);
+    }
 }


Test patch:
diff --git a/tests/Jenssegers/DateTest.php b/tests/Jenssegers/DateTest.php
index 6798a36e..06137d03 100644
--- a/tests/Jenssegers/DateTest.php
+++ b/tests/Jenssegers/DateTest.php
@@ -189,4 +189,13 @@ class DateTest extends TestCaseBase
 
         $this->assertSame('Foobar', Carbon::translateTimeString('Foobar', 'xx'));
     }
+
+    public function testTranslateTimeStringWithOrdinalWords()
+    {
+        $date = Carbon::translateTimeString('Premier lundi de mai', 'fr', 'en');
+        $this->assertSame('first monday of may', mb_strtolower($date));
+
+        $date = Carbon::translateTimeString('Premier lundi de mai', 'fr', 'es');
+        $this->assertSame('primer lunes de mayo', mb_strtolower($date));
+    }
 }
diff --git a/tests/Localization/SlSiTest.php b/tests/Localization/SlSiTest.php
index ea71159a..872d113d 100644
--- a/tests/Localization/SlSiTest.php
+++ b/tests/Localization/SlSiTest.php
@@ -331,11 +331,11 @@ class SlSiTest extends LocalizationTestCase
 
         // Carbon::now()->subYears(2)->diffForHumans()
         // '2 years ago'
-        'pred 2 letoma',
+        'pred 2 leti',
 
         // Carbon::now()->subYears(2)->diffForHumans(null, false, true)
         // '2yrs ago'
-        'pred 2 letoma',
+        'pred 2 leti',
 
         // Carbon::now()->addSecond()->diffForHumans()
         // '1 second from now'
@@ -399,7 +399,7 @@ class SlSiTest extends LocalizationTestCase
 
         // Carbon::now()->subYears(2)->subMonths(3)->subDay()->subSecond()->diffForHumans(null, null, true, 4)
         // '2yrs 3mos 1d 1s ago'
-        'pred 2 letoma 3 mes. 1 dnem 1 s',
+        'pred 2 leti 3 mes. 1 dnem 1 s',
 
         // Carbon::now()->addWeek()->addHours(10)->diffForHumans(null, true, false, 2)
         // '1 week 10 hours'
diff --git a/tests/Localization/SlTest.php b/tests/Localization/SlTest.php
index c6878835..e53c4db3 100644
--- a/tests/Localization/SlTest.php
+++ b/tests/Localization/SlTest.php
@@ -331,11 +331,11 @@ class SlTest extends LocalizationTestCase
 
         // Carbon::now()->subYears(2)->diffForHumans()
         // '2 years ago'
-        'pred 2 letoma',
+        'pred 2 leti',
 
         // Carbon::now()->subYears(2)->diffForHumans(null, false, true)
         // '2yrs ago'
-        'pred 2 letoma',
+        'pred 2 leti',
 
         // Carbon::now()->addSecond()->diffForHumans()
         // '1 second from now'
@@ -399,7 +399,7 @@ class SlTest extends LocalizationTestCase
 
         // Carbon::now()->subYears(2)->subMonths(3)->subDay()->subSecond()->diffForHumans(null, null, true, 4)
         // '2yrs 3mos 1d 1s ago'
-        'pred 2 letoma 3 mes. 1 dnem 1 s',
+        'pred 2 leti 3 mes. 1 dnem 1 s',
 
         // Carbon::now()->addWeek()->addHours(10)->diffForHumans(null, true, false, 2)
         // '1 week 10 hours'