Explorar el Código

Notifications: pluralize the "new articles" count message (#8988)

* Generate new articles notification string in PHP

Closes #6470

Changes proposed in this pull request:

- Generate notifications string  in PHP
- Use plurals support

* New articles notification: switch to plural forms

* README status

* fix paramInt invocation

* i18n

* make fix-all

* Apply suggestion from @Frenzie

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Frans de Jonge hace 13 horas
padre
commit
612ac4f117

+ 10 - 2
app/i18n/cs/gen.php

@@ -179,8 +179,16 @@ return array(
 		'confirm_action_feed_cat' => 'Opravdu chcete provést tuto akci? Přijdete o související oblíbené položky a uživatelské dotazy. Toto nelze zrušit!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => 'Ve FreshRSS je %%d nových článků k přečtení.',
-			'body_unread_articles' => '(nepřečtené: %%d)',
+			'body_new_articles' => array(
+				0 => 'Ve FreshRSS je %d nových článků k přečtení.',	// DIRTY
+				1 => 'Ve FreshRSS je %d nových článků k přečtení.',	// DIRTY
+				2 => 'Ve FreshRSS je %d nových článků k přečtení.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(nepřečtené: %d)',	// DIRTY
+				1 => '(nepřečtené: %d)',	// DIRTY
+				2 => '(nepřečtené: %d)',	// DIRTY
+			),
 			'request_failed' => 'Požadavek selhal, to může být způsobeno problémy s připojení k internetu.',
 			'title_new_articles' => 'FreshRSS: nové články!',
 		),

+ 8 - 2
app/i18n/de/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Möchten Sie diese Aktion wirklich ausführen? Sie verlieren damit alle zugehörigen Favoriten und Suchanfragen. Der Vorgang kann nicht rückgängig gemacht werden!',
 		'confirm_exit_slider' => 'Sollen die nicht gespeicherten Einstellungen wirklich verworfen werden?',
 		'feedback' => array(
-			'body_new_articles' => 'Es gibt %%d neue Artikel zum Lesen auf FreshRSS.',
-			'body_unread_articles' => '(Ungelesen: %%d)',
+			'body_new_articles' => array(
+				0 => 'Es gibt %d neuen Artikel zum Lesen auf FreshRSS.',	// DIRTY
+				1 => 'Es gibt %d neue Artikel zum Lesen auf FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(Ungelesen: %d)',	// DIRTY
+				1 => '(Ungelesen: %d)',	// DIRTY
+			),
 			'request_failed' => 'Eine Anfrage ist fehlgeschlagen, dies könnte durch Probleme mit der Internetverbindung verursacht worden sein.',
 			'title_new_articles' => 'FreshRSS: neue Artikel!',
 		),

+ 8 - 2
app/i18n/el/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Είστε σίγουροι για την ενέργεια; Θα χάσετε τα αγαπημένα σας και τις ροές που έχετε δημιουργήσει. Είναι μη αναστρέψιμη!',
 		'confirm_exit_slider' => 'Είστε σίγουροι οτι δεν θέλετε να αποθηκεύσετε τις τρέχουσες αλλαγές σας;',
 		'feedback' => array(
-			'body_new_articles' => 'Υπάρχουν %%d νέα άρθρα να διαβάσετε στο FreshRSS.',
-			'body_unread_articles' => '(αδιάβαστα: %%d)',
+			'body_new_articles' => array(
+				0 => 'Υπάρχουν %d νέα άρθρα να διαβάσετε στο FreshRSS.',	// DIRTY
+				1 => 'Υπάρχουν %d νέα άρθρα να διαβάσετε στο FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(αδιάβαστα: %d)',	// DIRTY
+				1 => '(αδιάβαστα: %d)',	// DIRTY
+			),
 			'request_failed' => 'Η αναζήτηση απέτυχε, ελέγξτε για πιθανά προβλήματα με την σύνδεση σας.',
 			'title_new_articles' => 'FreshRSS: Νέα άρθρα!',
 		),

+ 8 - 2
app/i18n/en-US/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be canceled!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// IGNORE
 		'feedback' => array(
-			'body_new_articles' => 'There are %%d new articles to read on FreshRSS.',	// IGNORE
-			'body_unread_articles' => '(unread: %%d)',	// IGNORE
+			'body_new_articles' => array(
+				0 => 'There is %d new article to read on FreshRSS.',	// IGNORE
+				1 => 'There are %d new articles to read on FreshRSS.',	// IGNORE
+			),
+			'body_unread_articles' => array(
+				0 => '(unread: %d)',	// IGNORE
+				1 => '(unread: %d)',	// IGNORE
+			),
 			'request_failed' => 'A request has failed, it may have been caused by internet connection problems.',	// IGNORE
 			'title_new_articles' => 'FreshRSS: new articles!',	// IGNORE
 		),

+ 8 - 2
app/i18n/en/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favourites and user queries. It cannot be cancelled!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',
 		'feedback' => array(
-			'body_new_articles' => 'There are %%d new articles to read on FreshRSS.',
-			'body_unread_articles' => '(unread: %%d)',
+			'body_new_articles' => array(
+				0 => 'There is %d new article to read on FreshRSS.',
+				1 => 'There are %d new articles to read on FreshRSS.',
+			),
+			'body_unread_articles' => array(
+				0 => '(unread: %d)',
+				1 => '(unread: %d)',
+			),
 			'request_failed' => 'A request has failed, it may have been caused by internet connection problems.',
 			'title_new_articles' => 'FreshRSS: new articles!',
 		),

+ 8 - 2
app/i18n/es/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => '¿Seguro que quieres hacerlo? Perderás todos los favoritos relacionados y las búsquedas de usuario. ¡Y no hay marcha atrás!',
 		'confirm_exit_slider' => '¿Estás seguro de que quieres descartar los cambios no guardados?',
 		'feedback' => array(
-			'body_new_articles' => 'Hay %%d nuevos artículos para leer en FreshRSS.',
-			'body_unread_articles' => '(No leídos: %%d)',
+			'body_new_articles' => array(
+				0 => 'Hay %d artículo nuevo para leer en FreshRSS.',	// DIRTY
+				1 => 'Hay %d nuevos artículos para leer en FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(No leídos: %d)',	// DIRTY
+				1 => '(No leídos: %d)',	// DIRTY
+			),
 			'request_failed' => 'La petición ha fallado. Puede ser debido a problemas de conexión a internet.',
 			'title_new_articles' => 'FreshRSS: ¡nuevos artículos!',
 		),

+ 8 - 2
app/i18n/fa/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => ' آیا مطمئن هستید که می خواهید این عمل را انجام دهید؟ موارد دلخواه و درخواست های کاربر مرتبط را از دست خواهید داد. نمی توان آن را لغو کرد!',
 		'confirm_exit_slider' => 'مطمئنید می‌خواهید تنظیمات ذخیره‌نشده را نادیده بگیرید؟',
 		'feedback' => array(
-			'body_new_articles' => ' %%d مقاله جدید برای خواندن در FreshRSS وجود دارد.',
-			'body_unread_articles' => ' (خوانده نشده: %%d)',
+			'body_new_articles' => array(
+				0 => ' %d مقاله جدید برای خواندن در FreshRSS وجود دارد.',	// DIRTY
+				1 => ' %d مقاله جدید برای خواندن در FreshRSS وجود دارد.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => ' (خوانده نشده: %d)',	// DIRTY
+				1 => ' (خوانده نشده: %d)',	// DIRTY
+			),
 			'request_failed' => ' یک درخواست شکست خورده است',
 			'title_new_articles' => ' FreshRSS: مقالات جدید!',
 		),

+ 8 - 2
app/i18n/fi/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Haluatko varmasti toteuttaa toiminnon? Luokkaan kuuluvat suosikit ja kyselyt poistetaan. Tätä ei voi peruuttaa!',
 		'confirm_exit_slider' => 'Haluatko varmasti hylätä muutetut asetukset?',
 		'feedback' => array(
-			'body_new_articles' => 'FreshRSS-sovelluksessa on %%d uutta artikkelia luettavana.',
-			'body_unread_articles' => '(lukematta: %%d)',
+			'body_new_articles' => array(
+				0 => 'FreshRSS-sovelluksessa on %d uusi artikkeli luettavana.',	// DIRTY
+				1 => 'FreshRSS-sovelluksessa on %d uutta artikkelia luettavana.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(lukematta: %d)',	// DIRTY
+				1 => '(lukematta: %d)',	// DIRTY
+			),
 			'request_failed' => 'Pyyntö epäonnistui. Internetyhteydessä on ehkä ollut ongelmia.',
 			'title_new_articles' => 'FreshRSS: uusia artikkeleita!',
 		),

+ 8 - 2
app/i18n/fr/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !',
 		'confirm_exit_slider' => 'Êtes-vous sûr de vouloir abandonner les paramètres non enregistrés ?',
 		'feedback' => array(
-			'body_new_articles' => 'Il y a %%d nouveaux articles à lire sur FreshRSS.',
-			'body_unread_articles' => '(non lus : %%d)',
+			'body_new_articles' => array(
+				0 => 'Il y a %d nouvel articles à lire sur FreshRSS.',
+				1 => 'Il y a %d nouveaux articles à lire sur FreshRSS.',
+			),
+			'body_unread_articles' => array(
+				0 => '(non lu : %d)',
+				1 => '(non lus : %d)',
+			),
 			'request_failed' => 'Une requête a échoué, cela peut être dû à des problèmes de connexion à Internet.',
 			'title_new_articles' => 'FreshRSS : nouveaux articles !',
 		),

+ 8 - 2
app/i18n/he/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'האם אתם בטוחים שברצוניכם לבצע פעולה זו? מועדפים ושאילתות עשויות לאבוד. אין אפשרות לבטל אותה!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => 'ישנם	\\d מאמרים חדשים לקרוא ב FreshRSS.',
-			'body_unread_articles' => '(unread: %%d)',	// TODO
+			'body_new_articles' => array(
+				0 => 'ישנם %d מאמרים חדשים לקרוא ב FreshRSS.',	// DIRTY
+				1 => 'ישנם %d מאמרים חדשים לקרוא ב FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(unread: %d)',	// TODO
+				1 => '(unread: %d)',	// TODO
+			),
 			'request_failed' => 'A request has failed, it may have been caused by internet connection problems.',	// TODO
 			'title_new_articles' => 'FreshRSS: מאמרים חדשים!',
 		),

+ 8 - 2
app/i18n/hu/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Biztos hogy végrehajtod ezt a műveletet? Minden kapcsolódó kedvenc és lekérdezés törölve lesz. Nem lehet megszakítani!',
 		'confirm_exit_slider' => 'Biztosan elveti a nem mentett beállításokat?',
 		'feedback' => array(
-			'body_new_articles' => '%%d db új cikk olvasható a FreshRSS-ben.',
-			'body_unread_articles' => '(olvasatlan: %%d)',
+			'body_new_articles' => array(
+				0 => '%d db új cikk olvasható a FreshRSS-ben.',	// DIRTY
+				1 => '%d db új cikk olvasható a FreshRSS-ben.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(olvasatlan: %d)',	// DIRTY
+				1 => '(olvasatlan: %d)',	// DIRTY
+			),
 			'request_failed' => 'Egy művelet nem sikerült, lehetséges hogy az internet kapcsolattal vannak problémák.',
 			'title_new_articles' => 'FreshRSS: új cikkek!',
 		),

+ 6 - 2
app/i18n/id/gen.php

@@ -167,8 +167,12 @@ return array(
 		'confirm_action_feed_cat' => 'Apakah Anda yakin ingin melakukan ini? Anda akan kehilangan favorit dan pencarian pengguna terkait. Ini tidak dapat dibatalkan.',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => 'Ada %%d artikel baru untuk dibaca di FreshRSS.',
-			'body_unread_articles' => '(belum dibaca: %%d)',
+			'body_new_articles' => array(
+				0 => 'Ada %d artikel baru untuk dibaca di FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(belum dibaca: %d)',	// DIRTY
+			),
 			'request_failed' => 'Permintaan gagal, mungkin dikarenakan masalah koneksi internet.',
 			'title_new_articles' => 'FreshRSS: artikel baru!',
 		),

+ 8 - 2
app/i18n/it/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Sei sicuro di voler continuare? Verranno persi i preferiti e le ricerche utente correlate!',
 		'confirm_exit_slider' => 'Sei sicuro di voler perdere le impostazioni non salvate?',
 		'feedback' => array(
-			'body_new_articles' => 'Ci sono %%d nuovi articoli da leggere.',
-			'body_unread_articles' => '(non letti: %%d)',
+			'body_new_articles' => array(
+				0 => 'C\'è %d nuovo articolo da leggere.',	// DIRTY
+				1 => 'Ci sono %d nuovi articoli da leggere.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(non letti: %d)',	// DIRTY
+				1 => '(non letti: %d)',	// DIRTY
+			),
 			'request_failed' => 'Richiesta fallita, probabilmente a causa di problemi di connessione',
 			'title_new_articles' => 'Feed RSS Reader: nuovi articoli!',
 		),

+ 6 - 2
app/i18n/ja/gen.php

@@ -167,8 +167,12 @@ return array(
 		'confirm_action_feed_cat' => '本当に実行してもいいですか? あなたは関連するお気に入りとユーザークエリを失います。キャンセルできません!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => '%%d の新規記事がFreshRSSにはあります。',
-			'body_unread_articles' => '(未読: %%d)',
+			'body_new_articles' => array(
+				0 => '%d の新規記事がFreshRSSにはあります。',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(未読: %d)',	// DIRTY
+			),
 			'request_failed' => 'おそらくインターネット接続に問題があるため、リクエストは失敗しました。',
 			'title_new_articles' => 'FreshRSS: 新規記事!',
 		),

+ 6 - 2
app/i18n/ko/gen.php

@@ -167,8 +167,12 @@ return array(
 		'confirm_action_feed_cat' => '정말 이 작업을 수행하시겠습니까? 관련된 즐겨찾기와 사용자 쿼리가 삭제됩니다. 이 작업은 되돌릴 수 없습니다!!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => '%%d 개의 새 글이 FreshRSS에 있습니다.',
-			'body_unread_articles' => '(%%d 개 읽지 않음)',
+			'body_new_articles' => array(
+				0 => '%d 개의 새 글이 FreshRSS에 있습니다.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(%d 개 읽지 않음)',	// DIRTY
+			),
 			'request_failed' => '요청한 작업을 수행할 수 없습니다. 인터넷 연결에 문제가 발생한 것 같습니다.',
 			'title_new_articles' => 'FreshRSS: 새 글이 있습니다!',
 		),

+ 10 - 2
app/i18n/lv/gen.php

@@ -179,8 +179,16 @@ return array(
 		'confirm_action_feed_cat' => 'Vai esat pārliecināts, ka vēlaties veikt šo darbību? Jūs zaudēsiet saistītos mīļākos rakstus un lietotāja pieprasījumus. To nevar atcelt!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => 'FreshRSS ir %%d jauni raksti lasīšanai.',
-			'body_unread_articles' => '(neizlasīti: %%d)',
+			'body_new_articles' => array(
+				0 => 'FreshRSS ir %d jauni raksti lasīšanai.',	// DIRTY
+				1 => 'FreshRSS ir %d jauni raksti lasīšanai.',	// DIRTY
+				2 => 'FreshRSS ir %d jauni raksti lasīšanai.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(neizlasīti: %d)',	// DIRTY
+				1 => '(neizlasīti: %d)',	// DIRTY
+				2 => '(neizlasīti: %d)',	// DIRTY
+			),
 			'request_failed' => 'Pieprasījums nav izdevies, iespējams, to izraisījušas interneta savienojuma problēmas.',
 			'title_new_articles' => 'FreshRSS: jauni raksti!',
 		),

+ 8 - 2
app/i18n/nl/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Weet u zeker dat u dit wilt doen? U verliest alle gereleteerde favorieten en gebruikers informatie. Het kan niet ongedaan worden gemaakt!',
 		'confirm_exit_slider' => 'Weet u zeker dat u de niet opgeslagen instellingen wilt negeren?',
 		'feedback' => array(
-			'body_new_articles' => 'Er zijn %%d nieuwe artikelen om te lezen op FreshRSS.',
-			'body_unread_articles' => '(ongelezen: %%d)',
+			'body_new_articles' => array(
+				0 => 'Er is %d nieuw artikel om te lezen op FreshRSS.',
+				1 => 'Er zijn %d nieuwe artikelen om te lezen op FreshRSS.',
+			),
+			'body_unread_articles' => array(
+				0 => '(ongelezen: %d)',
+				1 => '(ongelezen: %d)',
+			),
 			'request_failed' => 'Een opdracht is mislukt, mogelijk door Internet verbindings problemen.',
 			'title_new_articles' => 'FreshRSS: nieuwe artikelen!',
 		),

+ 8 - 2
app/i18n/oc/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Volètz vertadièrament contunhar ? Perdretz los favorits e filtres ligats. Aquesta accion se pòt pas anullar !',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => 'I a %%d nòus articles per legir sus FreshRSS.',
-			'body_unread_articles' => '(unread: %%d)',	// TODO
+			'body_new_articles' => array(
+				0 => 'I a %d nòus articles per legir sus FreshRSS.',	// DIRTY
+				1 => 'I a %d nòus articles per legir sus FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(unread: %d)',	// TODO
+				1 => '(unread: %d)',	// TODO
+			),
 			'request_failed' => 'Una requèsta a fach meuca, aquò pòt venir d’un problèma de connexion Internet.',
 			'title_new_articles' => 'FreshRSS : nòus articles !',
 		),

+ 10 - 2
app/i18n/pl/gen.php

@@ -179,8 +179,16 @@ return array(
 		'confirm_action_feed_cat' => 'Czy jesteś pewien, że chcesz przeprowadzić daną operację? Stracisz powiązane zapytania i ulubione wiadomości. Tych zmian nie można wycofać!',
 		'confirm_exit_slider' => 'Czy na pewno chcesz odrzucić niezapisane ustawienia?',
 		'feedback' => array(
-			'body_new_articles' => 'W FreshRSS znajduje się %%d wiadomości do przeczytania.',
-			'body_unread_articles' => '(Nieprzeczytane: %%d)',
+			'body_new_articles' => array(
+				0 => 'W FreshRSS znajduje się %d wiadomości do przeczytania.',	// DIRTY
+				1 => 'W FreshRSS znajduje się %d wiadomości do przeczytania.',	// DIRTY
+				2 => 'W FreshRSS znajduje się %d wiadomości do przeczytania.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(Nieprzeczytane: %d)',	// DIRTY
+				1 => '(Nieprzeczytane: %d)',	// DIRTY
+				2 => '(Nieprzeczytane: %d)',	// DIRTY
+			),
 			'request_failed' => 'Zapytanie nie powiodło się. Może to być spowodowane problemami z łącznością z internetem.',
 			'title_new_articles' => 'FreshRSS: nowe wiadomości!',
 		),

+ 8 - 2
app/i18n/pt-BR/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Você tem certeza que deseja efetuar esta ação ? Você irá perder favoritos e queries de usuários. Não poderá ser cancelado!',
 		'confirm_exit_slider' => 'Tem certeza de que deseja descartar as configurações não salvas?',
 		'feedback' => array(
-			'body_new_articles' => 'Há %%d novos artigos para ler no FreshRSS.',
-			'body_unread_articles' => '(não lido: %%d)',
+			'body_new_articles' => array(
+				0 => 'Há %d novo artigo para ler no FreshRSS.',	// DIRTY
+				1 => 'Há %d novos artigos para ler no FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(não lido: %d)',	// DIRTY
+				1 => '(não lido: %d)',	// DIRTY
+			),
 			'request_failed' => 'Uma solicitação falhou, isto pode ter sido causado por problemas de conexão com a internet.',
 			'title_new_articles' => 'FreshRSS: novos artigos!',
 		),

+ 8 - 2
app/i18n/pt-PT/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Tem certeza que deseja efetuar esta ação ? vai perder favoritos e pesquisas personalizadas. Não poderá ser revertida!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => 'Há %%d novos artigos para ler no FreshRSS.',
-			'body_unread_articles' => '(não lido: %%d)',
+			'body_new_articles' => array(
+				0 => 'Há %d novo artigo para ler no FreshRSS.',	// DIRTY
+				1 => 'Há %d novos artigos para ler no FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(não lido: %d)',	// DIRTY
+				1 => '(não lido: %d)',	// DIRTY
+			),
 			'request_failed' => 'Uma solicitação falhou, isto pode ter sido causado por problemas de ligação a internet.',
 			'title_new_articles' => 'FreshRSS: novos artigos!',
 		),

+ 10 - 2
app/i18n/ru/gen.php

@@ -179,8 +179,16 @@ return array(
 		'confirm_action_feed_cat' => 'Вы уверены, что хотите выполнить это действие? Вы потеряете связанные избранные статьи и пользовательские запросы. Это нельзя отменить!',
 		'confirm_exit_slider' => 'Вы уверены, что хотите отменить несохраненные настройки?',
 		'feedback' => array(
-			'body_new_articles' => '%%d новых статей в FreshRSS.',
-			'body_unread_articles' => '(Непрочитанные: %%d)',
+			'body_new_articles' => array(
+				0 => '%d новых статей в FreshRSS.',	// DIRTY
+				1 => '%d новых статей в FreshRSS.',	// DIRTY
+				2 => '%d новых статей в FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(Непрочитанные: %d)',	// DIRTY
+				1 => '(Непрочитанные: %d)',	// DIRTY
+				2 => '(Непрочитанные: %d)',	// DIRTY
+			),
 			'request_failed' => 'Запрос не удался. Возможно, это вызвано проблемами с подключением к Интернет.',
 			'title_new_articles' => 'FreshRSS: новые статьи!',
 		),

+ 10 - 2
app/i18n/sk/gen.php

@@ -179,8 +179,16 @@ return array(
 		'confirm_action_feed_cat' => 'Určite chcete vykonať túto akciu? Prídete o súvisiace obľúbené a používateľské dopyty. Zmeny budú nezvratné!',
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
-			'body_new_articles' => 'Počet nových článkov v čítačke FreshRSS: %%d',
-			'body_unread_articles' => '(neprečítané: %%d)',
+			'body_new_articles' => array(
+				0 => 'Počet nových článkov v čítačke FreshRSS: %d',	// DIRTY
+				1 => 'Počet nových článkov v čítačke FreshRSS: %d',	// DIRTY
+				2 => 'Počet nových článkov v čítačke FreshRSS: %d',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(neprečítané: %d)',	// DIRTY
+				1 => '(neprečítané: %d)',	// DIRTY
+				2 => '(neprečítané: %d)',	// DIRTY
+			),
 			'request_failed' => 'Nepodarilo sa spracovať váš dopyt, pravdepodobne kvôli problému s pripojením do internetu.',
 			'title_new_articles' => 'FreshRSS: nové články!',
 		),

+ 8 - 2
app/i18n/tr/gen.php

@@ -173,8 +173,14 @@ return array(
 		'confirm_action_feed_cat' => 'Bu eylemi gerçekleştirmek istediğinizden emin misiniz? İlgili favoriler ve kullanıcı sorguları kaybolacak. Bu işlem geri alınamaz!',
 		'confirm_exit_slider' => 'Kaydedilmemiş ayarları atmak istediğinizden emin misiniz?',
 		'feedback' => array(
-			'body_new_articles' => 'FreshRSS’de okunacak %%d yeni makale var.',
-			'body_unread_articles' => '(okunmamış: %%d)',
+			'body_new_articles' => array(
+				0 => 'FreshRSS’de okunacak %d yeni makale var.',	// DIRTY
+				1 => 'FreshRSS’de okunacak %d yeni makale var.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(okunmamış: %d)',	// DIRTY
+				1 => '(okunmamış: %d)',	// DIRTY
+			),
 			'request_failed' => 'Bir istek başarısız oldu, bu internet bağlantı sorunlarından kaynaklanmış olabilir.',
 			'title_new_articles' => 'FreshRSS: yeni makaleler!',
 		),

+ 10 - 2
app/i18n/uk/gen.php

@@ -179,8 +179,16 @@ return array(
 		'confirm_action_feed_cat' => 'Точно виконати цю дію? Ви втратите повʼязані вподобання й користувацькі запити. Дію неможливо скасувати!',
 		'confirm_exit_slider' => 'Точно відкинути незбережені параметри?',
 		'feedback' => array(
-			'body_new_articles' => 'Наявні нові статті (%%d) у FreshRSS.',
-			'body_unread_articles' => '(непрочитано: %%d)',
+			'body_new_articles' => array(
+				0 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY
+				1 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY
+				2 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(непрочитано: %d)',	// DIRTY
+				1 => '(непрочитано: %d)',	// DIRTY
+				2 => '(непрочитано: %d)',	// DIRTY
+			),
 			'request_failed' => 'Не вдалося виконати запит. Можливо, інтернет-зʼєднання нестабільне.',
 			'title_new_articles' => 'FreshRSS: нові статті!',
 		),

+ 6 - 2
app/i18n/zh-CN/gen.php

@@ -167,8 +167,12 @@ return array(
 		'confirm_action_feed_cat' => '你确定要执行此操作吗?你将丢失相关的收藏和自定义查询,这将不可撤销!',
 		'confirm_exit_slider' => '您确定要放弃未保存的设置吗?',
 		'feedback' => array(
-			'body_new_articles' => 'FreshRSS 中有 %%d 篇文章等待阅读。',
-			'body_unread_articles' => '(未读: %%d)',
+			'body_new_articles' => array(
+				0 => 'FreshRSS 中有 %d 篇文章等待阅读。',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(未读: %d)',	// DIRTY
+			),
 			'request_failed' => '请求失败,这可能是因为网络连接问题。',
 			'title_new_articles' => 'FreshRSS: 新文章!',
 		),

+ 6 - 2
app/i18n/zh-TW/gen.php

@@ -167,8 +167,12 @@ return array(
 		'confirm_action_feed_cat' => '您確定要執行此操作嗎?您將丟失相關的收藏和使用者查詢。這無法被取消!',
 		'confirm_exit_slider' => '您確定要丟棄所有未儲存的設定嗎?',
 		'feedback' => array(
-			'body_new_articles' => 'FreshRSS 中有 %%d 篇文章待閱讀。',
-			'body_unread_articles' => '(未讀: %%d)',
+			'body_new_articles' => array(
+				0 => 'FreshRSS 中有 %d 篇文章待閱讀。',	// DIRTY
+			),
+			'body_unread_articles' => array(
+				0 => '(未讀: %d)',	// DIRTY
+			),
 			'request_failed' => '請求失敗,有可能是網路連線問題造成的。',
 			'title_new_articles' => 'FreshRSS: 新文章!',
 		),

+ 0 - 2
app/views/helpers/javascript_vars.phtml

@@ -83,8 +83,6 @@ echo json_encode([
 		'confirmation_default' => _t('gen.js.confirm_action'),
 		'confirm_exit_slider' => _t('gen.js.confirm_exit_slider'),
 		'notif_title_articles' => _t('gen.js.feedback.title_new_articles'),
-		'notif_body_new_articles' => _t('gen.js.feedback.body_new_articles'),
-		'notif_body_unread_articles' => _t('gen.js.feedback.body_unread_articles'),
 		'notif_request_failed' => _t('gen.js.feedback.request_failed'),
 		'category_empty' => _t('gen.js.category_empty'),
 		'labels_empty' => _t('gen.js.labels_empty'),

+ 10 - 1
app/views/javascript/nbUnreadsPerFeed.phtml

@@ -6,14 +6,23 @@ $result = [
 	'feeds' => [],
 	'tags' => [],
 ];
+$nbUnreadFeeds = 0;
 foreach ($this->categories as $cat) {
 	foreach ($cat->feeds() as $feed) {
 		if ($feed->priority() > FreshRSS_Feed::PRIORITY_HIDDEN) {
-			$result['feeds'][$feed->id()] = $feed->nbNotRead();
+			$feedUnread = $feed->nbNotRead();
+			$result['feeds'][$feed->id()] = $feedUnread;
+			$nbUnreadFeeds += $feedUnread;
 		}
 	}
 }
 foreach ($this->tags as $tag) {
 	$result['tags'][$tag->id()] = $tag->nbUnread();
 }
+$nbUnreadBefore = max(0, Minz_Request::paramInt('previous_unread') ?: 0);
+$nbNew = max(0, $nbUnreadFeeds - $nbUnreadBefore);
+$result['notifBody'] = trim(
+	(Minz_Translate::plural('gen.js.feedback.body_new_articles', $nbNew) ?? _t('gen.js.feedback.body_new_articles', $nbNew)) . ' ' .
+	(Minz_Translate::plural('gen.js.feedback.body_unread_articles', $nbUnreadFeeds) ?? _t('gen.js.feedback.body_unread_articles', $nbUnreadFeeds))
+);
 echo json_encode($result);

+ 6 - 7
p/scripts/main.js

@@ -2043,7 +2043,7 @@ async function notifs_html5_ask_permission() {
 	}
 }
 
-function notifs_html5_show(nb, nb_new) {
+function notifs_html5_show(body) {
 	if (!context.html5_enable_notif) {
 		return;	// from config
 	}
@@ -2054,7 +2054,7 @@ function notifs_html5_show(nb, nb_new) {
 	try {
 		const notification = new window.Notification(context.i18n.notif_title_articles, {
 			icon: '../themes/icons/favicon-256-padding.png',
-			body: context.i18n.notif_body_new_articles.replace('%%d', nb_new) + ' ' + context.i18n.notif_body_unread_articles.replace('%%d', nb),
+			body: body,
 			tag: 'freshRssNewArticles',
 		});
 
@@ -2093,8 +2093,10 @@ function init_notifs_html5() {
 // </notifs html5>
 
 function refreshUnreads() {
+	const title = document.querySelector('.category.all .title');
+	const nb_unreads_before = title ? str2int(title.getAttribute('data-unread')) : 0;
 	const req = new XMLHttpRequest();
-	req.open('GET', './?c=javascript&a=nbUnreadsPerFeed', true);
+	req.open('GET', './?c=javascript&a=nbUnreadsPerFeed&previous_unread=' + encodeURIComponent(nb_unreads_before), true);
 	req.responseType = 'json';
 	req.onload = function (e) {
 		const json = xmlHttpRequestJson(this);
@@ -2104,8 +2106,6 @@ function refreshUnreads() {
 		const isAll = document.querySelector('.category.all.active');
 		let new_articles = false;
 		let nbUnreadFeeds = 0;
-		const title = document.querySelector('.category.all .title');
-		const nb_unreads_before = title ? str2int(title.getAttribute('data-unread')) : 0;
 
 		Object.keys(json.feeds).forEach(function (feed_id) {
 			const nbUnreads = json.feeds[feed_id];
@@ -2150,8 +2150,7 @@ function refreshUnreads() {
 
 		if (nb_unreads > 0 && new_articles) {
 			faviconNbUnread(nb_unreads);
-			const nb_new = nb_unreads - nb_unreads_before;
-			notifs_html5_show(nb_unreads, nb_new);
+			notifs_html5_show(json.notifBody);
 		}
 	};
 	req.send();