Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F53370948
D298.1774768185.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
89 KB
Referenced Files
None
Subscribers
None
D298.1774768185.diff
View Options
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -63,6 +63,8 @@
matrix-sticker-pack-list.cpp
matrix-sticker-pack-source.cpp
matrix-user-given-attrs-map.cpp
+ matrix-verification.cpp
+ matrix-verification-list.cpp
kazv-abstract-list-model.cpp
qt-promise-handler.cpp
@@ -186,6 +188,8 @@
AddStickerPopup.qml
StickerPackNameProvider.qml
ConfirmationOverlay.qml
+ VerificationsPage.qml
+ SasEmojis.qml
event-types/Simple.qml
event-types/Text.qml
event-types/Emote.qml
@@ -266,6 +270,7 @@
l10n.js
global-this.js
matrix-helpers.js
+ sas-emoji-defs.js
)
kazv_add_qml_files(kazvqmlqmlmodule
diff --git a/src/contents/ui/Main.qml b/src/contents/ui/Main.qml
--- a/src/contents/ui/Main.qml
+++ b/src/contents/ui/Main.qml
@@ -194,6 +194,15 @@
pushJoinRoomPage();
}
},
+ Kirigami.Action {
+ objectName: 'verifications'
+ enabled: root.loggedIn
+ icon.name: 'checkmark'
+ text: l10n.get('global-drawer-action-verifications')
+ onTriggered: {
+ pushVerificationsPage();
+ }
+ },
Kirigami.Action {
objectName: 'aboutAction'
text: l10n.get('global-drawer-action-about')
@@ -301,6 +310,10 @@
pageStack.layers.push(Qt.resolvedUrl("SettingsPage.qml"));
}
+ function pushVerificationsPage() {
+ pageStack.layers.push(Qt.resolvedUrl("VerificationsPage.qml"));
+ }
+
function pushCreateRoomPage() {
pageStack.layers.push(Qt.resolvedUrl("CreateRoomPage.qml"), {});
}
diff --git a/src/contents/ui/SasEmojis.qml b/src/contents/ui/SasEmojis.qml
new file mode 100644
--- /dev/null
+++ b/src/contents/ui/SasEmojis.qml
@@ -0,0 +1,25 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import org.kde.kirigami as Kirigami
+import 'sas-emoji-defs.js' as SasEmojis
+
+GridLayout {
+ required property var emojiIndices
+
+ Repeater {
+ model: emojiIndices
+ delegate: Label {
+ required property var modelData
+ text: SasEmojis.sasEmojis[modelData].emoji
+ font.family: 'emoji'
+ Component.onCompleted: console.log('emoji index', modelData)
+ }
+ }
+}
diff --git a/src/contents/ui/VerificationsPage.qml b/src/contents/ui/VerificationsPage.qml
new file mode 100644
--- /dev/null
+++ b/src/contents/ui/VerificationsPage.qml
@@ -0,0 +1,103 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import org.kde.kirigami as Kirigami
+import '.' as Kazv
+import moe.kazv.mxc.kazv as MK
+
+Kazv.ClosableScrollableOverlay {
+ id: verificationsPage
+ title: l10n.get('verifications-page-title')
+ property var verificationList: matrixSdk.verificationList()
+
+ Kirigami.CardsListView {
+ model: verificationsPage.verificationList
+ delegate: Kirigami.AbstractCard {
+ id: c
+ required property int index
+ property var verification: verificationsPage.verificationList.at(index)
+ // NOTE: never put a Layout as contentItem as it will cause binding loops
+ contentItem: Item {
+ implicitWidth: delegateLayout.implicitWidth
+ implicitHeight: delegateLayout.implicitHeight
+ ColumnLayout {
+ id: delegateLayout
+ anchors {
+ left: parent.left
+ top: parent.top
+ right: parent.right
+ // IMPORTANT: never put the bottom margin
+ }
+ Label {
+ text: `${verification.userId} ${verification.deviceId}`
+ wrapMode: Text.Wrap
+ Layout.fillWidth: true
+ }
+ Label {
+ text: c.getStateText()
+ wrapMode: Text.Wrap
+ Layout.fillWidth: true
+ }
+ Kazv.SasEmojis {
+ visible: c.verification.stateType == MK.MatrixVerification.CodeDisplayed
+ emojiIndices: c.verification.emojiIndices
+ }
+ Label {
+ visible: c.verification.stateType == MK.MatrixVerification.CodeDisplayed
+ text: c.verification.decimalCodes
+ wrapMode: Text.Wrap
+ Layout.fillWidth: true
+ }
+ RowLayout {
+ Button {
+ visible: c.verification.stateType == MK.MatrixVerification.TheyRequested
+ text: l10n.get('verification-action-ready')
+ onClicked: c.verification.ready()
+ }
+ Button {
+ visible: c.verification.stateType == MK.MatrixVerification.CodeDisplayed
+ text: l10n.get('verification-action-confirm-sas-match')
+ onClicked: c.verification.confirmSasMatch()
+ }
+ Button {
+ visible: c.verification.stateType == MK.MatrixVerification.CodeDisplayed
+ text: l10n.get('verification-action-deny-sas-match')
+ onClicked: c.verification.denySasMatch()
+ }
+ Button {
+ text: l10n.get('verification-action-cancel')
+ onClicked: c.verification.cancel()
+ }
+ }
+ }
+ }
+
+ function getStateText() {
+ switch (verification.stateType) {
+ case MK.MatrixVerification.TheyRequested:
+ return l10n.get('verification-state-they-requested');
+ case MK.MatrixVerification.Waiting:
+ return l10n.get('verification-state-waiting');
+ case MK.MatrixVerification.VerifiedThem:
+ return l10n.get('verification-state-waiting-after-verified');
+ case MK.MatrixVerification.CodeDisplayed:
+ return l10n.get('verification-state-confirm-code');
+ case MK.MatrixVerification.Done:
+ return l10n.get('verification-state-done');
+ case MK.MatrixVerification.Cancelled:
+ return l10n.get('verification-state-cancelled');
+ }
+ return '';
+ }
+ Component.onCompleted: {
+ console.log('verification:', verification.userId, verification.deviceId, verification.stateType, verification.emojiIndices, verification.decimalCodes);
+ }
+ }
+ }
+}
diff --git a/src/js/sas-emoji-defs.js b/src/js/sas-emoji-defs.js
new file mode 100644
--- /dev/null
+++ b/src/js/sas-emoji-defs.js
@@ -0,0 +1,2562 @@
+const sasEmojis = [
+ {
+ "number": 0,
+ "emoji": "🐶",
+ "description": "Dog",
+ "unicode": "U+1F436",
+ "translated_descriptions": {
+ "ar": "كلب",
+ "bg": "Куче",
+ "ca": "Gos",
+ "cs": "Pes",
+ "de": "Hund",
+ "eo": "Hundo",
+ "es": "Perro",
+ "et": "Koer",
+ "fa": "سگ",
+ "fi": "Koira",
+ "fr": "Chien",
+ "hr": "pas",
+ "hu": "Kutya",
+ "id": "Anjing",
+ "it": "Cane",
+ "ja": "犬",
+ "nb_NO": "Hund",
+ "nl": "Hond",
+ "pt": "Cão",
+ "pt_BR": "Cachorro",
+ "ru": "Собака",
+ "si": "බල්ලා",
+ "sk": "Pes",
+ "sq": "Qen",
+ "sr": "пас",
+ "sv": "Hund",
+ "szl": null,
+ "tzm": "Aydi",
+ "uk": "Пес",
+ "vi": "Chó",
+ "zh_Hans": "狗",
+ "zh_Hant": "狗"
+ }
+ },
+ {
+ "number": 1,
+ "emoji": "🐱",
+ "description": "Cat",
+ "unicode": "U+1F431",
+ "translated_descriptions": {
+ "ar": "هِرَّة",
+ "bg": "Котка",
+ "ca": "Gat",
+ "cs": "Kočka",
+ "de": "Katze",
+ "eo": "Kato",
+ "es": "Gato",
+ "et": "Kass",
+ "fa": "گربه",
+ "fi": "Kissa",
+ "fr": "Chat",
+ "hr": "mačka",
+ "hu": "Macska",
+ "id": "Kucing",
+ "it": "Gatto",
+ "ja": "猫",
+ "nb_NO": "Katt",
+ "nl": "Kat",
+ "pt": "Gato",
+ "pt_BR": "Gato",
+ "ru": "Кошка",
+ "si": "පූසා",
+ "sk": "Mačka",
+ "sq": "Mace",
+ "sr": "мачка",
+ "sv": "Katt",
+ "szl": null,
+ "tzm": "Amuc",
+ "uk": "Кіт",
+ "vi": "Mèo",
+ "zh_Hans": "猫",
+ "zh_Hant": "貓"
+ }
+ },
+ {
+ "number": 2,
+ "emoji": "🦁",
+ "description": "Lion",
+ "unicode": "U+1F981",
+ "translated_descriptions": {
+ "ar": "أَسَد",
+ "bg": "Лъв",
+ "ca": "Lleó",
+ "cs": "Lev",
+ "de": "Löwe",
+ "eo": "Leono",
+ "es": "León",
+ "et": "Lõvi",
+ "fa": "شیر",
+ "fi": "Leijona",
+ "fr": "Lion",
+ "hr": "lav",
+ "hu": "Oroszlán",
+ "id": "Singa",
+ "it": "Leone",
+ "ja": "ライオン",
+ "nb_NO": "Løve",
+ "nl": "Leeuw",
+ "pt": "Leão",
+ "pt_BR": "Leão",
+ "ru": "Лев",
+ "si": "සිංහයා",
+ "sk": "Lev",
+ "sq": "Luan",
+ "sr": "лав",
+ "sv": "Lejon",
+ "szl": null,
+ "tzm": "Izem",
+ "uk": "Лев",
+ "vi": "Sư tử",
+ "zh_Hans": "狮子",
+ "zh_Hant": "獅子"
+ }
+ },
+ {
+ "number": 3,
+ "emoji": "🐎",
+ "description": "Horse",
+ "unicode": "U+1F40E",
+ "translated_descriptions": {
+ "ar": "حِصَان",
+ "bg": "Кон",
+ "ca": "Cavall",
+ "cs": "Kůň",
+ "de": "Pferd",
+ "eo": "Ĉevalo",
+ "es": "Caballo",
+ "et": "Hobune",
+ "fa": "اسب",
+ "fi": "Hevonen",
+ "fr": "Cheval",
+ "hr": "konj",
+ "hu": "Ló",
+ "id": "Kuda",
+ "it": "Cavallo",
+ "ja": "馬",
+ "nb_NO": "Hest",
+ "nl": "Paard",
+ "pt": "Cavalo",
+ "pt_BR": "Cavalo",
+ "ru": "Лошадь",
+ "si": "අශ්වයා",
+ "sk": "Kôň",
+ "sq": "Kalë",
+ "sr": "коњ",
+ "sv": "Häst",
+ "szl": null,
+ "tzm": "Ayyis",
+ "uk": "Кінь",
+ "vi": "Ngựa",
+ "zh_Hans": "马",
+ "zh_Hant": "馬"
+ }
+ },
+ {
+ "number": 4,
+ "emoji": "🦄",
+ "description": "Unicorn",
+ "unicode": "U+1F984",
+ "translated_descriptions": {
+ "ar": "حصان وحيد القرن",
+ "bg": "Еднорог",
+ "ca": "Unicorn",
+ "cs": "Jednorožec",
+ "de": "Einhorn",
+ "eo": "Unukorno",
+ "es": "Unicornio",
+ "et": "Ükssarvik",
+ "fa": "تک شاخ",
+ "fi": "Yksisarvinen",
+ "fr": "Licorne",
+ "hr": "jednorog",
+ "hu": "Egyszarvú",
+ "id": "Unicorn",
+ "it": "Unicorno",
+ "ja": "ユニコーン",
+ "nb_NO": "Enhjørning",
+ "nl": "Eenhoorn",
+ "pt": "Unicórnio",
+ "pt_BR": "Unicórnio",
+ "ru": "Единорог",
+ "si": null,
+ "sk": "Jednorožec",
+ "sq": "Njëbrirësh",
+ "sr": "једнорог",
+ "sv": "Enhörning",
+ "szl": null,
+ "tzm": null,
+ "uk": "Єдиноріг",
+ "vi": "Kỳ lân",
+ "zh_Hans": "独角兽",
+ "zh_Hant": "獨角獸"
+ }
+ },
+ {
+ "number": 5,
+ "emoji": "🐷",
+ "description": "Pig",
+ "unicode": "U+1F437",
+ "translated_descriptions": {
+ "ar": "خِنزِير",
+ "bg": "Прасе",
+ "ca": "Porc",
+ "cs": "Prase",
+ "de": "Schwein",
+ "eo": "Porko",
+ "es": "Cerdo",
+ "et": "Siga",
+ "fa": "خوک",
+ "fi": "Sika",
+ "fr": "Cochon",
+ "hr": "svinja",
+ "hu": "Malac",
+ "id": "Babi",
+ "it": "Maiale",
+ "ja": "ブタ",
+ "nb_NO": "Gris",
+ "nl": "Varken",
+ "pt": "Porco",
+ "pt_BR": "Porco",
+ "ru": "Свинья",
+ "si": null,
+ "sk": "Prasa",
+ "sq": "Derr",
+ "sr": "прасе",
+ "sv": "Gris",
+ "szl": null,
+ "tzm": "Ilef",
+ "uk": "Свиня",
+ "vi": "Heo",
+ "zh_Hans": "猪",
+ "zh_Hant": "豬"
+ }
+ },
+ {
+ "number": 6,
+ "emoji": "🐘",
+ "description": "Elephant",
+ "unicode": "U+1F418",
+ "translated_descriptions": {
+ "ar": "فِيل",
+ "bg": "Слон",
+ "ca": "Elefant",
+ "cs": "Slon",
+ "de": "Elefant",
+ "eo": "Elefanto",
+ "es": "Elefante",
+ "et": "Elevant",
+ "fa": "فیل",
+ "fi": "Norsu",
+ "fr": "Éléphant",
+ "hr": "slon",
+ "hu": "Elefánt",
+ "id": "Gajah",
+ "it": "Elefante",
+ "ja": "ゾウ",
+ "nb_NO": "Elefant",
+ "nl": "Olifant",
+ "pt": "Elefante",
+ "pt_BR": "Elefante",
+ "ru": "Слон",
+ "si": null,
+ "sk": "Slon",
+ "sq": "Elefant",
+ "sr": "слон",
+ "sv": "Elefant",
+ "szl": null,
+ "tzm": "Ilu",
+ "uk": "Слон",
+ "vi": "Voi",
+ "zh_Hans": "大象",
+ "zh_Hant": "大象"
+ }
+ },
+ {
+ "number": 7,
+ "emoji": "🐰",
+ "description": "Rabbit",
+ "unicode": "U+1F430",
+ "translated_descriptions": {
+ "ar": "أَرنَب",
+ "bg": "Заек",
+ "ca": "Conill",
+ "cs": "Králík",
+ "de": "Hase",
+ "eo": "Kuniklo",
+ "es": "Conejo",
+ "et": "Jänes",
+ "fa": "خرگوش",
+ "fi": "Kani",
+ "fr": "Lapin",
+ "hr": "zec",
+ "hu": "Nyúl",
+ "id": "Kelinci",
+ "it": "Coniglio",
+ "ja": "うさぎ",
+ "nb_NO": "Kanin",
+ "nl": "Konijn",
+ "pt": "Coelho",
+ "pt_BR": "Coelho",
+ "ru": "Кролик",
+ "si": null,
+ "sk": "Zajac",
+ "sq": "Lepur",
+ "sr": "зец",
+ "sv": "Kanin",
+ "szl": null,
+ "tzm": "Agnin",
+ "uk": "Кріль",
+ "vi": "Thỏ",
+ "zh_Hans": "兔子",
+ "zh_Hant": "兔子"
+ }
+ },
+ {
+ "number": 8,
+ "emoji": "🐼",
+ "description": "Panda",
+ "unicode": "U+1F43C",
+ "translated_descriptions": {
+ "ar": "باندَا",
+ "bg": "Панда",
+ "ca": "Panda",
+ "cs": "Panda",
+ "de": "Panda",
+ "eo": "Pando",
+ "es": "Panda",
+ "et": "Panda",
+ "fa": "پاندا",
+ "fi": "Panda",
+ "fr": "Panda",
+ "hr": "panda",
+ "hu": "Panda",
+ "id": "Panda",
+ "it": "Panda",
+ "ja": "パンダ",
+ "nb_NO": "Panda",
+ "nl": "Panda",
+ "pt": "Panda",
+ "pt_BR": "Panda",
+ "ru": "Панда",
+ "si": null,
+ "sk": "Panda",
+ "sq": "Panda",
+ "sr": "панда",
+ "sv": "Panda",
+ "szl": null,
+ "tzm": null,
+ "uk": "Панда",
+ "vi": "Gấu trúc",
+ "zh_Hans": "熊猫",
+ "zh_Hant": "熊貓"
+ }
+ },
+ {
+ "number": 9,
+ "emoji": "🐓",
+ "description": "Rooster",
+ "unicode": "U+1F413",
+ "translated_descriptions": {
+ "ar": "دِيك",
+ "bg": "Петел",
+ "ca": "Gall",
+ "cs": "Kohout",
+ "de": "Hahn",
+ "eo": "Virkoko",
+ "es": "Gallo",
+ "et": "Kukk",
+ "fa": "خروس",
+ "fi": "Kukko",
+ "fr": "Coq",
+ "hr": "kokot",
+ "hu": "Kakas",
+ "id": "Ayam",
+ "it": "Gallo",
+ "ja": "ニワトリ",
+ "nb_NO": "Hane",
+ "nl": "Haan",
+ "pt": "Galo",
+ "pt_BR": "Galo",
+ "ru": "Петух",
+ "si": null,
+ "sk": "Kohút",
+ "sq": "Këndes",
+ "sr": "петао",
+ "sv": "Tupp",
+ "szl": null,
+ "tzm": "Ayaẓiḍ",
+ "uk": "Когут",
+ "vi": "Gà trống",
+ "zh_Hans": "公鸡",
+ "zh_Hant": "公雞"
+ }
+ },
+ {
+ "number": 10,
+ "emoji": "🐧",
+ "description": "Penguin",
+ "unicode": "U+1F427",
+ "translated_descriptions": {
+ "ar": "بطريق",
+ "bg": "Пингвин",
+ "ca": "Pingüí",
+ "cs": "Tučňák",
+ "de": "Pinguin",
+ "eo": "Pingveno",
+ "es": "Pingüino",
+ "et": "Pingviin",
+ "fa": "پنگوئن",
+ "fi": "Pingviini",
+ "fr": "Manchot",
+ "hr": "pingvin",
+ "hu": "Pingvin",
+ "id": "Penguin",
+ "it": "Pinguino",
+ "ja": "ペンギン",
+ "nb_NO": "Pingvin",
+ "nl": "Pinguïn",
+ "pt": "Pinguim",
+ "pt_BR": "Pinguim",
+ "ru": "Пингвин",
+ "si": null,
+ "sk": "Tučniak",
+ "sq": "Pinguin",
+ "sr": "пингвин",
+ "sv": "Pingvin",
+ "szl": null,
+ "tzm": null,
+ "uk": "Пінгвін",
+ "vi": "Chim cánh cụt",
+ "zh_Hans": "企鹅",
+ "zh_Hant": "企鵝"
+ }
+ },
+ {
+ "number": 11,
+ "emoji": "🐢",
+ "description": "Turtle",
+ "unicode": "U+1F422",
+ "translated_descriptions": {
+ "ar": "سُلحفاة",
+ "bg": "Костенурка",
+ "ca": "Tortuga",
+ "cs": "Želva",
+ "de": "Schildkröte",
+ "eo": "Testudo",
+ "es": "Tortuga",
+ "et": "Kilpkonn",
+ "fa": "لاکپشت",
+ "fi": "Kilpikonna",
+ "fr": "Tortue",
+ "hr": "kornjača",
+ "hu": "Teknős",
+ "id": "Kura-Kura",
+ "it": "Tartaruga",
+ "ja": "亀",
+ "nb_NO": "Skilpadde",
+ "nl": "Schildpad",
+ "pt": "Tartaruga",
+ "pt_BR": "Tartaruga",
+ "ru": "Черепаха",
+ "si": null,
+ "sk": "Korytnačka",
+ "sq": "Breshkë",
+ "sr": "корњача",
+ "sv": "Sköldpadda",
+ "szl": null,
+ "tzm": "Ifker",
+ "uk": "Черепаха",
+ "vi": "Rùa",
+ "zh_Hans": "乌龟",
+ "zh_Hant": "烏龜"
+ }
+ },
+ {
+ "number": 12,
+ "emoji": "🐟",
+ "description": "Fish",
+ "unicode": "U+1F41F",
+ "translated_descriptions": {
+ "ar": "سَمَكة",
+ "bg": "Риба",
+ "ca": "Peix",
+ "cs": "Ryba",
+ "de": "Fisch",
+ "eo": "Fiŝo",
+ "es": "Pez",
+ "et": "Kala",
+ "fa": "ماهی",
+ "fi": "Kala",
+ "fr": "Poisson",
+ "hr": "riba",
+ "hu": "Hal",
+ "id": "Ikan",
+ "it": "Pesce",
+ "ja": "魚",
+ "nb_NO": "Fisk",
+ "nl": "Vis",
+ "pt": "Peixe",
+ "pt_BR": "Peixe",
+ "ru": "Рыба",
+ "si": null,
+ "sk": "Ryba",
+ "sq": "Peshk",
+ "sr": "риба",
+ "sv": "Fisk",
+ "szl": null,
+ "tzm": "Aselm",
+ "uk": "Риба",
+ "vi": "Cá",
+ "zh_Hans": "鱼",
+ "zh_Hant": "魚"
+ }
+ },
+ {
+ "number": 13,
+ "emoji": "🐙",
+ "description": "Octopus",
+ "unicode": "U+1F419",
+ "translated_descriptions": {
+ "ar": "أُخطُبُوط",
+ "bg": "Октопод",
+ "ca": "Pop",
+ "cs": "Chobotnice",
+ "de": "Oktopus",
+ "eo": "Polpo",
+ "es": "Pulpo",
+ "et": "Kaheksajalg",
+ "fa": "اختاپوس",
+ "fi": "Tursas",
+ "fr": "Poulpe",
+ "hr": "hobotnica",
+ "hu": "Polip",
+ "id": "Gurita",
+ "it": "Polpo",
+ "ja": "たこ",
+ "nb_NO": "Blekksprut",
+ "nl": "Octopus",
+ "pt": "Polvo",
+ "pt_BR": "Polvo",
+ "ru": "Осьминог",
+ "si": null,
+ "sk": "Chobotnica",
+ "sq": "Oktapod",
+ "sr": "октопод",
+ "sv": "Bläckfisk",
+ "szl": null,
+ "tzm": null,
+ "uk": "Восьминіг",
+ "vi": "Bạch tuộc",
+ "zh_Hans": "章鱼",
+ "zh_Hant": "章魚"
+ }
+ },
+ {
+ "number": 14,
+ "emoji": "🦋",
+ "description": "Butterfly",
+ "unicode": "U+1F98B",
+ "translated_descriptions": {
+ "ar": "فَرَاشَة",
+ "bg": "Пеперуда",
+ "ca": "Papallona",
+ "cs": "Motýl",
+ "de": "Schmetterling",
+ "eo": "Papilio",
+ "es": "Mariposa",
+ "et": "Liblikas",
+ "fa": "پروانه",
+ "fi": "Perhonen",
+ "fr": "Papillon",
+ "hr": "leptir",
+ "hu": "Pillangó",
+ "id": "Kupu-Kupu",
+ "it": "Farfalla",
+ "ja": "ちょうちょ",
+ "nb_NO": "Sommerfugl",
+ "nl": "Vlinder",
+ "pt": "Borboleta",
+ "pt_BR": "Borboleta",
+ "ru": "Бабочка",
+ "si": null,
+ "sk": "Motýľ",
+ "sq": "Flutur",
+ "sr": "лептир",
+ "sv": "Fjäril",
+ "szl": null,
+ "tzm": null,
+ "uk": "Метелик",
+ "vi": "Bướm",
+ "zh_Hans": "蝴蝶",
+ "zh_Hant": "蝴蝶"
+ }
+ },
+ {
+ "number": 15,
+ "emoji": "🌷",
+ "description": "Flower",
+ "unicode": "U+1F337",
+ "translated_descriptions": {
+ "ar": "زَهرَة",
+ "bg": "Цвете",
+ "ca": "Flor",
+ "cs": "Květina",
+ "de": "Blume",
+ "eo": "Floro",
+ "es": "Flor",
+ "et": "Lill",
+ "fa": "گل",
+ "fi": "Kukka",
+ "fr": "Fleur",
+ "hr": "svijet",
+ "hu": "Virág",
+ "id": "Bunga",
+ "it": "Fiore",
+ "ja": "花",
+ "nb_NO": "Blomst",
+ "nl": "Bloem",
+ "pt": "Flor",
+ "pt_BR": "Flor",
+ "ru": "Цветок",
+ "si": null,
+ "sk": "Kvet",
+ "sq": "Lule",
+ "sr": "цвет",
+ "sv": "Blomma",
+ "szl": null,
+ "tzm": null,
+ "uk": "Квітка",
+ "vi": "Hoa",
+ "zh_Hans": "花",
+ "zh_Hant": "花"
+ }
+ },
+ {
+ "number": 16,
+ "emoji": "🌳",
+ "description": "Tree",
+ "unicode": "U+1F333",
+ "translated_descriptions": {
+ "ar": "شَجَرَة",
+ "bg": "Дърво",
+ "ca": "Arbre",
+ "cs": "Strom",
+ "de": "Baum",
+ "eo": "Arbo",
+ "es": "Árbol",
+ "et": "Puu",
+ "fa": "درخت",
+ "fi": "Puu",
+ "fr": "Arbre",
+ "hr": "drvo",
+ "hu": "Fa",
+ "id": "Pohon",
+ "it": "Albero",
+ "ja": "木",
+ "nb_NO": "Tre",
+ "nl": "Boom",
+ "pt": "Árvore",
+ "pt_BR": "Árvore",
+ "ru": "Дерево",
+ "si": null,
+ "sk": "Strom",
+ "sq": "Pemë",
+ "sr": "дрво",
+ "sv": "Träd",
+ "szl": null,
+ "tzm": "Aseklu",
+ "uk": "Дерево",
+ "vi": "Cây",
+ "zh_Hans": "树",
+ "zh_Hant": "樹"
+ }
+ },
+ {
+ "number": 17,
+ "emoji": "🌵",
+ "description": "Cactus",
+ "unicode": "U+1F335",
+ "translated_descriptions": {
+ "ar": "صبار",
+ "bg": "Кактус",
+ "ca": "Cactus",
+ "cs": "Kaktus",
+ "de": "Kaktus",
+ "eo": "Kakto",
+ "es": "Cactus",
+ "et": "Kaktus",
+ "fa": "کاکتوس",
+ "fi": "Kaktus",
+ "fr": "Cactus",
+ "hr": "kaktus",
+ "hu": "Kaktusz",
+ "id": "Kaktus",
+ "it": "Cactus",
+ "ja": "サボテン",
+ "nb_NO": "Kaktus",
+ "nl": "Cactus",
+ "pt": "Cato",
+ "pt_BR": "Cacto",
+ "ru": "Кактус",
+ "si": null,
+ "sk": "Kaktus",
+ "sq": "Kaktus",
+ "sr": "кактус",
+ "sv": "Kaktus",
+ "szl": null,
+ "tzm": null,
+ "uk": "Кактус",
+ "vi": "Xương rồng",
+ "zh_Hans": "仙人掌",
+ "zh_Hant": "仙人掌"
+ }
+ },
+ {
+ "number": 18,
+ "emoji": "🍄",
+ "description": "Mushroom",
+ "unicode": "U+1F344",
+ "translated_descriptions": {
+ "ar": "فُطر",
+ "bg": "Гъба",
+ "ca": "Bolet",
+ "cs": "Houba",
+ "de": "Pilz",
+ "eo": "Fungo",
+ "es": "Seta",
+ "et": "Seen",
+ "fa": "قارچ",
+ "fi": "Sieni",
+ "fr": "Champignon",
+ "hr": "gljiva",
+ "hu": "Gomba",
+ "id": "Jamur",
+ "it": "Fungo",
+ "ja": "きのこ",
+ "nb_NO": "Sopp",
+ "nl": "Paddenstoel",
+ "pt": "Cogumelo",
+ "pt_BR": "Cogumelo",
+ "ru": "Гриб",
+ "si": null,
+ "sk": "Huba",
+ "sq": "Kërpudhë",
+ "sr": "печурка",
+ "sv": "Svamp",
+ "szl": null,
+ "tzm": "Agursel",
+ "uk": "Гриб",
+ "vi": "Nấm",
+ "zh_Hans": "蘑菇",
+ "zh_Hant": "蘑菇"
+ }
+ },
+ {
+ "number": 19,
+ "emoji": "🌏",
+ "description": "Globe",
+ "unicode": "U+1F30F",
+ "translated_descriptions": {
+ "ar": "كُرَةٌ أرضِيَّة",
+ "bg": "Глобус",
+ "ca": "Globus terraqüi",
+ "cs": "Zeměkoule",
+ "de": "Globus",
+ "eo": "Globo",
+ "es": "Globo",
+ "et": "Maakera",
+ "fa": "زمین",
+ "fi": "Maapallo",
+ "fr": "Globe",
+ "hr": "Globus",
+ "hu": "Földgömb",
+ "id": "Bola Dunia",
+ "it": "Globo",
+ "ja": "地球",
+ "nb_NO": "Globus",
+ "nl": "Wereldbol",
+ "pt": "Globo",
+ "pt_BR": "Globo",
+ "ru": "Глобус",
+ "si": null,
+ "sk": "Zemeguľa",
+ "sq": "Rruzull",
+ "sr": "глобус",
+ "sv": "Jordklot",
+ "szl": null,
+ "tzm": null,
+ "uk": "Глобус",
+ "vi": "Địa cầu",
+ "zh_Hans": "地球",
+ "zh_Hant": "地球"
+ }
+ },
+ {
+ "number": 20,
+ "emoji": "🌙",
+ "description": "Moon",
+ "unicode": "U+1F319",
+ "translated_descriptions": {
+ "ar": "قَمَر",
+ "bg": "Луна",
+ "ca": "Lluna",
+ "cs": "Měsíc",
+ "de": "Mond",
+ "eo": "Luno",
+ "es": "Luna",
+ "et": "Kuu",
+ "fa": "ماه",
+ "fi": "Kuu",
+ "fr": "Lune",
+ "hr": "mjesec",
+ "hu": "Hold",
+ "id": "Bulan",
+ "it": "Luna",
+ "ja": "月",
+ "nb_NO": "Måne",
+ "nl": "Maan",
+ "pt": "Lua",
+ "pt_BR": "Lua",
+ "ru": "Луна",
+ "si": null,
+ "sk": "Mesiac",
+ "sq": "Hënë",
+ "sr": "месец",
+ "sv": "Måne",
+ "szl": null,
+ "tzm": "Ayyur",
+ "uk": "Місяць",
+ "vi": "Mặt trăng",
+ "zh_Hans": "月亮",
+ "zh_Hant": "月亮"
+ }
+ },
+ {
+ "number": 21,
+ "emoji": "☁️",
+ "description": "Cloud",
+ "unicode": "U+2601U+FE0F",
+ "translated_descriptions": {
+ "ar": "سَحابَة",
+ "bg": "Облак",
+ "ca": "Núvol",
+ "cs": "Mrak",
+ "de": "Wolke",
+ "eo": "Nubo",
+ "es": "Nube",
+ "et": "Pilv",
+ "fa": "ابر",
+ "fi": "Pilvi",
+ "fr": "Nuage",
+ "hr": "oblak",
+ "hu": "Felhő",
+ "id": "Awan",
+ "it": "Nuvola",
+ "ja": "雲",
+ "nb_NO": "Sky",
+ "nl": "Wolk",
+ "pt": "Nuvem",
+ "pt_BR": "Nuvem",
+ "ru": "Облако",
+ "si": null,
+ "sk": "Oblak",
+ "sq": "Re",
+ "sr": "облак",
+ "sv": "Moln",
+ "szl": null,
+ "tzm": null,
+ "uk": "Хмара",
+ "vi": "Mây",
+ "zh_Hans": "云",
+ "zh_Hant": "雲朵"
+ }
+ },
+ {
+ "number": 22,
+ "emoji": "🔥",
+ "description": "Fire",
+ "unicode": "U+1F525",
+ "translated_descriptions": {
+ "ar": "نار",
+ "bg": "Огън",
+ "ca": "Foc",
+ "cs": "Oheň",
+ "de": "Feuer",
+ "eo": "Fajro",
+ "es": "Fuego",
+ "et": "Tuli",
+ "fa": "آتش",
+ "fi": "Tuli",
+ "fr": "Feu",
+ "hr": "vatra",
+ "hu": "Tűz",
+ "id": "Api",
+ "it": "Fuoco",
+ "ja": "炎",
+ "nb_NO": "Flamme",
+ "nl": "Vuur",
+ "pt": "Fogo",
+ "pt_BR": "Fogo",
+ "ru": "Огонь",
+ "si": null,
+ "sk": "Oheň",
+ "sq": "Zjarr",
+ "sr": "ватра",
+ "sv": "Eld",
+ "szl": null,
+ "tzm": "Timessi",
+ "uk": "Вогонь",
+ "vi": "Lửa",
+ "zh_Hans": "火",
+ "zh_Hant": "火"
+ }
+ },
+ {
+ "number": 23,
+ "emoji": "🍌",
+ "description": "Banana",
+ "unicode": "U+1F34C",
+ "translated_descriptions": {
+ "ar": "مَوزَة",
+ "bg": "Банан",
+ "ca": "Plàtan",
+ "cs": "Banán",
+ "de": "Banane",
+ "eo": "Banano",
+ "es": "Plátano",
+ "et": "Banaan",
+ "fa": "موز",
+ "fi": "Banaani",
+ "fr": "Banane",
+ "hr": "banana",
+ "hu": "Banán",
+ "id": "Pisang",
+ "it": "Banana",
+ "ja": "バナナ",
+ "nb_NO": "Banan",
+ "nl": "Banaan",
+ "pt": "Banana",
+ "pt_BR": "Banana",
+ "ru": "Банан",
+ "si": null,
+ "sk": "Banán",
+ "sq": "Banane",
+ "sr": "банана",
+ "sv": "Banan",
+ "szl": null,
+ "tzm": "Tabanant",
+ "uk": "Банан",
+ "vi": "Chuối",
+ "zh_Hans": "香蕉",
+ "zh_Hant": "香蕉"
+ }
+ },
+ {
+ "number": 24,
+ "emoji": "🍎",
+ "description": "Apple",
+ "unicode": "U+1F34E",
+ "translated_descriptions": {
+ "ar": "تُفَّاحَة",
+ "bg": "Ябълка",
+ "ca": "Poma",
+ "cs": "Jablko",
+ "de": "Apfel",
+ "eo": "Pomo",
+ "es": "Manzana",
+ "et": "Õun",
+ "fa": "سیب",
+ "fi": "Omena",
+ "fr": "Pomme",
+ "hr": "jabuka",
+ "hu": "Alma",
+ "id": "Apel",
+ "it": "Mela",
+ "ja": "リンゴ",
+ "nb_NO": "Eple",
+ "nl": "Appel",
+ "pt": "Maçã",
+ "pt_BR": "Maçã",
+ "ru": "Яблоко",
+ "si": null,
+ "sk": "Jablko",
+ "sq": "Mollë",
+ "sr": "јабука",
+ "sv": "Äpple",
+ "szl": null,
+ "tzm": "Tadeffuyt",
+ "uk": "Яблуко",
+ "vi": "Táo",
+ "zh_Hans": "苹果",
+ "zh_Hant": "蘋果"
+ }
+ },
+ {
+ "number": 25,
+ "emoji": "🍓",
+ "description": "Strawberry",
+ "unicode": "U+1F353",
+ "translated_descriptions": {
+ "ar": "فَراوِلَة",
+ "bg": "Ягода",
+ "ca": "Maduixa",
+ "cs": "Jahoda",
+ "de": "Erdbeere",
+ "eo": "Frago",
+ "es": "Fresa",
+ "et": "Maasikas",
+ "fa": "توت فرنگی",
+ "fi": "Mansikka",
+ "fr": "Fraise",
+ "hr": "jagoda",
+ "hu": "Eper",
+ "id": "Stroberi",
+ "it": "Fragola",
+ "ja": "いちご",
+ "nb_NO": "Jordbær",
+ "nl": "Aardbei",
+ "pt": "Morango",
+ "pt_BR": "Morango",
+ "ru": "Клубника",
+ "si": null,
+ "sk": "Jahoda",
+ "sq": "Luleshtrydhe",
+ "sr": "јагода",
+ "sv": "Jordgubbe",
+ "szl": null,
+ "tzm": null,
+ "uk": "Полуниця",
+ "vi": "Dâu tây",
+ "zh_Hans": "草莓",
+ "zh_Hant": "草莓"
+ }
+ },
+ {
+ "number": 26,
+ "emoji": "🌽",
+ "description": "Corn",
+ "unicode": "U+1F33D",
+ "translated_descriptions": {
+ "ar": "ذُرَة",
+ "bg": "Царевица",
+ "ca": "Blat de moro",
+ "cs": "Kukuřice",
+ "de": "Mais",
+ "eo": "Maizo",
+ "es": "Maíz",
+ "et": "Mais",
+ "fa": "ذرت",
+ "fi": "Maissi",
+ "fr": "Maïs",
+ "hr": "kukuruza",
+ "hu": "Kukorica",
+ "id": "Jagung",
+ "it": "Mais",
+ "ja": "とうもろこし",
+ "nb_NO": "Mais",
+ "nl": "Maïs",
+ "pt": "Milho",
+ "pt_BR": "Milho",
+ "ru": "Кукуруза",
+ "si": null,
+ "sk": "Kukurica",
+ "sq": "Misër",
+ "sr": "кукуруз",
+ "sv": "Majs",
+ "szl": null,
+ "tzm": null,
+ "uk": "Кукурудза",
+ "vi": "Bắp",
+ "zh_Hans": "玉米",
+ "zh_Hant": "玉米"
+ }
+ },
+ {
+ "number": 27,
+ "emoji": "🍕",
+ "description": "Pizza",
+ "unicode": "U+1F355",
+ "translated_descriptions": {
+ "ar": "بِيتزا",
+ "bg": "Пица",
+ "ca": "Pizza",
+ "cs": "Pizza",
+ "de": "Pizza",
+ "eo": "Pico",
+ "es": "Pizza",
+ "et": "Pitsa",
+ "fa": "پیتزا",
+ "fi": "Pizza",
+ "fr": "Pizza",
+ "hr": "pizza",
+ "hu": "Pizza",
+ "id": "Pizza",
+ "it": "Pizza",
+ "ja": "ピザ",
+ "nb_NO": "Pizza",
+ "nl": "Pizza",
+ "pt": "Piza",
+ "pt_BR": "Pizza",
+ "ru": "Пицца",
+ "si": null,
+ "sk": "Pizza",
+ "sq": "Picë",
+ "sr": "пица",
+ "sv": "Pizza",
+ "szl": null,
+ "tzm": null,
+ "uk": "Піца",
+ "vi": "Pizza",
+ "zh_Hans": "披萨",
+ "zh_Hant": "披薩"
+ }
+ },
+ {
+ "number": 28,
+ "emoji": "🎂",
+ "description": "Cake",
+ "unicode": "U+1F382",
+ "translated_descriptions": {
+ "ar": "كَعكَة",
+ "bg": "Торта",
+ "ca": "Pastís",
+ "cs": "Dort",
+ "de": "Kuchen",
+ "eo": "Torto",
+ "es": "Tarta",
+ "et": "Kook",
+ "fa": "کیک",
+ "fi": "Kakku",
+ "fr": "Gâteau",
+ "hr": "torta",
+ "hu": "Süti",
+ "id": "Kue",
+ "it": "Torta",
+ "ja": "ケーキ",
+ "nb_NO": "Kake",
+ "nl": "Taart",
+ "pt": "Bolo",
+ "pt_BR": "Bolo",
+ "ru": "Торт",
+ "si": null,
+ "sk": "Torta",
+ "sq": "Tortë",
+ "sr": "торта",
+ "sv": "Tårta",
+ "szl": null,
+ "tzm": null,
+ "uk": "Пиріг",
+ "vi": "Bánh",
+ "zh_Hans": "蛋糕",
+ "zh_Hant": "蛋糕"
+ }
+ },
+ {
+ "number": 29,
+ "emoji": "❤️",
+ "description": "Heart",
+ "unicode": "U+2764U+FE0F",
+ "translated_descriptions": {
+ "ar": "قَلب",
+ "bg": "Сърце",
+ "ca": "Cor",
+ "cs": "Srdce",
+ "de": "Herz",
+ "eo": "Koro",
+ "es": "Corazón",
+ "et": "Süda",
+ "fa": "قلب",
+ "fi": "Sydän",
+ "fr": "Cœur",
+ "hr": "srca",
+ "hu": "Szív",
+ "id": "Hati",
+ "it": "Cuore",
+ "ja": "ハート",
+ "nb_NO": "Hjerte",
+ "nl": "Hart",
+ "pt": "Coração",
+ "pt_BR": "Coração",
+ "ru": "Сердце",
+ "si": null,
+ "sk": "Srdce",
+ "sq": "Zemër",
+ "sr": "срце",
+ "sv": "Hjärta",
+ "szl": null,
+ "tzm": "Ul",
+ "uk": "Серце",
+ "vi": "Tim",
+ "zh_Hans": "心",
+ "zh_Hant": "愛心"
+ }
+ },
+ {
+ "number": 30,
+ "emoji": "😀",
+ "description": "Smiley",
+ "unicode": "U+1F600",
+ "translated_descriptions": {
+ "ar": "اِبتِسَامَة",
+ "bg": "Усмивка",
+ "ca": "Somrient",
+ "cs": "Smajlík",
+ "de": "Lächeln",
+ "eo": "Rideto",
+ "es": "Emoticono",
+ "et": "Smaili",
+ "fa": "خنده",
+ "fi": "Hymynaama",
+ "fr": "Sourire",
+ "hr": "smajlića",
+ "hu": "Mosoly",
+ "id": "Senyuman",
+ "it": "Faccina sorridente",
+ "ja": "スマイル",
+ "nb_NO": "Smilefjes",
+ "nl": "Smiley",
+ "pt": "Sorriso",
+ "pt_BR": "Sorriso",
+ "ru": "Улыбка",
+ "si": null,
+ "sk": "Smajlík",
+ "sq": "Emotikon",
+ "sr": "смајли",
+ "sv": "Smiley",
+ "szl": null,
+ "tzm": null,
+ "uk": "Посмішка",
+ "vi": "Mặt cười",
+ "zh_Hans": "笑脸",
+ "zh_Hant": "笑臉"
+ }
+ },
+ {
+ "number": 31,
+ "emoji": "🤖",
+ "description": "Robot",
+ "unicode": "U+1F916",
+ "translated_descriptions": {
+ "ar": "رُوبُوت",
+ "bg": "Робот",
+ "ca": "Robot",
+ "cs": "Robot",
+ "de": "Roboter",
+ "eo": "Roboto",
+ "es": "Robot",
+ "et": "Robot",
+ "fa": "ربات",
+ "fi": "Robotti",
+ "fr": "Robot",
+ "hr": "robot",
+ "hu": "Robot",
+ "id": "Robot",
+ "it": "Robot",
+ "ja": "ロボット",
+ "nb_NO": "Robot",
+ "nl": "Robot",
+ "pt": "Robô",
+ "pt_BR": "Robô",
+ "ru": "Робот",
+ "si": null,
+ "sk": "Robot",
+ "sq": "Robot",
+ "sr": "робот",
+ "sv": "Robot",
+ "szl": null,
+ "tzm": "Aṛubu",
+ "uk": "Робот",
+ "vi": "Rô-bô",
+ "zh_Hans": "机器人",
+ "zh_Hant": "機器人"
+ }
+ },
+ {
+ "number": 32,
+ "emoji": "🎩",
+ "description": "Hat",
+ "unicode": "U+1F3A9",
+ "translated_descriptions": {
+ "ar": "قُبَّعَة",
+ "bg": "Шапка",
+ "ca": "Barret",
+ "cs": "Klobouk",
+ "de": "Hut",
+ "eo": "Ĉapelo",
+ "es": "Sombrero",
+ "et": "Kübar",
+ "fa": "کلاه",
+ "fi": "Hattu",
+ "fr": "Chapeau",
+ "hr": "kapa",
+ "hu": "Kalap",
+ "id": "Topi",
+ "it": "Cappello",
+ "ja": "帽子",
+ "nb_NO": "Hatt",
+ "nl": "Hoed",
+ "pt": "Chapéu",
+ "pt_BR": "Chapéu",
+ "ru": "Шляпа",
+ "si": null,
+ "sk": "Klobúk",
+ "sq": "Kapë",
+ "sr": "шешир",
+ "sv": "Hatt",
+ "szl": null,
+ "tzm": "Taraza",
+ "uk": "Капелюх",
+ "vi": "Mũ",
+ "zh_Hans": "帽子",
+ "zh_Hant": "帽子"
+ }
+ },
+ {
+ "number": 33,
+ "emoji": "👓",
+ "description": "Glasses",
+ "unicode": "U+1F453",
+ "translated_descriptions": {
+ "ar": "نَظَّارَة",
+ "bg": "Очила",
+ "ca": "Ulleres",
+ "cs": "Brýle",
+ "de": "Brille",
+ "eo": "Okulvitroj",
+ "es": "Gafas",
+ "et": "Prillid",
+ "fa": "عینک",
+ "fi": "Silmälasit",
+ "fr": "Lunettes",
+ "hr": "naočale",
+ "hu": "Szemüveg",
+ "id": "Kacamata",
+ "it": "Occhiali",
+ "ja": "めがね",
+ "nb_NO": "Briller",
+ "nl": "Bril",
+ "pt": "Óculos",
+ "pt_BR": "Óculos",
+ "ru": "Очки",
+ "si": null,
+ "sk": "Okuliare",
+ "sq": "Syze",
+ "sr": "наочаре",
+ "sv": "Glasögon",
+ "szl": null,
+ "tzm": null,
+ "uk": "Окуляри",
+ "vi": "Kính mắt",
+ "zh_Hans": "眼镜",
+ "zh_Hant": "眼鏡"
+ }
+ },
+ {
+ "number": 34,
+ "emoji": "🔧",
+ "description": "Spanner",
+ "unicode": "U+1F527",
+ "translated_descriptions": {
+ "ar": "مِفتَاحُ رَبط",
+ "bg": "Гаечен ключ",
+ "ca": "Clau anglesa",
+ "cs": "Klíč",
+ "de": "Schraubenschlüssel",
+ "eo": "Ŝraŭbŝlosilo",
+ "es": "Llave inglesa",
+ "et": "Mutrivõti",
+ "fa": "آچار",
+ "fi": "Kiintoavain",
+ "fr": "Clé à molette",
+ "hr": "ključ",
+ "hu": "Csavarkulcs",
+ "id": "Kunci Bengkel",
+ "it": "Chiave inglese",
+ "ja": "スパナ",
+ "nb_NO": "Fastnøkkel",
+ "nl": "Moersleutel",
+ "pt": "Chave inglesa",
+ "pt_BR": "Chave inglesa",
+ "ru": "Ключ",
+ "si": null,
+ "sk": "Vidlicový kľúč",
+ "sq": "Çelës",
+ "sr": "кључ",
+ "sv": "Skruvnyckel",
+ "szl": null,
+ "tzm": null,
+ "uk": "Гайковий ключ",
+ "vi": "Cờ-lê",
+ "zh_Hans": "扳手",
+ "zh_Hant": "扳手"
+ }
+ },
+ {
+ "number": 35,
+ "emoji": "🎅",
+ "description": "Santa",
+ "unicode": "U+1F385",
+ "translated_descriptions": {
+ "ar": "سانتا",
+ "bg": "Дядо Коледа",
+ "ca": "Pare Noél",
+ "cs": "Mikuláš",
+ "de": "Weihnachtsmann",
+ "eo": "Kristnaska viro",
+ "es": "Papá Noel",
+ "et": "Jõuluvana",
+ "fa": "بابا نوئل",
+ "fi": "Joulupukki",
+ "fr": "Père Noël",
+ "hr": "deda Mraz",
+ "hu": "Télapó",
+ "id": "Santa",
+ "it": "Babbo Natale",
+ "ja": "サンタ",
+ "nb_NO": "Julenisse",
+ "nl": "Kerstman",
+ "pt": "Pai Natal",
+ "pt_BR": "Papai-noel",
+ "ru": "Санта",
+ "si": null,
+ "sk": "Mikuláš",
+ "sq": "Babagjyshi i Vitit të Ri",
+ "sr": "деда Мраз",
+ "sv": "Tomte",
+ "szl": null,
+ "tzm": null,
+ "uk": "Санта Клаус",
+ "vi": "ông già Nô-en",
+ "zh_Hans": "圣诞老人",
+ "zh_Hant": "聖誕老人"
+ }
+ },
+ {
+ "number": 36,
+ "emoji": "👍",
+ "description": "Thumbs Up",
+ "unicode": "U+1F44D",
+ "translated_descriptions": {
+ "ar": "رَفعُ إِبهَام",
+ "bg": "Палец нагоре",
+ "ca": "Polzes amunt",
+ "cs": "Palec nahoru",
+ "de": "Daumen Hoch",
+ "eo": "Dikfingro supren",
+ "es": "Pulgar arriba",
+ "et": "Pöidlad püsti",
+ "fa": "لایک",
+ "fi": "Peukalo ylös",
+ "fr": "Pouce en l’air",
+ "hr": "palac gore",
+ "hu": "Hüvelykujj fel",
+ "id": "Jempol",
+ "it": "Pollice alzato",
+ "ja": "いいね",
+ "nb_NO": "Tommel Opp",
+ "nl": "Duim omhoog",
+ "pt": "Polegar para cima",
+ "pt_BR": "Joinha",
+ "ru": "Большой палец вверх",
+ "si": null,
+ "sk": "Palec nahor",
+ "sq": null,
+ "sr": "палчић горе",
+ "sv": "Tummen upp",
+ "szl": null,
+ "tzm": null,
+ "uk": "Великий палець вгору",
+ "vi": "Thích",
+ "zh_Hans": "赞",
+ "zh_Hant": "讚"
+ }
+ },
+ {
+ "number": 37,
+ "emoji": "☂️",
+ "description": "Umbrella",
+ "unicode": "U+2602U+FE0F",
+ "translated_descriptions": {
+ "ar": "مِظَلَّة",
+ "bg": "Чадър",
+ "ca": "Paraigües",
+ "cs": "Deštník",
+ "de": "Regenschirm",
+ "eo": "Ombrelo",
+ "es": "Paraguas",
+ "et": "Vihmavari",
+ "fa": "چتر",
+ "fi": "Sateenvarjo",
+ "fr": "Parapluie",
+ "hr": "kišobran",
+ "hu": "Esernyő",
+ "id": "Payung",
+ "it": "Ombrello",
+ "ja": "傘",
+ "nb_NO": "Paraply",
+ "nl": "Paraplu",
+ "pt": "Guarda-chuva",
+ "pt_BR": "Guarda-chuva",
+ "ru": "Зонт",
+ "si": null,
+ "sk": "Dáždnik",
+ "sq": "Ombrellë",
+ "sr": "кишобран",
+ "sv": "Paraply",
+ "szl": null,
+ "tzm": null,
+ "uk": "Парасолька",
+ "vi": "Cái ô",
+ "zh_Hans": "伞",
+ "zh_Hant": "雨傘"
+ }
+ },
+ {
+ "number": 38,
+ "emoji": "⌛",
+ "description": "Hourglass",
+ "unicode": "U+231B",
+ "translated_descriptions": {
+ "ar": "سَاعَةٌ رَملِيَّة",
+ "bg": "Пясъчен часовник",
+ "ca": "Rellotge de sorra",
+ "cs": "Přesýpací hodiny",
+ "de": "Sanduhr",
+ "eo": "Sablohorloĝo",
+ "es": "Reloj de arena",
+ "et": "Liivakell",
+ "fa": "ساعت شنی",
+ "fi": "Tiimalasi",
+ "fr": "Sablier",
+ "hr": "pješčani sat",
+ "hu": "Homokóra",
+ "id": "Jam Pasir",
+ "it": "Clessidra",
+ "ja": "砂時計",
+ "nb_NO": "Timeglass",
+ "nl": "Zandloper",
+ "pt": "Ampulheta",
+ "pt_BR": "Ampulheta",
+ "ru": "Песочные часы",
+ "si": null,
+ "sk": "Presýpacie hodiny",
+ "sq": "Klepsidër",
+ "sr": "пешчаник",
+ "sv": "Timglas",
+ "szl": null,
+ "tzm": null,
+ "uk": "Пісковий годинник",
+ "vi": "Đồng hồ cát",
+ "zh_Hans": "沙漏",
+ "zh_Hant": "沙漏"
+ }
+ },
+ {
+ "number": 39,
+ "emoji": "⏰",
+ "description": "Clock",
+ "unicode": "U+23F0",
+ "translated_descriptions": {
+ "ar": "سَاعَة",
+ "bg": "Часовник",
+ "ca": "Rellotge",
+ "cs": "Hodiny",
+ "de": "Uhr",
+ "eo": "Horloĝo",
+ "es": "Reloj",
+ "et": "Kell",
+ "fa": "ساعت",
+ "fi": "Pöytäkello",
+ "fr": "Réveil",
+ "hr": "sat",
+ "hu": "Óra",
+ "id": "Jam",
+ "it": "Orologio",
+ "ja": "時計",
+ "nb_NO": "Klokke",
+ "nl": "Wekker",
+ "pt": "Relógio",
+ "pt_BR": "Relógio",
+ "ru": "Часы",
+ "si": null,
+ "sk": "Budík",
+ "sq": "Sahat",
+ "sr": "сат",
+ "sv": "Klocka",
+ "szl": null,
+ "tzm": null,
+ "uk": "Годинник",
+ "vi": "Đồng hồ",
+ "zh_Hans": "时钟",
+ "zh_Hant": "時鐘"
+ }
+ },
+ {
+ "number": 40,
+ "emoji": "🎁",
+ "description": "Gift",
+ "unicode": "U+1F381",
+ "translated_descriptions": {
+ "ar": "هَدِيَّة",
+ "bg": "Подарък",
+ "ca": "Regal",
+ "cs": "Dárek",
+ "de": "Geschenk",
+ "eo": "Donaco",
+ "es": "Regalo",
+ "et": "Kingitus",
+ "fa": "هدیه",
+ "fi": "Lahja",
+ "fr": "Cadeau",
+ "hr": "poklon",
+ "hu": "Ajándék",
+ "id": "Kado",
+ "it": "Regalo",
+ "ja": "ギフト",
+ "nb_NO": "Gave",
+ "nl": "Geschenk",
+ "pt": "Presente",
+ "pt_BR": "Presente",
+ "ru": "Подарок",
+ "si": null,
+ "sk": "Darček",
+ "sq": "Dhuratë",
+ "sr": "поклон",
+ "sv": "Present",
+ "szl": null,
+ "tzm": null,
+ "uk": "Подарунок",
+ "vi": "Quà tặng",
+ "zh_Hans": "礼物",
+ "zh_Hant": "禮物"
+ }
+ },
+ {
+ "number": 41,
+ "emoji": "💡",
+ "description": "Light Bulb",
+ "unicode": "U+1F4A1",
+ "translated_descriptions": {
+ "ar": "مِصبَاح",
+ "bg": "Лампа",
+ "ca": "Bombeta",
+ "cs": "Žárovka",
+ "de": "Glühbirne",
+ "eo": "Lampo",
+ "es": "Bombilla",
+ "et": "Lambipirn",
+ "fa": "لامپ",
+ "fi": "Hehkulamppu",
+ "fr": "Ampoule",
+ "hr": "žarulja",
+ "hu": "Égő",
+ "id": "Bohlam Lampu",
+ "it": "Lampadina",
+ "ja": "電球",
+ "nb_NO": "Lyspære",
+ "nl": "Gloeilamp",
+ "pt": "Lâmpada",
+ "pt_BR": "Lâmpada",
+ "ru": "Лампочка",
+ "si": null,
+ "sk": "Žiarovka",
+ "sq": "Llambë",
+ "sr": "сијалица",
+ "sv": "Lampa",
+ "szl": null,
+ "tzm": null,
+ "uk": "Лампочка",
+ "vi": "Bóng đèn tròn",
+ "zh_Hans": "灯泡",
+ "zh_Hant": "燈泡"
+ }
+ },
+ {
+ "number": 42,
+ "emoji": "📕",
+ "description": "Book",
+ "unicode": "U+1F4D5",
+ "translated_descriptions": {
+ "ar": "كِتَاب",
+ "bg": "Книга",
+ "ca": "Llibre",
+ "cs": "Kniha",
+ "de": "Buch",
+ "eo": "Libro",
+ "es": "Libro",
+ "et": "Raamat",
+ "fa": "کتاب",
+ "fi": "Kirja",
+ "fr": "Livre",
+ "hr": "knjiga",
+ "hu": "Könyv",
+ "id": "Buku",
+ "it": "Libro",
+ "ja": "本",
+ "nb_NO": "Bok",
+ "nl": "Boek",
+ "pt": "Livro",
+ "pt_BR": "Livro",
+ "ru": "Книга",
+ "si": null,
+ "sk": "Kniha",
+ "sq": "Libër",
+ "sr": "књига",
+ "sv": "Bok",
+ "szl": null,
+ "tzm": "Adlis",
+ "uk": "Книга",
+ "vi": "Sách",
+ "zh_Hans": "书",
+ "zh_Hant": "書"
+ }
+ },
+ {
+ "number": 43,
+ "emoji": "✏️",
+ "description": "Pencil",
+ "unicode": "U+270FU+FE0F",
+ "translated_descriptions": {
+ "ar": "قَلَمُ رَصاص",
+ "bg": "Молив",
+ "ca": "Llapis",
+ "cs": "Tužka",
+ "de": "Bleistift",
+ "eo": "Krajono",
+ "es": "Lápiz",
+ "et": "Pliiats",
+ "fa": "مداد",
+ "fi": "Lyijykynä",
+ "fr": "Crayon",
+ "hr": "olovka",
+ "hu": "Ceruza",
+ "id": "Pensil",
+ "it": "Matita",
+ "ja": "鉛筆",
+ "nb_NO": "Blyant",
+ "nl": "Potlood",
+ "pt": "Lápis",
+ "pt_BR": "Lápis",
+ "ru": "Карандаш",
+ "si": null,
+ "sk": "Ceruzka",
+ "sq": "Laps",
+ "sr": "оловка",
+ "sv": "Penna",
+ "szl": null,
+ "tzm": null,
+ "uk": "Олівець",
+ "vi": "Viết chì",
+ "zh_Hans": "铅笔",
+ "zh_Hant": "鉛筆"
+ }
+ },
+ {
+ "number": 44,
+ "emoji": "📎",
+ "description": "Paperclip",
+ "unicode": "U+1F4CE",
+ "translated_descriptions": {
+ "ar": "مِشبَكُ وَرَق",
+ "bg": "Кламер",
+ "ca": "Clip",
+ "cs": "Sponka",
+ "de": "Büroklammer",
+ "eo": "Paperkuntenilo",
+ "es": "Clip",
+ "et": "Kirjaklamber",
+ "fa": "گیره کاغذ",
+ "fi": "Paperiliitin",
+ "fr": "Trombone",
+ "hr": "spajalica",
+ "hu": "Gémkapocs",
+ "id": "Klip Kertas",
+ "it": "Graffetta",
+ "ja": "クリップ",
+ "nb_NO": "BInders",
+ "nl": "Papierklemmetje",
+ "pt": "Clipe",
+ "pt_BR": "Clipe de papel",
+ "ru": "Скрепка",
+ "si": null,
+ "sk": "Kancelárska sponka",
+ "sq": "Kapëse",
+ "sr": "спајалица",
+ "sv": "Gem",
+ "szl": null,
+ "tzm": null,
+ "uk": "Спиначка",
+ "vi": "Kẹp giấy",
+ "zh_Hans": "回形针",
+ "zh_Hant": "迴紋針"
+ }
+ },
+ {
+ "number": 45,
+ "emoji": "✂️",
+ "description": "Scissors",
+ "unicode": "U+2702U+FE0F",
+ "translated_descriptions": {
+ "ar": "مِقَصّ",
+ "bg": "Ножици",
+ "ca": "Tisores",
+ "cs": "Nůžky",
+ "de": "Schere",
+ "eo": "Tondilo",
+ "es": "Tijeras",
+ "et": "Käärid",
+ "fa": "قیچی",
+ "fi": "Sakset",
+ "fr": "Ciseaux",
+ "hr": "škare",
+ "hu": "Olló",
+ "id": "Gunting",
+ "it": "Forbici",
+ "ja": "はさみ",
+ "nb_NO": "Saks",
+ "nl": "Schaar",
+ "pt": "Tesoura",
+ "pt_BR": "Tesoura",
+ "ru": "Ножницы",
+ "si": null,
+ "sk": "Nožnice",
+ "sq": "Gërshërë",
+ "sr": "маказе",
+ "sv": "Sax",
+ "szl": null,
+ "tzm": null,
+ "uk": "Ножиці",
+ "vi": "Cái kéo",
+ "zh_Hans": "剪刀",
+ "zh_Hant": "剪刀"
+ }
+ },
+ {
+ "number": 46,
+ "emoji": "🔒",
+ "description": "Lock",
+ "unicode": "U+1F512",
+ "translated_descriptions": {
+ "ar": "قُفل",
+ "bg": "Катинар",
+ "ca": "Cadenat",
+ "cs": "Zámek",
+ "de": "Schloss",
+ "eo": "Seruro",
+ "es": "Candado",
+ "et": "Lukk",
+ "fa": "قفل",
+ "fi": "Lukko",
+ "fr": "Cadenas",
+ "hr": "zaključati",
+ "hu": "Lakat",
+ "id": "Gembok",
+ "it": "Lucchetto",
+ "ja": "錠前",
+ "nb_NO": "Lås",
+ "nl": "Slot",
+ "pt": "Cadeado",
+ "pt_BR": "Cadeado",
+ "ru": "Замок",
+ "si": null,
+ "sk": "Zámka",
+ "sq": "Dry",
+ "sr": "катанац",
+ "sv": "Lås",
+ "szl": null,
+ "tzm": null,
+ "uk": "Замок",
+ "vi": "Ổ khóa",
+ "zh_Hans": "锁",
+ "zh_Hant": "鎖頭"
+ }
+ },
+ {
+ "number": 47,
+ "emoji": "🔑",
+ "description": "Key",
+ "unicode": "U+1F511",
+ "translated_descriptions": {
+ "ar": "مِفتَاح",
+ "bg": "Ключ",
+ "ca": "Clau",
+ "cs": "Klíč ke dveřím",
+ "de": "Schlüssel",
+ "eo": "Ŝlosilo",
+ "es": "Llave",
+ "et": "Võti",
+ "fa": "کلید",
+ "fi": "Avain",
+ "fr": "Clé",
+ "hr": "ključ",
+ "hu": "Kulcs",
+ "id": "Kunci",
+ "it": "Chiave",
+ "ja": "鍵",
+ "nb_NO": "Nøkkel",
+ "nl": "Sleutel",
+ "pt": "Chave",
+ "pt_BR": "Chave",
+ "ru": "Ключ",
+ "si": null,
+ "sk": "Kľúč",
+ "sq": "Çelës",
+ "sr": "кључ",
+ "sv": "Nyckel",
+ "szl": null,
+ "tzm": "Tasarut",
+ "uk": "Ключ",
+ "vi": "Chìa khóa",
+ "zh_Hans": "钥匙",
+ "zh_Hant": "鑰匙"
+ }
+ },
+ {
+ "number": 48,
+ "emoji": "🔨",
+ "description": "Hammer",
+ "unicode": "U+1F528",
+ "translated_descriptions": {
+ "ar": "مِطرَقَة",
+ "bg": "Чук",
+ "ca": "Martell",
+ "cs": "Kladivo",
+ "de": "Hammer",
+ "eo": "Martelo",
+ "es": "Martillo",
+ "et": "Haamer",
+ "fa": "چکش",
+ "fi": "Vasara",
+ "fr": "Marteau",
+ "hr": "čekić",
+ "hu": "Kalapács",
+ "id": "Palu",
+ "it": "Martello",
+ "ja": "金槌",
+ "nb_NO": "Hammer",
+ "nl": "Hamer",
+ "pt": "Martelo",
+ "pt_BR": "Martelo",
+ "ru": "Молоток",
+ "si": null,
+ "sk": "Kladivo",
+ "sq": "Çekiç",
+ "sr": "чекић",
+ "sv": "Hammare",
+ "szl": null,
+ "tzm": null,
+ "uk": "Молоток",
+ "vi": "Búa",
+ "zh_Hans": "锤子",
+ "zh_Hant": "鎚子"
+ }
+ },
+ {
+ "number": 49,
+ "emoji": "☎️",
+ "description": "Telephone",
+ "unicode": "U+260EU+FE0F",
+ "translated_descriptions": {
+ "ar": "تِلِفُون",
+ "bg": "Телефон",
+ "ca": "Telèfon",
+ "cs": "Telefon",
+ "de": "Telefon",
+ "eo": "Telefono",
+ "es": "Teléfono",
+ "et": "Telefon",
+ "fa": "تلفن",
+ "fi": "Puhelin",
+ "fr": "Téléphone",
+ "hr": "telefon",
+ "hu": "Telefon",
+ "id": "Telepon",
+ "it": "Telefono",
+ "ja": "電話機",
+ "nb_NO": "Telefon",
+ "nl": "Telefoon",
+ "pt": "Telefone",
+ "pt_BR": "Telefone",
+ "ru": "Телефон",
+ "si": null,
+ "sk": "Telefón",
+ "sq": "Telefon",
+ "sr": "телефон",
+ "sv": "Telefon",
+ "szl": null,
+ "tzm": "Atilifun",
+ "uk": "Телефон",
+ "vi": "Điện thoại",
+ "zh_Hans": "电话",
+ "zh_Hant": "電話"
+ }
+ },
+ {
+ "number": 50,
+ "emoji": "🏁",
+ "description": "Flag",
+ "unicode": "U+1F3C1",
+ "translated_descriptions": {
+ "ar": "عَلَم",
+ "bg": "Флаг",
+ "ca": "Bandera",
+ "cs": "Vlajka",
+ "de": "Flagge",
+ "eo": "Flago",
+ "es": "Bandera",
+ "et": "Lipp",
+ "fa": "پرچم",
+ "fi": "Lippu",
+ "fr": "Drapeau",
+ "hr": "zastava",
+ "hu": "Zászló",
+ "id": "Bendera",
+ "it": "Bandiera",
+ "ja": "旗",
+ "nb_NO": "Flagg",
+ "nl": "Vlag",
+ "pt": "Bandeira",
+ "pt_BR": "Bandeira",
+ "ru": "Флаг",
+ "si": null,
+ "sk": "Zástava",
+ "sq": "Flamur",
+ "sr": "застава",
+ "sv": "Flagga",
+ "szl": null,
+ "tzm": "Acenyal",
+ "uk": "Прапор",
+ "vi": "Lá cờ",
+ "zh_Hans": "旗帜",
+ "zh_Hant": "旗幟"
+ }
+ },
+ {
+ "number": 51,
+ "emoji": "🚂",
+ "description": "Train",
+ "unicode": "U+1F682",
+ "translated_descriptions": {
+ "ar": "قِطَار",
+ "bg": "Влак",
+ "ca": "Tren",
+ "cs": "Vlak",
+ "de": "Zug",
+ "eo": "Vagonaro",
+ "es": "Tren",
+ "et": "Rong",
+ "fa": "قطار",
+ "fi": "Juna",
+ "fr": "Train",
+ "hr": "vlak",
+ "hu": "Vonat",
+ "id": "Kereta Api",
+ "it": "Treno",
+ "ja": "電車",
+ "nb_NO": "Tog",
+ "nl": "Trein",
+ "pt": "Comboio",
+ "pt_BR": "Trem",
+ "ru": "Поезд",
+ "si": null,
+ "sk": "Vlak",
+ "sq": "Tren",
+ "sr": "воз",
+ "sv": "Tåg",
+ "szl": null,
+ "tzm": null,
+ "uk": "Потяг",
+ "vi": "Xe lửa",
+ "zh_Hans": "火车",
+ "zh_Hant": "火車"
+ }
+ },
+ {
+ "number": 52,
+ "emoji": "🚲",
+ "description": "Bicycle",
+ "unicode": "U+1F6B2",
+ "translated_descriptions": {
+ "ar": "دَرّاجَة",
+ "bg": "Колело",
+ "ca": "Bicicleta",
+ "cs": "Kolo",
+ "de": "Fahrrad",
+ "eo": "Biciklo",
+ "es": "Bicicleta",
+ "et": "Jalgratas",
+ "fa": "دوچرخه",
+ "fi": "Polkupyörä",
+ "fr": "Vélo",
+ "hr": "bicikl",
+ "hu": "Kerékpár",
+ "id": "Sepeda",
+ "it": "Bicicletta",
+ "ja": "自転車",
+ "nb_NO": "Sykkel",
+ "nl": "Fiets",
+ "pt": "Bicicleta",
+ "pt_BR": "Bicicleta",
+ "ru": "Велосипед",
+ "si": null,
+ "sk": "Bicykel",
+ "sq": "Biçikletë",
+ "sr": "бицикл",
+ "sv": "Cykel",
+ "szl": null,
+ "tzm": null,
+ "uk": "Велосипед",
+ "vi": "Xe đạp",
+ "zh_Hans": "自行车",
+ "zh_Hant": "腳踏車"
+ }
+ },
+ {
+ "number": 53,
+ "emoji": "✈️",
+ "description": "Aeroplane",
+ "unicode": "U+2708U+FE0F",
+ "translated_descriptions": {
+ "ar": "طَائِرة",
+ "bg": "Самолет",
+ "ca": "Avió",
+ "cs": "Letadlo",
+ "de": "Flugzeug",
+ "eo": "Aviadilo",
+ "es": "Avión",
+ "et": "Lennuk",
+ "fa": "هواپیما",
+ "fi": "Lentokone",
+ "fr": "Avion",
+ "hr": "avion",
+ "hu": "Repülő",
+ "id": "Pesawat",
+ "it": "Aeroplano",
+ "ja": "飛行機",
+ "nb_NO": "Fly",
+ "nl": "Vliegtuig",
+ "pt": "Avião",
+ "pt_BR": "Avião",
+ "ru": "Самолет",
+ "si": null,
+ "sk": "Lietadlo",
+ "sq": "Avion",
+ "sr": "авион",
+ "sv": "Flygplan",
+ "szl": null,
+ "tzm": null,
+ "uk": "Літак",
+ "vi": "Máy bay",
+ "zh_Hans": "飞机",
+ "zh_Hant": "飛機"
+ }
+ },
+ {
+ "number": 54,
+ "emoji": "🚀",
+ "description": "Rocket",
+ "unicode": "U+1F680",
+ "translated_descriptions": {
+ "ar": "صَارُوخ",
+ "bg": "Ракета",
+ "ca": "Coet",
+ "cs": "Raketa",
+ "de": "Rakete",
+ "eo": "Raketo",
+ "es": "Cohete",
+ "et": "Rakett",
+ "fa": "موشک",
+ "fi": "Raketti",
+ "fr": "Fusée",
+ "hr": "raketa",
+ "hu": "Rakáta",
+ "id": "Roket",
+ "it": "Razzo",
+ "ja": "ロケット",
+ "nb_NO": "Rakett",
+ "nl": "Raket",
+ "pt": "Foguetão",
+ "pt_BR": "Foguete",
+ "ru": "Ракета",
+ "si": null,
+ "sk": "Raketa",
+ "sq": "Raketë",
+ "sr": "ракета",
+ "sv": "Raket",
+ "szl": null,
+ "tzm": null,
+ "uk": "Ракета",
+ "vi": "Tên lửa",
+ "zh_Hans": "火箭",
+ "zh_Hant": "火箭"
+ }
+ },
+ {
+ "number": 55,
+ "emoji": "🏆",
+ "description": "Trophy",
+ "unicode": "U+1F3C6",
+ "translated_descriptions": {
+ "ar": "كَأسُ النَّصر",
+ "bg": "Трофей",
+ "ca": "Trofeu",
+ "cs": "Pohár",
+ "de": "Pokal",
+ "eo": "Trofeo",
+ "es": "Trofeo",
+ "et": "Auhind",
+ "fa": "جام",
+ "fi": "Palkinto",
+ "fr": "Trophée",
+ "hr": "trofej",
+ "hu": "Trófea",
+ "id": "Piala",
+ "it": "Trofeo",
+ "ja": "トロフィー",
+ "nb_NO": "Pokal",
+ "nl": "Trofee",
+ "pt": "Troféu",
+ "pt_BR": "Troféu",
+ "ru": "Кубок",
+ "si": null,
+ "sk": "Trofej",
+ "sq": "Trofe",
+ "sr": "пехар",
+ "sv": "Trofé",
+ "szl": null,
+ "tzm": null,
+ "uk": "Приз",
+ "vi": "Cúp",
+ "zh_Hans": "奖杯",
+ "zh_Hant": "獎盃"
+ }
+ },
+ {
+ "number": 56,
+ "emoji": "⚽",
+ "description": "Ball",
+ "unicode": "U+26BD",
+ "translated_descriptions": {
+ "ar": "كُرَة",
+ "bg": "Топка",
+ "ca": "Pilota",
+ "cs": "Míč",
+ "de": "Ball",
+ "eo": "Pilko",
+ "es": "Bola",
+ "et": "Pall",
+ "fa": "توپ",
+ "fi": "Pallo",
+ "fr": "Ballon",
+ "hr": "lopta",
+ "hu": "Labda",
+ "id": "Bola",
+ "it": "Palla",
+ "ja": "ボール",
+ "nb_NO": "Ball",
+ "nl": "Bal",
+ "pt": "Bola",
+ "pt_BR": "Bola",
+ "ru": "Мяч",
+ "si": null,
+ "sk": "Lopta",
+ "sq": "Top",
+ "sr": "лопта",
+ "sv": "Boll",
+ "szl": null,
+ "tzm": "Tcama",
+ "uk": "М'яч",
+ "vi": "Banh",
+ "zh_Hans": "球",
+ "zh_Hant": "足球"
+ }
+ },
+ {
+ "number": 57,
+ "emoji": "🎸",
+ "description": "Guitar",
+ "unicode": "U+1F3B8",
+ "translated_descriptions": {
+ "ar": "غيتار",
+ "bg": "Китара",
+ "ca": "Guitarra",
+ "cs": "Kytara",
+ "de": "Gitarre",
+ "eo": "Gitaro",
+ "es": "Guitarra",
+ "et": "Kitarr",
+ "fa": "گیتار",
+ "fi": "Kitara",
+ "fr": "Guitare",
+ "hr": "gitara",
+ "hu": "Gitár",
+ "id": "Gitar",
+ "it": "Chitarra",
+ "ja": "ギター",
+ "nb_NO": "Gitar",
+ "nl": "Gitaar",
+ "pt": "Guitarra",
+ "pt_BR": "Guitarra",
+ "ru": "Гитара",
+ "si": null,
+ "sk": "Gitara",
+ "sq": "Kitarë",
+ "sr": "гитара",
+ "sv": "Gitarr",
+ "szl": null,
+ "tzm": "Agiṭaṛ",
+ "uk": "Гітара",
+ "vi": "Ghi-ta",
+ "zh_Hans": "吉他",
+ "zh_Hant": "吉他"
+ }
+ },
+ {
+ "number": 58,
+ "emoji": "🎺",
+ "description": "Trumpet",
+ "unicode": "U+1F3BA",
+ "translated_descriptions": {
+ "ar": "بُوق",
+ "bg": "Тромпет",
+ "ca": "Trompeta",
+ "cs": "Trumpeta",
+ "de": "Trompete",
+ "eo": "Trumpeto",
+ "es": "Trompeta",
+ "et": "Trompet",
+ "fa": "شیپور",
+ "fi": "Trumpetti",
+ "fr": "Trompette",
+ "hr": "truba",
+ "hu": "Trombita",
+ "id": "Terompet",
+ "it": "Trombetta",
+ "ja": "トランペット",
+ "nb_NO": "Trompet",
+ "nl": "Trompet",
+ "pt": "Trompete",
+ "pt_BR": "Trombeta",
+ "ru": "Труба",
+ "si": null,
+ "sk": "Trúbka",
+ "sq": "Trombë",
+ "sr": "труба",
+ "sv": "Trumpet",
+ "szl": null,
+ "tzm": null,
+ "uk": "Труба",
+ "vi": "Kèn",
+ "zh_Hans": "喇叭",
+ "zh_Hant": "喇叭"
+ }
+ },
+ {
+ "number": 59,
+ "emoji": "🔔",
+ "description": "Bell",
+ "unicode": "U+1F514",
+ "translated_descriptions": {
+ "ar": "جَرَس",
+ "bg": "Звънец",
+ "ca": "Campana",
+ "cs": "Zvonek",
+ "de": "Glocke",
+ "eo": "Sonorilo",
+ "es": "Campana",
+ "et": "Kelluke",
+ "fa": "زنگ",
+ "fi": "Soittokello",
+ "fr": "Cloche",
+ "hr": "zvono",
+ "hu": "Harang",
+ "id": "Lonceng",
+ "it": "Campana",
+ "ja": "ベル",
+ "nb_NO": "Bjelle",
+ "nl": "Bel",
+ "pt": "Sino",
+ "pt_BR": "Sino",
+ "ru": "Колокол",
+ "si": null,
+ "sk": "Zvonec",
+ "sq": "Kambanë",
+ "sr": "звоно",
+ "sv": "Bjällra",
+ "szl": null,
+ "tzm": null,
+ "uk": "Дзвін",
+ "vi": "Chuông",
+ "zh_Hans": "铃铛",
+ "zh_Hant": "鈴鐺"
+ }
+ },
+ {
+ "number": 60,
+ "emoji": "⚓",
+ "description": "Anchor",
+ "unicode": "U+2693",
+ "translated_descriptions": {
+ "ar": "مِرسَاة",
+ "bg": "Котва",
+ "ca": "Àncora",
+ "cs": "Kotva",
+ "de": "Anker",
+ "eo": "Ankro",
+ "es": "Ancla",
+ "et": "Ankur",
+ "fa": "لنگر",
+ "fi": "Ankkuri",
+ "fr": "Ancre",
+ "hr": "sidro",
+ "hu": "Horgony",
+ "id": "Jangkar",
+ "it": "Ancora",
+ "ja": "いかり",
+ "nb_NO": "Anker",
+ "nl": "Anker",
+ "pt": "Âncora",
+ "pt_BR": "Âncora",
+ "ru": "Якорь",
+ "si": null,
+ "sk": "Kotva",
+ "sq": "Spirancë",
+ "sr": "сидро",
+ "sv": "Ankare",
+ "szl": null,
+ "tzm": null,
+ "uk": "Якір",
+ "vi": "Mỏ neo",
+ "zh_Hans": "锚",
+ "zh_Hant": "船錨"
+ }
+ },
+ {
+ "number": 61,
+ "emoji": "🎧",
+ "description": "Headphones",
+ "unicode": "U+1F3A7",
+ "translated_descriptions": {
+ "ar": "سَمّاعَة رَأس",
+ "bg": "Слушалки",
+ "ca": "Auriculars",
+ "cs": "Sluchátka",
+ "de": "Kopfhörer",
+ "eo": "Kapaŭdilo",
+ "es": "Cascos",
+ "et": "Kõrvaklapid",
+ "fa": "هدفون",
+ "fi": "Kuulokkeet",
+ "fr": "Casque audio",
+ "hr": "slušalice",
+ "hu": "Fejhallgató",
+ "id": "Headphone",
+ "it": "Cuffie",
+ "ja": "ヘッドホン",
+ "nb_NO": "Hodetelefoner",
+ "nl": "Koptelefoon",
+ "pt": "Fones",
+ "pt_BR": "Fones de ouvido",
+ "ru": "Наушники",
+ "si": null,
+ "sk": "Slúchadlá",
+ "sq": "Kufje",
+ "sr": "слушалице",
+ "sv": "Hörlurar",
+ "szl": null,
+ "tzm": null,
+ "uk": "Навушники",
+ "vi": "Tai nghe",
+ "zh_Hans": "耳机",
+ "zh_Hant": "耳機"
+ }
+ },
+ {
+ "number": 62,
+ "emoji": "📁",
+ "description": "Folder",
+ "unicode": "U+1F4C1",
+ "translated_descriptions": {
+ "ar": "مُجَلَّد",
+ "bg": "Папка",
+ "ca": "Carpeta",
+ "cs": "Složka",
+ "de": "Ordner",
+ "eo": "Dosierujo",
+ "es": "Carpeta",
+ "et": "Kaust",
+ "fa": "پوشه",
+ "fi": "Kansio",
+ "fr": "Dossier",
+ "hr": "mapu",
+ "hu": "Mappa",
+ "id": "Map",
+ "it": "Cartella",
+ "ja": "フォルダー",
+ "nb_NO": "Mappe",
+ "nl": "Map",
+ "pt": "Pasta",
+ "pt_BR": "Pasta",
+ "ru": "Папка",
+ "si": null,
+ "sk": "Fascikel",
+ "sq": "Dosje",
+ "sr": "фасцикла",
+ "sv": "Mapp",
+ "szl": null,
+ "tzm": "Asdaw",
+ "uk": "Тека",
+ "vi": "Thư mục",
+ "zh_Hans": "文件夹",
+ "zh_Hant": "資料夾"
+ }
+ },
+ {
+ "number": 63,
+ "emoji": "📌",
+ "description": "Pin",
+ "unicode": "U+1F4CC",
+ "translated_descriptions": {
+ "ar": "دَبُّوس",
+ "bg": "Кабърче",
+ "ca": "Xinxeta",
+ "cs": "Špendlík",
+ "de": "Stecknadel",
+ "eo": "Pinglo",
+ "es": "Alfiler",
+ "et": "Nööpnõel",
+ "fa": "سنجاق",
+ "fi": "Nuppineula",
+ "fr": "Punaise",
+ "hr": "pribadača",
+ "hu": "Rajszeg",
+ "id": "Pin",
+ "it": "Puntina",
+ "ja": "ピン",
+ "nb_NO": "Tegnestift",
+ "nl": "Duimspijker",
+ "pt": "Pionés",
+ "pt_BR": "Alfinete",
+ "ru": "Булавка",
+ "si": null,
+ "sk": "Špendlík",
+ "sq": "Karficë",
+ "sr": "чиода",
+ "sv": "Häftstift",
+ "szl": null,
+ "tzm": null,
+ "uk": "Кнопка",
+ "vi": "Ghim",
+ "zh_Hans": "图钉",
+ "zh_Hant": "圖釘"
+ }
+ }
+]
diff --git a/src/l10n/en/100-ui.ftl b/src/l10n/en/100-ui.ftl
--- a/src/l10n/en/100-ui.ftl
+++ b/src/l10n/en/100-ui.ftl
@@ -27,6 +27,7 @@
global-drawer-action-settings = Settings
global-drawer-action-create-room = Create room
global-drawer-action-join-room = Join room
+global-drawer-action-verifications = Device Verification
global-drawer-action-about = About { -kt-app-name }
action-settings-page-title = Configure shortcuts
@@ -460,3 +461,15 @@
confirm-deletion-popup-cancel-action = Cancel
get-room-id-by-alias-failed-prompt = Unable to get room id by alias. Error code: { $errorCode }. Error message: { $errorMsg }.
+
+verifications-page-title = Device Verification
+verification-state-they-requested = requested to verify this device.
+verification-state-waiting = Waiting for the other party.
+verification-state-waiting-after-verified = Waiting for the other party.
+verification-state-confirm-code = Please confirm whether the codes match the other device.
+verification-state-done = The process is done.
+verification-state-cancelled = The process is cancelled.
+verification-action-ready = Continue
+verification-action-cancel = Cancel
+verification-action-confirm-sas-match = They match
+verification-action-deny-sas-match = They do not match
diff --git a/src/matrix-sdk.hpp b/src/matrix-sdk.hpp
--- a/src/matrix-sdk.hpp
+++ b/src/matrix-sdk.hpp
@@ -28,6 +28,7 @@
Q_MOC_INCLUDE("matrix-event.hpp")
Q_MOC_INCLUDE("matrix-sticker-pack-list.hpp")
Q_MOC_INCLUDE("matrix-user-given-attrs-map.hpp")
+Q_MOC_INCLUDE("matrix-verification-list.hpp")
class MatrixRoomList;
class MatrixDeviceList;
@@ -39,6 +40,7 @@
class MatrixUserGivenAttrsMap;
class KazvSessionLockGuard;
class DbStore;
+class MatrixVerificationList;
struct MatrixSdkPrivate;
std::filesystem::path sessionDirForUserAndDeviceId(std::filesystem::path userDataDir, std::string userId, std::string deviceId);
@@ -116,6 +118,8 @@
Q_INVOKABLE QStringList directRoomIds(QString userId) const;
+ Q_INVOKABLE MatrixVerificationList *verificationList() const;
+
Kazv::RandomInterface &randomGenerator() const;
private:
diff --git a/src/matrix-sdk.cpp b/src/matrix-sdk.cpp
--- a/src/matrix-sdk.cpp
+++ b/src/matrix-sdk.cpp
@@ -49,6 +49,7 @@
#include "kazv-session-lock-guard.hpp"
#include "db-store.hpp"
#include "sso-login-process.hpp"
+#include "matrix-verification-list.hpp"
using namespace Qt::Literals::StringLiterals;
using namespace Kazv;
@@ -159,6 +160,7 @@
NotificationHandler notificationHandler;
DbStatus dbStatus;
PendingSaveEvents pendingSaveEvents{};
+ lager::state<VerificationTrackerModel> verificationTrackerState;
void runIoContext() {
thread->start();
@@ -441,6 +443,18 @@
);
});
+ m_d->watchable.after<VerificationTrackerModelChanged>(
+ [this](VerificationTrackerModelChanged) {
+ auto model = lager::get<VerificationTracker>(m_d->sdk.context()).model;
+ QMetaObject::invokeMethod(
+ this, [this, model=std::move(model)]() {
+ qCDebug(kazvLog) << "Verification tracker model changed" << model.processes.size();
+ m_d->verificationTrackerState.set(model);
+ lager::commit(m_d->verificationTrackerState);
+ });
+ }
+ );
+
connect(&m_d->saveTimer, &QTimer::timeout, &m_d->saveTimer, [m_d=m_d.get()]() {
m_d->maybeSerialize();
});
@@ -588,6 +602,11 @@
return roomIds;
}
+MatrixVerificationList *MatrixSdk::verificationList() const
+{
+ return new MatrixVerificationList(m_d->clientOnSecondaryRoot, m_d->verificationTrackerState);
+}
+
std::string MatrixSdk::validateHomeserverUrl(const QString &url)
{
if (url.isEmpty()) {
diff --git a/src/matrix-verification-list.hpp b/src/matrix-verification-list.hpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-verification-list.hpp
@@ -0,0 +1,30 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <kazv-defs.hpp>
+#include "kazv-abstract-list-model.hpp"
+#include <crypto/verification-tracker.hpp>
+#include <client/client.hpp>
+#include <QQmlEngine>
+Q_MOC_INCLUDE("matrix-verification.hpp")
+class MatrixVerification;
+
+class MatrixVerificationList : public KazvAbstractListModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+
+ Kazv::Client m_client;
+ lager::reader<Kazv::VerificationTrackerModel> m_model;
+
+public:
+ explicit MatrixVerificationList(Kazv::Client client, lager::reader<Kazv::VerificationTrackerModel> model, QObject *parent = 0);
+ ~MatrixVerificationList() override;
+
+ Q_INVOKABLE MatrixVerification *at(int index) const;
+};
diff --git a/src/matrix-verification-list.cpp b/src/matrix-verification-list.cpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-verification-list.cpp
@@ -0,0 +1,27 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include "matrix-verification-list.hpp"
+#include "matrix-verification.hpp"
+#include "helper.hpp"
+
+using namespace Kazv;
+using VTM = VerificationTrackerModel;
+
+MatrixVerificationList::MatrixVerificationList(Kazv::Client client, lager::reader<Kazv::VerificationTrackerModel> model, QObject *parent)
+ : KazvAbstractListModel(parent)
+ , m_client(std::move(client))
+ , m_model(std::move(model))
+{
+ initCountCursor(m_model[&VTM::processes].xform(containerSize));
+}
+
+MatrixVerificationList::~MatrixVerificationList() = default;
+
+MatrixVerification *MatrixVerificationList::at(int index) const
+{
+ return new MatrixVerification(m_client, m_model[&VTM::processes][lager::lenses::at(index)][lager::lenses::or_default]);
+}
diff --git a/src/matrix-verification.hpp b/src/matrix-verification.hpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-verification.hpp
@@ -0,0 +1,53 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <kazv-defs.hpp>
+#include <crypto/verification-tracker.hpp>
+#include <client/client.hpp>
+#include <lager/extra/qt.hpp>
+#include <QObject>
+#include <QQmlEngine>
+
+class MatrixVerification : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+
+ Kazv::Client m_client;
+ lager::reader<Kazv::VerificationTrackerModel::Process> m_process;
+
+public:
+ enum StateType {
+ TheyRequested,
+ Waiting,
+ CodeDisplayed,
+ VerifiedThem,
+ Done,
+ Cancelled,
+ };
+ Q_ENUM(StateType);
+
+ explicit MatrixVerification(Kazv::Client client, lager::reader<Kazv::VerificationTrackerModel::Process> process, QObject *parent = 0);
+ ~MatrixVerification() override;
+
+ LAGER_QT_READER(QString, userId);
+ LAGER_QT_READER(QString, deviceId);
+ LAGER_QT_READER(StateType, stateType);
+ LAGER_QT_READER(QList<int>, emojiIndices);
+ LAGER_QT_READER(QString, decimalCodes);
+
+public Q_SLOTS:
+ /// Signal the user is ready for this verification
+ void ready();
+ /// Cancel this verification
+ void cancel();
+ /// Confirm the SAS matches
+ void confirmSasMatch();
+ /// Deny the SAS matches
+ void denySasMatch();
+};
diff --git a/src/matrix-verification.cpp b/src/matrix-verification.cpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-verification.cpp
@@ -0,0 +1,92 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include "matrix-verification.hpp"
+#include "helper.hpp"
+#include "kazv-log.hpp"
+
+using namespace Kazv;
+using VTM = VerificationTrackerModel;
+using VP = VTM::Process;
+using namespace Qt::StringLiterals;
+
+MatrixVerification::MatrixVerification(Kazv::Client client, lager::reader<Kazv::VerificationTrackerModel::Process> process, QObject *parent)
+ : QObject(parent)
+ , m_client(std::move(client))
+ , m_process(std::move(process))
+ , LAGER_QT(userId)(m_process[&VP::theirUserId].xform(strToQt))
+ , LAGER_QT(deviceId)(m_process[&VP::theirDeviceId].xform(strToQt))
+ , LAGER_QT(stateType)(m_process[&VP::state].map([](const auto &state) {
+ return std::visit(lager::visitor(
+ [](VTM::ProcessTheyRequested) { return TheyRequested; },
+ [](VTM::ProcessWaiting) { return Waiting; },
+ [](VTM::ProcessCodeDisplayed) { return CodeDisplayed; },
+ [](VTM::ProcessVerifiedThem) { return VerifiedThem; },
+ [](VTM::ProcessDone) { return Done; },
+ [](VTM::ProcessCancelled) { return Cancelled; }
+ ), state);
+ }))
+ , LAGER_QT(emojiIndices)(m_process[&VP::state].map([](const auto &state) {
+ return std::visit(lager::visitor(
+ [](VTM::ProcessCodeDisplayed s) {
+ auto l = QList<int>(s.emojiIndices.begin(), s.emojiIndices.end());
+ qCDebug(kazvLog) << "emoji indices:" << l;
+ return l;
+ },
+ [](auto &&) {
+ return QList<int>();
+ }
+ ), state);
+ }))
+ , LAGER_QT(decimalCodes)(m_process[&VP::state].map([](const auto &state) {
+ return std::visit(lager::visitor(
+ [](VTM::ProcessCodeDisplayed s) {
+ QStringList sl;
+ std::transform(s.emojiIndices.begin(), s.emojiIndices.end(), std::back_inserter(sl), [](int a) { return QString::number(a); });
+ qCDebug(kazvLog) << "codes:" << sl;
+ return sl.join(u" "_s);
+ },
+ [](auto &&) {
+ return QString();
+ }
+ ), state);
+ }))
+{
+}
+
+MatrixVerification::~MatrixVerification() = default;
+
+void MatrixVerification::ready()
+{
+ m_client.readyForVerification(
+ m_process.get().theirUserId,
+ m_process.get().theirDeviceId
+ );
+}
+
+void MatrixVerification::cancel()
+{
+ m_client.cancelVerification(
+ m_process.get().theirUserId,
+ m_process.get().theirDeviceId
+ );
+}
+
+void MatrixVerification::confirmSasMatch()
+{
+ m_client.confirmVerificationSasMatch(
+ m_process.get().theirUserId,
+ m_process.get().theirDeviceId
+ );
+}
+
+void MatrixVerification::denySasMatch()
+{
+ m_client.denyVerificationSasMatch(
+ m_process.get().theirUserId,
+ m_process.get().theirDeviceId
+ );
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 29, 12:09 AM (8 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1250400
Default Alt Text
D298.1774768185.diff (89 KB)
Attached To
Mode
D298: Implement SAS verification
Attached
Detach File
Event Timeline
Log In to Comment