v4: every live update reaches every page that shows what it changed — the client kept each kind of event in one "latest" slot, so two arriving before a render lost the first (two notifications of one dump going public showed one); they now go through a subscription, useWSEvent, and each reaches every subscriber. A playlist made private sent its new title and description to everyone, and kept them on a visitor's page; playlists now follow the dumps' rule, broadcastChange: others get playlist_deleted, and playlist_created when it goes public again. A dump deleted or turned private sends its playlists' dumps again, so their counts and pages follow. Comments on a private dump reach its poster's other tabs. Reading the notifications clears the bell in every tab (notifications_read), and a category change makes every client fetch the categories again (categories_changed). The dump page gives way to a notice when its dump is deleted or made private. A profile gains the user's new dumps, the followed feed those of the users followed and the playlists followed, the search results follow edits and deletions, the index's category feed drops a dump edited out of it, and a renamed user's name follows on cards and comments. After a reconnection, every live list fetches the pages it holds again (usePagedList's resync), and the playlist, the profile, the dump, the categories and the follows are fetched again. The position memory of usePositionAwareSync is now inside the list sync hooks, so a returning item is put back without depending on the order the hooks are called.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-10-10 07:34:49 +00:00
parent 1c5a449d84
commit 308a8299f3
53 changed files with 1941 additions and 1044 deletions

View File

@@ -60,7 +60,7 @@ msgstr "{0}–{1} caractères : lettres, chiffres ou tirets bas"
msgid "email.digest.totals"
msgstr "{dumps, plural, one {# reco} other {# recos}}, {upvotes, plural, one {# vote} other {# votes}} et {comments, plural, one {# commentaire} other {# commentaires}}."
#: src/pages/Search.tsx:152
#: src/pages/Search.tsx:178
msgid "{label} ({count})"
msgstr "{label} ({count})"
@@ -144,7 +144,7 @@ msgstr "{n, plural, one {vote} other {votes}}"
msgid "email.digest.more"
msgstr "{n} de plus dans votre fil Suivi"
#: src/pages/Notifications.tsx:508
#: src/pages/Notifications.tsx:499
msgid "{totalUnread, plural, one {# new} other {# new}}"
msgstr "{totalUnread, plural, one {# nouvelle} other {# nouvelles}}"
@@ -211,8 +211,9 @@ msgstr "# Bienvenue sur {site} !\n"
msgid "← Back"
msgstr "← Retour"
#: src/pages/Dump.tsx:330
#: src/pages/Dump.tsx:557
#: src/pages/Dump.tsx:353
#: src/pages/Dump.tsx:378
#: src/pages/Dump.tsx:605
#: src/pages/DumpEdit.tsx:234
msgid "← Back to all dumps"
msgstr "← Retour à toutes les recos"
@@ -225,7 +226,7 @@ msgstr "+ Inviter quelqu'un"
msgid "+ New playlist"
msgstr "+ Nouvelle collection"
#: src/pages/Dump.tsx:404
#: src/pages/Dump.tsx:452
msgid "+ Playlist"
msgstr "+ Collection"
@@ -418,8 +419,8 @@ msgstr "par @{username}"
msgid "email.digest.playlistMeta"
msgstr "par @{username} · {n, plural, one {# reco} other {# recos}}"
#: src/contexts/ws/WSProvider.tsx:395
#: src/contexts/ws/WSProvider.tsx:764
#: src/contexts/ws/WSProvider.tsx:376
#: src/contexts/ws/WSProvider.tsx:765
msgid "Can't connect to the live updates server. Upvotes and notifications may not sync until it reconnects."
msgstr "Impossible de se connecter au serveur de mises à jour en direct. Les votes et les notifications pourraient ne pas se synchroniser avant la reconnexion."
@@ -439,7 +440,7 @@ msgstr "Connexion impossible"
#: src/components/profile/EmailEditor.tsx:83
#: src/components/shared/ConfirmModal.tsx:63
#: src/pages/Authorize.tsx:158
#: src/pages/Dump.tsx:446
#: src/pages/Dump.tsx:494
#: src/pages/DumpEdit.tsx:561
msgid "Cancel"
msgstr "Annuler"
@@ -554,7 +555,7 @@ msgstr "Confirmer le nouveau mot de passe"
msgid "Connecting…"
msgstr "Connexion…"
#: src/contexts/ws/WSProvider.tsx:757
#: src/contexts/ws/WSProvider.tsx:758
msgid "Connection lost — this message may not have been sent"
msgstr "Connexion perdue — ce message n'a peut-être pas été envoyé"
@@ -582,7 +583,7 @@ msgstr "Impossible de changer le mot de passe"
msgid "Could not connect to the server. Check your connection and try again."
msgstr "Impossible de joindre le serveur. Vérifiez votre connexion et réessayez."
#: src/components/profile/ProfilePlaylistsTab.tsx:178
#: src/components/profile/ProfilePlaylistsTab.tsx:171
#: src/pages/DumpEdit.tsx:555
msgid "Could not delete"
msgstr "Suppression impossible"
@@ -680,7 +681,7 @@ msgstr "Échec de la suppression ({0})"
#: src/components/playlist/PlaylistCard.tsx:149
#: src/components/playlist/PlaylistEditForm.tsx:213
#: src/components/profile/ProfilePlaylistsTab.tsx:208
#: src/components/profile/ProfilePlaylistsTab.tsx:201
#: src/pages/PlaylistDetail.tsx:172
msgid "Delete playlist"
msgstr "Supprimer la collection"
@@ -697,7 +698,7 @@ msgstr "Supprimer cette reco ? Cette action est irréversible."
msgid "Delete this message?"
msgstr "Supprimer ce message ?"
#: src/components/profile/ProfilePlaylistsTab.tsx:207
#: src/components/profile/ProfilePlaylistsTab.tsx:200
#: src/pages/PlaylistDetail.tsx:171
msgid "Delete this playlist? This cannot be undone."
msgstr "Supprimer cette collection ? Cette action est irréversible."
@@ -769,7 +770,7 @@ msgid "Dumped!"
msgstr "Recommandé !"
#: src/components/profile/ProfileDumpsTab.tsx:46
#: src/pages/Search.tsx:148
#: src/pages/Search.tsx:174
#: src/pages/UserPublicProfile.tsx:160
msgid "Dumps"
msgstr "Recos"
@@ -788,7 +789,7 @@ msgstr "Plus tôt"
#: src/components/chat/PendingItem.tsx:93
#: src/components/comment/CommentNode.tsx:256
#: src/components/playlist/PlaylistHeader.tsx:60
#: src/pages/Dump.tsx:553
#: src/pages/Dump.tsx:601
msgid "Edit"
msgstr "Modifier"
@@ -806,7 +807,7 @@ msgid "Edit email"
msgstr "Modifier l'e-mail"
#: src/components/dump/create/TitleField.tsx:69
#: src/pages/Dump.tsx:463
#: src/pages/Dump.tsx:511
msgid "Edit title"
msgstr "Modifier le titre"
@@ -820,7 +821,7 @@ msgstr "modifié"
#: src/components/chat/ChatMessageItem.tsx:132
#: src/components/comment/CommentNode.tsx:205
#: src/components/playlist/PlaylistHeader.tsx:95
#: src/pages/Dump.tsx:506
#: src/pages/Dump.tsx:554
msgid "edited {0}"
msgstr "modifié {0}"
@@ -830,7 +831,7 @@ msgstr "modifié {0}"
#: src/components/chat/ChatMessageItem.tsx:128
#: src/components/comment/CommentNode.tsx:203
#: src/components/playlist/PlaylistHeader.tsx:93
#: src/pages/Dump.tsx:504
#: src/pages/Dump.tsx:552
msgid "Edited {0}"
msgstr "Modifié le {0}"
@@ -851,7 +852,7 @@ msgstr "E-mail"
msgid "Email address"
msgstr "Adresse e-mail"
#: src/pages/Search.tsx:204
#: src/pages/Search.tsx:230
msgid "Enter a query to search."
msgstr "Saisissez une recherche."
@@ -942,16 +943,16 @@ msgstr "Suivre {targetUsername}"
msgid "Follow playlist"
msgstr "Suivre la collection"
#: src/components/feed/FollowedFeed.tsx:164
#: src/components/feed/FollowedFeed.tsx:192
msgid "Follow some public playlists to see their dumps here."
msgstr "Suivez des collections publiques pour voir leurs recos ici."
#: src/components/feed/FollowedFeed.tsx:156
#: src/components/feed/FollowedFeed.tsx:184
msgid "Follow some users to see their dumps here."
msgstr "Suivez des utilisateurs pour voir leurs recos ici."
#: src/components/feed/FeedTabBar.tsx:61
#: src/components/profile/ProfileFollowTab.tsx:140
#: src/components/profile/ProfileFollowTab.tsx:144
#: src/pages/Settings.tsx:57
#: src/pages/UserPublicProfile.tsx:163
msgid "Followed"
@@ -971,7 +972,7 @@ msgstr "Pour vous"
msgid "Forgot password?"
msgstr "Mot de passe oublié ?"
#: src/components/feed/FollowedFeed.tsx:137
#: src/components/feed/FollowedFeed.tsx:165
msgid "From people"
msgstr "De personnes"
@@ -980,7 +981,7 @@ msgstr "De personnes"
msgid "email.digest.network"
msgstr "De ceux que vous suivez"
#: src/components/feed/FollowedFeed.tsx:138
#: src/components/feed/FollowedFeed.tsx:166
msgid "From playlists"
msgstr "De collections"
@@ -1024,7 +1025,7 @@ msgstr "Si vous n'êtes pas à l'origine de cette demande, ignorez cet e-mail. V
msgid "image"
msgstr "image"
#: src/pages/Dump.tsx:573
#: src/pages/Dump.tsx:621
msgid "In collections"
msgstr "Dans les collections"
@@ -1109,7 +1110,7 @@ msgstr "Lien"
msgid "Link or file"
msgstr "Lien ou fichier"
#: src/contexts/ws/WSProvider.tsx:763
#: src/contexts/ws/WSProvider.tsx:764
msgid "Live updates are temporarily disconnected. Trying to reconnect…"
msgstr "Les mises à jour en direct sont temporairement interrompues. Tentative de reconnexion…"
@@ -1125,7 +1126,7 @@ msgstr "Charger plus"
msgid "Load older messages"
msgstr "Charger les messages plus anciens"
#: src/pages/Dump.tsx:306
#: src/pages/Dump.tsx:337
#: src/pages/DumpEdit.tsx:210
msgid "Loading dump…"
msgstr "Chargement de la reco…"
@@ -1271,7 +1272,7 @@ msgstr "Piste suivante"
msgid "No dumps in this playlist yet."
msgstr "Aucune reco dans cette collection pour l'instant."
#: src/pages/Search.tsx:220
#: src/pages/Search.tsx:246
msgid "No dumps match \"{q}\"."
msgstr "Aucune reco ne correspond à « {q} »."
@@ -1284,7 +1285,7 @@ msgstr "Pas encore de recos. Soyez le premier !"
msgid "No emoji found."
msgstr "Aucun emoji trouvé."
#: src/components/profile/ProfileFollowTab.tsx:113
#: src/components/profile/ProfileFollowTab.tsx:117
msgid "No followed playlists yet."
msgstr "Pas encore de collections suivies."
@@ -1300,21 +1301,21 @@ msgstr "Aucun message pour l'instant. Dites bonjour !"
msgid "No one yet."
msgstr "Personne pour le moment."
#: src/pages/Search.tsx:261
#: src/pages/Search.tsx:287
msgid "No playlists match \"{q}\"."
msgstr "Aucune collection ne correspond à « {q} »."
#: src/components/playlist/PlaylistMembershipPanel.tsx:51
#: src/components/profile/ProfilePlaylistsTab.tsx:185
#: src/pages/Playlists.tsx:118
#: src/components/profile/ProfilePlaylistsTab.tsx:178
#: src/pages/Playlists.tsx:126
msgid "No playlists yet."
msgstr "Pas encore de collections."
#: src/contexts/ws/WSProvider.tsx:932
#: src/contexts/ws/WSProvider.tsx:934
msgid "No reply from the server — this message may not have been sent"
msgstr "Pas de réponse du serveur — ce message n'a peut-être pas été envoyé"
#: src/pages/Search.tsx:235
#: src/pages/Search.tsx:261
msgid "No users match \"{q}\"."
msgstr "Aucun utilisateur ne correspond à « {q} »."
@@ -1336,18 +1337,18 @@ msgstr "Rien de neuf cette semaine."
#: src/components/profile/ProfileDumpsTab.tsx:97
#: src/components/profile/ProfileOverviewTab.tsx:47
#: src/pages/Notifications.tsx:522
#: src/pages/Notifications.tsx:513
msgid "Nothing here yet."
msgstr "Rien ici pour l'instant."
#: src/components/layout/NotificationBell.tsx:57
#: src/components/layout/NotificationBell.tsx:49
#: src/pages/Notifications.tsx:387
#: src/pages/Notifications.tsx:505
#: src/pages/Notifications.tsx:496
#: src/pages/Settings.tsx:163
msgid "Notifications"
msgstr "Notifications"
#: src/components/layout/NotificationBell.tsx:56
#: src/components/layout/NotificationBell.tsx:48
msgid "Notifications ({unreadNotificationCount} unread)"
msgstr "Notifications ({unreadNotificationCount} non lues)"
@@ -1469,11 +1470,11 @@ msgstr "Catégories de collections"
#: src/components/dump/create/StepIndicator.tsx:21
#: src/components/layout/AppHeader.tsx:172
#: src/components/layout/UserMenu.tsx:92
#: src/components/profile/ProfileFollowTab.tsx:144
#: src/components/profile/ProfilePlaylistsTab.tsx:156
#: src/pages/Playlists.tsx:52
#: src/pages/Playlists.tsx:106
#: src/pages/Search.tsx:151
#: src/components/profile/ProfileFollowTab.tsx:148
#: src/components/profile/ProfilePlaylistsTab.tsx:149
#: src/pages/Playlists.tsx:53
#: src/pages/Playlists.tsx:114
#: src/pages/Search.tsx:177
#: src/pages/UserPublicProfile.tsx:162
msgid "Playlists"
msgstr "Collections"
@@ -1501,7 +1502,7 @@ msgstr "Piste précédente"
#: src/components/playlist/PlaylistCard.tsx:106
#: src/components/playlist/PlaylistHeader.tsx:77
#: src/components/playlist/PlaylistMembershipPanel.tsx:81
#: src/pages/Dump.tsx:512
#: src/pages/Dump.tsx:560
msgid "private"
msgstr "privé"
@@ -1544,7 +1545,7 @@ msgstr "Inscription…"
msgid "Registration failed"
msgstr "Inscription échouée"
#: src/pages/Dump.tsx:564
#: src/pages/Dump.tsx:612
msgid "Related"
msgstr "Connexe"
@@ -1631,7 +1632,7 @@ msgid "email.reset.title"
msgstr "Réinitialiser votre mot de passe"
#: src/components/chat/PendingItem.tsx:86
#: src/pages/Dump.tsx:323
#: src/pages/Dump.tsx:371
#: src/pages/DumpEdit.tsx:227
msgid "Retry"
msgstr "Réessayer"
@@ -1646,7 +1647,7 @@ msgstr "Rôle"
#: src/components/playlist/PlaylistEditForm.tsx:229
#: src/components/profile/DescriptionEditor.tsx:89
#: src/components/profile/EmailEditor.tsx:75
#: src/pages/Dump.tsx:438
#: src/pages/Dump.tsx:486
#: src/pages/DumpEdit.tsx:564
msgid "Save"
msgstr "Enregistrer"
@@ -1656,14 +1657,14 @@ msgstr "Enregistrer"
#: src/components/profile/ChangePasswordModal.tsx:119
#: src/components/profile/DescriptionEditor.tsx:86
#: src/components/profile/EmailEditor.tsx:72
#: src/pages/Dump.tsx:437
#: src/pages/Dump.tsx:485
#: src/pages/ResetPassword.tsx:191
msgid "Saving…"
msgstr "Enregistrement…"
#: src/components/layout/AppHeader.tsx:182
#: src/components/layout/SearchBar.tsx:83
#: src/pages/Search.tsx:87
#: src/pages/Search.tsx:90
msgid "Search"
msgstr "Rechercher"
@@ -1679,11 +1680,11 @@ msgstr "Rechercher un emoji"
msgid "Search emoji…"
msgstr "Rechercher un emoji…"
#: src/pages/Search.tsx:215
#: src/pages/Search.tsx:241
msgid "Search failed"
msgstr "Recherche échouée"
#: src/pages/Search.tsx:210
#: src/pages/Search.tsx:236
msgid "Searching…"
msgstr "Recherche…"
@@ -1765,7 +1766,7 @@ msgstr "Quelqu'un a demandé à réinitialiser le mot de passe de votre compte {
#: src/components/form/FormError.tsx:31
#: src/components/layout/PageError.tsx:29
#: src/contexts/ws/WSProvider.tsx:732
#: src/contexts/ws/WSProvider.tsx:733
#: src/pages/PlaylistDetail.tsx:155
msgid "Something went wrong"
msgstr "Une erreur est survenue"
@@ -1799,7 +1800,7 @@ msgstr "la tribune"
msgid "the chat"
msgstr "la tribune"
#: src/hooks/playlist/usePlaylist.ts:182
#: src/hooks/playlist/usePlaylist.ts:177
msgid "The dump couldn't be removed. Try again."
msgstr "Le dump n'a pas pu être retiré. Réessayez."
@@ -1822,7 +1823,7 @@ msgstr "Le mois sur {site}"
msgid "email.digest.monthly.subject"
msgstr "Le mois sur {site}, {range}"
#: src/hooks/playlist/usePlaylist.ts:325
#: src/hooks/playlist/usePlaylist.ts:317
msgid "The new order couldn't be saved. Try again."
msgstr "Le nouvel ordre n'a pas pu être enregistré. Réessayez."
@@ -1830,6 +1831,10 @@ msgstr "Le nouvel ordre n'a pas pu être enregistré. Réessayez."
msgid "This comment couldn't be deleted. Try again."
msgstr "Ce commentaire n'a pas pu être supprimé. Réessayez."
#: src/pages/Dump.tsx:346
msgid "This dump was deleted, or made private."
msgstr "Cette reco a été supprimée, ou rendue privée."
#: src/pages/UserRegister.tsx:122
msgid "This invite link is missing, expired, or already used."
msgstr "Ce lien d'invitation est manquant, expiré ou déjà utilisé."
@@ -2035,8 +2040,8 @@ msgstr "Menu utilisateur"
msgid "Username"
msgstr "Nom d'utilisateur"
#: src/components/profile/ProfileFollowTab.tsx:143
#: src/pages/Search.tsx:150
#: src/components/profile/ProfileFollowTab.tsx:147
#: src/pages/Search.tsx:176
msgid "Users"
msgstr "Utilisateurs"
@@ -2122,7 +2127,7 @@ msgstr "Vous ne recevrez plus le récap mensuel. Vous pouvez le réactiver dans
msgid "You won't get the weekly digest any more. You can turn it back on in your settings."
msgstr "Vous ne recevrez plus le résumé hebdomadaire. Vous pouvez le réactiver dans vos paramètres."
#: src/pages/Notifications.tsx:525
#: src/pages/Notifications.tsx:516
msgid "You'll be notified when someone follows your playlists, upvotes your dumps, or posts new content."
msgstr "Vous serez notifié lorsque quelqu'un suit vos collections, valide vos recos ou publie du nouveau contenu."
@@ -2146,7 +2151,7 @@ msgstr "Vous recevez cet e-mail car une réinitialisation de mot de passe a ét
msgid "email.welcome.reason"
msgstr "Vous recevez cet e-mail car un compte {site} a été créé avec cette adresse."
#: src/contexts/ws/WSProvider.tsx:913
#: src/contexts/ws/WSProvider.tsx:915
msgid "You're offline — not sent"
msgstr "Hors ligne — message non envoyé"