Skip to content

Commit 99ef361

Browse files
hotmeteordriesvintstaylorotwell
authored
[10.x] Add APA style title helper (#49572)
* Add APA style title helper * Update Str.php * Update Str.php * Update Str.php * Update src/Illuminate/Support/Str.php * formatting * Update Str.php * formatting * formatting * formatting --------- Co-authored-by: Dries Vints <[email protected]> Co-authored-by: Taylor Otwell <[email protected]>
1 parent 4083fa5 commit 99ef361

File tree

3 files changed

+98
-11
lines changed

3 files changed

+98
-11
lines changed

src/Illuminate/Support/Str.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ public static function upper($value)
12381238
}
12391239

12401240
/**
1241-
* Convert the given string to title case.
1241+
* Convert the given string to proper case.
12421242
*
12431243
* @param string $value
12441244
* @return string
@@ -1249,7 +1249,7 @@ public static function title($value)
12491249
}
12501250

12511251
/**
1252-
* Convert the given string to title case for each word.
1252+
* Convert the given string to proper case for each word.
12531253
*
12541254
* @param string $value
12551255
* @return string
@@ -1267,6 +1267,52 @@ public static function headline($value)
12671267
return implode(' ', array_filter(explode('_', $collapsed)));
12681268
}
12691269

1270+
/**
1271+
* Convert the given string to APA-style title case.
1272+
*
1273+
* See: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case
1274+
*
1275+
* @param string $value
1276+
* @return string
1277+
*/
1278+
public static function apa($value)
1279+
{
1280+
$minorWords = [
1281+
'and', 'as', 'but', 'for', 'if', 'nor', 'or', 'so', 'yet', 'a', 'an',
1282+
'the', 'at', 'by', 'for', 'in', 'of', 'off', 'on', 'per', 'to', 'up', 'via'
1283+
];
1284+
1285+
$endPunctuation = ['.', '!', '?', ':', '', ','];
1286+
1287+
$words = preg_split('/\s+/', $value, -1, PREG_SPLIT_NO_EMPTY);
1288+
1289+
$words[0] = ucfirst(mb_strtolower($words[0]));
1290+
1291+
for ($i = 0; $i < count($words); $i++) {
1292+
$lowercaseWord = mb_strtolower($words[$i]);
1293+
1294+
if (str_contains($lowercaseWord, '-')) {
1295+
$hyphenatedWords = explode('-', $lowercaseWord);
1296+
1297+
$hyphenatedWords = array_map(function ($part) use ($minorWords) {
1298+
return (in_array($part, $minorWords) && mb_strlen($part) <= 3) ? $part : ucfirst($part);
1299+
}, $hyphenatedWords);
1300+
1301+
$words[$i] = implode('-', $hyphenatedWords);
1302+
} else {
1303+
if (in_array($lowercaseWord, $minorWords) &&
1304+
mb_strlen($lowercaseWord) <= 3 &&
1305+
! ($i === 0 || in_array(mb_substr($words[$i - 1], -1), $endPunctuation))) {
1306+
$words[$i] = $lowercaseWord;
1307+
} else {
1308+
$words[$i] = ucfirst($lowercaseWord);
1309+
}
1310+
}
1311+
}
1312+
1313+
return implode(' ', $words);
1314+
}
1315+
12701316
/**
12711317
* Get the singular form of an English word.
12721318
*

src/Illuminate/Support/Stringable.php

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ public function upper()
788788
}
789789

790790
/**
791-
* Convert the given string to title case.
791+
* Convert the given string to proper case.
792792
*
793793
* @return static
794794
*/
@@ -798,25 +798,35 @@ public function title()
798798
}
799799

800800
/**
801-
* Transliterate a string to its closest ASCII representation.
801+
* Convert the given string to proper case for each word.
802802
*
803-
* @param string|null $unknown
804-
* @param bool|null $strict
805803
* @return static
806804
*/
807-
public function transliterate($unknown = '?', $strict = false)
805+
public function headline()
808806
{
809-
return new static(Str::transliterate($this->value, $unknown, $strict));
807+
return new static(Str::headline($this->value));
810808
}
811809

812810
/**
813-
* Convert the given string to title case for each word.
811+
* Convert the given string to APA-style title case.
814812
*
815813
* @return static
816814
*/
817-
public function headline()
815+
public function apa()
818816
{
819-
return new static(Str::headline($this->value));
817+
return new static(Str::apa($this->value));
818+
}
819+
820+
/**
821+
* Transliterate a string to its closest ASCII representation.
822+
*
823+
* @param string|null $unknown
824+
* @param bool|null $strict
825+
* @return static
826+
*/
827+
public function transliterate($unknown = '?', $strict = false)
828+
{
829+
return new static(Str::transliterate($this->value, $unknown, $strict));
820830
}
821831

822832
/**

tests/Support/SupportStrTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,37 @@ public function testStringHeadline()
6767
$this->assertSame('Orwell 1984', Str::headline(' orwell_- 1984 '));
6868
}
6969

70+
public function testStringApa()
71+
{
72+
$this->assertSame('Tom and Jerry', Str::apa('tom and jerry'));
73+
$this->assertSame('Tom and Jerry', Str::apa('TOM AND JERRY'));
74+
$this->assertSame('Tom and Jerry', Str::apa('Tom And Jerry'));
75+
76+
$this->assertSame('Back to the Future', Str::apa('back to the future'));
77+
$this->assertSame('Back to the Future', Str::apa('BACK TO THE FUTURE'));
78+
$this->assertSame('Back to the Future', Str::apa('Back To The Future'));
79+
80+
$this->assertSame('This, Then That', Str::apa('this, then that'));
81+
$this->assertSame('This, Then That', Str::apa('THIS, THEN THAT'));
82+
$this->assertSame('This, Then That', Str::apa('This, Then That'));
83+
84+
$this->assertSame('Bond. James Bond.', Str::apa('bond. james bond.'));
85+
$this->assertSame('Bond. James Bond.', Str::apa('BOND. JAMES BOND.'));
86+
$this->assertSame('Bond. James Bond.', Str::apa('Bond. James Bond.'));
87+
88+
$this->assertSame('Self-Report', Str::apa('self-report'));
89+
$this->assertSame('Self-Report', Str::apa('Self-report'));
90+
$this->assertSame('Self-Report', Str::apa('SELF-REPORT'));
91+
92+
$this->assertSame('As the World Turns, So Are the Days of Our Lives', Str::apa('as the world turns, so are the days of our lives'));
93+
$this->assertSame('As the World Turns, So Are the Days of Our Lives', Str::apa('AS THE WORLD TURNS, SO ARE THE DAYS OF OUR LIVES'));
94+
$this->assertSame('As the World Turns, So Are the Days of Our Lives', Str::apa('As The World Turns, So Are The Days Of Our Lives'));
95+
96+
$this->assertSame('To Kill a Mockingbird', Str::apa('to kill a mockingbird'));
97+
$this->assertSame('To Kill a Mockingbird', Str::apa('TO KILL A MOCKINGBIRD'));
98+
$this->assertSame('To Kill a Mockingbird', Str::apa('To Kill A Mockingbird'));
99+
}
100+
70101
public function testStringWithoutWordsDoesntProduceError()
71102
{
72103
$nbsp = chr(0xC2).chr(0xA0);

0 commit comments

Comments
 (0)