Skip to content

Commit a14884f

Browse files
jontjsnicolas-grekas
authored andcommitted
[String] Make AsciiSlugger fallback to parent locale's symbolsMap
1 parent 2277720 commit a14884f

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.3
5+
---
6+
7+
* Made `AsciiSlugger` fallback to parent locale's symbolsMap
8+
49
5.2.0
510
-----
611

Slugger/AsciiSlugger.php

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ public function slug(string $string, string $separator = '-', string $locale = n
111111
}
112112

113113
if ($this->symbolsMap instanceof \Closure) {
114+
// If the symbols map is passed as a closure, there is no need to fallback to the parent locale
115+
// as the closure can just provide substitutions for all locales of interest.
114116
$symbolsMap = $this->symbolsMap;
115117
array_unshift($transliterator, static function ($s) use ($symbolsMap, $locale) {
116118
return $symbolsMap($s, $locale);
@@ -119,9 +121,20 @@ public function slug(string $string, string $separator = '-', string $locale = n
119121

120122
$unicodeString = (new UnicodeString($string))->ascii($transliterator);
121123

122-
if (\is_array($this->symbolsMap) && isset($this->symbolsMap[$locale])) {
123-
foreach ($this->symbolsMap[$locale] as $char => $replace) {
124-
$unicodeString = $unicodeString->replace($char, ' '.$replace.' ');
124+
if (\is_array($this->symbolsMap)) {
125+
$map = null;
126+
if (isset($this->symbolsMap[$locale])) {
127+
$map = $this->symbolsMap[$locale];
128+
} else {
129+
$parent = self::getParentLocale($locale);
130+
if ($parent && isset($this->symbolsMap[$parent])) {
131+
$map = $this->symbolsMap[$parent];
132+
}
133+
}
134+
if ($map) {
135+
foreach ($map as $char => $replace) {
136+
$unicodeString = $unicodeString->replace($char, ' '.$replace.' ');
137+
}
125138
}
126139
}
127140

@@ -143,17 +156,28 @@ private function createTransliterator(string $locale): ?\Transliterator
143156
}
144157

145158
// Locale not supported and no parent, fallback to any-latin
146-
if (false === $str = strrchr($locale, '_')) {
159+
if (!$parent = self::getParentLocale($locale)) {
147160
return $this->transliterators[$locale] = null;
148161
}
149162

150163
// Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales
151-
$parent = substr($locale, 0, -\strlen($str));
152-
153164
if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) {
154165
$transliterator = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id);
155166
}
156167

157168
return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null;
158169
}
170+
171+
private static function getParentLocale(?string $locale): ?string
172+
{
173+
if (!$locale) {
174+
return null;
175+
}
176+
if (false === $str = strrchr($locale, '_')) {
177+
// no parent locale
178+
return null;
179+
}
180+
181+
return substr($locale, 0, -\strlen($str));
182+
}
159183
}

Tests/SluggerTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,37 @@ public function testSlugCharReplacementLocaleMethod()
6565
$this->assertSame('yo_y_tu_a_esta_direccion_slug_en_senal_test_es', $slug);
6666
}
6767

68+
public function testSlugCharReplacementLocaleConstructWithoutSymbolsMap()
69+
{
70+
$slugger = new AsciiSlugger('en');
71+
$slug = (string) $slugger->slug('you & me with this address [email protected]', '_');
72+
73+
$this->assertSame('you_and_me_with_this_address_slug_at_test_uk', $slug);
74+
}
75+
76+
public function testSlugCharReplacementParentLocaleConstructWithoutSymbolsMap()
77+
{
78+
$slugger = new AsciiSlugger('en_GB');
79+
$slug = (string) $slugger->slug('you & me with this address [email protected]', '_');
80+
81+
$this->assertSame('you_and_me_with_this_address_slug_at_test_uk', $slug);
82+
}
83+
84+
public function testSlugCharReplacementParentLocaleConstruct()
85+
{
86+
$slugger = new AsciiSlugger('fr_FR', ['fr' => ['&' => 'et', '@' => 'chez']]);
87+
$slug = (string) $slugger->slug('toi & moi avec cette adresse [email protected]', '_');
88+
89+
$this->assertSame('toi_et_moi_avec_cette_adresse_slug_chez_test_fr', $slug);
90+
}
91+
92+
public function testSlugCharReplacementParentLocaleMethod()
93+
{
94+
$slugger = new AsciiSlugger(null, ['es' => ['&' => 'y', '@' => 'en senal']]);
95+
$slug = (string) $slugger->slug('yo & tu a esta dirección [email protected]', '_', 'es_ES');
96+
$this->assertSame('yo_y_tu_a_esta_direccion_slug_en_senal_test_es', $slug);
97+
}
98+
6899
public function testSlugClosure()
69100
{
70101
$slugger = new AsciiSlugger(null, function ($s, $locale) {

0 commit comments

Comments
 (0)