Skip to content

Commit 220b5bc

Browse files
committed
feature symfony#54470 [Emoji] Add the "text" locale (nicolas-grekas)
This PR was merged into the 7.1 branch. Discussion ---------- [Emoji] Add the "text" locale | Q | A | ------------- | --- | Branch? | 7.1 | Bug fix? | no | New feature? | no | Deprecations? | no | Issues | - | License | MIT - Adding the "text" locale, which is a merge from slack+github+gitlab maps - Fixes the gitlab maps which were missing aliases and combined emojis - Ordering the github/gitlab/slack maps so that we can compare them - Fixing a typo - Removing a needless check that prevents listing ` '🙂‍↔' => 'head shaking horizontally',` - Simplifying the build script a bit Commits ------- 60c9176 [Emoji] Add the "text" locale
2 parents 3d81d39 + 60c9176 commit 220b5bc

File tree

134 files changed

+12306
-4073
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+12306
-4073
lines changed

src/Symfony/Component/Emoji/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ CHANGELOG
44
7.1
55
---
66

7-
* Add the component
7+
* Extract the component from symfony/intl
88
* Add the `gitlab` locale to `EmojiTransliterator`
9+
* Add the `text` locale to `EmojiTransliterator`

src/Symfony/Component/Emoji/EmojiTransliterator.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ final class EmojiTransliterator extends \Transliterator
2424
'emoji-github' => 'github-emoji',
2525
'emoji-gitlab' => 'gitlab-emoji',
2626
'emoji-slack' => 'slack-emoji',
27+
'emoji-text' => 'text-emoji',
2728
'github-emoji' => 'emoji-github',
2829
'gitlab-emoji' => 'emoji-gitlab',
2930
'slack-emoji' => 'emoji-slack',
31+
'text-emoji' => 'emoji-text',
3032
];
3133

3234
public readonly string $id;
@@ -119,7 +121,7 @@ public function transliterate(string $string, int $start = 0, int $end = -1): st
119121
}
120122

121123
// Here we rely on intl to validate the $string, $start and $end arguments
122-
// and to slice the string. Slicing is done by replacing the part if $string
124+
// and to slice the string. Slicing is done by replacing the part of $string
123125
// between $start and $end by a unique cookie that can be reliably used to
124126
// identify which part of $string should be transliterated.
125127

src/Symfony/Component/Emoji/Resources/bin/build.php

Lines changed: 67 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@
2020
$emojisCodePoints = Builder::getEmojisCodePoints();
2121
Builder::saveRules(Builder::buildRules($emojisCodePoints));
2222
Builder::saveRules(Builder::buildStripRules($emojisCodePoints));
23-
Builder::saveRules(Builder::buildGitHubRules($emojisCodePoints));
24-
Builder::saveRules(Builder::buildGitlabRules($emojisCodePoints));
25-
Builder::saveRules(Builder::buildSlackRules($emojisCodePoints));
23+
24+
$emojiMaps = ['slack', 'github', 'gitlab'];
25+
26+
foreach ($emojiMaps as $map) {
27+
$maps = Builder::{"build{$map}Maps"}($emojisCodePoints);
28+
Builder::saveRules(array_combine(["emoji-$map", "$map-emoji"], Builder::createRules($maps, true)));
29+
}
30+
31+
Builder::saveRules(Builder::buildTextRules($emojisCodePoints, $emojiMaps));
2632

2733
final class Builder
2834
{
@@ -45,10 +51,10 @@ public static function getEmojisCodePoints(): array
4551
throw new \DomainException("Could not parse line: \"$line\".");
4652
}
4753

48-
$codePoints = strtolower(trim($matches['codePoints']));
54+
$codePoints = str_replace(' ', '-', trim($matches['codePoints']));
4955
$emojisCodePoints[$codePoints] = $matches['emoji'];
5056
// We also add a version without the "Zero Width Joiner"
51-
$codePoints = str_replace('200d ', '', $codePoints);
57+
$codePoints = str_replace('-200D-', '-', $codePoints);
5258
$emojisCodePoints[$codePoints] = $matches['emoji'];
5359
}
5460

@@ -67,7 +73,6 @@ public static function buildRules(array $emojisCodePoints): Generator
6773
->name('*.xml')
6874
;
6975

70-
$ignored = [];
7176
$mapsByLocale = [];
7277

7378
foreach ($files as $file) {
@@ -89,16 +94,8 @@ public static function buildRules(array $emojisCodePoints): Generator
8994
continue;
9095
}
9196
$parts = preg_split('//u', $emoji, -1, \PREG_SPLIT_NO_EMPTY);
92-
$emojiCodePoints = implode(' ', array_map('dechex', array_map('mb_ord', $parts)));
97+
$emojiCodePoints = strtoupper(implode('-', array_map('dechex', array_map('mb_ord', $parts))));
9398
if (!array_key_exists($emojiCodePoints, $emojisCodePoints)) {
94-
$ignored[] = [
95-
'locale' => $locale,
96-
'emoji' => $emoji,
97-
'name' => $name,
98-
];
99-
continue;
100-
}
101-
if (!self::testEmoji($emoji, $locale, $emojiCodePoints)) {
10299
continue;
103100
}
104101
$codePointsCount = mb_strlen($emoji);
@@ -128,108 +125,83 @@ public static function buildRules(array $emojisCodePoints): Generator
128125
}
129126
}
130127

131-
public static function buildGitHubRules(array $emojisCodePoints): iterable
128+
public static function buildGitHubMaps(array $emojisCodePoints): array
132129
{
133130
$emojis = json_decode((new Filesystem())->readFile(__DIR__.'/vendor/github-emojis.json'), true, flags: JSON_THROW_ON_ERROR);
134-
135-
$ignored = [];
136131
$maps = [];
137132

138133
foreach ($emojis as $shortCode => $url) {
139-
$emojiCodePoints = str_replace('-', ' ', strtolower(basename(parse_url($url, \PHP_URL_PATH), '.png')));
134+
$emojiCodePoints = strtoupper(basename(parse_url($url, \PHP_URL_PATH), '.png'));
135+
140136
if (!array_key_exists($emojiCodePoints, $emojisCodePoints)) {
141-
$ignored[] = [
142-
'emojiCodePoints' => $emojiCodePoints,
143-
'shortCode' => $shortCode,
144-
];
145137
continue;
146138
}
147139
$emoji = $emojisCodePoints[$emojiCodePoints];
148-
if (!self::testEmoji($emoji, 'github', $emojiCodePoints)) {
149-
continue;
150-
}
151-
$codePointsCount = mb_strlen($emoji);
152-
$maps[$codePointsCount][$emoji] = ":$shortCode:";
140+
$emojiPriority = mb_strlen($emoji) << 1;
141+
$maps[$emojiPriority + 1][":$shortCode:"] = $emoji;
153142
}
154143

155-
$maps = self::createRules($maps);
156-
157-
return ['emoji-github' => $maps, 'github-emoji' => array_flip($maps)];
144+
return $maps;
158145
}
159146

160-
public static function buildGitlabRules(array $emojisCodePoints): iterable
147+
public static function buildGitlabMaps(array $emojisCodePoints): array
161148
{
162149
$emojis = json_decode((new Filesystem())->readFile(__DIR__.'/vendor/gitlab-emojis.json'), true, flags: JSON_THROW_ON_ERROR);
163-
164-
$ignored = [];
165150
$maps = [];
166151

167152
foreach ($emojis as $emojiItem) {
168-
$emojiCodePoints = strtolower($emojiItem['unicode']);
169-
if (!array_key_exists($emojiCodePoints, $emojisCodePoints)) {
170-
$ignored[] = [
171-
'emojiCodePoints' => $emojiCodePoints,
172-
'name' => $emojiItem['name'],
173-
];
174-
continue;
175-
}
176-
$emoji = $emojisCodePoints[$emojiCodePoints];
177-
if (!self::testEmoji($emoji, 'gitlab', $emojiCodePoints)) {
178-
continue;
153+
$emoji = $emojiItem['moji'];
154+
$emojiPriority = mb_strlen($emoji) << 1;
155+
$maps[$emojiPriority + 1][$emojiItem['shortname']] = $emoji;
156+
157+
foreach ($emojiItem['aliases'] as $alias) {
158+
$maps[$emojiPriority][$alias] = $emoji;
179159
}
180-
$codePointsCount = mb_strlen($emoji);
181-
$maps[$codePointsCount][$emoji] = $emojiItem['shortname'];
182160
}
183161

184-
$maps = self::createRules($maps);
185-
186-
return ['emoji-gitlab' => $maps, 'gitlab-emoji' => array_flip($maps)];
162+
return $maps;
187163
}
188164

189-
public static function buildSlackRules(array $emojisCodePoints): iterable
165+
public static function buildSlackMaps(array $emojisCodePoints): array
190166
{
191167
$emojis = json_decode((new Filesystem())->readFile(__DIR__.'/vendor/slack-emojis.json'), true, flags: JSON_THROW_ON_ERROR);
192-
193-
$ignored = [];
194-
$emojiSlackMaps = [];
195-
$slackEmojiMaps = [];
168+
$maps = [];
196169

197170
foreach ($emojis as $data) {
198-
$emojiCodePoints = str_replace('-', ' ', strtolower($data['unified']));
199-
$shortCode = $data['short_name'];
200-
$shortCodes = $data['short_names'];
201-
$shortCodes = array_map(fn ($v) => ":$v:", $shortCodes);
171+
$emoji = $emojisCodePoints[$data['unified']];
172+
$emojiPriority = mb_strlen($emoji) << 1;
173+
$maps[$emojiPriority + 1][":{$data['short_name']}:"] = $emoji;
202174

203-
if (!array_key_exists($emojiCodePoints, $emojisCodePoints)) {
204-
$ignored[] = [
205-
'emojiCodePoints' => $emojiCodePoints,
206-
'shortCode' => $shortCode,
207-
];
208-
continue;
175+
foreach ($data['short_names'] as $shortName) {
176+
$maps[$emojiPriority][":$shortName:"] = $emoji;
209177
}
210-
$emoji = $emojisCodePoints[$emojiCodePoints];
211-
if (!self::testEmoji($emoji, 'slack', $emojiCodePoints)) {
212-
continue;
213-
}
214-
$codePointsCount = mb_strlen($emoji);
215-
$emojiSlackMaps[$codePointsCount][$emoji] = ":$shortCode:";
216-
foreach ($shortCodes as $short_name) {
217-
$slackEmojiMaps[$codePointsCount][$short_name] = $emoji;
178+
}
179+
180+
return $maps;
181+
}
182+
183+
public static function buildTextRules(array $emojiCodePoints, array $locales): iterable
184+
{
185+
$maps = [];
186+
187+
foreach ($locales as $locale) {
188+
foreach (self::{"build{$locale}Maps"}($emojiCodePoints) as $emojiPriority => $map) {
189+
foreach ($map as $text => $emoji) {
190+
$maps[$emojiPriority][str_replace('_', '-', $text)] ??= $emoji;
191+
}
218192
}
219193
}
220194

221-
return ['emoji-slack' => self::createRules($emojiSlackMaps), 'slack-emoji' => self::createRules($slackEmojiMaps)];
195+
[$map, $reverse] = self::createRules($maps, true);
196+
197+
return ['emoji-text' => $map, 'text-emoji' => $reverse];
222198
}
223199

224200
public static function buildStripRules(array $emojisCodePoints): iterable
225201
{
226202
$maps = [];
227-
foreach ($emojisCodePoints as $codePoints => $emoji) {
228-
if (!self::testEmoji($emoji, 'strip', $codePoints)) {
229-
continue;
230-
}
231-
$codePointsCount = mb_strlen($emoji);
232-
$maps[$codePointsCount][$emoji] = '';
203+
foreach ($emojisCodePoints as $emoji) {
204+
$maps[mb_strlen($emoji)][$emoji] = '';
233205
}
234206

235207
return ['emoji-strip' => self::createRules($maps)];
@@ -269,24 +241,26 @@ public static function saveRules(iterable $rulesByLocale): void
269241
$fs->dumpFile($file, preg_replace('/QUICK_CHECK = .*;/m', "QUICK_CHECK = {$quickCheck};", $fs->readFile($file)));
270242
}
271243

272-
private static function testEmoji(string $emoji, string $locale, string $codePoints): bool
244+
public static function createRules(array $maps, bool $reverse = false): array
273245
{
274-
if (!Transliterator::createFromRules("\\$emoji > test ;")) {
275-
printf('Could not create transliterator for "%s" in "%s" locale. Code Point: "%s". Error: "%s".'."\n", $emoji, $locale, $codePoints, intl_get_error_message());
246+
// We must sort the maps by the number of code points, because the order really matters:
247+
// 🫶🏼 must be before 🫶
248+
krsort($maps);
276249

277-
return false;
250+
if (!$reverse) {
251+
return array_merge(...$maps);
278252
}
279253

280-
return true;
281-
}
254+
$emojiText = $textEmoji = [];
282255

283-
private static function createRules(array $maps): array
284-
{
285-
// We must sort the maps by the number of code points, because the order really matters:
286-
// 🫶🏼 must be before 🫶
287-
krsort($maps);
288-
$maps = array_merge(...$maps);
256+
foreach ($maps as $map) {
257+
uksort($map, static fn ($a, $b) => strnatcmp(substr($a, 1, -1), substr($b, 1, -1)));
258+
$textEmoji = array_merge($map, $textEmoji);
289259

290-
return $maps;
260+
$map = array_flip($map);
261+
$emojiText += $map;
262+
}
263+
264+
return [$emojiText, $textEmoji];
291265
}
292266
}

src/Symfony/Component/Emoji/Resources/data/emoji-af.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Emoji/Resources/data/emoji-am.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Emoji/Resources/data/emoji-ar.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Emoji/Resources/data/emoji-ar_sa.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Emoji/Resources/data/emoji-as.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Emoji/Resources/data/emoji-az.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Emoji/Resources/data/emoji-be.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)