snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
226
tools/setup/emoji/generate_emoji_names_table
Executable file
226
tools/setup/emoji/generate_emoji_names_table
Executable file
@@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# This is a debugging tool that takes as input a bunch of different
|
||||
# emoji data sources, and outputs a convenient HTML table that can be
|
||||
# used to sanity-check the differences between these different data
|
||||
# sources' decisions about what names to provide to each Unicode
|
||||
# codepoint.
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import orjson
|
||||
|
||||
TOOLS_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
ZULIP_PATH = os.path.dirname(TOOLS_DIR)
|
||||
sys.path.append(ZULIP_PATH)
|
||||
|
||||
from tools.setup.emoji.emoji_names import EMOJI_NAME_MAPS
|
||||
from tools.setup.emoji.emoji_setup_utils import emoji_is_supported, get_emoji_code
|
||||
|
||||
UNIFIED_REACTIONS_FILE = os.path.join(
|
||||
ZULIP_PATH, "zerver", "management", "data", "unified_reactions.json"
|
||||
)
|
||||
EMOJI_DATA_FILE = os.path.join(ZULIP_PATH, "node_modules", "emoji-datasource-google", "emoji.json")
|
||||
EMOJI_CACHE = os.path.join(ZULIP_PATH, "static", "generated", "emoji")
|
||||
OUTPUT_FILE = os.path.join(EMOJI_CACHE, "emoji_names_table.html")
|
||||
|
||||
# Emoji sets that we currently support.
|
||||
EMOJISETS = ["google", "twitter"]
|
||||
|
||||
with open(EMOJI_DATA_FILE, "rb") as fp:
|
||||
EMOJI_DATA = orjson.loads(fp.read())
|
||||
with open(UNIFIED_REACTIONS_FILE, "rb") as fp:
|
||||
UNIFIED_REACTIONS_MAP = orjson.loads(fp.read())
|
||||
|
||||
EMOJI_IMAGE_TEMPLATE = """
|
||||
<img class="emoji" src="images-{emojiset}-64/{emoji_code}.png" title={emojiset}>
|
||||
"""
|
||||
|
||||
TABLE_ROW_TEMPLATE = """
|
||||
<tr>
|
||||
<td class="new-sorting-info">{sorting_info}</td>
|
||||
<td class="emoji-code">{emoji_code}</td>
|
||||
<td class="emoji-images">{images_html}</td>
|
||||
<td class="zulip-emoji-names">{zulip_names}</td>
|
||||
<td class="iamcal-emoji-names">{iamcal_names}</td>
|
||||
<td class="gemoji-emoji-names">{gemoji_names}</td>
|
||||
<td class="unicode-name">{unicode_name}</td>
|
||||
</tr>
|
||||
"""
|
||||
|
||||
EMOJI_LISTING_TEMPLATE = """
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
{table_css}
|
||||
</style>
|
||||
<title>Zulip emoji names</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="new-sorting-info">Category</th>
|
||||
<th class="emoji-code">Emoji code</th>
|
||||
<th class="emoji-images">Images</th>
|
||||
<th class="zulip-emoji-names">Zulip</th>
|
||||
<th class="iamcal-emoji-names">Iamcal (Slack)</th>
|
||||
<th class="gemoji-emoji-names">Gemoji (unordered)</th>
|
||||
<th class="unicode-name">Unicode</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tbody}
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
TABLE_CSS = """
|
||||
.emoji {
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
position: relative;
|
||||
margin-top: -7px;
|
||||
vertical-align: middle;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.emoji-images {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
table, td, th {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td, th {
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.google {
|
||||
background-image: url('sheet-google-64.png') !important;
|
||||
}
|
||||
|
||||
.twitter {
|
||||
background-image: url('sheet-twitter-64.png') !important;
|
||||
}
|
||||
"""
|
||||
|
||||
SORTED_CATEGORIES = [
|
||||
"Smileys & Emotion",
|
||||
"People & Body",
|
||||
"Animals & Nature",
|
||||
"Food & Drink",
|
||||
"Activities",
|
||||
"Travel & Places",
|
||||
"Objects",
|
||||
"Symbols",
|
||||
"Flags",
|
||||
"Component",
|
||||
]
|
||||
|
||||
emoji_code_to_zulip_names: dict[str, str] = {}
|
||||
emoji_code_to_iamcal_names: dict[str, str] = {}
|
||||
emoji_code_to_gemoji_names: dict[str, str] = {}
|
||||
emoji_collection: dict[str, list[dict[str, Any]]] = {category: [] for category in SORTED_CATEGORIES}
|
||||
|
||||
|
||||
def generate_emoji_code_to_emoji_names_maps() -> None:
|
||||
# Prepare gemoji names map.
|
||||
reverse_unified_reactions_map: dict[str, list[str]] = {}
|
||||
for name in UNIFIED_REACTIONS_MAP:
|
||||
emoji_code = UNIFIED_REACTIONS_MAP[name]
|
||||
if emoji_code in reverse_unified_reactions_map:
|
||||
reverse_unified_reactions_map[emoji_code].append(name)
|
||||
else:
|
||||
reverse_unified_reactions_map[emoji_code] = [name]
|
||||
|
||||
for emoji_code, names in reverse_unified_reactions_map.items():
|
||||
emoji_code_to_gemoji_names[emoji_code] = ", ".join(names)
|
||||
|
||||
# Prepare iamcal names map.
|
||||
for emoji_dict in EMOJI_DATA:
|
||||
emoji_code = get_emoji_code(emoji_dict)
|
||||
emoji_code_to_iamcal_names[emoji_code] = ", ".join(emoji_dict["short_names"])
|
||||
|
||||
# Prepare zulip names map.
|
||||
for emoji_code in EMOJI_NAME_MAPS:
|
||||
canonical_name = EMOJI_NAME_MAPS[emoji_code]["canonical_name"]
|
||||
aliases = EMOJI_NAME_MAPS[emoji_code]["aliases"]
|
||||
names = [canonical_name]
|
||||
names.extend(aliases)
|
||||
emoji_code_to_zulip_names[emoji_code] = ", ".join(names)
|
||||
|
||||
|
||||
def get_sorting_info(category: str, sort_order: int) -> str:
|
||||
return f"{category} {sort_order}"
|
||||
|
||||
|
||||
def get_images_html(emoji_code: str) -> str:
|
||||
images_html = ""
|
||||
for emojiset in EMOJISETS:
|
||||
images_html += EMOJI_IMAGE_TEMPLATE.format(
|
||||
emoji_code=emoji_code,
|
||||
emojiset=emojiset,
|
||||
)
|
||||
|
||||
return images_html
|
||||
|
||||
|
||||
def generate_emoji_collection() -> None:
|
||||
generate_emoji_code_to_emoji_names_maps()
|
||||
# Prepare `emoji_collection`.
|
||||
for emoji_dict in EMOJI_DATA:
|
||||
if not emoji_is_supported(emoji_dict):
|
||||
continue
|
||||
category = emoji_dict["category"]
|
||||
emoji_code = get_emoji_code(emoji_dict)
|
||||
sort_order = emoji_dict["sort_order"]
|
||||
emoji_collection[category].append(
|
||||
{
|
||||
"category": category,
|
||||
"emoji_code": emoji_code,
|
||||
"images_html": get_images_html(emoji_code),
|
||||
"gemoji_names": emoji_code_to_gemoji_names.get(emoji_code, ""),
|
||||
"iamcal_names": emoji_code_to_iamcal_names.get(emoji_code, ""),
|
||||
"zulip_names": emoji_code_to_zulip_names.get(emoji_code, ""),
|
||||
"unicode_name": (emoji_dict["name"] or "").lower(),
|
||||
"sort_order": sort_order,
|
||||
"sorting_info": get_sorting_info(category, sort_order),
|
||||
}
|
||||
)
|
||||
|
||||
# Sort `emoji_collection`.
|
||||
for category in SORTED_CATEGORIES:
|
||||
emoji_collection[category].sort(key=lambda x: x["sort_order"])
|
||||
|
||||
|
||||
def main() -> None:
|
||||
generate_emoji_collection()
|
||||
|
||||
tbody = ""
|
||||
for category in SORTED_CATEGORIES:
|
||||
for emoji_entry in emoji_collection[category]:
|
||||
tbody += TABLE_ROW_TEMPLATE.format(**emoji_entry)
|
||||
|
||||
with open(OUTPUT_FILE, "w") as fp:
|
||||
fp.write(
|
||||
EMOJI_LISTING_TEMPLATE.format(
|
||||
tbody=tbody,
|
||||
table_css=TABLE_CSS,
|
||||
)
|
||||
)
|
||||
|
||||
print(
|
||||
"Done! Open http://localhost:9991/static/generated/emoji/emoji_names_table.html "
|
||||
"to view(after starting the dev server)."
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user