Compare commits

..

32 Commits
main ... 8.16.x

Author SHA1 Message Date
Fedor Indutny
ffc75db55f 8.16.0
Some checks failed
CI / Lint (push) Has been cancelled
CI / Danger (push) Has been cancelled
CI / Dependencies (push) Has been cancelled
Commits Check / Commit Title Check (push) Has been cancelled
CI / Sticker Creator (push) Has been cancelled
CI / Storybook (push) Has been cancelled
CI / Benchmark (10, 500, 500, 2, 500, largeGroupSendWithBlocks, 50, ts/test-mock/benchmarks/group_send_bench.node.js) (push) Has been cancelled
CI / Benchmark (500, 50, 2, 500, largeGroupSend, 20, ts/test-mock/benchmarks/group_send_bench.node.js) (push) Has been cancelled
CI / Benchmark (500, groupSend, 100, ts/test-mock/benchmarks/group_send_bench.node.js) (push) Has been cancelled
CI / Benchmark (backup, ts/test-mock/benchmarks/backup_bench.node.js) (push) Has been cancelled
CI / Benchmark (callHistorySearch, 100, ts/test-mock/benchmarks/call_history_search_bench.node.js) (push) Has been cancelled
CI / Benchmark (convoOpen, 100, ts/test-mock/benchmarks/convo_open_bench.node.js) (push) Has been cancelled
CI / Benchmark (send, 100, ts/test-mock/benchmarks/send_bench.node.js) (push) Has been cancelled
CI / Benchmark (startup, 10, ts/test-mock/benchmarks/startup_bench.node.js) (push) Has been cancelled
ICU Book / Build ICU Book (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Linux (arm64, ubuntu-22.04-arm64-4-cores) (push) Has been cancelled
CI / Check Min OS Version (ubuntu-latest) (push) Has been cancelled
CI / Check Min OS Version (windows-latest) (push) Has been cancelled
CI / Linux (x64, ubuntu-22.04-8-cores) (push) Has been cancelled
CI / Windows (push) Has been cancelled
CI / Mock Tests (0) (push) Has been cancelled
CI / Mock Tests (1) (push) Has been cancelled
CI / Mock Tests (2) (push) Has been cancelled
CI / Mock Tests (3) (push) Has been cancelled
CI / Check Min OS Version (macos-latest) (push) Has been cancelled
CI / Auto Merge Ready (push) Has been cancelled
2026-06-24 13:54:47 -07:00
Fedor Indutny
0fa97f34bf Update strings 2026-06-24 13:54:46 -07:00
automated-signal
7ae592f636
Fix deprecated name field in donation config
Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
2026-06-24 20:38:58 +00:00
automated-signal
882b117769
Fix crash on Linux when calling memoryUsage
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-24 20:35:27 +00:00
Jamie Kyle
48ee28585c 8.16.0-beta.1
Some checks failed
Commits Check / Commit Title Check (push) Has been cancelled
CI / Dependencies (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Sticker Creator (push) Has been cancelled
CI / Danger (push) Has been cancelled
CI / Storybook (push) Has been cancelled
CI / Benchmark (10, 500, 500, 2, 500, largeGroupSendWithBlocks, 50, ts/test-mock/benchmarks/group_send_bench.node.js) (push) Has been cancelled
CI / Benchmark (500, 50, 2, 500, largeGroupSend, 20, ts/test-mock/benchmarks/group_send_bench.node.js) (push) Has been cancelled
CI / Benchmark (500, groupSend, 100, ts/test-mock/benchmarks/group_send_bench.node.js) (push) Has been cancelled
CI / Benchmark (backup, ts/test-mock/benchmarks/backup_bench.node.js) (push) Has been cancelled
CI / Benchmark (callHistorySearch, 100, ts/test-mock/benchmarks/call_history_search_bench.node.js) (push) Has been cancelled
CI / Benchmark (convoOpen, 100, ts/test-mock/benchmarks/convo_open_bench.node.js) (push) Has been cancelled
CI / Benchmark (send, 100, ts/test-mock/benchmarks/send_bench.node.js) (push) Has been cancelled
CI / Benchmark (startup, 10, ts/test-mock/benchmarks/startup_bench.node.js) (push) Has been cancelled
ICU Book / Build ICU Book (push) Has been cancelled
CI / Auto Merge Ready (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Linux (arm64, ubuntu-22.04-arm64-4-cores) (push) Has been cancelled
CI / Linux (x64, ubuntu-22.04-8-cores) (push) Has been cancelled
CI / Windows (push) Has been cancelled
CI / Check Min OS Version (macos-latest) (push) Has been cancelled
CI / Mock Tests (0) (push) Has been cancelled
CI / Mock Tests (1) (push) Has been cancelled
CI / Mock Tests (2) (push) Has been cancelled
CI / Mock Tests (3) (push) Has been cancelled
CI / Check Min OS Version (ubuntu-latest) (push) Has been cancelled
CI / Check Min OS Version (windows-latest) (push) Has been cancelled
2026-06-17 16:03:58 -07:00
Jamie Kyle
79177cf936 Update strings 2026-06-17 16:02:58 -07:00
Jamie Kyle
67acaf20fc Update release notes 2026-06-17 15:41:09 -07:00
automated-signal
e8abc5f127
Update to latest AccountRecord proto
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-17 12:48:10 -07:00
automated-signal
1f247ab860
Avoid toasting on remote config changes when linking as new device
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-17 12:47:41 -07:00
automated-signal
d74aefd33b
Add toast for sticker creator for invalid file formats
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
2026-06-17 19:06:14 +00:00
automated-signal
d09fed20f4
Fix highlight when scrolling to unloaded pinned message
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
2026-06-17 11:54:39 -07:00
automated-signal
ef4db684b1
Fix jumbomoji for messages with whitespace
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
Co-authored-by: Jamie Kyle <jamie@signal.org>
2026-06-17 11:50:55 -07:00
automated-signal
7b5184fd27
Remove plaintextExport feature flag
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
2026-06-17 11:30:02 -07:00
automated-signal
dee13e5e09
Re-enable requestSingleInstanceLock for MAS
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-17 11:29:46 -07:00
automated-signal
5f877d56dd
Fix dependency errors
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-17 11:17:54 -07:00
automated-signal
d73b575030
Disable text selection in sticker creator
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
2026-06-17 09:08:17 -07:00
automated-signal
7aba3af2bf
Fix sticker creator localization
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
2026-06-17 09:07:59 -07:00
automated-signal
b8f9cc7531
Request backfill and skip queueing for undownloadable attachments
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-17 14:07:09 +00:00
automated-signal
d0a96bc9b9
More localization strings for MAS
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-16 22:45:57 +00:00
automated-signal
cdc49e399c
Fix document ordering in All Media gallery
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-16 15:44:44 -07:00
automated-signal
b4679c00eb
Update yauzl to 3.4.0
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-16 22:42:19 +00:00
automated-signal
db21c709e3
Pin node-gyp to fix windows CI
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
Co-authored-by: Fedor Indutny <indutny@signal.org>
2026-06-16 22:29:30 +00:00
automated-signal
71bb310aac
Simplify CI dependencies
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-15 15:35:58 -07:00
automated-signal
a97335174c
Get/push MAS strings
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-15 15:08:47 -07:00
automated-signal
9b31e04f3e
Fix boolean condition in remove-strings
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-15 14:06:23 -07:00
automated-signal
77c6c9c253
Add package.json version tag for MAS builds
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
2026-06-15 13:23:19 -07:00
automated-signal
b5575f3af5
Show system contact icon in GroupMembershipList
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-15 12:31:32 -07:00
automated-signal
02d06deb86
Respect global pinned chat remoteConfig value
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-15 12:31:23 -07:00
automated-signal
b95c9c575b
Support building for MAS
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-15 12:31:06 -07:00
automated-signal
4133a3d592
Move windows-ucv into the monorepo
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
2026-06-15 12:30:57 -07:00
automated-signal
88862d14e4
Simplify recovery key warning dialogs
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-11 13:28:04 -07:00
automated-signal
10fbf84e7c
Refresh StickerManager to use design system components
Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
2026-06-11 13:27:58 -07:00
121 changed files with 408 additions and 1837 deletions

View File

@ -16618,7 +16618,7 @@ DEALINGS IN THE SOFTWARE.
```
## memmap2 0.9.11
## memmap2 0.9.9
```
Copyright (c) 2020 Yevhenii Reizner

View File

@ -215,20 +215,11 @@ CREATE TABLE attachment_downloads_backup_stats (
```sql
CREATE TABLE attachments_protected_from_deletion (
path TEXT NOT NULL,
reuseToken TEXT NOT NULL,
PRIMARY KEY (path, reuseToken)
messageId TEXT NOT NULL,
PRIMARY KEY (path, messageId)
) STRICT
```
<details>
<summary>Index: attachments_protected_from_deletion → attachments_protected_from_deletion_reuseToken</summary>
```sql
CREATE INDEX attachments_protected_from_deletion_reuseToken ON attachments_protected_from_deletion (reuseToken)
```
</details>
<details>
<summary>Index: attachments_protected_from_deletion → sqlite_autoindex_attachments_protected_from_deletion_1</summary>
@ -1178,6 +1169,53 @@ CREATE INDEX message_attachments_thumbnailPath ON message_attachments (thumbnail
</details>
<details>
<summary>Trigger: message_attachments → stop_protecting_attachments_after_insert</summary>
```sql
CREATE TRIGGER stop_protecting_attachments_after_insert AFTER INSERT ON message_attachments BEGIN
DELETE FROM attachments_protected_from_deletion
WHERE
messageId IS NEW.messageId
AND path IN (
NEW.path,
NEW.thumbnailPath,
NEW.screenshotPath,
NEW.backupThumbnailPath
);
END
```
</details>
<details>
<summary>Trigger: message_attachments → stop_protecting_attachments_after_update</summary>
```sql
CREATE TRIGGER stop_protecting_attachments_after_update AFTER
UPDATE OF path,
thumbnailPath,
screenshotPath,
backupThumbnailPath ON message_attachments WHEN OLD.path IS NOT NEW.path
OR OLD.thumbnailPath IS NOT NEW.thumbnailPath
OR OLD.screenshotPath IS NOT NEW.screenshotPath
OR OLD.backupThumbnailPath IS NOT NEW.backupThumbnailPath BEGIN
DELETE FROM attachments_protected_from_deletion
WHERE
messageId IS NEW.messageId
AND path IN (
NEW.path,
NEW.thumbnailPath,
NEW.screenshotPath,
NEW.backupThumbnailPath
);
END
```
</details>
---
</details>

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Bywerking afgelaai"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Maak Signal op jou foon oop"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Ons het 'n fout in die plakkerpakket-skepper wat die koppelvlak in die verkeerde taal vertoon het, herstel."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "تمَّ تنزيل التحديث"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "افتح تطبيق سيجنال على هاتفك"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "أصلحنا خطًأ في مُنشِئ المُلصَقات كان يتسبَّب في عرض الواجهة بلغة خاطئة. على الرغم من أن المُلصَقات عبارة عن صور (أي أنها تُعبِّر عن ألف كلمة)، إلّا أنه لا يزال من المهم اختيار الكلمات المناسبة أيضًا."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Yeniləmə yükləndi"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Signal-ı telefonunuzda açın"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "İnterfeysi səhv dildə göstərən stiker yaradıcısı ilə bağlı bir nasazlığı aradan qaldırdıq. Bununla belə stikerlər sadəcə şəkillərdən ibarətdir (buna görə min sözə dəyər) və sözləri doğru seçmək də çox vacibdir."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Актуализацията е изтеглена"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Отворете Signal на телефона си"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Отстранихме бъг в създателя на стикери, заради който на интерфейса се показваше грешният език."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "আপডেট ডাউনলোড হয়েছে"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "আপনার ফোনে সিগন্যাল খুলুন"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "আমরা স্টিকার ক্রিয়েটর-এর একটি বাগ সংশোধন করেছি, যার কারণে ইন্টারফেইসটি ভুল ভাষায় দেখানো হচ্ছিলো।"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Ažuriranje je preuzeto"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Otvorite Signal na telefonu"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Ispravili smo grešku u kreatoru naljepnica koja je prikazivala interfejs na pogrešnom jeziku."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Actualització descarregada"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Obriu el Signal al telèfon."
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Hem solucionat un error al creador d'stickers que feia que la interfície es mostrés en l'idioma incorrecte."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Aktualizace stažena"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Otevřete Signal na svém telefonu"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Opravili jsme chybu v nástroji na tvorbu nálepek, kvůli které se rozhraní zobrazovalo v nesprávném jazyce."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Opdatering downloadet"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Åbn Signal på din telefon"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Vi har rettet en fejl i klistermærkeværktøjet, hvor brugerfladen blev vist på det forkerte sprog. Selvom klistermærker er billeder (og derfor siger mere end tusind ord), er det stadig vigtigt at få ordene sagt rigtigt."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Update heruntergeladen"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Öffne Signal auf deinem Telefon"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Wir haben einen Fehler im Sticker-Creator behoben, der die Benutzeroberfläche in der falschen Sprache anzeigte. Auch wenn Sticker Bilder sind (und somit mehr sagen als tausend Worte), ist es dennoch wichtig, die richtigen Worte zu finden."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Έγινε λήψη της ενημέρωσης"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Άνοιξε το Signal στο κινητό σου"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Διορθώσαμε ένα σφάλμα στο εργαλείο δημιουργίας αυτοκόλλητων, το οποίο εμφάνιζε τη διεπαφή σε λάθος γλώσσα."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -8908,10 +8908,6 @@
"messageformat": "Update Downloaded",
"description": "The title of update dialog when update download is completed."
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store",
"description": "The action text of build expiration dialog when app is installed from the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Open Signal on your phone",
"description": "Title of a banner alerting users if their primary device (e.g. phone) has not been logged into recently."
@ -10995,14 +10991,6 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "We fixed a bug in the sticker creator that displayed the interface in the wrong language. Even though stickers are pictures (and therefore worth a thousand words) it's still important to get the words right too.",
"description": "(Deleted 2026/06/24) Release notes for 8.16"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature.",
"description": "Release notes for 8.17"
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say.",
"description": "Release notes for 8.17"
"description": "Release notes for 8.16"
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Actualización descargada"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Abre Signal en tu teléfono"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Hemos solucionado un error en el creador de stickers que hacía que la interfaz se mostrase en el idioma incorrecto. Aunque los stickers sean imágenes (y ya por sí solos valgan más que mil palabras), sigue siendo importante encontrar las palabras adecuadas."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Uuendus alla laaditud"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Ava Signal enda telefonis"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Parandasime kleebistelooja vea, mille tõttu kuvati liidest vales keeles."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Deskargatu da eguneraketa"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Ireki Signal telefonoan"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Interfazea hizkuntza okerrean bistaratzen zuen akats bat konpondu dugu eranskailu-sortzailean."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "به‌روزرسانی بارگیری شد"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "باز کردن سیگنال روی گوشی"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "اشکالی را در سازنده استیکر برطرف کردیم که رابط کاربری را به زبان اشتباه نمایش می‌داد."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Päivitys ladattu"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Avaa Signal puhelimessa"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Korjasimme tarrojen luontisovelluksen virheen, joka näytti käyttöliittymän väärällä kielellä."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Mise à jour téléchargée"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Ouvrez Signal sur votre téléphone"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "L'outil de création de stickers s'affichait dans la mauvaise langue ? C'est de l'histoire ancienne. Même si les stickers sont des images et qu'une image vaut mille mots, nous n'allions pas laisser ce bug avoir le dernier mot."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Nuashonrú Íoslódáilte"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Oscail Signal ar do ghuthán"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Réitíomar fabht sa chruthaitheoir greamán a thaispeáin an comhéadan sa teanga chontráilte."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Actualización descargada"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Abre Signal no teu móbil"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Arranxamos un erro no creador de paquetes de stickers que mostraba a interface nun idioma diferente."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "અપડેટ ડાઉનલોડ થઈ ગયું"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "તમારા ફોન પર Signal ખોલો"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "અમે એવો બગ ઉકેલ્યો છે જે સ્ટીકર ક્રિએટરમાં ખોટી ભાષામાં ઇન્ટરફેસ દર્શાવતો હતો."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "העדכון ירד"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "פתח את Signal בטלפון שלך"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "תיקנו באג ביוצר הסטיקרים שהציג את הממשק בשפה הלא נכונה."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "अपडेट किया गया"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "अपने फ़ोन पर Signal खोलें"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "हमने स्टिकर क्रिएटर की एक गड़बड़ी को ठीक कर दिया है, जिसकी वजह से ऐप की स्क्रीन किसी दूसरी भाषा में दिख रही थी। यह बात ठीक है कि स्टिकर तस्वीरें हैं (और जैसा कहा जाता है कि एक तस्वीर हज़ार शब्दों के बराबर होती है), लेकिन शब्दों का सही तरीके से नज़र आना भी उतना ही ज़रूरी है।"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Ažuriranje je preuzeto"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Otvorite Signal na vašem telefonu"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Ispravili smo programsku pogrešku alata za izradu naljepnica koja je prikazivala sučelje na pogrešnom jeziku."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Frissítés letöltve"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Nyisd meg a Signalt a telefonodon!"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Kijavítottunk egy hibát a matricakészítőben, amely miatt a felület rossz nyelven jelent meg."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Pembaruan Diunduh"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Buka Signal di ponsel Anda"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Kami telah memperbaiki bug pada pembuat stiker yang sebelumnya menampilkan antarmuka dalam bahasa yang tidak sesuai."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Aggiornamento scaricato"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Apri Signal sul tuo telefono"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Abbiamo risolto un bug nello strumento per creare gli adesivi, dove a volte si vedeva l'interfaccia tradotta in una lingua diversa da quella impostata. Sì, un'immagine (e quindi un adesivo) vale più di mille parole, ma prima devi usare le giuste parole per trovarla."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "アップデートがダウンロードされました"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "ご利用のスマートフォンでSignalを開いてください"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "ステッカークリエイターで、インターフェイスが誤った言語で表示されるバグを修正しました。"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "განახლება გადმოწერილია"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "გახსენი Signal-ი შენს ტელეფონში"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "სტიკერების შემქმნელის ბაგი გამოვასწორეთ, რომლის გამოც ინტერფეისი არასწორ ენაზე ჩანდა. მიუხედავად იმისა, რომ სტიკერი სურათია, სათაურიც სწორად უნდა ჩანდეს."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Жаңа нұсқасы жүктеп алынды"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Телефоныңызда Signal қолданбасын ашыңыз"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Интерфейсті басқа тілде көрсетіп тұратын стикер жасау құралындағы ақауды түзеттік. Стикерлер (мың сөздің орнын басатын) суреттерден ғана тұрса да, сөздерді дұрыс қолдана білу әлі де маңызды."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "កំណែថ្មីត្រូវបានទាញយក"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "បើក Signal នៅលើទូរសព្ទរបស់អ្នក"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "យើងបានដោះស្រាយបញ្ហាមួយនៅក្នុងមុខងារបង្កើតស្ទីកគ័រដែលបានបង្ហាញអ៊ីនធើហ្វេសខុសភាសា។ ទោះបីជាស្ទីកគ័រគឺជារូបភាព (ដែលមានអត្ថន័យរាប់ពាន់ពាក្យក៏ដោយ) ការសរសេរឱ្យត្រូវពាក្យក៏នៅតែមានសារៈសំខាន់ដែរ។"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "ಅಪ್‌ಡೇಟ್ ಡೌನ್‌ಲೋಡ್ ಆಗಿದೆ"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "ನಿಮ್ಮ ಫೋನ್‌ನಲ್ಲಿ Signal ತೆರೆಯಿರಿ"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "ಇಂಟರ್‌ಫೇಸ್ ಅನ್ನು ತಪ್ಪು ಭಾಷೆಯಲ್ಲಿ ಪ್ರದರ್ಶಿಸುತ್ತಿದ್ದ ಸ್ಟಿಕ್ಕರ್ ಕ್ರಿಯೇಟರ್‌ನಲ್ಲಿನ ಬಗ್ ಅನ್ನು ನಾವು ಸರಿಪಡಿಸಿದ್ದೇವೆ. ಸ್ಟಿಕ್ಕರ್‌ಗಳು ಚಿತ್ರಗಳಾಗಿದ್ದರೂ (ಮತ್ತು ಒಂದು ಚಿತ್ರ ಸಾವಿರ ಪದಗಳಿಗೆ ಸಮಾನವಾದರೂ), ಪದಗಳನ್ನು ಸರಿಯಾಗಿ ಬಳಸುವುದೂ ಅಷ್ಟೇ ಮುಖ್ಯವಾಗಿದೆ."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "업데이트 다운로드 완료"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "휴대전화에서 Signal을 여세요."
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "스티커 제작 도구에서 인터페이스 언어가 잘못 표시되던 오류를 수정했어요. 스티커가 백 마디 말보다 나은 그림이긴 하지만, 정확한 글로 표시하는 것도 역시 중요하니까요."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Жаңы версия жүктөлүп алынды"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Телефонуңузда Signal'ды ачыңыз"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Интерфейси туура эмес тилде көрүнгөн стикерлерди түзгүчтөгү мүчүлүштүктү оңдодук. Стикерлер сүрөт түрүндө болсо да, алардагы текст туура көрүнүшү керек."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Naujinys atsisiųstas"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Atverkite savo telefone Signal programėlę"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Ištaisėme lipdukų kūrimo priemonės klaidą, dėl kurios sąsaja buvo rodoma neteisinga kalba."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Atjauninājums ir lejupielādēts"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Atveriet Signal tālrunī"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Mēs uzlīmju izveides programmā salabojām kļūdu, kuras dēļ saskarne tika rādīta nepareizā valodā. Lai gan uzlīmes ir attēli (un tāpēc tās ir tūkstoš vārdu vērtas), mums šķiet svarīgi uzrakstīt pareizi arī vārdus."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Новата верзија е преземена"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Отворете Signal на вашиот телефон"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Решивме грешка во креаторот на налепници при која се прикажуваше интерфејсот во погрешен јазик."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "അപ്ഡേറ്റ് ഡൗൺലോഡ് ചെയ്‌തു"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "നിങ്ങളുടെ ഫോണിൽ Signal തുറക്കുക"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "സ്റ്റിക്കർ ക്രിയേറ്ററിലെ ഇന്റർഫേസ് തെറ്റായ ഭാഷയിൽ കാണിച്ചിരുന്ന ഒരു തകരാർ ഞങ്ങൾ പരിഹരിച്ചു. സ്റ്റിക്കറുകൾ ചിത്രങ്ങളാണെങ്കിലും (അതിനാൽ തന്നെ ആയിരം വാക്കുകൾക്ക് തുല്യമാണെങ്കിലും) വാക്കുകൾ കൃത്യമായിരിക്കുക എന്നതും പ്രധാനമാണ്."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "अपडेट डाउनलोड केली"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "आपल्या फोनवर Signal उघडा"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "आम्ही स्टिकर निर्मात्यामधील एक बग दुरुस्त केला जो चुकीच्या भाषेमध्ये इंटरफेस दाखवायचा. जरी स्टिकर ही चित्रं असली (आणि म्हणूनच प्रत्येकी 1000 शब्दांसारखी असली), तरी योग्य ते शब्द वापरणं गरजेचं असतंच."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Kemas Kini Dimuat Turun"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Buka Signal di telefon anda"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Kami telah membetulkan pepijat dalam pencipta pelekat yang memaparkan antara muka dalam bahasa yang salah."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "အပ်ဒိတ် ဒေါင်းလုဒ်လုပ်ပြီး"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "သင့်ဖုန်းတွင် Signal ကို ဖွင့်ရန်"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "စတစ်ကာဖန်တီးရေးတွင် Interface ကို မှားယွင်းသော ဘာသာစကားဖြင့် ပြသနေသည့် ချွတ်ယွင်းချက်တစ်ခုကို ပြင်ဆင်ပြီးဖြစ်ပါသည်။"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Oppdateringen er lastet ned"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Åpne Signal på telefonen"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Vi har rettet opp i en feil som førte til at brukergrensesnittet for klistremerker ble vist på feil språk."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Update gedownload"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Open Signal op je telefoon"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "We hebben een fout opgelost in de stickerpakketmaker waardoor de interface in de verkeerde taal werd weergegeven. Ook al zegt een sticker meer dan duizend woorden, de juiste woorden maken het verschil."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "ਅੱਪਡੇਟ ਡਾਊਨਲੋਡ ਕੀਤੀ ਗਈ"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "ਆਪਣੇ ਫ਼ੋਨ ਉੱਤੇ Signal ਖੋਲ੍ਹੋ"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "ਅਸੀਂ ਸਟਿੱਕਰ ਕ੍ਰੀਏਟਰ ਵਿੱਚ ਇੱਕ ਬੱਗ ਠੀਕ ਕੀਤਾ ਹੈ ਜਿਸ ਵਿੱਚ ਇੰਟਰਫੇਸ ਗਲਤ ਭਾਸ਼ਾ ਵਿੱਚ ਦਿਖਾਈ ਦਿੰਦਾ ਸੀ।"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Aktualizacja pobrana"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Otwórz Signal na swoim telefonie"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Naprawiliśmy błąd w kreatorze naklejek, który powodował wyświetlanie interfejsu w nieprawidłowym języku. Choć naklejki są obrazkami (a obraz wart jest tysiąca słów), to warto dobrze dobrać też i słowa."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Update concluído"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Abra o Signal no seu celular"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Corrigimos um erro no criador de figurinhas que mostrava o idioma errado na interface. A gente sabe que as figurinhas são imagens e valem mais que mil palavras, mas também é importante usar as palavras certas, né?"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Atualização descarregada"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Abra o Signal no seu telemóvel"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Corrigimos um erro no criador de autocolantes que mostrava a interface no idioma errado."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Actualizare Descărcată"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Deschide Signal pe telefonul tău"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Am reparat un bug în creatorul de abțibilduri care afișa interfața în limba greșită. Deși abțibildurile sunt imagini (deci valorează o mie de cuvinte) este important totuși să nimerești cuvintele potrivite."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Обновление загружено"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Откройте Signal на своем телефоне"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Мы исправили ошибку в создателе стикеров, из-за которой интерфейс отображался на неправильном языке. Несмотря на то, что стикеры представляют собой картинки (и, следовательно, стоят тысячи слов), правильно подбирать слова всё равно очень важно."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Aktualizácia bola stiahnutá"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Otvorte Signal na svojom telefóne"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Opravili sme chybu v nástroji na vytváranie nálepiek, ktorá zobrazovala rozhranie v nesprávnom jazyku."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Posodobitev prenesena"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Odprite Signal v svoji napravi"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Odpravili smo napako v urejevalniku nalepk, zaradi katere je bil uporabniški vmesnik prikazan v napačnem jeziku. Čeprav so nalepke slike (in zato povedo več kot tisoč besed), je še vedno pomembno, da so tudi besede pravilne."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Përditësimi u shkarkua"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Hap Signal në telefonin tënd"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Rregulluam një gabim në krijuesin e ngjitëseve që e shfaqte ndërfaqen në gjuhën e gabuar."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Нова верзија је преузета"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Отворите Signal на телефону"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Поправили смо грешку у креатору налепница која је интерфејс приказивала на погрешном језику."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Uppdatering nedladdad"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Öppna Signal på din telefon"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Vi har åtgärdat ett fel i klistermärkesskaparen som gjorde att gränssnittet visades på fel språk."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Sasisho Limepakuliwa"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Fungua Signal kwenye simu yako"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Tumerekebisha hitilafu kwenye programu ya kutengeneza vibadiko ambavyo vilikuwa vikionyesha kiolesura katika lugha isiyo sahihi. Ingawa vibandiko ni picha (na picha husema mengi), bado ni muhimu kuhakikisha kwamba maneno nayo yako sahihi."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "புதுப்பிப்பு பதிவிறக்கப்பட்டது"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "உங்கள் மொபைலில் சிக்னல்-ஐத் திறக்கவும்"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "ஸ்டிக்கர் கிரியேட்டரில் இடைமுகத்தை தவறான மொழியில் காட்டக்கூடிய ஒரு பிழையைச் சரிசெய்தோம்."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "అప్‌డేట్ డౌన్‌లోడ్ చేయబడింది"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "మీ ఫోన్‌పై Signal ని ఓపెన్ చేయండి"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "స్టిక్కర్ క్రియేటర్‌లో ఇంటర్‌ఫేస్‌ను తప్పు భాషలో ప్రదర్శించిన ఒక బగ్‌ను మేము సరిచేశాము. స్టిక్కర్‌లు చిత్రాలే అయినప్పటికీ (అందువల్లనే వెయ్యి మాటలతో సమానం), పదాలను సరిగ్గా ఎంచుకోవడం కూడా ఇప్పటికీ ముఖ్యమే."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "ดาวน์โหลดการอัปเดตแล้ว"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "เปิด Signal บนโทรศัพท์ของคุณ"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "แก้ไขบั๊กในศูนย์สร้างสรรค์ชุดสติกเกอร์ (Sticker Creator) ที่เคยแสดงผลผิดภาษา"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Na-download na ang Update"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "I-open ang Signal sa iyong phone"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Inayos namin ang isang bug sa sticker creator na nagpapakita ng interface sa maling language."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Güncelleme İndirildi"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Signal'ı telefonunda aç"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Arayüzü yanlış dilde gösteren çıkartma oluşturucudaki bir hatayı düzelttik. Çıkartmalar bazen onlarca kelimeyi barındıran resimler de olsa, kelimeleri doğru anlamak halen önemli."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "يېڭىلانما چۈشۈرۈلدى"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "تېلېفونىڭىزدا Signal نى ئېچىڭ"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "بىز چىراي ئىپادە ياساش قورالىدىكى كۆرۈنمە يۈزنىڭ خاتا تىلدا كۆرسىتىلىشىگە سەۋەب بولغان بىر خاتالىقنى تۈزەتتۇق .8.16 نەشر نۇسخىسى ئۈچۈن تارقىتىلدى. گەرچە چىراي ئىپادىلىرى رەسىم بولغاچقا «مىڭ سۆزنىڭ قىممىتىگە ئىگە» دەپ قارالسىمۇ، سۆزلەرنىمۇ توغرا ئىشلىتىش يەنىلا ناھايىتى مۇھىم."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Оновлення завантажено"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Відкрийте Signal на телефоні"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Ми виправили помилку під час вибору стікерів, коли інтерфейс показувався іншою мовою. Хоч це й зображення (і вони самі по собі варті тисячі слів), все ж важливо добирати правильні слова."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "اپ ڈیٹ ڈاؤن لوڈ ہو گئی ہے"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "اپنے فون پر Signal کھولیں"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "ہم نے اسٹیکر کے تخلیق کار میں ایک نقص کی درستگی کی جس کی وجہ سے انٹرفیس غلط زبان میں ظاہر ہو رہا تھا۔ اگرچہ اسٹیکر تصویریں ہوتے ہیں (اس لیے ہزاروں الفاظ کا متبادل بھی ہیں) اس لیے ضروری ہے کہ الفاظ درست ہوں۔"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "Đã tải Bản Cập Nhật"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "Mở Signal trên điện thoại của bạn"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "Chúng tôi đã sửa một lỗi trong trình tạo nhãn dán khiến giao diện hiển thị sai ngôn ngữ."
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "已經下載咗更新"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "喺手機度打開 Signal"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "我們修正咗貼圖製作器入面攪到介面顯示嘅語言唔啱嘅錯誤。就算貼圖係圖(所謂「一圖勝千言」),但文字都要寫啱至得㗎。"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "更新已下载完毕"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "在您的手机上打开Signal"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "我们修复了贴纸创建器中的一个错误,该错误会导致界面显示为错误的语言。"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "更新已下載"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "在手機上開啟 Signal"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "我們修正了貼圖製作器中會導致介面不能顯示正確語言的錯誤。儘管貼圖是圖像(所謂「一圖勝千言」),但文字也要寫對。"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -6700,9 +6700,6 @@
"icu:DialogUpdate__downloaded": {
"messageformat": "更新已下載"
},
"icu:DialogExpiredBuild__upgrade-mas": {
"messageformat": "Click to go to the App Store"
},
"icu:CriticalIdlePrimaryDevice__title": {
"messageformat": "在手機上開啟 Signal"
},
@ -8270,11 +8267,5 @@
},
"icu:WhatsNew__8.16--0": {
"messageformat": "我們修正了貼圖製作器中會導致介面不能顯示正確語言的錯誤。儘管貼圖是圖像(所謂「一圖勝千言」),但文字也要寫對。"
},
"icu:WhatsNew__8.17--0": {
"messageformat": "Group admins can now delete recently sent messages in a group chat. If someone accidentally posts a spoiler in your Book Club group and then walks away from their phone, a group admin can delete it to keep the plot twist intact. You can easily see when a message was deleted and who removed it, just like the existing \"Delete for Everyone\" feature."
},
"icu:WhatsNew__8.17--1": {
"messageformat": "We also increased the maximum number of pinned chats from 4 to 10, so you can show 6 more people how much you love what they have to say."
}
}

View File

@ -20,35 +20,35 @@
},
{
"family": "ipv6",
"address": "2600:9000:27e0:1600:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:1e00:1d:4f32:50c0:93a1"
},
{
"family": "ipv6",
"address": "2600:9000:27e0:2c00:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:2400:1d:4f32:50c0:93a1"
},
{
"family": "ipv6",
"address": "2600:9000:27e0:3c00:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:6c00:1d:4f32:50c0:93a1"
},
{
"family": "ipv6",
"address": "2600:9000:27e0:4200:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:aa00:1d:4f32:50c0:93a1"
},
{
"family": "ipv6",
"address": "2600:9000:27e0:4a00:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:ae00:1d:4f32:50c0:93a1"
},
{
"family": "ipv6",
"address": "2600:9000:27e0:6a00:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:ce00:1d:4f32:50c0:93a1"
},
{
"family": "ipv6",
"address": "2600:9000:27e0:a800:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:e400:1d:4f32:50c0:93a1"
},
{
"family": "ipv6",
"address": "2600:9000:27e0:c800:1d:4f32:50c0:93a1"
"address": "2600:9000:27e0:f200:1d:4f32:50c0:93a1"
}
]
},
@ -146,11 +146,11 @@
"endpoints": [
{
"family": "ipv4",
"address": "142.251.41.19"
"address": "142.251.215.243"
},
{
"family": "ipv6",
"address": "2607:f8b0:4007:803::2013"
"address": "2607:f8b0:4007:808::2013"
}
]
},

View File

@ -6,7 +6,7 @@
"description": "Private messaging from your desktop",
"desktopName": "signal.desktop",
"repository": "https://github.com/signalapp/Signal-Desktop.git",
"version": "8.19.0-alpha.1",
"version": "8.16.0",
"license": "AGPL-3.0-only",
"author": {
"name": "Signal Messenger, LLC",
@ -112,19 +112,18 @@
"electron:install-app-deps": "electron-builder install-app-deps",
"check-upgradeable-deps": "node scripts/check-upgradeable-deps.mjs",
"react-devtools": "react-devtools",
"run-with-devtools": "cross-env REACT_DEVTOOLS=1 run-p --print-label react-devtools start",
"update-signal-symbols": "node scripts/update-signal-symbols.mjs"
"run-with-devtools": "cross-env REACT_DEVTOOLS=1 run-p --print-label react-devtools start"
},
"optionalDependencies": {
"fs-xattr": "0.4.0"
},
"dependencies": {
"@indutny/mac-screen-share": "1.2.5",
"@indutny/simple-windows-notifications": "2.0.21",
"@signalapp/libsignal-client": "0.96.3",
"@indutny/mac-screen-share": "1.0.13",
"@indutny/simple-windows-notifications": "2.0.16",
"@signalapp/libsignal-client": "0.95.0",
"@signalapp/mute-state-change": "workspace:*",
"@signalapp/ringrtc": "2.69.4",
"@signalapp/sqlcipher": "3.3.9",
"@signalapp/sqlcipher": "3.3.5",
"@signalapp/windows-ucv": "workspace:*",
"google-libphonenumber": "3.2.44"
},
@ -368,7 +367,7 @@
"minOSVersion": "21.0.1"
}
},
"singleArchFiles": "node_modules/{@signalapp,@indutny}/{libsignal-client/prebuilds/**,ringrtc/build/**,sqlcipher/prebuilds/**,mac-screen-share/prebuilds/**}",
"singleArchFiles": "node_modules/@signalapp/{libsignal-client/prebuilds/**,ringrtc/build/**,sqlcipher/prebuilds/**}",
"target": [
{
"target": "zip",
@ -619,7 +618,7 @@
"node_modules/@signalapp/windows-ucv/build/Release/*.node",
"node_modules/@signalapp/mute-state-change/build/Release/*.node",
"node_modules/@indutny/simple-windows-notifications/prebuilds/${platform}-${arch}/*.node",
"node_modules/@indutny/mac-screen-share/prebuilds/${platform}-${arch}/*.node",
"node_modules/@indutny/mac-screen-share/build/Release/*.node",
"node_modules/fs-xattr/build/Release/*.node",
"!node_modules/tar",
"sticker-creator/dist/**"

View File

@ -31,11 +31,11 @@
},
"license": "AGPL-3.0-only",
"dependencies": {
"bindings": "1.5.0",
"node-addon-api": "8.8.0"
"bindings": "^1.5.0",
"node-addon-api": "*"
},
"devDependencies": {
"@types/bindings": "1.5.5",
"@types/bindings": "^1.5.5",
"@types/node": "24.12.0",
"typescript": "6.0.3"
}

76
pnpm-lock.yaml generated
View File

@ -38,14 +38,14 @@ importers:
.:
dependencies:
'@indutny/mac-screen-share':
specifier: 1.2.5
version: 1.2.5
specifier: 1.0.13
version: 1.0.13
'@indutny/simple-windows-notifications':
specifier: 2.0.21
version: 2.0.21
specifier: 2.0.16
version: 2.0.16
'@signalapp/libsignal-client':
specifier: 0.96.3
version: 0.96.3
specifier: 0.95.0
version: 0.95.0
'@signalapp/mute-state-change':
specifier: workspace:*
version: link:packages/mute-state-change
@ -53,8 +53,8 @@ importers:
specifier: 2.69.4
version: 2.69.4
'@signalapp/sqlcipher':
specifier: 3.3.9
version: 3.3.9
specifier: 3.3.5
version: 3.3.5
'@signalapp/windows-ucv':
specifier: workspace:*
version: link:packages/windows-ucv
@ -715,14 +715,14 @@ importers:
packages/windows-ucv:
dependencies:
bindings:
specifier: 1.5.0
specifier: ^1.5.0
version: 1.5.0
node-addon-api:
specifier: 8.8.0
version: 8.8.0
specifier: '*'
version: 8.5.0
devDependencies:
'@types/bindings':
specifier: 1.5.5
specifier: ^1.5.5
version: 1.5.5
'@types/node':
specifier: 24.12.0
@ -1733,8 +1733,8 @@ packages:
'@indutny/inflate@1.0.5':
resolution: {integrity: sha512-dZObKXR6i2uQnHmXLyGEpQh/+AHwBQI4pbCRYQaI7qd6krNrN8a8GksoPSg/C6mSpjWsfXMBYpHiwnl5l/B5Jg==, tarball: https://registry.npmjs.org/@indutny/inflate/-/inflate-1.0.5.tgz}
'@indutny/mac-screen-share@1.2.5':
resolution: {integrity: sha512-k+w3/kRXubx2bPEmgNXblRbjJp+ofk3b5oFbBrTeAFOboV6ZrBJE4vgoHWWyAaT6L/RthWzxrpFPFCpJ2rVX8g==, tarball: https://registry.npmjs.org/@indutny/mac-screen-share/-/mac-screen-share-1.2.5.tgz}
'@indutny/mac-screen-share@1.0.13':
resolution: {integrity: sha512-fCOYWGaIuZAwfk/eUUjqPKge4+PKKCwTsuH9SSoaBZMP8IsWQtyyrTVpeuq84oDren4b9EUgRGgh2t950sQA0w==, tarball: https://registry.npmjs.org/@indutny/mac-screen-share/-/mac-screen-share-1.0.13.tgz}
'@indutny/parallel-prettier@3.0.0':
resolution: {integrity: sha512-v6WkYfLUYfDELBsynhrMpDxLMZZ7LRhfB1hfeb4ERoViW5zb7aovfAsNjiZrWH4k0KZcCi3iMNF+d9i8h0UmzA==, tarball: https://registry.npmjs.org/@indutny/parallel-prettier/-/parallel-prettier-3.0.0.tgz}
@ -1757,8 +1757,8 @@ packages:
resolution: {integrity: sha512-h0Y+bFkVSalOYfprzUGUdwsB0A9JJ7g7XZAsUInMxIn8SnRa1xPFmAdHks/Q9gCCOA+THHaDo/SF54+dUTHR6Q==, tarball: https://registry.npmjs.org/@indutny/rezip-electron/-/rezip-electron-3.0.2.tgz}
hasBin: true
'@indutny/simple-windows-notifications@2.0.21':
resolution: {integrity: sha512-qJEd8Ly34cEB2Vy5qvtaTAA/BzCdFZkW4cYE8gBgxksMONhTgXhvdL0Fs8ljbXyiAzxbwQpzODEQcxzSvpjedw==, tarball: https://registry.npmjs.org/@indutny/simple-windows-notifications/-/simple-windows-notifications-2.0.21.tgz}
'@indutny/simple-windows-notifications@2.0.16':
resolution: {integrity: sha512-twYOSz8l/bJkYumNiOE6vkdPXr6pmoR0fq6OBLaxVoGRz404mWLjFVMaRcVD2zVzzaQBXIUyaxfLbVjxnM5M4A==, tarball: https://registry.npmjs.org/@indutny/simple-windows-notifications/-/simple-windows-notifications-2.0.16.tgz}
'@indutny/sneequals@4.0.0':
resolution: {integrity: sha512-kQUBQtcm4aVqJil+KRfA7SycJqcWlFEa7MJTYyl4XAahHOPXnzgqvlzUPQOw1tRFlvnzxRpXNUpJxej2fdAPjg==, tarball: https://registry.npmjs.org/@indutny/sneequals/-/sneequals-4.0.0.tgz}
@ -4193,8 +4193,8 @@ packages:
'@signalapp/libsignal-client@0.92.2':
resolution: {integrity: sha512-mSYKpw32Rtmm+D1y8NKzNA9wkiuU60gXRGuum6NTGRN9C3NI4R1cb6xE9w7q+6rjR4zAb4qZWb9QUG5QcLr7pg==, tarball: https://registry.npmjs.org/@signalapp/libsignal-client/-/libsignal-client-0.92.2.tgz}
'@signalapp/libsignal-client@0.96.3':
resolution: {integrity: sha512-KZAIr8dR7XTlLo8fNOBVx4btTeZ3FnnUuuiOe+oeTgs4EEmg4gkN5RTqgnVgG+nUfNTzR0SXl2gTqFx79apOeg==, tarball: https://registry.npmjs.org/@signalapp/libsignal-client/-/libsignal-client-0.96.3.tgz}
'@signalapp/libsignal-client@0.95.0':
resolution: {integrity: sha512-CrbsJWpZSr1+Rj+c69R9vQ9mllmrixXqkGOCfalOaYOrX+pFQnDnnLIl3kPRekFfTqWq3SQFOlVOB56g6KpDow==, tarball: https://registry.npmjs.org/@signalapp/libsignal-client/-/libsignal-client-0.95.0.tgz}
'@signalapp/minimask@1.0.1':
resolution: {integrity: sha512-QAwo0joA60urTNbW9RIz6vLKQjy+jdVtH7cvY0wD9PVooD46MAjE40MLssp4xUJrph91n2XvtJ3pbEUDrmT2AA==, tarball: https://registry.npmjs.org/@signalapp/minimask/-/minimask-1.0.1.tgz}
@ -4213,8 +4213,8 @@ packages:
resolution: {integrity: sha512-OLavGfCzfYuqUVoAtTeHi7QrXpVNmT8LxzOI9XOPId29bn5gJNrAG31IPVw7Fw7vvWpZwZHFi5MTmcmZGibs4A==, tarball: https://registry.npmjs.org/@signalapp/ringrtc/-/ringrtc-2.69.4.tgz}
hasBin: true
'@signalapp/sqlcipher@3.3.9':
resolution: {integrity: sha512-51NAV0CqIEreGx3r0hq85vjHC8NXZhGr9efywaqHRsjpbEdvdYARmFxObmMI55rjyqE5eLQ/QsPJzigBoQ6thw==, tarball: https://registry.npmjs.org/@signalapp/sqlcipher/-/sqlcipher-3.3.9.tgz}
'@signalapp/sqlcipher@3.3.5':
resolution: {integrity: sha512-0kkHQixiaFOFYCXP6J8zsvXeq7REf5nucX+BMY8Gy5E6F2BEM2Ap9NsDNaB+wHZ6QqqsItQRvSE4PaYhTtWGIg==, tarball: https://registry.npmjs.org/@signalapp/sqlcipher/-/sqlcipher-3.3.5.tgz}
'@sinclair/typebox@0.27.8':
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==, tarball: https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz}
@ -8542,10 +8542,6 @@ packages:
resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==, tarball: https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz}
engines: {node: ^18 || ^20 || >= 21}
node-addon-api@8.8.0:
resolution: {integrity: sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==, tarball: https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.8.0.tgz}
engines: {node: ^18 || ^20 || >= 21}
node-api-version@0.2.1:
resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==, tarball: https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz}
@ -10443,12 +10439,12 @@ packages:
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==, tarball: https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz}
undici@6.27.0:
resolution: {integrity: sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==, tarball: https://registry.npmjs.org/undici/-/undici-6.27.0.tgz}
undici@6.26.0:
resolution: {integrity: sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==, tarball: https://registry.npmjs.org/undici/-/undici-6.26.0.tgz}
engines: {node: '>=18.17'}
undici@7.28.0:
resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==, tarball: https://registry.npmjs.org/undici/-/undici-7.28.0.tgz}
undici@7.25.0:
resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==, tarball: https://registry.npmjs.org/undici/-/undici-7.25.0.tgz}
engines: {node: '>=20.18.1'}
unicorn-magic@0.3.0:
@ -11371,7 +11367,7 @@ snapshots:
semver: 7.7.4
sumchecker: 3.0.1
optionalDependencies:
undici: 7.28.0
undici: 7.25.0
transitivePeerDependencies:
- supports-color
@ -11835,10 +11831,10 @@ snapshots:
'@indutny/inflate@1.0.5': {}
'@indutny/mac-screen-share@1.2.5':
'@indutny/mac-screen-share@1.0.13':
dependencies:
bindings: 1.5.0
node-addon-api: 8.8.0
node-addon-api: 8.5.0
'@indutny/parallel-prettier@3.0.0(prettier@3.8.3)':
dependencies:
@ -11867,10 +11863,10 @@ snapshots:
functional-red-black-tree: 1.0.1
yauzl: 3.4.0
'@indutny/simple-windows-notifications@2.0.21':
'@indutny/simple-windows-notifications@2.0.16':
dependencies:
bindings: 1.5.0
node-addon-api: 8.8.0
node-addon-api: 8.5.0
'@indutny/sneequals@4.0.0': {}
@ -14562,7 +14558,7 @@ snapshots:
node-gyp-build: 4.8.4
type-fest: 4.26.1
'@signalapp/libsignal-client@0.96.3':
'@signalapp/libsignal-client@0.95.0':
dependencies:
node-gyp-build: 4.8.4
type-fest: 4.26.1
@ -14607,9 +14603,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@signalapp/sqlcipher@3.3.9':
'@signalapp/sqlcipher@3.3.5':
dependencies:
node-addon-api: 8.8.0
node-addon-api: 8.5.0
node-gyp-build: 4.8.4
'@sinclair/typebox@0.27.8': {}
@ -19732,8 +19728,6 @@ snapshots:
node-addon-api@8.5.0: {}
node-addon-api@8.8.0: {}
node-api-version@0.2.1:
dependencies:
semver: 7.7.4
@ -19773,7 +19767,7 @@ snapshots:
semver: 7.7.4
tar: 7.5.15
tinyglobby: 0.2.17
undici: 6.27.0
undici: 6.26.0
which: 6.0.1
node-int64@0.4.0: {}
@ -21939,9 +21933,9 @@ snapshots:
undici-types@7.16.0: {}
undici@6.27.0: {}
undici@6.26.0: {}
undici@7.28.0:
undici@7.25.0:
optional: true
unicorn-magic@0.3.0: {}

View File

@ -79,9 +79,9 @@ allowBuilds:
'@indutny/simple-windows-notifications@2.0.16': true
'@parcel/watcher@2.5.6': true
'@signalapp/libsignal-client@0.92.2': true # duplicate package
'@signalapp/libsignal-client@0.96.3': true
'@signalapp/libsignal-client@0.95.0': true
'@signalapp/ringrtc@2.69.4': true
'@signalapp/sqlcipher@3.3.9': true
'@signalapp/sqlcipher@3.3.5': true
'@signalapp/windows-ucv@1.0.1': true
'@swc/core@1.10.16': true
'@tailwindcss/oxide@4.3.0': true

View File

@ -1,323 +0,0 @@
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { readFile, copyFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { assert } from './utils/assert.mjs';
const DESIGN_ASSETS_PATH = process.env.DESIGN_ASSETS_PATH;
assert(DESIGN_ASSETS_PATH != null, 'Missing DESIGN_ASSETS_PATH');
const DESKTOP_ROOT_DIR = join(import.meta.dirname, '..');
const DESIGN_ROOT_DIR = join(DESKTOP_ROOT_DIR, DESIGN_ASSETS_PATH);
const DESIGN_SYMBOLS_FONT_PATH = join(
DESIGN_ROOT_DIR,
'Signal Symbols',
'Font',
'SignalSymbolsVariable.woff2'
);
const DESKTOP_SYMBOLS_FONT_PATH = join(
DESKTOP_ROOT_DIR,
'fonts',
'signal-symbols',
'SignalSymbolsVariable.woff2'
);
const DESIGN_SYMBOLS_JSON_PATH = join(
DESIGN_ROOT_DIR,
'Signal Symbols',
'Font',
'symbols.json'
);
const DESKTOP_SYMBOLS_DEFS_PATH = join(
DESKTOP_ROOT_DIR,
'ts',
'axo',
'_internal',
'AxoSymbolDefs.generated.std.ts'
);
/**
* @typedef {Readonly<{ name: string; unicode: string }>} Glyph
* @typedef {ReadonlyArray<Glyph>} Glyphs
* @typedef {string | { ltr: string; rtl: string }} AxoSymbolBidi
* @typedef {{ icon: AxoSymbolBidi | null; inline: AxoSymbolBidi | null }} AxoSymbolValue
* @typedef {Readonly<{ name: string; value: AxoSymbolValue }>} AxoSymbol
*/
async function copyVariableFontFile() {
console.log('Copying variable font file...');
await copyFile(DESIGN_SYMBOLS_FONT_PATH, DESKTOP_SYMBOLS_FONT_PATH);
}
async function generateAxoSymbolDefs() {
console.log('Generating axo symbol defs...');
const text = await readFile(DESIGN_SYMBOLS_JSON_PATH, 'utf-8');
/** @type {Glyphs} */
const glyphs = JSON.parse(text);
/** @type {Map<string, Glyph>} */
const glyphsByName = new Map();
for (const glyph of glyphs) {
glyphsByName.set(glyph.name, glyph);
}
/**
* @param {string} name
* @returns {boolean}
*/
function isLeftOnly(name) {
return name.includes('left') && !name.includes('right');
}
/**
* @param {string} name
* @returns {boolean}
*/
function isRightOnly(name) {
return name.includes('right') && !name.includes('left');
}
/** @type {Array<AxoSymbol>} */
const symbols = [];
/**
* @param {string} name
* @returns {string}
*/
function stripInline(name) {
return name.replace(/-inline$/, '');
}
/**
* @param {Glyph} glyph
* @returns {string}
*/
function getSymbolName(glyph) {
const base = stripInline(glyph.name);
if (isLeftOnly(glyph.name)) {
return base.replace('left', '[start]');
}
if (isRightOnly(glyph.name)) {
return base.replace('right', '[end]');
}
return base;
}
/**
* @param {Glyph} glyph
* @returns {AxoSymbolBidi}
*/
function getSymbolBidi(glyph) {
/** @type {string | null} */
let otherName = null;
if (isLeftOnly(glyph.name)) {
otherName = glyph.name.replace('left', 'right');
}
if (isRightOnly(glyph.name)) {
otherName = glyph.name.replace('right', 'left');
}
if (otherName != null) {
const other = glyphsByName.get(otherName);
if (other == null) {
throw new Error(`Missing glyph ${otherName} for ${glyph.name}`);
}
return { ltr: glyph.unicode, rtl: other.unicode };
}
return glyph.unicode;
}
/** @type {Set<string>} */
const seen = new Set();
/**
* @param {Glyph} glyph
* @returns {AxoSymbolValue}
*/
function getSymbolValue(glyph) {
/** @type {Glyph | null} */
let icon;
/** @type {Glyph | null} */
let inline;
if (glyph.name.endsWith('-inline')) {
icon = glyphsByName.get(stripInline(glyph.name)) ?? null;
inline = glyph;
} else {
icon = glyph;
inline = glyphsByName.get(`${glyph.name}-inline`) ?? null;
}
if (icon != null) {
seen.add(icon.name);
}
if (inline != null) {
seen.add(inline.name);
}
return {
icon: icon != null ? getSymbolBidi(icon) : null,
inline: inline != null ? getSymbolBidi(inline) : null,
};
}
for (const glyph of glyphs) {
if (seen.has(glyph.name)) {
continue;
}
symbols.push({
name: getSymbolName(glyph),
value: getSymbolValue(glyph),
});
}
let res = '';
res += '// Copyright 2025 Signal Messenger, LLC\n';
res += '// SPDX-License-Identifier: AGPL-3.0-only\n';
res += '\n';
res +=
'// WARNING: This file is automatically generated, do not edit directly\n';
{
res += '\n';
res += '// Can be used in <AxoSymbol.Icon>\n';
res += 'export type AxoSymbolIconName =\n';
const lines = [];
for (const symbol of symbols) {
if (symbol.value.icon != null) {
lines.push(` | '${symbol.name}'`);
}
}
res += lines.join('\n');
res += ';\n';
}
{
res += '\n';
res += '// Symbols that can only be used in <AxoSymbol.InlineGlyph>\n';
res += 'type AxoSymbolInlineGlyphOnlyName =\n';
const lines = [];
for (const symbol of symbols) {
if (symbol.value.icon == null && symbol.value.inline != null) {
lines.push(` | '${symbol.name}'`);
}
}
res += lines.join('\n');
res += ';\n';
}
{
res += '\n';
res +=
'// Symbols with an inline-specific glyph that override the icon glyph\n';
res += 'type AxoSymbolInlineGlyphOverrideName =\n';
const lines = [];
for (const symbol of symbols) {
if (symbol.value.icon != null && symbol.value.inline != null) {
lines.push(` | '${symbol.name}'`);
}
}
res += lines.join('\n');
res += ';\n';
}
res += '\n';
res += '// Symbols that can be used in <AxoSymbol.InlineGlyph>\n';
res += 'export type AxoSymbolInlineGlyphName =\n';
res += ' | AxoSymbolIconName\n';
res += ' | AxoSymbolInlineGlyphOnlyName;\n';
res += '\n';
res += 'type SymbolDef = string | { ltr: string; rtl: string };\n';
res += 'type IconDefsName = AxoSymbolIconName;\n';
res += 'type InlineDefsName =\n';
res += ' | AxoSymbolInlineGlyphOnlyName\n';
res += ' | AxoSymbolInlineGlyphOverrideName;\n';
res += '\n';
res += 'const IconDefs: Record<string, SymbolDef> = {\n';
for (const symbol of symbols) {
if (symbol.value.icon != null) {
res += ' ';
if (/^[a-z_]+$/.test(symbol.name)) {
res += symbol.name;
} else {
res += `'${symbol.name}'`;
}
res += ': ';
if (typeof symbol.value.icon === 'string') {
res += `'\\u{${symbol.value.icon}}'`;
} else {
res += '{ ';
res += `ltr: '\\u{${symbol.value.icon.ltr}}', `;
res += `rtl: '\\u{${symbol.value.icon.rtl}}'`;
res += ' }';
}
res += ',\n';
}
}
res += '} satisfies Record<IconDefsName, SymbolDef>;\n';
res += '\n';
res += 'const InlineDefs: Record<string, SymbolDef> = {\n';
for (const symbol of symbols) {
if (symbol.value.inline != null) {
res += ' ';
if (/^[a-z_]+$/.test(symbol.name)) {
res += symbol.name;
} else {
res += `'${symbol.name}'`;
}
res += ': ';
if (typeof symbol.value.inline === 'string') {
res += `'\\u{${symbol.value.inline}}'`;
} else {
res += '{ ';
res += `ltr: '\\u{${symbol.value.inline.ltr}}', `;
res += `rtl: '\\u{${symbol.value.inline.rtl}}'`;
res += ' }';
}
res += ',\n';
}
}
res += '} satisfies Record<InlineDefsName, SymbolDef>;\n';
res += '\n';
res += '/** @testexport */\n';
res +=
'export function _getAllAxoSymbolIconNames(): ReadonlyArray<AxoSymbolIconName> {\n';
res += ' return Object.keys(IconDefs) as Array<AxoSymbolIconName>;\n';
res += '}\n';
res += '\n';
res += '/** @testexport */\n';
res +=
'export function _getAllAxoSymbolInlineGlyphNames(): ReadonlyArray<AxoSymbolInlineGlyphName> {\n';
res += ' return Object.keys(IconDefs) as Array<AxoSymbolIconName>;\n';
res += '}\n';
res += '\n';
res += 'export function getAxoSymbolIcon(\n';
res += ' name: AxoSymbolIconName,\n';
res += " dir: 'ltr' | 'rtl'\n";
res += '): string {\n';
res += ' const value = IconDefs[name];\n';
res += ' if (value == null) {\n';
res +=
// eslint-disable-next-line no-template-curly-in-string
' throw new TypeError(`Invalid symbol name for icon: ${name}`);\n';
res += ' }\n';
res += " return typeof value === 'string' ? value : value[dir];\n";
res += '}\n';
res += '\n';
res += 'export function getAxoSymbolInlineGlyph(\n';
res += ' name: AxoSymbolInlineGlyphName,\n';
res += " dir: 'ltr' | 'rtl'\n";
res += '): string {\n';
res += ' const value = InlineDefs[name] ?? IconDefs[name];\n';
res += ' if (value == null) {\n';
res +=
// eslint-disable-next-line no-template-curly-in-string
' throw new TypeError(`Invalid symbol name for inline glyph: ${name}`);\n';
res += ' }\n';
res += " return typeof value === 'string' ? value : value[dir];\n";
res += '}\n';
await writeFile(DESKTOP_SYMBOLS_DEFS_PATH, res, 'utf-8');
}
await Promise.all([copyVariableFontFile(), generateAxoSymbolDefs()]);

View File

@ -85,7 +85,7 @@ const ScalarKeys = [
'global.nicknames.min',
'global.normalDeleteMaxAgeInSeconds',
'global.pinnedChatLimit',
'global.pinnedMessageLimit',
'global.pinned_message_limit',
'global.textAttachmentLimitBytes',
'global.videoAttachments.transcodeTargetBytes',
] as const;

View File

@ -81,10 +81,7 @@ export function Row(): ReactNode {
<AxoStackedButton.Row spacing="md">
<AxoStackedButton.Root symbol="camera" label="Video" />
<AxoStackedButton.Root symbol="phone" label="Audio" />
<AxoStackedButton.Root
symbol="bell"
label="Hippopotomonstrosesquippedaliophobia"
/>
<AxoStackedButton.Root symbol="bell" label="Mute" />
<AxoStackedButton.Root symbol="search" label="Search" />
</AxoStackedButton.Row>
);

View File

@ -101,7 +101,7 @@ export namespace AxoStackedButton {
'outline-none select-none'
)}
aria-disabled={(pending || disabled) ?? undefined}
aria-label={pending ? intl.get('AxoButton.Pending') : undefined}
aria-label={pending ? intl.get('AxoButton.Pending') : label}
onClick={handleClick}
{...rest}
>
@ -129,9 +129,8 @@ export namespace AxoStackedButton {
</span>
<span
className={tw(
'line-clamp-2 w-full contain-inline-size',
'w-full truncate contain-inline-size',
'text-center type-caption font-medium',
'text-pretty wrap-break-word [word-break:auto-phrase] hyphens-auto',
disabled
? 'text-label-disabled forced-colors:text-[GrayText]'
: 'text-label-primary'
@ -171,7 +170,7 @@ export namespace AxoStackedButton {
<div
className={tw(
// Position items
'flex w-full items-start justify-center',
'flex w-full items-center justify-center',
RowSpacings.get(props.spacing),
// Allow items to wrap
'flex-wrap',

View File

@ -2361,8 +2361,6 @@ async function startApp(): Promise<void> {
actionSource: 'syncMessage',
});
} else {
// Sync message from other desktops or primary to download packs. Note,
// sticker sync messages do not contain position but storage records do.
void Stickers.downloadStickerPack(id, key, {
finalStatus: 'installed',
actionSource: 'syncMessage',

View File

@ -360,9 +360,7 @@ export function CompositionInput(props: Props): ReactElement {
canSendRef.current = true;
quill.setContents(delta);
if (cursorToEnd) {
// Waiting a tick here helps cursor positioning with custom blots
// that do not have surrounding guards
setTimeout(() => quill.setSelection(quill.getLength(), 0), 0);
quill.setSelection(quill.getLength(), 0);
}
},
[]
@ -598,15 +596,6 @@ export function CompositionInput(props: Props): ReactElement {
return true;
}
// If the cursor is at the beginning of a line, getLeaf() returns the blot that starts
// that line, even though the cursor is actually before it (offset === 0)
if (
(isMentionBlot(blotToDelete) || isEmojiBlot(blotToDelete)) &&
offset === 0
) {
return true;
}
// To match macOS option-delete, search back through non-newline whitespace
if (context.event.altKey && platform === 'darwin') {
const value = blotToDelete.value();

View File

@ -25,20 +25,6 @@ export function Basic(): JSX.Element {
<DialogExpiredBuild
containerWidthBreakpoint={containerWidthBreakpoint}
i18n={i18n}
isMAS={false}
/>
</FakeLeftPaneContainer>
);
}
export function MAS(): JSX.Element {
const containerWidthBreakpoint = WidthBreakpoint.Wide;
return (
<FakeLeftPaneContainer containerWidthBreakpoint={containerWidthBreakpoint}>
<DialogExpiredBuild
containerWidthBreakpoint={containerWidthBreakpoint}
i18n={i18n}
isMAS
/>
</FakeLeftPaneContainer>
);

View File

@ -12,30 +12,20 @@ import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser.dom.ts';
export type PropsType = {
containerWidthBreakpoint: WidthBreakpoint;
i18n: LocalizerType;
isMAS: boolean;
};
const WEBSITE_URL = 'https://signal.org/download/';
const APP_STORE_URL =
'https://apps.apple.com/app/signal-private-messenger/id1230208093';
export function DialogExpiredBuild({
containerWidthBreakpoint,
i18n,
isMAS,
}: PropsType): JSX.Element | null {
return (
<LeftPaneDialog
containerWidthBreakpoint={containerWidthBreakpoint}
type="error"
onClick={() => {
openLinkInWebBrowser(isMAS ? APP_STORE_URL : WEBSITE_URL);
openLinkInWebBrowser('https://signal.org/download/');
}}
clickLabel={
isMAS
? i18n('icu:DialogExpiredBuild__upgrade-mas')
: i18n('icu:upgrade')
}
clickLabel={i18n('icu:upgrade')}
hasAction
>
{i18n('icu:expiredWarning')}{' '}

View File

@ -192,7 +192,6 @@ const useProps = (overrideProps: OverridePropsType = {}): PropsType => {
hasPendingUpdate: false,
i18n,
isMacOS: false,
isMAS: false,
isOnline: true,
preferredWidthFromStorage: 320,
challengeStatus: 'idle',

View File

@ -133,7 +133,6 @@ export type PropsType = {
getServerAlertToShow: (alerts: ServerAlertsType) => ServerAlert | null;
i18n: LocalizerType;
isMacOS: boolean;
isMAS: boolean;
isNotificationProfileActive: boolean;
preferredWidthFromStorage: number;
selectedChatFolder: ChatFolder | null;
@ -250,7 +249,6 @@ export function LeftPane({
i18n,
lookupConversationWithoutServiceId,
isMacOS,
isMAS,
isNotificationProfileActive,
isOnline,
isUpdateDownloaded,
@ -691,10 +689,7 @@ export function LeftPane({
...commonDialogProps,
});
} else if (hasExpiredDialog) {
maybeRedDialog = renderExpiredBuildDialog({
...commonDialogProps,
isMAS,
});
maybeRedDialog = renderExpiredBuildDialog(commonDialogProps);
}
const dialogs = new Array<{ key: string; dialog: JSX.Element }>();

View File

@ -881,82 +881,6 @@ export function MediaEditor({
const [isSaving, setIsSaving] = useState(false);
const handleSave = useCallback(async () => {
if (!fabricCanvas) {
return;
}
setEditMode(undefined);
setIsSaving(true);
let data: Uint8Array<ArrayBuffer>;
let blurHash: string;
try {
const renderFabricCanvas = await cloneFabricCanvas(fabricCanvas);
renderFabricCanvas.remove(
...renderFabricCanvas.getObjects().filter(obj => obj.excludeFromExport)
);
let finalImageState: ImageStateType;
const pendingCrop = getPendingCrop(fabricCanvas);
if (pendingCrop) {
finalImageState = getNewImageStateFromCrop(imageState, pendingCrop);
moveFabricObjectsForCrop(renderFabricCanvas, pendingCrop);
drawFabricBackgroundImage({
fabricCanvas: renderFabricCanvas,
image,
imageState: finalImageState,
});
} else {
finalImageState = imageState;
}
renderFabricCanvas.setDimensions({
width: finalImageState.width,
height: finalImageState.height,
});
renderFabricCanvas.setZoom(1);
const renderedCanvas = renderFabricCanvas.toCanvasElement();
data = await canvasToBytes(renderedCanvas);
const blob = new Blob([data], {
type: IMAGE_PNG,
});
blurHash = await imageToBlurHash(blob);
} catch (err) {
onTryClose();
throw err;
} finally {
setIsSaving(false);
}
onDone({
contentType: IMAGE_PNG,
data,
caption: caption !== '' ? caption : undefined,
captionBodyRanges: captionBodyRanges ?? undefined,
blurHash,
isViewOnce: localIsViewOnce,
isHighQuality: localIsHighQuality,
});
}, [
captionBodyRanges,
imageState,
localIsHighQuality,
localIsViewOnce,
fabricCanvas,
image,
imageToBlurHash,
caption,
onDone,
onTryClose,
setEditMode,
setIsSaving,
]);
// In an ideal world we'd use <ModalHost /> to get the nice animation benefits
// but because of the way IText is implemented -- with a hidden textarea -- to
// capture keyboard events, we can't use ModalHost since that traps focus, and
@ -1492,7 +1416,7 @@ export function MediaEditor({
}}
emojiSkinToneDefault={emojiSkinToneDefault ?? null}
onSelectEmoji={onSelectEmoji}
onSubmit={handleSave}
onSubmit={noop}
onTextTooLong={onTextTooLong}
ourConversationId={ourConversationId}
placeholder={i18n('icu:MediaEditor__input-placeholder')}
@ -1528,7 +1452,78 @@ export function MediaEditor({
size="md"
disabled={!image}
pending={isSaving || isSending}
onClick={handleSave}
onClick={async () => {
if (!fabricCanvas) {
return;
}
setEditMode(undefined);
setIsSaving(true);
let data: Uint8Array<ArrayBuffer>;
let blurHash: string;
try {
const renderFabricCanvas =
await cloneFabricCanvas(fabricCanvas);
renderFabricCanvas.remove(
...renderFabricCanvas
.getObjects()
.filter(obj => obj.excludeFromExport)
);
let finalImageState: ImageStateType;
const pendingCrop = getPendingCrop(fabricCanvas);
if (pendingCrop) {
finalImageState = getNewImageStateFromCrop(
imageState,
pendingCrop
);
moveFabricObjectsForCrop(
renderFabricCanvas,
pendingCrop
);
drawFabricBackgroundImage({
fabricCanvas: renderFabricCanvas,
image,
imageState: finalImageState,
});
} else {
finalImageState = imageState;
}
renderFabricCanvas.setDimensions({
width: finalImageState.width,
height: finalImageState.height,
});
renderFabricCanvas.setZoom(1);
const renderedCanvas =
renderFabricCanvas.toCanvasElement();
data = await canvasToBytes(renderedCanvas);
const blob = new Blob([data], {
type: IMAGE_PNG,
});
blurHash = await imageToBlurHash(blob);
} catch (err) {
onTryClose();
throw err;
} finally {
setIsSaving(false);
}
onDone({
contentType: IMAGE_PNG,
data,
caption: caption !== '' ? caption : undefined,
captionBodyRanges: captionBodyRanges ?? undefined,
blurHash,
isViewOnce: localIsViewOnce,
isHighQuality: localIsHighQuality,
});
}}
>
{doneButtonLabel || i18n('icu:save')}
</AxoButton.Root>

View File

@ -28,10 +28,7 @@ export function WhatsNewModal({
const releaseNotes: ReleaseNotesType = {
date: new Date(window.getBuildCreation?.() || Date.now()),
version: window.getVersion?.(),
features: [
<I18n i18n={i18n} id="icu:WhatsNew__8.17--0" />,
<I18n i18n={i18n} id="icu:WhatsNew__8.17--1" />,
],
features: [<I18n i18n={i18n} id="icu:WhatsNew__8.16--0" />],
};
if (releaseNotes.features.length === 1 && !releaseNotes.header) {

View File

@ -309,11 +309,7 @@ export const MessageMetadata = forwardRef<HTMLDivElement, Readonly<PropsType>>(
return (
<SizeObserver onSizeChange={onResize}>
{measureRef => (
<div
className={className}
ref={refMerger(measureRef, ref)}
aria-live="off"
>
<div className={className} ref={refMerger(measureRef, ref)}>
{children}
</div>
)}
@ -322,7 +318,7 @@ export const MessageMetadata = forwardRef<HTMLDivElement, Readonly<PropsType>>(
}
return (
<div className={className} ref={ref} aria-live="off">
<div className={className} ref={ref}>
{children}
</div>
);

View File

@ -893,6 +893,7 @@ export async function runDownloadAttachmentJobInner({
const existingAttachmentData = await getExistingAttachmentDataForReuse({
plaintextHash: downloadedAttachment.plaintextHash,
contentType: attachment.contentType,
messageId,
logId,
});

View File

@ -1826,32 +1826,19 @@ export class BackupExportStream extends Readable {
} else if (contact && contact[0]) {
const [contactDetails] = contact;
const { name } = contactDetails;
const hasName =
name != null &&
Boolean(
name.givenName ||
name.familyName ||
name.prefix ||
name.suffix ||
name.middleName ||
name.nickname
);
item = {
contactMessage: {
contact: {
name:
hasName && name != null
? {
givenName: name.givenName ?? null,
familyName: name.familyName ?? null,
prefix: name.prefix ?? null,
suffix: name.suffix ?? null,
middleName: name.middleName ?? null,
nickname: name.nickname ?? null,
}
: null,
name: contactDetails.name
? {
givenName: contactDetails.name.givenName ?? null,
familyName: contactDetails.name.familyName ?? null,
prefix: contactDetails.name.prefix ?? null,
suffix: contactDetails.name.suffix ?? null,
middleName: contactDetails.name.middleName ?? null,
nickname: contactDetails.name.nickname ?? null,
}
: null,
number:
contactDetails.number?.map(number => ({
value: number.value,
@ -2512,17 +2499,16 @@ export class BackupExportStream extends Readable {
previousName: { e164: BigInt(renderInfo.e164) },
},
};
} else if (renderInfo.username) {
} else {
strictAssert(
renderInfo.username,
'Title transition must have username or e164'
);
updateMessage.update = {
learnedProfileChange: {
previousName: { username: renderInfo.username },
},
};
} else {
log.warn(
`${logId}: Dropping title transition without username or e164`
);
return { kind: NonBubbleResultKind.Drop };
}
return { kind: NonBubbleResultKind.Directionless, patch };

View File

@ -3624,6 +3624,15 @@ class CallingClass {
});
log.info(logId);
if (callRejectReason === CallRejectReason.ReceivedOfferWhileActive) {
// This is a special case where we won't update our local call, because we have
// an ongoing active call. The ended call would stomp on the active call.
log.info(
`${logId}: Got offer while active for conversation ${conversation?.idForLogging()}`
);
return;
}
// Attempt to translate the rejection reason to its CallEndedReason
// counterpart.
const callEndedReason =
@ -3655,25 +3664,17 @@ class CallingClass {
'CallingClass.handleRejectedIncomingCallRequest'
);
if (callRejectReason === CallRejectReason.ReceivedOfferWhileActive) {
// This is a special case where we won't update our local call, because we have
// an ongoing active call. The ended call would stomp on the active call.
log.info(
`${logId}: Got offer while active for conversation ${conversation?.idForLogging()}`
);
} else {
if (!this.#reduxInterface) {
log.error(`${logId}: Unable to update redux for call`);
}
this.#reduxInterface?.callStateChange({
acceptedTime: null,
callEndedReason,
callState: CallState.Ended,
conversationId: conversation.id,
});
if (!this.#reduxInterface) {
log.error(`${logId}: Unable to update redux for call`);
}
this.#reduxInterface?.callStateChange({
acceptedTime: null,
callEndedReason,
callState: CallState.Ended,
conversationId: conversation.id,
});
await updateCallHistoryFromLocalEvent({
callEvent,
receivedAtCounter,
@ -3707,7 +3708,7 @@ class CallingClass {
this.videoRenderer.enable(call);
if (this.#cameraEnabled) {
// Start sending video from the camera (if not already).
drop(this.enableCaptureAndSend(call));
await this.enableCaptureAndSend(call);
}
}
if (call.state === CallState.Ended) {

View File

@ -1,173 +0,0 @@
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import {
DonationPermit,
DonationPermitRequestContext,
DonationPermitResponse,
ServerPublicParams,
} from '@signalapp/libsignal-client/zkgroup.js';
import { z } from 'zod';
import * as Bytes from '../Bytes.std.ts';
import { strictAssert } from '../util/assert.std.ts';
import { isInFuture, isInPast } from '../util/timestamp.std.ts';
import { createDonationPermits } from '../textsecure/WebAPI.preload.ts';
import { createLogger } from '../logging/log.std.ts';
import { itemStorage } from '../textsecure/Storage.preload.ts';
import { safeParseStrict, safeParseUnknown } from '../util/schemas.std.ts';
import { DAY } from '../util/durations/index.std.ts';
const log = createLogger('donationPermits');
const MAX_PERMIT_CACHE_TIME = DAY;
const PERMIT_COUNT_PER_REQUEST = 3;
const PERMIT_STORAGE_KEY = 'donationPermits';
const permitStorageSchema = z.object({
permitsBase64: z.array(z.string()),
expiresAt: z.number(),
});
let cachedPermits: Array<DonationPermit> = [];
let cachedPermitsExpiresAt: number | undefined;
let storageLoaded = false;
/**
* @throws {Error} If a permit could not be fetched.
*/
export async function fetchDonationPermit(): Promise<DonationPermit> {
if (!storageLoaded) {
loadPermitsFromStorage();
}
if (isCacheRefreshNeeded()) {
log.info(`Requesting ${PERMIT_COUNT_PER_REQUEST} donation permits`);
const { permits, expiresAt } = await requestDonationPermits();
cachedPermitsExpiresAt = expiresAt;
cachedPermits = permits;
log.info(`Got ${permits.length} permits expiring ${expiresAt}`);
} else {
log.info('Using saved donation permit');
}
const permit = cachedPermits.shift();
strictAssert(permit, 'Donation permit is required');
await savePermitsToStorage({
permits: cachedPermits,
expiresAt: cachedPermitsExpiresAt,
});
return permit;
}
function isCacheRefreshNeeded(): boolean {
return (
cachedPermits.length === 0 ||
cachedPermitsExpiresAt == null ||
isInPast(cachedPermitsExpiresAt)
);
}
async function requestDonationPermits(): Promise<{
permits: Array<DonationPermit>;
expiresAt: number;
}> {
const serverPublicParams = new ServerPublicParams(
Bytes.fromBase64(window.getServerPublicParams())
);
const context = DonationPermitRequestContext.forCount(
PERMIT_COUNT_PER_REQUEST
);
const request = context.request();
const permitRequest = Bytes.toBase64(request.serialize());
const response = await createDonationPermits({ permitRequest });
const { permitResponse: permitResponseBytes } = response;
const permitResponse = new DonationPermitResponse(
Bytes.fromBase64(permitResponseBytes)
);
const permits = context.receive(
permitResponse,
serverPublicParams,
new Date()
);
strictAssert(permits.length, 'Donation permits must be present');
const expiresAt = Math.min(
permitResponse.expiration.getTime(),
new Date().getTime() + MAX_PERMIT_CACHE_TIME
);
strictAssert(isInFuture(expiresAt), 'Expiry must be in future');
return { permits, expiresAt };
}
function loadPermitsFromStorage(): void {
const permitsJson = itemStorage.get(PERMIT_STORAGE_KEY);
if (!permitsJson) {
return;
}
try {
const permitsData = JSON.parse(permitsJson) as unknown;
const result = safeParseUnknown(permitStorageSchema, permitsData);
if (!result.success) {
throw new Error(
`Could not load permits from storage: ${z.prettifyError(result.error)}`
);
}
const { permitsBase64, expiresAt } = result.data;
const permits = permitsBase64.map(
permitBase64 => new DonationPermit(Bytes.fromBase64(permitBase64))
);
cachedPermits = permits;
cachedPermitsExpiresAt = expiresAt;
storageLoaded = true;
log.info(
`Loaded from storage: ${permits.length} permits, expiring ${expiresAt}`
);
} catch (error) {
log.error(error);
}
}
async function savePermitsToStorage({
permits,
expiresAt,
}: {
permits: Array<DonationPermit>;
expiresAt: number | undefined;
}): Promise<void> {
if (!expiresAt) {
log.warn('expiresAt is required to save permits to storage');
return;
}
try {
const permitsBase64 = permits.map(permit =>
Bytes.toBase64(permit.serialize())
);
const storageValue = { permitsBase64, expiresAt };
const result = safeParseStrict(permitStorageSchema, storageValue);
if (!result.success) {
throw new Error(
`Permit storage validation failed: ${z.prettifyError(result.error)}`
);
}
await itemStorage.put(PERMIT_STORAGE_KEY, JSON.stringify(storageValue));
log.info(
`Saved to storage: ${permits.length} permits, expiring ${expiresAt}`
);
} catch (error) {
log.error(error);
}
}

View File

@ -58,7 +58,6 @@ import {
confirmPaypalBoostPayment,
} from '../textsecure/WebAPI.preload.ts';
import { itemStorage } from '../textsecure/Storage.preload.ts';
import { fetchDonationPermit } from './donationPermits.preload.ts';
const { createDonationReceipt } = DataWriter;
@ -687,15 +686,11 @@ export async function _createPaymentIntent({
log.info(`${logId}: Creating new workflow`);
const donationPermit = await fetchDonationPermit();
const donationPermitBase64 = Bytes.toBase64(donationPermit.serialize());
const payload = {
currency: currencyType,
amount: paymentAmount,
level: 1,
paymentMethod: 'CARD',
donationPermitBase64,
};
const { clientSecret } = await createBoostPaymentIntent(payload);
const paymentIntentId = clientSecret.split('_secret_')[0];

View File

@ -2306,12 +2306,11 @@ export async function mergeStickerPackRecord(
const wasUninstalled = Boolean(localStickerPack?.uninstalledAt);
const isUninstalled = Boolean(stickerPack.uninstalledAt);
const newPosition = stickerPack.position ?? undefined;
details.push(
`wasUninstalled=${wasUninstalled}`,
`isUninstalled=${isUninstalled}`,
`oldPosition=${localStickerPack?.position ?? '?'}`,
`newPosition=${newPosition ?? '?'}`
`newPosition=${stickerPack.position ?? '?'}`
);
if (!wasUninstalled && isUninstalled) {
@ -2342,17 +2341,13 @@ export async function mergeStickerPackRecord(
stickerPack.key,
{
actionSource: 'storageService',
position: newPosition,
}
);
} else {
drop(
Stickers.downloadStickerPack(stickerPack.id, stickerPack.key, {
finalStatus: 'installed',
actionSource: 'storageService',
position: newPosition,
})
);
void Stickers.downloadStickerPack(stickerPack.id, stickerPack.key, {
finalStatus: 'installed',
actionSource: 'storageService',
});
}
}

View File

@ -1365,10 +1365,10 @@ type WritableInterface = {
createOrUpdateStickerPack: (pack: StickerPackType) => void;
createOrUpdateStickerPacks: (packs: ReadonlyArray<StickerPackType>) => void;
// Returns previous sticker pack status
updateStickerPackStatusAndPosition: (
updateStickerPackStatus: (
id: string,
status: StickerPackStatusType,
options?: { timestamp?: number; position?: number }
options?: { timestamp: number }
) => StickerPackStatusType | null;
updateStickerPackInfo: (info: StickerPackInfoType) => void;
createOrUpdateSticker: (sticker: StickerType) => void;
@ -1390,12 +1390,8 @@ type WritableInterface = {
addUninstalledStickerPacks: (
pack: ReadonlyArray<UninstalledStickerPackType>
) => void;
// Returns wasPreviouslyUninstalled: `true` if sticker pack was previously uninstalled
installStickerPack: (
packId: string,
timestamp: number,
position?: number
) => { wasPreviouslyUninstalled: boolean; position?: number };
// Returns `true` if sticker pack was previously uninstalled
installStickerPack: (packId: string, timestamp: number) => boolean;
// Returns `true` if sticker pack was not previously uninstalled
uninstallStickerPack: (packId: string, timestamp: number) => boolean;
clearAllErrorStickerPackAttempts: () => void;
@ -1488,12 +1484,20 @@ type WritableInterface = {
plaintextHash,
version,
contentType,
messageId,
}: {
plaintextHash: string;
version: number;
contentType: MIMEType;
}) => (ExistingAttachmentData & { reuseToken: string }) | undefined;
_protectAttachmentPathFromDeletion: ({ path }: { path: string }) => string;
messageId: string;
}) => ExistingAttachmentData | undefined;
_protectAttachmentPathFromDeletion: ({
path,
messageId,
}: {
path: string;
messageId: string;
}) => void;
resetProtectedAttachmentPaths: () => void;
removeAll: () => void;

View File

@ -302,10 +302,7 @@ import type {
} from '../types/Colors.std.ts';
import { sqlLogger } from './sqlLogger.node.ts';
import { permissiveMessageAttachmentSchema } from './server/messageAttachments.std.ts';
import {
getFilePathsReferencedByAttachment,
getFilePathsReferencedByMessage,
} from '../util/messageFilePaths.std.ts';
import { getFilePathsReferencedByMessage } from '../util/messageFilePaths.std.ts';
import { createMessagesOnInsertTrigger } from './migrations/1500-search-polls.std.ts';
import { isValidPlaintextHash } from '../types/Crypto.std.ts';
import { Emoji } from '../axo/emoji.std.ts';
@ -728,7 +725,7 @@ export const DataWriter: ServerWritableInterface = {
createOrUpdateStickerPack,
createOrUpdateStickerPacks,
updateStickerPackStatusAndPosition,
updateStickerPackStatus,
updateStickerPackInfo,
createOrUpdateSticker,
createOrUpdateStickers,
@ -2919,10 +2916,6 @@ function saveMessageAttachment({
logger.info('Recovered from invalid message_attachment save');
}
if (attachment.reuseToken != null) {
releaseAttachmentPathProtections(db, attachment);
}
}
function getAndProtectExistingAttachmentPath(
@ -2931,12 +2924,14 @@ function getAndProtectExistingAttachmentPath(
plaintextHash,
version,
contentType,
messageId,
}: {
plaintextHash: string;
version: number;
contentType: string;
messageId: string;
}
): (ExistingAttachmentData & { reuseToken: string }) | undefined {
): ExistingAttachmentData | undefined {
if (!isValidPlaintextHash(plaintextHash)) {
logger.error('getAndProtectExistingAttachmentPath: Invalid plaintextHash');
return;
@ -2976,71 +2971,40 @@ function getAndProtectExistingAttachmentPath(
LIMIT 1;
`;
return db.transaction(() => {
const existingData = db.prepare(query).get<ExistingAttachmentData>(params);
const existingData = db.prepare(query).get<ExistingAttachmentData>(params);
if (!existingData) {
return undefined;
}
if (!existingData) {
return undefined;
}
const reuseToken = randomBytes(16).toString('hex');
const [protectQuery, protectParams] = sql`
const [protectQuery, protectParams] = sql`
WITH existingMessageAttachmentPaths(path) AS (
VALUES
(${existingData.path}),
(${existingData.thumbnailPath}),
(${existingData.screenshotPath})
)
INSERT OR REPLACE INTO attachments_protected_from_deletion(path, reuseToken)
SELECT path, ${reuseToken}
INSERT OR REPLACE INTO attachments_protected_from_deletion(path, messageId)
SELECT path, ${messageId}
FROM existingMessageAttachmentPaths
WHERE path IS NOT NULL;
`;
db.prepare(protectQuery).run(protectParams);
db.prepare(protectQuery).run(protectParams);
return { ...existingData, reuseToken };
})();
return existingData;
}
function _protectAttachmentPathFromDeletion(
db: WritableDB,
{ path }: { path: string }
): string {
const reuseToken = randomBytes(16).toString('hex');
{ path, messageId }: { path: string; messageId: string }
): void {
const [protectQuery, protectParams] = sql`
INSERT OR REPLACE INTO attachments_protected_from_deletion
(path, reuseToken)
(path, messageId)
VALUES
(${path}, ${reuseToken});
(${path}, ${messageId});
`;
db.prepare(protectQuery).run(protectParams);
return reuseToken;
}
function releaseAttachmentPathProtections(
db: WritableDB,
attachment: AttachmentType
): void {
const { reuseToken } = attachment;
if (!reuseToken) {
return;
}
const { externalAttachments } =
getFilePathsReferencedByAttachment(attachment);
if (!externalAttachments.size) {
return;
}
const [query, params] = sql`
DELETE FROM attachments_protected_from_deletion
WHERE reuseToken = ${reuseToken}
AND path IN (${sqlJoin([...externalAttachments])});
`;
db.prepare(query).run(params);
}
function resetProtectedAttachmentPaths(db: WritableDB): void {
@ -3049,7 +3013,7 @@ function resetProtectedAttachmentPaths(db: WritableDB): void {
function getAllProtectedAttachmentPaths(db: ReadableDB): Array<string> {
return db
.prepare('SELECT DISTINCT path FROM attachments_protected_from_deletion', {
.prepare('SELECT path FROM attachments_protected_from_deletion', {
pluck: true,
})
.all<string>();
@ -6981,15 +6945,14 @@ function createOrUpdateStickerPacks(
}
})();
}
function updateStickerPackStatusAndPosition(
function updateStickerPackStatus(
db: WritableDB,
id: string,
status: StickerPackStatusType,
options?: { timestamp?: number; position?: number }
options?: { timestamp: number }
): StickerPackStatusType | null {
const timestamp = options ? options.timestamp || Date.now() : Date.now();
const installedAt = status === 'installed' ? timestamp : null;
const position = options?.position;
return db.transaction(() => {
const [select, selectParams] = sql`
@ -7003,37 +6966,13 @@ function updateStickerPackStatusAndPosition(
})
.get<StickerPackRow['status']>(selectParams) ?? null;
if (position != null) {
db.prepare(
`
UPDATE sticker_packs
SET
status = $status,
installedAt = $installedAt,
position = $position
WHERE id = $id;
`
).run({
id,
status,
installedAt,
position,
});
} else {
db.prepare(
`
UPDATE sticker_packs
SET
status = $status,
installedAt = $installedAt
WHERE id = $id;
`
).run({
id,
status,
installedAt,
});
}
const [update, updateParams] = sql`
UPDATE sticker_packs
SET status = ${status}, installedAt = ${installedAt}
WHERE id IS ${id}
`;
db.prepare(update).run(updateParams);
return oldStatus;
})();
@ -7540,56 +7479,30 @@ function getStickerPackInfo(
return undefined;
})();
}
function installStickerPack(
db: WritableDB,
packId: string,
timestamp: number,
position?: number
): { wasPreviouslyUninstalled: boolean; position?: number } {
timestamp: number
): boolean {
return db.transaction(() => {
const status = 'installed';
removeUninstalledStickerPack(db, packId);
// Default position to the end of the list
const newPosition: number =
position ??
db
.prepare(
`
SELECT IFNULL(MAX(position) + 1, 0)
FROM sticker_packs
WHERE id != $packId
`,
{
pluck: true,
}
)
.get({ packId }) ??
0;
const oldStatus = updateStickerPackStatusAndPosition(
db,
packId,
'installed',
{
position: newPosition,
timestamp,
}
);
const oldStatus = updateStickerPackStatus(db, packId, status, {
timestamp,
});
const wasPreviouslyUninstalled = oldStatus !== 'installed';
if (!wasPreviouslyUninstalled) {
return { wasPreviouslyUninstalled: false };
if (wasPreviouslyUninstalled) {
const [query, params] = sql`
UPDATE sticker_packs SET
storageNeedsSync = 1
WHERE id IS ${packId};
`;
db.prepare(query).run(params);
}
const [query, params] = sql`
UPDATE sticker_packs SET
storageNeedsSync = 1
WHERE id IS ${packId};
`;
db.prepare(query).run(params);
return { wasPreviouslyUninstalled: true, position: newPosition };
return wasPreviouslyUninstalled;
})();
}
function uninstallStickerPack(
@ -7599,7 +7512,7 @@ function uninstallStickerPack(
): boolean {
return db.transaction(() => {
const status = 'downloaded';
const oldStatus = updateStickerPackStatusAndPosition(db, packId, status);
const oldStatus = updateStickerPackStatus(db, packId, status);
const wasPreviouslyInstalled = oldStatus === 'installed';

View File

@ -1,24 +0,0 @@
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { WritableDB } from '../Interface.std.ts';
export default function updateToSchemaVersion1730(db: WritableDB): void {
// Each row is an outstanding reuse claim on a path, keyed by an ephemeral token
// returned to the caller. saveMessageAttachments releases the claim in the same
// transaction that writes the message_attachments row referencing the path.
db.exec(`
DROP TABLE attachments_protected_from_deletion;
CREATE TABLE attachments_protected_from_deletion (
path TEXT NOT NULL,
reuseToken TEXT NOT NULL,
PRIMARY KEY (path, reuseToken)
) STRICT;
CREATE INDEX attachments_protected_from_deletion_reuseToken
ON attachments_protected_from_deletion (reuseToken);
DROP TRIGGER stop_protecting_attachments_after_update;
DROP TRIGGER stop_protecting_attachments_after_insert;
`);
}

View File

@ -149,7 +149,6 @@ import updateToSchemaVersion1690 from './1690-poll-terminate-notification-timest
import updateToSchemaVersion1700 from './1700-trim-profile-names.std.ts';
import updateToSchemaVersion1710 from './1710-emoji-skin-tone-default.std.ts';
import updateToSchemaVersion1720 from './1720-update-recent-emoji.std.ts';
import updateToSchemaVersion1730 from './1730-protected-attachments-dedupe-token.std.ts';
import { DataWriter } from '../Server.node.ts';
import { strictAssert } from '../../util/assert.std.ts';
@ -1661,7 +1660,6 @@ export const SCHEMA_VERSIONS: ReadonlyArray<SchemaUpdateType> = [
{ version: 1700, update: updateToSchemaVersion1700 },
{ version: 1710, update: updateToSchemaVersion1710 },
{ version: 1720, update: updateToSchemaVersion1720 },
{ version: 1730, update: updateToSchemaVersion1730 },
];
class DBVersionFromFutureError extends Error {

View File

@ -86,7 +86,6 @@ type InstallStickerPackPayloadType = ReadonlyDeep<{
actionSource: ActionSourceType;
status: 'installed';
installedAt: number;
position: number | undefined;
recentStickers: Array<RecentStickerType>;
}>;
type InstallStickerPackAction = ReadonlyDeep<{
@ -238,27 +237,20 @@ function downloadStickerPack(
function installStickerPack(
packId: string,
packKey: string,
{
actionSource,
position,
}: { actionSource: ActionSourceType; position?: number }
{ actionSource }: { actionSource: ActionSourceType }
): InstallStickerPackAction {
return {
type: 'stickers/INSTALL_STICKER_PACK',
payload: doInstallStickerPack(packId, packKey, { actionSource, position }),
payload: doInstallStickerPack(packId, packKey, { actionSource }),
};
}
async function doInstallStickerPack(
packId: string,
packKey: string,
{
actionSource,
position,
}: { actionSource: ActionSourceType; position?: number }
{ actionSource }: { actionSource: ActionSourceType }
): Promise<InstallStickerPackPayloadType> {
const timestamp = Date.now();
const { wasPreviouslyUninstalled, position: newPosition } =
await DataWriter.installStickerPack(packId, timestamp, position);
const changed = await DataWriter.installStickerPack(packId, timestamp);
if (actionSource === 'ui') {
// Kick this off, but don't wait for it
@ -270,7 +262,7 @@ async function doInstallStickerPack(
actionSource !== 'storageService' &&
// Stickers downloaded on startup should already be synced
actionSource !== 'startup' &&
wasPreviouslyUninstalled
changed
) {
storageServiceUploadJob({ reason: 'doInstallServicePack' });
}
@ -282,7 +274,6 @@ async function doInstallStickerPack(
actionSource,
status: 'installed',
installedAt: timestamp,
position: newPosition,
recentStickers: recentStickers.map(item => ({
packId: item.packId,
stickerId: item.id,
@ -438,10 +429,7 @@ export function reducer(
if (isInstallingPack) {
newPack = {
...payload,
stickerCount:
oldPack.stickerCount !== 0
? oldPack.stickerCount
: payload.stickerCount,
stickerCount: oldPack.stickerCount,
title: payload.title === '' ? oldPack.title : payload.title,
author: payload.author === '' ? oldPack.author : payload.author,
// TODO: Ephemeral stickers are stored at a different path then downloaded stickers
@ -511,8 +499,6 @@ export function reducer(
const { packs } = state;
const existingPack = packs[packId];
const position = 'position' in payload ? payload.position : undefined;
// A pack might be deleted as part of the uninstall process
if (!existingPack) {
return {
@ -535,7 +521,6 @@ export function reducer(
...existingPack,
status,
installedAt,
position: position ?? existingPack.position,
},
},
recentStickers,

View File

@ -140,14 +140,12 @@ export const getInstalledStickerPacks = createSelector(
packs: Dictionary<StickerPackDBType>,
blessedPacks: Dictionary<boolean>
): Array<StickerPackType> => {
const list = filter(packs, pack => pack.status === 'installed');
const sorted = orderBy<StickerPackDBType>(
list,
['position', 'installedAt'],
['asc', 'asc']
return filterAndTransformPacks(
packs,
pack => pack.status === 'installed',
pack => pack.installedAt,
blessedPacks
);
return sorted.map(pack => translatePackFromDB(pack, packs, blessedPacks));
}
);

Some files were not shown because too many files have changed in this diff Show More