Page MenuHomePhorge

D298.1774768185.diff
No OneTemporary

Size
89 KB
Referenced Files
None
Subscribers
None

D298.1774768185.diff

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

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)

Event Timeline