Ver código fonte

Add current English text to DIRTY translation comments (#9525)

* Add English references to DIRTY translation comments

Translators currently have to find the English source separately for each `// DIRTY` entry. The translation formatter now appends it on the same line, including English plural fallback for languages with additional plural forms. It keeps hints on one safe PHP comment line and refreshes them when English changes.

Only comments change in the locale files; translation values and plural rules are unchanged. Single-form translations show both English forms as `Singular: … | Plural: …`. Generated README contribution links match bare and annotated TODO/DIRTY markers and retain the end-of-line anchor.

Closes #9463.

* Show both English forms for single-form translations
Jgolding1998 8 horas atrás
pai
commit
d03296f074
72 arquivos alterados com 399 adições e 264 exclusões
  1. 1 0
      CREDITS.md
  2. 31 31
      README.fr.md
  3. 31 31
      README.md
  4. 1 1
      app/i18n/ar/admin.php
  5. 1 1
      app/i18n/az/admin.php
  6. 2 2
      app/i18n/cs/admin.php
  7. 5 5
      app/i18n/cs/conf.php
  8. 3 3
      app/i18n/cs/feedback.php
  9. 7 7
      app/i18n/cs/gen.php
  10. 3 3
      app/i18n/cs/sub.php
  11. 1 1
      app/i18n/el/admin.php
  12. 2 2
      app/i18n/el/conf.php
  13. 5 5
      app/i18n/el/gen.php
  14. 1 1
      app/i18n/es/admin.php
  15. 2 2
      app/i18n/fa/admin.php
  16. 2 2
      app/i18n/fa/conf.php
  17. 5 5
      app/i18n/fa/gen.php
  18. 1 1
      app/i18n/fi/admin.php
  19. 2 2
      app/i18n/fi/conf.php
  20. 5 5
      app/i18n/fi/gen.php
  21. 2 2
      app/i18n/he/admin.php
  22. 5 5
      app/i18n/he/conf.php
  23. 4 4
      app/i18n/he/feedback.php
  24. 3 3
      app/i18n/he/gen.php
  25. 1 1
      app/i18n/he/sub.php
  26. 2 2
      app/i18n/hu/conf.php
  27. 5 5
      app/i18n/hu/gen.php
  28. 1 1
      app/i18n/id/admin.php
  29. 2 2
      app/i18n/ja/admin.php
  30. 1 1
      app/i18n/ja/gen.php
  31. 4 4
      app/i18n/ko/admin.php
  32. 5 5
      app/i18n/ko/conf.php
  33. 3 3
      app/i18n/ko/gen.php
  34. 2 2
      app/i18n/ko/sub.php
  35. 1 1
      app/i18n/lt/admin.php
  36. 3 3
      app/i18n/lv/admin.php
  37. 5 5
      app/i18n/lv/conf.php
  38. 3 3
      app/i18n/lv/feedback.php
  39. 7 7
      app/i18n/lv/gen.php
  40. 2 2
      app/i18n/lv/sub.php
  41. 1 1
      app/i18n/oc/admin.php
  42. 5 5
      app/i18n/oc/conf.php
  43. 3 3
      app/i18n/oc/feedback.php
  44. 3 3
      app/i18n/oc/gen.php
  45. 4 4
      app/i18n/oc/sub.php
  46. 1 1
      app/i18n/pt-BR/admin.php
  47. 1 1
      app/i18n/ru/admin.php
  48. 2 2
      app/i18n/ru/conf.php
  49. 7 7
      app/i18n/ru/gen.php
  50. 2 2
      app/i18n/sk/admin.php
  51. 5 5
      app/i18n/sk/conf.php
  52. 7 7
      app/i18n/sk/gen.php
  53. 8 8
      app/i18n/sk/sub.php
  54. 1 1
      app/i18n/tr/admin.php
  55. 2 2
      app/i18n/tr/conf.php
  56. 5 5
      app/i18n/tr/gen.php
  57. 1 1
      app/i18n/uk/admin.php
  58. 2 2
      app/i18n/uk/conf.php
  59. 7 7
      app/i18n/uk/gen.php
  60. 3 3
      app/i18n/zh-CN/admin.php
  61. 2 2
      app/i18n/zh-CN/api.php
  62. 1 1
      app/i18n/zh-CN/conf.php
  63. 1 1
      app/i18n/zh-CN/feedback.php
  64. 5 5
      app/i18n/zh-CN/gen.php
  65. 6 6
      app/i18n/zh-CN/sub.php
  66. 2 2
      app/i18n/zh-TW/admin.php
  67. 1 1
      app/i18n/zh-TW/gen.php
  68. 1 1
      cli/check.translation.php
  69. 29 4
      cli/i18n/I18nFile.php
  70. 4 0
      cli/i18n/I18nValue.php
  71. 4 0
      docs/en/internationalization.md
  72. 101 0
      tests/cli/i18n/I18nFileTest.php

+ 1 - 0
CREDITS.md

@@ -180,6 +180,7 @@ People are sorted by name so please keep this order.
 * [Julien Reichardt](https://github.com/j8r): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:j8r)
 * [Julien-Pierre Avérous](https://github.com/javerous): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:javerous), [Web](https://www.sourcemac.fr/)
 * [junkfood](https://github.com/JunkFood02): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:JunkFood02)
+* [Justin Golding](https://github.com/Jgolding1998): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:Jgolding1998)
 * [Justin Tracey](https://github.com/jtracey): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:jtracey), [Web](https://unsuspicious.click)
 * [Kachelkaiser](https://github.com/Kachelkaiser): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:Kachelkaiser)
 * [Kaibin Yang](https://github.com/ghost): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:SkyYkb), [Web](https://kaibinyang.com/)

+ 31 - 31
README.fr.md

@@ -236,37 +236,37 @@ Voir le [dépôt dédié à ces extensions](https://github.com/FreshRSS/Extensio
 
 | Langage | Progression | |
 | - | - | - |
-| العربية (ar) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Far+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Azərbaycanca (az) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Faz+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Беларуская (be) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fbe+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Čeština (cs) | ■■■■■■■■・・ 81% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fcs+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Deutsch (de) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Ελληνικά (el) | ■■■■■■■・・・ 75% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fel+%2F%28TODO%7CDIRTY%29%24%2F) |
-| English (en) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen+%2F%28TODO%7CDIRTY%29%24%2F) |
-| English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Español (es) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%24%2F) |
-| فارسی (fa) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Suomi (fi) | ■■■■■■■■■・ 91% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Français (fr) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
-| עברית (he) | ■■■■・・・・・・ 41% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Magyar (hu) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Bahasa Indonesia (id) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Italiano (it) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 日本語 (ja) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 한국어 (ko) | ■■■■■■■■・・ 80% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fko+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Lietuvių (lt) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flt+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Latviešu (lv) | ■■■■■■■■・・ 81% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flv+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Nederlands (nl) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fnl+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Occitan (oc) | ■■■■■■■・・・ 73% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Polski (pl) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Português (Brasil) (pt-BR) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Português (Portugal) (pt-PT) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-PT+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Русский (ru) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fru+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Slovenčina (sk) | ■■■■■■■■・・ 80% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fsk+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Türkçe (tr) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ftr+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Українська (uk) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 简体中文 (zh-CN) | ■■■■■■■■■・ 95% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 正體中文 (zh-TW) | ■■■■■■■■■・ 97% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-TW+%2F%28TODO%7CDIRTY%29%24%2F) |
+| العربية (ar) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Far+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Azərbaycanca (az) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Faz+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Беларуская (be) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fbe+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Čeština (cs) | ■■■■■■■■・・ 81% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fcs+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Deutsch (de) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Ελληνικά (el) | ■■■■■■■・・・ 75% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fel+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| English (en) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Español (es) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| فارسی (fa) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Suomi (fi) | ■■■■■■■■■・ 91% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Français (fr) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| עברית (he) | ■■■■・・・・・・ 41% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Magyar (hu) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Bahasa Indonesia (id) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Italiano (it) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 日本語 (ja) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 한국어 (ko) | ■■■■■■■■・・ 80% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fko+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Lietuvių (lt) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flt+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Latviešu (lv) | ■■■■■■■■・・ 81% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flv+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Nederlands (nl) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fnl+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Occitan (oc) | ■■■■■■■・・・ 73% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Polski (pl) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Português (Brasil) (pt-BR) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Português (Portugal) (pt-PT) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-PT+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Русский (ru) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fru+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Slovenčina (sk) | ■■■■■■■■・・ 80% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fsk+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Türkçe (tr) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ftr+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Українська (uk) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 简体中文 (zh-CN) | ■■■■■■■■■・ 95% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 正體中文 (zh-TW) | ■■■■■■■■■・ 97% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-TW+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
 
 </translations>
 

+ 31 - 31
README.md

@@ -132,37 +132,37 @@ See the [repository dedicated to those extensions](https://github.com/FreshRSS/E
 
 | Language | Progress | |
 | - | - | - |
-| العربية (ar) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Far+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Azərbaycanca (az) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Faz+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Беларуская (be) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fbe+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Čeština (cs) | ■■■■■■■■・・ 81% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fcs+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Deutsch (de) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Ελληνικά (el) | ■■■■■■■・・・ 75% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fel+%2F%28TODO%7CDIRTY%29%24%2F) |
-| English (en) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen+%2F%28TODO%7CDIRTY%29%24%2F) |
-| English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Español (es) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%24%2F) |
-| فارسی (fa) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Suomi (fi) | ■■■■■■■■■・ 91% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Français (fr) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
-| עברית (he) | ■■■■・・・・・・ 41% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Magyar (hu) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Bahasa Indonesia (id) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Italiano (it) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 日本語 (ja) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 한국어 (ko) | ■■■■■■■■・・ 80% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fko+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Lietuvių (lt) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flt+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Latviešu (lv) | ■■■■■■■■・・ 81% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flv+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Nederlands (nl) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fnl+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Occitan (oc) | ■■■■■■■・・・ 73% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Polski (pl) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Português (Brasil) (pt-BR) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Português (Portugal) (pt-PT) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-PT+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Русский (ru) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fru+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Slovenčina (sk) | ■■■■■■■■・・ 80% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fsk+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Türkçe (tr) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ftr+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Українська (uk) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 简体中文 (zh-CN) | ■■■■■■■■■・ 95% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%24%2F) |
-| 正體中文 (zh-TW) | ■■■■■■■■■・ 97% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-TW+%2F%28TODO%7CDIRTY%29%24%2F) |
+| العربية (ar) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Far+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Azərbaycanca (az) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Faz+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Беларуская (be) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fbe+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Čeština (cs) | ■■■■■■■■・・ 81% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fcs+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Deutsch (de) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Ελληνικά (el) | ■■■■■■■・・・ 75% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fel+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| English (en) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Español (es) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| فارسی (fa) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Suomi (fi) | ■■■■■■■■■・ 91% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Français (fr) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| עברית (he) | ■■■■・・・・・・ 41% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Magyar (hu) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Bahasa Indonesia (id) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Italiano (it) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 日本語 (ja) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 한국어 (ko) | ■■■■■■■■・・ 80% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fko+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Lietuvių (lt) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flt+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Latviešu (lv) | ■■■■■■■■・・ 81% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flv+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Nederlands (nl) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fnl+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Occitan (oc) | ■■■■■■■・・・ 73% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Polski (pl) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Português (Brasil) (pt-BR) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Português (Portugal) (pt-PT) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-PT+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Русский (ru) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fru+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Slovenčina (sk) | ■■■■■■■■・・ 80% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fsk+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Türkçe (tr) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ftr+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| Українська (uk) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 简体中文 (zh-CN) | ■■■■■■■■■・ 95% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
+| 正體中文 (zh-TW) | ■■■■■■■■■・ 97% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-TW+%2F%28TODO%7CDIRTY%29%28+-+.%2A%29%3F%24%2F) |
 
 </translations>
 

+ 1 - 1
app/i18n/ar/admin.php

@@ -15,7 +15,7 @@ return array(
 		'allow_anonymous' => 'السماح بالقراءة المجهولة لمقالات المستخدم الافتراضي (%s)',
 		'allow_anonymous_refresh' => 'السماح بالتحديث المجهول للمقالات',
 		'api_enabled' => 'السماح بالوصول إلى <abbr>API</abbr> <small>(مطلوب لتطبيقات الجوال ومشاركة استعلامات المستخدم)</small>',
-		'form' => 'نموذج الويب (تقليدي، يتطلب JavaScript)',	// DIRTY
+		'form' => 'نموذج الويب (تقليدي، يتطلب JavaScript)',	// DIRTY - Web form (traditional)
 		'http' => 'HTTP (متقدم: يديره خادم الويب، OIDC، SSO…)',
 		'none' => 'لا شيء (خطير)',
 		'title' => 'المصادقة',

+ 1 - 1
app/i18n/az/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Buraxılış kanalı',
 			'edge' => 'Davamlı buraxılış (“edge”)',
-			'latest' => 'Stabil buraxılış (“latest”)',	// DIRTY
+			'latest' => 'Stabil buraxılış (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'FreshRSS-i yenilə',
 		'viaGit' => 'git və GitHub.com vasitəsilə yeniləmə başladı',

+ 2 - 2
app/i18n/cs/admin.php

@@ -14,7 +14,7 @@ return array(
 	'auth' => array(
 		'allow_anonymous' => 'Povolit anonymní čtení článků výchozího uživatele (%s)',
 		'allow_anonymous_refresh' => 'Povolit anonymní obnovení článků',
-		'api_enabled' => 'Povolit přístup k <abbr>API</abbr> <small>(vyžadováno pro mobilní aplikace and sharing user queries)</small>',	// DIRTY
+		'api_enabled' => 'Povolit přístup k <abbr>API</abbr> <small>(vyžadováno pro mobilní aplikace and sharing user queries)</small>',	// DIRTY - Allow <abbr>API</abbr> access <small>(required for mobile apps and sharing user queries)</small>
 		'form' => 'Webový formulář (tradiční)',
 		'http' => 'HTTP (advanced: managed by Web server, OIDC, SSO…)',	// TODO
 		'none' => 'Žádný (nebezpečné)',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Kanál pro vydání',
 			'edge' => 'Vydání "Rolling" / Nepřetržitě aktualizované vydání (“edge”)',
-			'latest' => 'Stabilní vydání (“latest”)',	// DIRTY
+			'latest' => 'Stabilní vydání (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Aktualizovat systém',
 		'viaGit' => 'Aktualizace přes git a GitHub.com začala',

+ 5 - 5
app/i18n/cs/conf.php

@@ -144,7 +144,7 @@ return array(
 		),
 	),
 	'mark_read_button' => array(
-		'_' => '„označit vše jako přečtené“ button',	// DIRTY
+		'_' => '„označit vše jako přečtené“ button',	// DIRTY - “Mark all as read” button
 		'big' => 'Big',	// TODO
 		'none' => 'None',	// TODO
 		'small' => 'Small',	// TODO
@@ -283,13 +283,13 @@ return array(
 			'article_viewed' => 'když je článek zobrazen',
 			'focus' => 'při zaměření (kromě důležitých kanálů)',
 			'keep_max_n_unread' => 'Maximální počet článků, které ponechat jako nepřečtené',
-			'scroll' => 'během posouvání (kromě důležitých kanálů)',	// DIRTY
+			'scroll' => 'během posouvání (kromě důležitých kanálů)',	// DIRTY - while scrolling (except for important feeds)
 			'upon_gone' => 'když se již nenachází v upstreamu zpráv.',
 			'upon_reception' => 'po obdržení článku',
 			'when' => 'Označit článek jako přečtený…',
 			'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category',	// TODO
 			'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category',	// TODO
-			'when_same_title_in_feed' => 'když shodný název již existuje v top <i>n</i> nejnovějších článcích (of the feed)',	// DIRTY
+			'when_same_title_in_feed' => 'když shodný název již existuje v top <i>n</i> nejnovějších článcích (of the feed)',	// DIRTY - if an identical title already exists in the top <i>n</i> newest articles of the feed
 		),
 		'show' => array(
 			'_' => 'Počet zobrazených článků',
@@ -308,8 +308,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Při otevření připnout článek na začátek',
-		'sticky_sort' => 'Zachovat ruční řazení při navigaci',	// DIRTY
-		'sticky_sort_help' => 'Určuje, zda se zachová poslední ruční řazení, nebo zda každá kategorie či kanál vždy použije vlastní výchozí nebo globální nastavení.',	// DIRTY
+		'sticky_sort' => 'Zachovat ruční řazení při navigaci',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Určuje, zda se zachová poslední ruční řazení, nebo zda každá kategorie či kanál vždy použije vlastní výchozí nebo globální nastavení.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Čtení',
 		'view' => array(
 			'default' => 'Výchozí zobrazení',

+ 3 - 3
app/i18n/cs/feedback.php

@@ -58,11 +58,11 @@ return array(
 	),
 	'import_export' => array(
 		'export_no_zip_extension' => 'Na serveru není přítomno rozšíření ZIP. Zkuste exportovat soubory jeden po druhém.',
-		'feeds_imported' => 'Vaše kanály byly naimportovány a budou nyní aktualizovány / Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
-		'feeds_imported_with_errors' => 'Vaše kanály byly naimportovány, došlo ale k nějakým chybám / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
+		'feeds_imported' => 'Vaše kanály byly naimportovány a budou nyní aktualizovány / Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.
+		'feeds_imported_with_errors' => 'Vaše kanály byly naimportovány, došlo ale k nějakým chybám / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.
 		'file_cannot_be_uploaded' => 'Soubor nelze nahrát!',
 		'no_zip_extension' => 'Na serveru není přítomno rozšíření ZIP.',
-		'zip_error' => 'Během importu ZIP došlo k chybě.',	// DIRTY
+		'zip_error' => 'Během importu ZIP došlo k chybě.',	// DIRTY - An error occurred during ZIP processing.
 	),
 	'profile' => array(
 		'error' => 'Váš profil nelze změnit',

+ 7 - 7
app/i18n/cs/gen.php

@@ -180,14 +180,14 @@ return array(
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
 			'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
+				0 => 'Ve FreshRSS je %d nových článků k přečtení.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'Ve FreshRSS je %d nových článků k přečtení.',	// DIRTY - There are %d new articles to read on FreshRSS.
+				2 => 'Ve FreshRSS je %d nových článků k přečtení.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(nepřečtené: %d)',	// DIRTY
-				1 => '(nepřečtené: %d)',	// DIRTY
-				2 => '(nepřečtené: %d)',	// DIRTY
+				0 => '(nepřečtené: %d)',	// DIRTY - (unread: %d)
+				1 => '(nepřečtené: %d)',	// DIRTY - (unread: %d)
+				2 => '(nepřečtené: %d)',	// DIRTY - (unread: %d)
 			),
 			'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!',
@@ -315,7 +315,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Záložky',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Záložky',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 3 - 3
app/i18n/cs/sub.php

@@ -70,10 +70,10 @@ return array(
 		),
 		'description' => 'Popis',
 		'empty' => 'Tento kanál je prázdný. Ověřte prosím, zda je stále udržován.',
-		'error' => 'Vyskytl se problém s kanálem. Ověřte prosím, že je vždy dostupný.',	// DIRTY
+		'error' => 'Vyskytl se problém s kanálem. Ověřte prosím, že je vždy dostupný.',	// DIRTY - This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
 		'export-as-opml' => array(
 			'download' => 'Stáhnout',
-			'help' => 'Soubor XML (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// DIRTY
+			'help' => 'Soubor XML (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// DIRTY - XML file (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)
 			'label' => 'Exportovat jako OPML',
 		),
 		'ext_favicon' => 'Set automatically',	// TODO
@@ -155,7 +155,7 @@ return array(
 				'help' => 'JSON s tečkovým zápisem používá tečky mezi objekty a závorky pro pole. (e.g. <code>data.items[0].title</code>)',
 				'item' => array(
 					'_' => 'vyhledávání nových <strong>položek</strong><br /><small>(nejdůležitější)</small>',
-					'help' => 'JSON cesta k poli obsahujícímu položky, např.: <code>$</code> or <code>newsItems</code>',	// DIRTY
+					'help' => 'JSON cesta k poli obsahujícímu položky, např.: <code>$</code> or <code>newsItems</code>',	// DIRTY - JSON path to the array containing the items, e.g. <code>$</code> or <code>newsItems</code>
 				),
 				'item_author' => 'autor položky',
 				'item_categories' => 'štítky položky',

+ 1 - 1
app/i18n/el/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Κανάλι κυκλοφορίας',
 			'edge' => 'Rolling release («edge»)',
-			'latest' => 'Σταθερή κυκλοφορία («latest»)',	// DIRTY
+			'latest' => 'Σταθερή κυκλοφορία («latest»)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Ενημέρωση συστήματος',
 		'viaGit' => 'Ξεκίνησε η ενημέρωση μέσω git και GitHub.com',

+ 2 - 2
app/i18n/el/conf.php

@@ -308,8 +308,8 @@ return array(
 			'when' => 'Σήμανση άρθρου ως αγαπημένου…',
 		),
 		'sticky_post' => 'Καρφίτσωμα του άρθρου στην κορυφή όταν ανοίγεται',
-		'sticky_sort' => 'Διατήρηση της χειροκίνητης ταξινόμησης κατά την πλοήγηση',	// DIRTY
-		'sticky_sort_help' => 'Καθορίζει αν διατηρείται η τελευταία χειροκίνητη ταξινόμηση ή αν κάθε κατηγορία ή ροή χρησιμοποιεί πάντα τη δική της προεπιλεγμένη ή καθολική ρύθμιση.',	// DIRTY
+		'sticky_sort' => 'Διατήρηση της χειροκίνητης ταξινόμησης κατά την πλοήγηση',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Καθορίζει αν διατηρείται η τελευταία χειροκίνητη ταξινόμηση ή αν κάθε κατηγορία ή ροή χρησιμοποιεί πάντα τη δική της προεπιλεγμένη ή καθολική ρύθμιση.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Ανάγνωση',
 		'view' => array(
 			'default' => 'Προεπιλεγμένη προβολή',

+ 5 - 5
app/i18n/el/gen.php

@@ -174,12 +174,12 @@ return array(
 		'confirm_exit_slider' => 'Είστε σίγουροι οτι δεν θέλετε να αποθηκεύσετε τις τρέχουσες αλλαγές σας;',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => 'Υπάρχουν %d νέα άρθρα να διαβάσετε στο FreshRSS.',	// DIRTY
-				1 => 'Υπάρχουν %d νέα άρθρα να διαβάσετε στο FreshRSS.',	// DIRTY
+				0 => 'Υπάρχουν %d νέα άρθρα να διαβάσετε στο FreshRSS.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'Υπάρχουν %d νέα άρθρα να διαβάσετε στο FreshRSS.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(αδιάβαστα: %d)',	// DIRTY
-				1 => '(αδιάβαστα: %d)',	// DIRTY
+				0 => '(αδιάβαστα: %d)',	// DIRTY - (unread: %d)
+				1 => '(αδιάβαστα: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Η αναζήτηση απέτυχε, ελέγξτε για πιθανά προβλήματα με την σύνδεση σας.',
 			'title_new_articles' => 'FreshRSS: Νέα άρθρα!',
@@ -307,7 +307,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Σελιδοδείκτες',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Σελιδοδείκτες',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 1 - 1
app/i18n/es/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Canal de publicación',
 			'edge' => 'Versión de pruebas (“edge”)',
-			'latest' => 'Versión estable (“latest”)',	// DIRTY
+			'latest' => 'Versión estable (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Actualizar sistema',
 		'viaGit' => 'Actualización comenzada vía git y GitHub',

+ 2 - 2
app/i18n/fa/admin.php

@@ -15,7 +15,7 @@ return array(
 		'allow_anonymous' => ' اجازه خواندن ناشناس مقالات کاربر پیش‌فرض (%s)',
 		'allow_anonymous_refresh' => ' اجازه بازخوانی ناشناس مقالات را بدهید',
 		'api_enabled' => 'اجازه دسترسی به <abbr>API</abbr> <small>(برای برنامه‌های موبایل و اشتراک‌گذاری پرس‌وجوهای کاربر لازم است)</small>',
-		'form' => 'فرم وب (سنتی، نیازمند JavaScript)',	// DIRTY
+		'form' => 'فرم وب (سنتی، نیازمند JavaScript)',	// DIRTY - Web form (traditional)
 		'http' => 'HTTP (پیشرفته: مدیریت‌شده توسط وب‌سرور، OIDC، SSO و...)',
 		'none' => ' هیچ (خطرناک)',
 		'title' => ' احراز هویت',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => ' کانال انتشار',
 			'edge' => 'انتشار پیوسته («edge»)',
-			'latest' => 'انتشار پایدار («latest»)',	// DIRTY
+			'latest' => 'انتشار پایدار («latest»)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'به‌روزرسانی FreshRSS',
 		'viaGit' => 'به‌روزرسانی از طریق git و GitHub.com شروع شد',

+ 2 - 2
app/i18n/fa/conf.php

@@ -308,8 +308,8 @@ return array(
 			'when' => 'یک مطلب را به عنوان مورد علاقه علامت‌گذاری کن...',
 		),
 		'sticky_post' => ' وقتی باز شد مقاله را به بالا بچسبانید',
-		'sticky_sort' => 'حفظ ترتیب مرتب‌سازی دستی هنگام پیمایش',	// DIRTY
-		'sticky_sort_help' => 'تعیین می‌کند که آیا آخرین ترتیب مرتب‌سازی دستی فعال بماند یا هر دسته یا خوراک همیشه از تنظیم پیش‌فرض یا سراسری خود استفاده کند.',	// DIRTY
+		'sticky_sort' => 'حفظ ترتیب مرتب‌سازی دستی هنگام پیمایش',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'تعیین می‌کند که آیا آخرین ترتیب مرتب‌سازی دستی فعال بماند یا هر دسته یا خوراک همیشه از تنظیم پیش‌فرض یا سراسری خود استفاده کند.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => ' خواندن',
 		'view' => array(
 			'default' => ' نمای پیش فرض',

+ 5 - 5
app/i18n/fa/gen.php

@@ -174,12 +174,12 @@ return array(
 		'confirm_exit_slider' => 'مطمئنید می‌خواهید تنظیمات ذخیره‌نشده را نادیده بگیرید؟',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => ' %d مقاله جدید برای خواندن در FreshRSS وجود دارد.',	// DIRTY
-				1 => ' %d مقاله جدید برای خواندن در FreshRSS وجود دارد.',	// DIRTY
+				0 => ' %d مقاله جدید برای خواندن در FreshRSS وجود دارد.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => ' %d مقاله جدید برای خواندن در FreshRSS وجود دارد.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => ' (خوانده نشده: %d)',	// DIRTY
-				1 => ' (خوانده نشده: %d)',	// DIRTY
+				0 => ' (خوانده نشده: %d)',	// DIRTY - (unread: %d)
+				1 => ' (خوانده نشده: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => ' یک درخواست شکست خورده است',
 			'title_new_articles' => ' FreshRSS: مقالات جدید!',
@@ -307,7 +307,7 @@ return array(
 		'linkedin' => ' لینکدین',
 		'mastodon' => ' ماستودون',
 		'movim' => ' Movim',
-		'nextcloud-bookmarks' => 'Nextcloud نشانک‌ها',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud نشانک‌ها',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => ' همه چیزخوار',
 		'pinboard' => ' پینبرد',
 		'pinterest' => ' پینترست',

+ 1 - 1
app/i18n/fi/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Julkaisukanava',
 			'edge' => 'Uusin versio (“edge”)',
-			'latest' => 'Vakaa versio (“latest”)',	// DIRTY
+			'latest' => 'Vakaa versio (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Päivitä FreshRSS',
 		'viaGit' => 'Päivitys gitin ja GitHub.comin avulla on aloitettu',

+ 2 - 2
app/i18n/fi/conf.php

@@ -308,8 +308,8 @@ return array(
 			'when' => 'Merkitse artikkeli suosikiksi…',
 		),
 		'sticky_post' => 'Kiinnitä artikkeli ylimmäksi avattaessa',
-		'sticky_sort' => 'Säilytä manuaalinen lajittelujärjestys navigoinnin aikana',	// DIRTY
-		'sticky_sort_help' => 'Määrittää, pysyykö viimeisin manuaalinen lajittelu käytössä vai käyttääkö jokainen luokka tai syöte aina omaa oletus- tai yleisasetustaan.',	// DIRTY
+		'sticky_sort' => 'Säilytä manuaalinen lajittelujärjestys navigoinnin aikana',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Määrittää, pysyykö viimeisin manuaalinen lajittelu käytössä vai käyttääkö jokainen luokka tai syöte aina omaa oletus- tai yleisasetustaan.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Lukeminen',
 		'view' => array(
 			'default' => 'Oletusnäkymä',

+ 5 - 5
app/i18n/fi/gen.php

@@ -174,12 +174,12 @@ return array(
 		'confirm_exit_slider' => 'Haluatko varmasti hylätä muutetut asetukset?',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => 'FreshRSS-sovelluksessa on %d uusi artikkeli luettavana.',	// DIRTY
-				1 => 'FreshRSS-sovelluksessa on %d uutta artikkelia luettavana.',	// DIRTY
+				0 => 'FreshRSS-sovelluksessa on %d uusi artikkeli luettavana.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'FreshRSS-sovelluksessa on %d uutta artikkelia luettavana.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(lukematta: %d)',	// DIRTY
-				1 => '(lukematta: %d)',	// DIRTY
+				0 => '(lukematta: %d)',	// DIRTY - (unread: %d)
+				1 => '(lukematta: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Pyyntö epäonnistui. Internetyhteydessä on ehkä ollut ongelmia.',
 			'title_new_articles' => 'FreshRSS: uusia artikkeleita!',
@@ -307,7 +307,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Kirjanmerkit',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Kirjanmerkit',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 2 - 2
app/i18n/he/admin.php

@@ -14,7 +14,7 @@ return array(
 	'auth' => array(
 		'allow_anonymous' => 'הרשאה לאנונימיים לקרוא את מאמרי משתמש ברירת המחדל (%s)',
 		'allow_anonymous_refresh' => 'הרשאה לאנונימיים לרענן את רשימת המאמרים',
-		'api_enabled' => 'הרשאת גישה ל <abbr>API</abbr> <small>(נדרש ליישומים סלולריים and sharing user queries)</small>',	// DIRTY
+		'api_enabled' => 'הרשאת גישה ל <abbr>API</abbr> <small>(נדרש ליישומים סלולריים and sharing user queries)</small>',	// DIRTY - Allow <abbr>API</abbr> access <small>(required for mobile apps and sharing user queries)</small>
 		'form' => 'טופס אינטרנטי (מסורתי)',
 		'http' => 'HTTP (advanced: managed by Web server, OIDC, SSO…)',	// TODO
 		'none' => 'ללא (מסוכן)',
@@ -67,7 +67,7 @@ return array(
 		'number_entries' => '%d מאמרים',
 		'overview' => 'Overview',	// TODO
 		'percent_of_total' => '% מסך הכל',
-		'repartition' => 'חלוקת המאמרים: %s',	// DIRTY
+		'repartition' => 'חלוקת המאמרים: %s',	// DIRTY - Articles repartition: %s
 		'status_favorites' => 'מועדפים',
 		'status_read' => 'נקרא',
 		'status_total' => 'סך הכל',

+ 5 - 5
app/i18n/he/conf.php

@@ -144,7 +144,7 @@ return array(
 		),
 	),
 	'mark_read_button' => array(
-		'_' => '“סימון הכל כנקרא” button',	// DIRTY
+		'_' => '“סימון הכל כנקרא” button',	// DIRTY - “Mark all as read” button
 		'big' => 'Big',	// TODO
 		'none' => 'None',	// TODO
 		'small' => 'Small',	// TODO
@@ -170,7 +170,7 @@ return array(
 	'profile' => array(
 		'_' => 'Profile management',	// TODO
 		'api' => array(
-			'_' => 'API management',	// DIRTY
+			'_' => 'API management',	// DIRTY - External access via API
 			'api_not_set' => 'API password not set',	// TODO
 			'api_set' => 'API password set',	// TODO
 			'check_link' => 'Check API status via: <kbd><a href="../api/" target="_blank">%s</a></kbd>',	// TODO
@@ -283,7 +283,7 @@ return array(
 			'article_viewed' => 'כאשר מאמר נצפה',
 			'focus' => 'when focused (except for important feeds)',	// TODO
 			'keep_max_n_unread' => 'Max number of articles to keep unread',	// TODO
-			'scroll' => '(except for important feeds) כאשר גוללים',	// DIRTY
+			'scroll' => '(except for important feeds) כאשר גוללים',	// DIRTY - while scrolling (except for important feeds)
 			'upon_gone' => 'when it is no longer in the upstream news feed',	// TODO
 			'upon_reception' => 'כאשר המאמר מתקבל',
 			'when' => 'סימון מאמרים כנקראו…',
@@ -308,8 +308,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'הצמדת המאמר לחלק העליון כאשר הוא פתוח',
-		'sticky_sort' => 'שמירת סדר המיון הידני בעת ניווט',	// DIRTY
-		'sticky_sort_help' => 'קובע אם סדר המיון הידני האחרון נשאר פעיל או שכל קטגוריה או הזנה משתמשת תמיד בהגדרת ברירת המחדל או הכללית שלה.',	// DIRTY
+		'sticky_sort' => 'שמירת סדר המיון הידני בעת ניווט',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'קובע אם סדר המיון הידני האחרון נשאר פעיל או שכל קטגוריה או הזנה משתמשת תמיד בהגדרת ברירת המחדל או הכללית שלה.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'קריאה',
 		'view' => array(
 			'default' => 'תצוגת ברירת המחדל',

+ 4 - 4
app/i18n/he/feedback.php

@@ -58,11 +58,11 @@ return array(
 	),
 	'import_export' => array(
 		'export_no_zip_extension' => 'הרחבת ZIP אינה מותקנת על השרת.',
-		'feeds_imported' => 'ההזנות שלך יובאו וכעת יעודכנו / Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
-		'feeds_imported_with_errors' => 'ההזנות שלך יובאו אך אירעו מספר שגיאות / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
+		'feeds_imported' => 'ההזנות שלך יובאו וכעת יעודכנו / Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.
+		'feeds_imported_with_errors' => 'ההזנות שלך יובאו אך אירעו מספר שגיאות / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.
 		'file_cannot_be_uploaded' => 'אין אפשרות להעלות את הקובץ!',
 		'no_zip_extension' => 'הרחבת ZIP אינה מותקנת על השרת.',
-		'zip_error' => 'אירעה שגיאה במהלך ייבוא קובץ הZIP.',	// DIRTY
+		'zip_error' => 'אירעה שגיאה במהלך ייבוא קובץ הZIP.',	// DIRTY - An error occurred during ZIP processing.
 	),
 	'profile' => array(
 		'error' => 'Your profile cannot be modified',	// TODO
@@ -100,7 +100,7 @@ return array(
 				'too_large' => 'Uploaded icon is too large. The maximum file size is <em>%s</em>.',	// TODO
 				'unsupported_format' => 'Unsupported image file format!',	// TODO
 			),
-			'internal_problem' => 'אין אפשרות להוסיף את ההזנה. <a href="%s">בדקו את הלוגים</a> לפרטים. You can try force adding by appending <code>#force_feed</code> to the URL.',	// DIRTY
+			'internal_problem' => 'אין אפשרות להוסיף את ההזנה. <a href="%s">בדקו את הלוגים</a> לפרטים. You can try force adding by appending <code>#force_feed</code> to the URL.',	// DIRTY - The newsfeed could not be added. <a href="%s">Check FreshRSS logs</a> for details. You can try force adding by appending <code>#force_feed</code> to the URL.
 			'invalid_url' => 'URL <em>%s</em> אינו תקין',
 			'n_actualized' => '%d הזנות עודכנו',
 			'n_entries_deleted' => '%d המאמרים נמחקו',

+ 3 - 3
app/i18n/he/gen.php

@@ -174,8 +174,8 @@ return array(
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => 'ישנם %d מאמרים חדשים לקרוא ב FreshRSS.',	// DIRTY
-				1 => 'ישנם %d מאמרים חדשים לקרוא ב FreshRSS.',	// DIRTY
+				0 => 'ישנם %d מאמרים חדשים לקרוא ב FreshRSS.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'ישנם %d מאמרים חדשים לקרוא ב FreshRSS.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
 				0 => '(unread: %d)',	// TODO
@@ -307,7 +307,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud סימניות',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud סימניות',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 1 - 1
app/i18n/he/sub.php

@@ -70,7 +70,7 @@ return array(
 		),
 		'description' => 'תיאור',
 		'empty' => 'הזנה זו ריקה. אנא ודאו שהיא עדיין מתוחזקת.',
-		'error' => 'הזנה זו נתקלה בשגיאה, אנא ודאו שהיא תקינה ואז נסו שנית.',	// DIRTY
+		'error' => 'הזנה זו נתקלה בשגיאה, אנא ודאו שהיא תקינה ואז נסו שנית.',	// DIRTY - This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
 		'export-as-opml' => array(
 			'download' => 'Download',	// TODO
 			'help' => 'XML file (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// TODO

+ 2 - 2
app/i18n/hu/conf.php

@@ -308,8 +308,8 @@ return array(
 			'when' => 'Cikk megjelölése kedvencnek…',
 		),
 		'sticky_post' => 'A cikk gördüljön felülre, amikor megnyitásra kerül',
-		'sticky_sort' => 'Kézi rendezés megtartása navigáció közben',	// DIRTY
-		'sticky_sort_help' => 'Meghatározza, hogy az utolsó kézi rendezés aktív marad-e, vagy minden kategória, illetve hírcsatorna mindig a saját alapértelmezett vagy globális beállítását használja.',	// DIRTY
+		'sticky_sort' => 'Kézi rendezés megtartása navigáció közben',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Meghatározza, hogy az utolsó kézi rendezés aktív marad-e, vagy minden kategória, illetve hírcsatorna mindig a saját alapértelmezett vagy globális beállítását használja.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Olvasás',
 		'view' => array(
 			'default' => 'Alapértelmezett nézet',

+ 5 - 5
app/i18n/hu/gen.php

@@ -174,12 +174,12 @@ return array(
 		'confirm_exit_slider' => 'Biztosan elveti a nem mentett beállításokat?',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => '%d db új cikk olvasható a FreshRSS-ben.',	// DIRTY
-				1 => '%d db új cikk olvasható a FreshRSS-ben.',	// DIRTY
+				0 => '%d db új cikk olvasható a FreshRSS-ben.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => '%d db új cikk olvasható a FreshRSS-ben.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(olvasatlan: %d)',	// DIRTY
-				1 => '(olvasatlan: %d)',	// DIRTY
+				0 => '(olvasatlan: %d)',	// DIRTY - (unread: %d)
+				1 => '(olvasatlan: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Egy művelet nem sikerült, lehetséges hogy az internet kapcsolattal vannak problémák.',
 			'title_new_articles' => 'FreshRSS: új cikkek!',
@@ -307,7 +307,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Könyvjelzők',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Könyvjelzők',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 1 - 1
app/i18n/id/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Kanal rilis',
 			'edge' => 'Rilis Baru (“edge”)',
-			'latest' => 'Rilis Stabil (“latest”)',	// DIRTY
+			'latest' => 'Rilis Stabil (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Pembaruan FreshRSS',
 		'viaGit' => 'Pembaruan lewat git dan Github.com dimulai',

+ 2 - 2
app/i18n/ja/admin.php

@@ -15,7 +15,7 @@ return array(
 		'allow_anonymous' => 'ログインしていないユーザーにもデフォルトユーザー(%s)の記事の閲覧を許可する',
 		'allow_anonymous_refresh' => 'ログインしていないユーザーにも記事の更新を許可する',
 		'api_enabled' => '<abbr>API</abbr>アクセスを許可する<small>(モバイルアプリやユーザークエリの共有に必要)</small>',
-		'form' => 'ウェブフォーム(JavaScriptが必要です)',	// DIRTY
+		'form' => 'ウェブフォーム(JavaScriptが必要です)',	// DIRTY - Web form (traditional)
 		'http' => 'HTTP(上級者向け:Webサーバー、OIDC、SSOなどで管理)',
 		'none' => 'なし(危険)',
 		'title' => '認証',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'リリースチャンネル',
 			'edge' => 'ローリングリリース(edge)',
-			'latest' => '安定版リリース(latest)',	// DIRTY
+			'latest' => '安定版リリース(latest)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'アップデートシステム',
 		'viaGit' => 'gitおよびGitHub.com経由でアップデートを開始しました。',

+ 1 - 1
app/i18n/ja/gen.php

@@ -299,7 +299,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud ブックマーク',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud ブックマーク',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 4 - 4
app/i18n/ko/admin.php

@@ -14,7 +14,7 @@ return array(
 	'auth' => array(
 		'allow_anonymous' => '누구나 기본 사용자의 글을 읽을 수 있도록 합니다(%s)',
 		'allow_anonymous_refresh' => '누구나 피드를 갱신할 수 있도록 합니다',
-		'api_enabled' => '<abbr>API</abbr> 사용을 허가합니다<small>(모바일 애플리케이션을 사용할 때 필요합니다	and sharing user queries)</small>',	// DIRTY
+		'api_enabled' => '<abbr>API</abbr> 사용을 허가합니다<small>(모바일 애플리케이션을 사용할 때 필요합니다	and sharing user queries)</small>',	// DIRTY - Allow <abbr>API</abbr> access <small>(required for mobile apps and sharing user queries)</small>
 		'form' => '웹폼 (전통적인 방식)',
 		'http' => 'HTTP (advanced: managed by Web server, OIDC, SSO…)',	// TODO
 		'none' => '사용하지 않음 (위험)',
@@ -67,7 +67,7 @@ return array(
 		'number_entries' => '%d 개의 글',
 		'overview' => 'Overview',	// TODO
 		'percent_of_total' => '전체에서의 비율 (%)',
-		'repartition' => '글 분류: %s',	// DIRTY
+		'repartition' => '글 분류: %s',	// DIRTY - Articles repartition: %s
 		'status_favorites' => '즐겨찾기',
 		'status_read' => '읽음',
 		'status_total' => '전체',
@@ -114,7 +114,7 @@ return array(
 			),
 			'title' => '사용자 회원가입 양식',
 		),
-		'sensitive-parameter' => 'Sensitive parameter. <kbd>./data/config.php</kbd>에서 직접 수정',	// DIRTY
+		'sensitive-parameter' => 'Sensitive parameter. <kbd>./data/config.php</kbd>에서 직접 수정',	// DIRTY - Sensitive parameter. Edit manually in <kbd>./data/config.php</kbd>
 		'tos' => array(
 			'disabled' => '주어지지 않음',
 			'enabled' => '<a href="./?a=tos">활성화됨</a>',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => '릴리즈 채널',
 			'edge' => '롤링 릴리즈 (“edge”)',
-			'latest' => '안정 릴리즈 (“latest”)',	// DIRTY
+			'latest' => '안정 릴리즈 (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => '업데이트',
 		'viaGit' => 'Git 및 GitHub.com을 통한 업데이트 시작 됨',

+ 5 - 5
app/i18n/ko/conf.php

@@ -144,7 +144,7 @@ return array(
 		),
 	),
 	'mark_read_button' => array(
-		'_' => '“모두 읽음으로 표시” button',	// DIRTY
+		'_' => '“모두 읽음으로 표시” button',	// DIRTY - “Mark all as read” button
 		'big' => 'Big',	// TODO
 		'none' => 'None',	// TODO
 		'small' => 'Small',	// TODO
@@ -283,13 +283,13 @@ return array(
 			'article_viewed' => '글을 읽었을 때',
 			'focus' => '포커스 됐을 때 (중요 피드 제외)',
 			'keep_max_n_unread' => '읽지 않은 상태로 유지할 최대 글 개수',
-			'scroll' => '스크롤을 하며 지나갈 때 (except for important feeds)',	// DIRTY
+			'scroll' => '스크롤을 하며 지나갈 때 (except for important feeds)',	// DIRTY - while scrolling (except for important feeds)
 			'upon_gone' => '원본 뉴스 피드에서 글 삭제 되었을 때',
 			'upon_reception' => '글을 가져오자마자',
 			'when' => '읽음으로 표시…',
 			'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category',	// TODO
 			'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category',	// TODO
-			'when_same_title_in_feed' => '상위 <i>n</i>개의 최신 글에 동일한 제목이 이미 있는 경우 (of the feed)',	// DIRTY
+			'when_same_title_in_feed' => '상위 <i>n</i>개의 최신 글에 동일한 제목이 이미 있는 경우 (of the feed)',	// DIRTY - if an identical title already exists in the top <i>n</i> newest articles of the feed
 		),
 		'show' => array(
 			'_' => '글 표시 방식',
@@ -308,8 +308,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => '글이 펼쳐진 경우 최상단에 고정하기',
-		'sticky_sort' => '탐색 중에도 수동 정렬 순서 유지',	// DIRTY
-		'sticky_sort_help' => '마지막 수동 정렬 순서를 계속 사용할지, 아니면 각 카테고리나 피드가 항상 자체 기본값 또는 전역 설정을 사용할지 결정합니다.',	// DIRTY
+		'sticky_sort' => '탐색 중에도 수동 정렬 순서 유지',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => '마지막 수동 정렬 순서를 계속 사용할지, 아니면 각 카테고리나 피드가 항상 자체 기본값 또는 전역 설정을 사용할지 결정합니다.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => '읽기',
 		'view' => array(
 			'default' => '기본 보기 모드',

+ 3 - 3
app/i18n/ko/gen.php

@@ -168,10 +168,10 @@ return array(
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => '%d 개의 새 글이 FreshRSS에 있습니다.',	// DIRTY
+				0 => '%d 개의 새 글이 FreshRSS에 있습니다.',	// DIRTY - Singular: There is %d new article to read on FreshRSS. | Plural: There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(%d 개 읽지 않음)',	// DIRTY
+				0 => '(%d 개 읽지 않음)',	// DIRTY - Singular: (unread: %d) | Plural: (unread: %d)
 			),
 			'request_failed' => '요청한 작업을 수행할 수 없습니다. 인터넷 연결에 문제가 발생한 것 같습니다.',
 			'title_new_articles' => 'FreshRSS: 새 글이 있습니다!',
@@ -299,7 +299,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud 북마크',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud 북마크',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 2 - 2
app/i18n/ko/sub.php

@@ -70,10 +70,10 @@ return array(
 		),
 		'description' => '설명',
 		'empty' => '이 피드는 비어있습니다. 피드가 계속 운영되고 있는지 확인하세요.',
-		'error' => '이 피드에 문제가 발생했습니다. 이 피드에 접근 권한이 있는지 확인하세요.',	// DIRTY
+		'error' => '이 피드에 문제가 발생했습니다. 이 피드에 접근 권한이 있는지 확인하세요.',	// DIRTY - This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
 		'export-as-opml' => array(
 			'download' => '다운로드',
-			'help' => 'XML 파일 (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// DIRTY
+			'help' => 'XML 파일 (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// DIRTY - XML file (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)
 			'label' => 'OPML로 내보내기',
 		),
 		'ext_favicon' => 'Set automatically',	// TODO

+ 1 - 1
app/i18n/lt/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Leidimų kanalas',
 			'edge' => 'Nuolatinis leidimas („edge“)',
-			'latest' => 'Stabilus leidimas („latest“)',	// DIRTY
+			'latest' => 'Stabilus leidimas („latest“)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Atnaujinti FreshRSS',
 		'viaGit' => 'Pradėtas atnaujinimas per „git“ ir „GitHub.com“',

+ 3 - 3
app/i18n/lv/admin.php

@@ -14,7 +14,7 @@ return array(
 	'auth' => array(
 		'allow_anonymous' => 'Ļaut anonīmi lasīt noklusējuma lietotāja rakstus (%s)',
 		'allow_anonymous_refresh' => 'Atļaut anonīmu rakstu atsvaidzināšanu',
-		'api_enabled' => 'Atļaut <abbr>API</abbr> piekļuvi <small>(nepieciešams mobilajām lietotnēm and sharing user queries)</small>',	// DIRTY
+		'api_enabled' => 'Atļaut <abbr>API</abbr> piekļuvi <small>(nepieciešams mobilajām lietotnēm and sharing user queries)</small>',	// DIRTY - Allow <abbr>API</abbr> access <small>(required for mobile apps and sharing user queries)</small>
 		'form' => 'Tīmekļa veidlapa (tradicionālā)',
 		'http' => 'HTTP (advanced: managed by Web server, OIDC, SSO…)',	// TODO
 		'none' => 'Nav (bīstami)',
@@ -67,7 +67,7 @@ return array(
 		'number_entries' => '%d raksti',
 		'overview' => 'Overview',	// TODO
 		'percent_of_total' => '% no kopsummas',
-		'repartition' => 'Rakstu pārdalīšana: %s',	// DIRTY
+		'repartition' => 'Rakstu pārdalīšana: %s',	// DIRTY - Articles repartition: %s
 		'status_favorites' => 'Mīļākie',
 		'status_read' => 'Izlasīti',
 		'status_total' => 'Kopā',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Izlaiduma kanāls',
 			'edge' => 'Ritošā atbrīvošana (“edge”)',
-			'latest' => 'Stabila atbrīvošana (“latest”)',	// DIRTY
+			'latest' => 'Stabila atbrīvošana (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Atjaunināt sistēmu',
 		'viaGit' => 'Atjaunināt, izmantojot git un GitHub.com sākts',

+ 5 - 5
app/i18n/lv/conf.php

@@ -17,7 +17,7 @@ return array(
 		'help' => 'Vairākas opcijas ir pieejamas atsevišķas barotnes iestatījumos.',
 		'keep_favourites' => 'Nekad neizdzēst mīļākos',
 		'keep_labels' => 'Nekad neizdzēst birkas',
-		'keep_max' => 'Maksimālais saglabājamo rakstu skaits',	// DIRTY
+		'keep_max' => 'Maksimālais saglabājamo rakstu skaits',	// DIRTY - Maximum number of articles to keep per feed
 		'keep_min_by_feed' => 'Minimālais rakstu skaits, kas jāsaglabā vienā barotnē',
 		'keep_period' => 'Maksimālais saglabājamo rakstu vecums',
 		'keep_unreads' => 'Nekad neizdzēst nelasītos rakstus',
@@ -144,7 +144,7 @@ return array(
 		),
 	),
 	'mark_read_button' => array(
-		'_' => '"atzīmēt visus kā izlasītus" button',	// DIRTY
+		'_' => '"atzīmēt visus kā izlasītus" button',	// DIRTY - “Mark all as read” button
 		'big' => 'Big',	// TODO
 		'none' => 'None',	// TODO
 		'small' => 'Small',	// TODO
@@ -289,7 +289,7 @@ return array(
 			'when' => 'Atzīmēt rakstu kā izlasītu…',
 			'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category',	// TODO
 			'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category',	// TODO
-			'when_same_title_in_feed' => 'ja identisks virsraksts jau ir jaunākajos <i>n</i> rakstos (of the feed)',	// DIRTY
+			'when_same_title_in_feed' => 'ja identisks virsraksts jau ir jaunākajos <i>n</i> rakstos (of the feed)',	// DIRTY - if an identical title already exists in the top <i>n</i> newest articles of the feed
 		),
 		'show' => array(
 			'_' => 'Rādāmie raksti',
@@ -308,8 +308,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Uzlīmēt rakstu augšā, kad atvērts',
-		'sticky_sort' => 'Saglabāt manuālo kārtošanas secību navigācijas laikā',	// DIRTY
-		'sticky_sort_help' => 'Nosaka, vai tiek saglabāta pēdējā manuālā kārtošanas secība, vai arī katra kategorija vai plūsma vienmēr izmanto savu noklusējuma vai globālo iestatījumu.',	// DIRTY
+		'sticky_sort' => 'Saglabāt manuālo kārtošanas secību navigācijas laikā',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Nosaka, vai tiek saglabāta pēdējā manuālā kārtošanas secība, vai arī katra kategorija vai plūsma vienmēr izmanto savu noklusējuma vai globālo iestatījumu.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Lasīšana',
 		'view' => array(
 			'default' => 'Noklusējuma skats',

+ 3 - 3
app/i18n/lv/feedback.php

@@ -58,11 +58,11 @@ return array(
 	),
 	'import_export' => array(
 		'export_no_zip_extension' => 'Jūsu serverī nav ZIP paplašinājuma. Lūdzu, mēģiniet eksportēt failus pa vienam.',
-		'feeds_imported' => 'Jūsu barotnes tika importētas un tagad tiks atjauninātas.	/ Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
-		'feeds_imported_with_errors' => 'Jūsu barotnes tika importētas, bet ir radušās dažas kļūdas / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
+		'feeds_imported' => 'Jūsu barotnes tika importētas un tagad tiks atjauninātas.	/ Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.
+		'feeds_imported_with_errors' => 'Jūsu barotnes tika importētas, bet ir radušās dažas kļūdas / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.
 		'file_cannot_be_uploaded' => 'Failu nevar augšupielādēt!',
 		'no_zip_extension' => 'Jūsu serverī nav ZIP paplašinājuma.',
-		'zip_error' => 'ZIP importa laikā notika kļūda.',	// DIRTY
+		'zip_error' => 'ZIP importa laikā notika kļūda.',	// DIRTY - An error occurred during ZIP processing.
 	),
 	'profile' => array(
 		'error' => 'Jūsu profilu nevar mainīt',

+ 7 - 7
app/i18n/lv/gen.php

@@ -180,14 +180,14 @@ return array(
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
 			'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
+				0 => 'FreshRSS ir %d jauni raksti lasīšanai.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'FreshRSS ir %d jauni raksti lasīšanai.',	// DIRTY - There are %d new articles to read on FreshRSS.
+				2 => 'FreshRSS ir %d jauni raksti lasīšanai.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(neizlasīti: %d)',	// DIRTY
-				1 => '(neizlasīti: %d)',	// DIRTY
-				2 => '(neizlasīti: %d)',	// DIRTY
+				0 => '(neizlasīti: %d)',	// DIRTY - (unread: %d)
+				1 => '(neizlasīti: %d)',	// DIRTY - (unread: %d)
+				2 => '(neizlasīti: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Pieprasījums nav izdevies, iespējams, to izraisījušas interneta savienojuma problēmas.',
 			'title_new_articles' => 'FreshRSS: jauni raksti!',
@@ -315,7 +315,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Grāmatzīmes',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Grāmatzīmes',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 2 - 2
app/i18n/lv/sub.php

@@ -70,7 +70,7 @@ return array(
 		),
 		'description' => 'Apraksts',
 		'empty' => 'Šī barotne ir tukša. Lūdzu, pārbaudiet, vai tā joprojām tiek uzturēta.',
-		'error' => 'Šajā barotnē ir radusies problēma. Lūdzu, pārbaudiet, vai tā vienmēr ir sasniedzama.',	// DIRTY
+		'error' => 'Šajā barotnē ir radusies problēma. Lūdzu, pārbaudiet, vai tā vienmēr ir sasniedzama.',	// DIRTY - This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
 		'export-as-opml' => array(
 			'download' => 'Lejupielādēt',
 			'help' => 'XML fails (datu apakškopa. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">Skatīt dokumentāciju</a>)',
@@ -80,7 +80,7 @@ return array(
 		'favicon_changed_by_ext' => 'The icon has been set by the <b>%s</b> extension.',	// TODO
 		'filteractions' => array(
 			'_' => 'Filtra darbības',
-			'help' => 'Uzrakstiet vienu meklēšanas filtru katrā rindā. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.',	// DIRTY
+			'help' => 'Uzrakstiet vienu meklēšanas filtru katrā rindā. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.',	// DIRTY - Write one search filter per line. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.
 			'view_filter' => 'Preview filters on existing articles (new window)',	// TODO
 		),
 		'global_hint' => 'Use <a href="%s">the global view</a> to see how many articles in each feed are matching a state or a search expression',	// TODO

+ 1 - 1
app/i18n/oc/admin.php

@@ -14,7 +14,7 @@ return array(
 	'auth' => array(
 		'allow_anonymous' => 'Autorizar la lectura anonima dels articles de l’utilizaire per defaut (%s)',
 		'allow_anonymous_refresh' => 'Autorizar l’actualizacion anonime dels fluxes',
-		'api_enabled' => 'Autorizar l’accès per <abbr>API</abbr><small>(necessari per las aplicacions mobil and sharing user queries)</small>',	// DIRTY
+		'api_enabled' => 'Autorizar l’accès per <abbr>API</abbr><small>(necessari per las aplicacions mobil and sharing user queries)</small>',	// DIRTY - Allow <abbr>API</abbr> access <small>(required for mobile apps and sharing user queries)</small>
 		'form' => 'Formulari (tradicional)',
 		'http' => 'HTTP (advanced: managed by Web server, OIDC, SSO…)',	// TODO
 		'none' => 'Cap (perilhós)',

+ 5 - 5
app/i18n/oc/conf.php

@@ -144,7 +144,7 @@ return array(
 		),
 	),
 	'mark_read_button' => array(
-		'_' => '« o marcar tot coma legit » button',	// DIRTY
+		'_' => '« o marcar tot coma legit » button',	// DIRTY - “Mark all as read” button
 		'big' => 'Big',	// TODO
 		'none' => 'None',	// TODO
 		'small' => 'Small',	// TODO
@@ -283,13 +283,13 @@ return array(
 			'article_viewed' => 'quand l’article es mostrat',
 			'focus' => 'when focused (except for important feeds)',	// TODO
 			'keep_max_n_unread' => 'Nombre max d’articles a gardar pas legits',
-			'scroll' => 'en davalant la pagina (except for important feeds)',	// DIRTY
+			'scroll' => 'en davalant la pagina (except for important feeds)',	// DIRTY - while scrolling (except for important feeds)
 			'upon_gone' => 'quand es pas mai dins lo flux de novèla font',
 			'upon_reception' => 'en recebre un article novèl',
 			'when' => 'Marcar un article coma legit…',
 			'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category',	// TODO
 			'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category',	// TODO
-			'when_same_title_in_feed' => 'se un títol identic existís ja demest lo <i>n</i> articles mai recents (of the feed)',	// DIRTY
+			'when_same_title_in_feed' => 'se un títol identic existís ja demest lo <i>n</i> articles mai recents (of the feed)',	// DIRTY - if an identical title already exists in the top <i>n</i> newest articles of the feed
 		),
 		'show' => array(
 			'_' => 'Articles de mostrar',
@@ -308,8 +308,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Gardar l’article amont quand es dobèrt',
-		'sticky_sort' => 'Servar l’òrdre de triada manual pendent la navigacion',	// DIRTY
-		'sticky_sort_help' => 'Determina se lo darrièr òrdre de triada manual es conservat o se cada categoria o flux utiliza totjorn son pròpri paramètre per defaut o global.',	// DIRTY
+		'sticky_sort' => 'Servar l’òrdre de triada manual pendent la navigacion',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Determina se lo darrièr òrdre de triada manual es conservat o se cada categoria o flux utiliza totjorn son pròpri paramètre per defaut o global.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Lectura',
 		'view' => array(
 			'default' => 'Vista per defaut',

+ 3 - 3
app/i18n/oc/feedback.php

@@ -58,11 +58,11 @@ return array(
 	),
 	'import_export' => array(
 		'export_no_zip_extension' => 'L’extension ZIP es pas presenta sul servidor. Volgatz ensajar d’exportar los fichièrs un per un.',
-		'feeds_imported' => 'Vòstres fluxes son estats importats seràn actualizats en seguida / Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
-		'feeds_imported_with_errors' => 'Vòstres fluxes son estats importats mas i a agut d’errors / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY
+		'feeds_imported' => 'Vòstres fluxes son estats importats seràn actualizats en seguida / Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported. If you are done importing, you can now click the <i>Update feeds</i> button.
+		'feeds_imported_with_errors' => 'Vòstres fluxes son estats importats mas i a agut d’errors / Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.',	// DIRTY - Your feeds have been imported, but some errors occurred. If you are done importing, you can now click the <i>Update feeds</i> button.
 		'file_cannot_be_uploaded' => 'Telecargament del fichièr impossible',
 		'no_zip_extension' => 'L’extension es pas presenta sul servidor.',
-		'zip_error' => 'Una error s’es producha pendent l’importacion del fichièr ZIP.',	// DIRTY
+		'zip_error' => 'Una error s’es producha pendent l’importacion del fichièr ZIP.',	// DIRTY - An error occurred during ZIP processing.
 	),
 	'profile' => array(
 		'error' => 'Impossible d’actualizar vòstre perfil',

+ 3 - 3
app/i18n/oc/gen.php

@@ -174,8 +174,8 @@ return array(
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
 			'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
+				0 => 'I a %d nòus articles per legir sus FreshRSS.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'I a %d nòus articles per legir sus FreshRSS.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
 				0 => '(unread: %d)',	// TODO
@@ -307,7 +307,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Marcapaginas',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Marcapaginas',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 4 - 4
app/i18n/oc/sub.php

@@ -70,7 +70,7 @@ return array(
 		),
 		'description' => 'Descripcion',	// IGNORE
 		'empty' => 'Aqueste flux es void. Assegurats-vos qu’es totjorn mantengut.',
-		'error' => 'Aqueste flux a rescontrat un problèma. Volgatz verificar que siá totjorn accessible.',	// DIRTY
+		'error' => 'Aqueste flux a rescontrat un problèma. Volgatz verificar que siá totjorn accessible.',	// DIRTY - This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
 		'export-as-opml' => array(
 			'download' => 'Download',	// TODO
 			'help' => 'XML file (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// TODO
@@ -80,7 +80,7 @@ return array(
 		'favicon_changed_by_ext' => 'The icon has been set by the <b>%s</b> extension.',	// TODO
 		'filteractions' => array(
 			'_' => 'Filtre d’accion',
-			'help' => 'Escrivètz una recèrca per linha. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.',	// DIRTY
+			'help' => 'Escrivètz una recèrca per linha. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.',	// DIRTY - Write one search filter per line. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.
 			'view_filter' => 'Preview filters on existing articles (new window)',	// TODO
 		),
 		'global_hint' => 'Use <a href="%s">the global view</a> to see how many articles in each feed are matching a state or a search expression',	// TODO
@@ -196,7 +196,7 @@ return array(
 			'clear_cache' => 'Escafar lo cache',
 			'clear_cache_help' => 'Escafar lo cache d’aqueste flux sul disc',
 			'reload_articles' => 'Recargar los articles',
-			'reload_articles_help' => 'Recargar los articles e recuperar lo contengut complet',	// DIRTY
+			'reload_articles_help' => 'Recargar los articles e recuperar lo contengut complet',	// DIRTY - Reload that many articles and fetch complete content if a selector is defined.
 			'title' => 'Mantenença',
 		),
 		'max_http_redir' => 'Max HTTP redireccions',
@@ -224,7 +224,7 @@ return array(
 			'main_stream' => 'Mostar al flux màger',
 		),
 		'proxy' => 'Definir un servidor proxy per trapar aqueste flux',
-		'proxy_help' => 'Seleccionatz un protocòl (ex : SOCKS5) e picatz l’adreça del proxy (ex : <kbd>127.0.0.1:1080</kbd> or <kbd>username:password@127.0.0.1:1080</kbd>)',	// DIRTY
+		'proxy_help' => 'Seleccionatz un protocòl (ex : SOCKS5) e picatz l’adreça del proxy (ex : <kbd>127.0.0.1:1080</kbd> or <kbd>username:password@127.0.0.1:1080</kbd>)',	// DIRTY - Select a protocol (e.g: SOCKS5) and enter the proxy address (e.g: <kbd>127.0.0.1:1080</kbd> or <kbd>username:password@127.0.0.1:1080</kbd>)
 		'reset_favicon' => 'Reset to default',	// TODO
 		'selector_preview' => array(
 			'show_raw' => 'Veire lo còdi font',

+ 1 - 1
app/i18n/pt-BR/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Canal de Release',
 			'edge' => 'Release contínua (“edge”)',
-			'latest' => 'Release estável (“latest”)',	// DIRTY
+			'latest' => 'Release estável (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Sistema de atualização',
 		'viaGit' => 'Atualização via git e GitHub.com iniciada',

+ 1 - 1
app/i18n/ru/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Релизный канал',
 			'edge' => 'Плавающий релиз (“edge”)',
-			'latest' => 'Стабильный релиз (“latest”)',	// DIRTY
+			'latest' => 'Стабильный релиз (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Обновить систему',
 		'viaGit' => 'Обновление с помощью git и GitHub.com запущено',

+ 2 - 2
app/i18n/ru/conf.php

@@ -308,8 +308,8 @@ return array(
 			'when' => 'Отмечать статью избранной…',
 		),
 		'sticky_post' => 'Прикрепить статью к верху при открытии',
-		'sticky_sort' => 'Сохранять ручной порядок сортировки при навигации',	// DIRTY
-		'sticky_sort_help' => 'Определяет, сохраняется ли последний ручной порядок сортировки или каждая категория либо лента всегда использует собственную настройку по умолчанию или глобальную.',	// DIRTY
+		'sticky_sort' => 'Сохранять ручной порядок сортировки при навигации',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Определяет, сохраняется ли последний ручной порядок сортировки или каждая категория либо лента всегда использует собственную настройку по умолчанию или глобальную.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Чтение',
 		'view' => array(
 			'default' => 'Вид по умолчанию',

+ 7 - 7
app/i18n/ru/gen.php

@@ -180,14 +180,14 @@ return array(
 		'confirm_exit_slider' => 'Вы уверены, что хотите отменить несохраненные настройки?',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => '%d новых статей в FreshRSS.',	// DIRTY
-				1 => '%d новых статей в FreshRSS.',	// DIRTY
-				2 => '%d новых статей в FreshRSS.',	// DIRTY
+				0 => '%d новых статей в FreshRSS.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => '%d новых статей в FreshRSS.',	// DIRTY - There are %d new articles to read on FreshRSS.
+				2 => '%d новых статей в FreshRSS.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(Непрочитанные: %d)',	// DIRTY
-				1 => '(Непрочитанные: %d)',	// DIRTY
-				2 => '(Непрочитанные: %d)',	// DIRTY
+				0 => '(Непрочитанные: %d)',	// DIRTY - (unread: %d)
+				1 => '(Непрочитанные: %d)',	// DIRTY - (unread: %d)
+				2 => '(Непрочитанные: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Запрос не удался. Возможно, это вызвано проблемами с подключением к Интернет.',
 			'title_new_articles' => 'FreshRSS: новые статьи!',
@@ -315,7 +315,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Закладки',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Закладки',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 2 - 2
app/i18n/sk/admin.php

@@ -14,7 +14,7 @@ return array(
 	'auth' => array(
 		'allow_anonymous' => 'Povoliť čítanie článkov prednastaveného používateľa (%s) bez prihlásenia.',
 		'allow_anonymous_refresh' => 'Povoliť obnovenie článkov bez prihlásenia',
-		'api_enabled' => 'Povoliť prístup cez <abbr>API</abbr> <small>(vyžadujú mobilné aplikácie and sharing user queries)</small>',	// DIRTY
+		'api_enabled' => 'Povoliť prístup cez <abbr>API</abbr> <small>(vyžadujú mobilné aplikácie and sharing user queries)</small>',	// DIRTY - Allow <abbr>API</abbr> access <small>(required for mobile apps and sharing user queries)</small>
 		'form' => 'Webový formulár (traditičný)',
 		'http' => 'HTTP (advanced: managed by Web server, OIDC, SSO…)',	// TODO
 		'none' => 'Žiadny (nebezpečné)',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Kanál verzií',
 			'edge' => 'Vývojárska verzia (“edge”)',
-			'latest' => 'Stabilná verzia (“latest”)',	// DIRTY
+			'latest' => 'Stabilná verzia (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Aktualizácia systému',
 		'viaGit' => 'Začala sa aktualizácia prostredníctvom git a GitHub.com',

+ 5 - 5
app/i18n/sk/conf.php

@@ -17,7 +17,7 @@ return array(
 		'help' => 'Viac možností nájdete v nastaveniach kanála',
 		'keep_favourites' => 'Nikdy nemazať obľúbené',
 		'keep_labels' => 'Nikdy nemazať štítky',
-		'keep_max' => 'Maximálny počet článkov na zachovanie',	// DIRTY
+		'keep_max' => 'Maximálny počet článkov na zachovanie',	// DIRTY - Maximum number of articles to keep per feed
 		'keep_min_by_feed' => 'Minimálny počet článkov kanála na zachovanie',
 		'keep_period' => 'Maximálny vek článkov na zachovanie',
 		'keep_unreads' => 'Nikdy nemazať neprečítané články',
@@ -144,7 +144,7 @@ return array(
 		),
 	),
 	'mark_read_button' => array(
-		'_' => '“Označiť všetko ako prečítané” button',	// DIRTY
+		'_' => '“Označiť všetko ako prečítané” button',	// DIRTY - “Mark all as read” button
 		'big' => 'Big',	// TODO
 		'none' => 'None',	// TODO
 		'small' => 'Small',	// TODO
@@ -289,7 +289,7 @@ return array(
 			'when' => 'Označiť článok ako prečítaný…',
 			'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category',	// TODO
 			'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category',	// TODO
-			'when_same_title_in_feed' => 'ak rovnaký nadpis už existuje v TOP <i>n</i> najnovších článkoch (of the feed)',	// DIRTY
+			'when_same_title_in_feed' => 'ak rovnaký nadpis už existuje v TOP <i>n</i> najnovších článkoch (of the feed)',	// DIRTY - if an identical title already exists in the top <i>n</i> newest articles of the feed
 		),
 		'show' => array(
 			'_' => 'Článkov na zobrazenie',
@@ -308,8 +308,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Po otvorení posunúť článok hore',
-		'sticky_sort' => 'Zachovať ručné zoradenie počas navigácie',	// DIRTY
-		'sticky_sort_help' => 'Určuje, či zostane zachované posledné ručné zoradenie, alebo či každá kategória či kanál vždy použije vlastné predvolené alebo globálne nastavenie.',	// DIRTY
+		'sticky_sort' => 'Zachovať ručné zoradenie počas navigácie',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Určuje, či zostane zachované posledné ručné zoradenie, alebo či každá kategória či kanál vždy použije vlastné predvolené alebo globálne nastavenie.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Čítanie',
 		'view' => array(
 			'default' => 'Prednastavené zobrazenie',

+ 7 - 7
app/i18n/sk/gen.php

@@ -180,14 +180,14 @@ return array(
 		'confirm_exit_slider' => 'Are you sure you want to discard unsaved settings?',	// TODO
 		'feedback' => array(
 			'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
+				0 => 'Počet nových článkov v čítačke FreshRSS: %d',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'Počet nových článkov v čítačke FreshRSS: %d',	// DIRTY - There are %d new articles to read on FreshRSS.
+				2 => 'Počet nových článkov v čítačke FreshRSS: %d',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(neprečítané: %d)',	// DIRTY
-				1 => '(neprečítané: %d)',	// DIRTY
-				2 => '(neprečítané: %d)',	// DIRTY
+				0 => '(neprečítané: %d)',	// DIRTY - (unread: %d)
+				1 => '(neprečítané: %d)',	// DIRTY - (unread: %d)
+				2 => '(neprečítané: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Nepodarilo sa spracovať váš dopyt, pravdepodobne kvôli problému s pripojením do internetu.',
 			'title_new_articles' => 'FreshRSS: nové články!',
@@ -315,7 +315,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Záložky',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Záložky',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 8 - 8
app/i18n/sk/sub.php

@@ -70,17 +70,17 @@ return array(
 		),
 		'description' => 'Popis',
 		'empty' => 'Tento kanál je prázdny. Overte, prosím, či je ešte spravovaný autorom.',
-		'error' => 'Vyskytol sa problém s týmto kanálom. Overte, prosím, či kanál stále existuje.',	// DIRTY
+		'error' => 'Vyskytol sa problém s týmto kanálom. Overte, prosím, či kanál stále existuje.',	// DIRTY - This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
 		'export-as-opml' => array(
 			'download' => 'Stiahnuť',
-			'help' => 'XML súbor (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// DIRTY
+			'help' => 'XML súbor (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)',	// DIRTY - XML file (data subset. <a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">See documentation</a>)
 			'label' => 'Exportovať ako OPML',
 		),
 		'ext_favicon' => 'Set automatically',	// TODO
 		'favicon_changed_by_ext' => 'The icon has been set by the <b>%s</b> extension.',	// TODO
 		'filteractions' => array(
 			'_' => 'Filtrovať akcie',
-			'help' => 'Napíšte jeden výraz hľadania na riadok. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.',	// DIRTY
+			'help' => 'Napíšte jeden výraz hľadania na riadok. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.',	// DIRTY - Write one search filter per line. Operators <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">see documentation</a>.
 			'view_filter' => 'Preview filters on existing articles (new window)',	// TODO
 		),
 		'global_hint' => 'Use <a href="%s">the global view</a> to see how many articles in each feed are matching a state or a search expression',	// TODO
@@ -129,11 +129,11 @@ return array(
 				),
 				'item_timestamp' => array(
 					'_' => 'položka dátum',
-					'help' => 'Výsledok spracuje <a href="https://www.php.net/strtotime" target="_blank"><code>strtotime()</code></a>',	// DIRTY
+					'help' => 'Výsledok spracuje <a href="https://www.php.net/strtotime" target="_blank"><code>strtotime()</code></a>',	// DIRTY - The result will be parsed by <a href="https://www.php.net/strtotime" target="_blank"><code>strtotime()</code></a>
 				),
 				'item_title' => array(
 					'_' => 'položka nadpis',
-					'help' => 'Použite hlavne <a href="https://developer.mozilla.org/docs/Web/XML/XPath/Reference/Axes" target="_blank">XPath axis</a> <code>descendant::</code> like <code>descendant::h2</code>',	// DIRTY
+					'help' => 'Použite hlavne <a href="https://developer.mozilla.org/docs/Web/XML/XPath/Reference/Axes" target="_blank">XPath axis</a> <code>descendant::</code> like <code>descendant::h2</code>',	// DIRTY - Use in particular the <a href="https://developer.mozilla.org/docs/Web/XML/XPath/Reference/Axes" target="_blank">XPath axis</a> <code>descendant::</code> like <code>descendant::h2</code>
 				),
 				'item_uid' => array(
 					'_' => 'položka unikátny identifikátor',
@@ -155,7 +155,7 @@ return array(
 				'help' => 'JSON so zápisom s bodkou používa bodky na oddelenie objekov a zložené zátvorky pre polia (príklad: <code>data.items[0].title</code>)',
 				'item' => array(
 					'_' => 'hľadajú sa <strong>položky</strong> noviniek<br /><small>(najdôležitejšie)</small>',
-					'help' => 'JSON cesta k polu obsahujúce položky, príklad: <code>$</code> or <code>newsItems</code>',	// DIRTY
+					'help' => 'JSON cesta k polu obsahujúce položky, príklad: <code>$</code> or <code>newsItems</code>',	// DIRTY - JSON path to the array containing the items, e.g. <code>$</code> or <code>newsItems</code>
 				),
 				'item_author' => 'autor položky',
 				'item_categories' => 'značky položky',
@@ -196,7 +196,7 @@ return array(
 			'clear_cache' => 'Vymazať vyrovnáciu pamäť',
 			'clear_cache_help' => 'Vymazať vyrovnáciu pamäť pre tento kanál.',
 			'reload_articles' => 'Obnoviť články',
-			'reload_articles_help' => 'Obnoviť články a stiahnuť kompletný obsah, ak je definovaný selektor.',	// DIRTY
+			'reload_articles_help' => 'Obnoviť články a stiahnuť kompletný obsah, ak je definovaný selektor.',	// DIRTY - Reload that many articles and fetch complete content if a selector is defined.
 			'title' => 'Údržba',
 		),
 		'max_http_redir' => 'Max HTTP presmerovaní',
@@ -224,7 +224,7 @@ return array(
 			'main_stream' => 'Zobraziť v prehľade kanálov',
 		),
 		'proxy' => 'Na sťahovanie tohto kanálu nastaviť proxy',
-		'proxy_help' => 'Vyberte protokol (napr.: SOCKS5) a zadajte adresu proxy servera (napr.: <kbd>127.0.0.1:1080</kbd> or <kbd>username:password@127.0.0.1:1080</kbd>)',	// DIRTY
+		'proxy_help' => 'Vyberte protokol (napr.: SOCKS5) a zadajte adresu proxy servera (napr.: <kbd>127.0.0.1:1080</kbd> or <kbd>username:password@127.0.0.1:1080</kbd>)',	// DIRTY - Select a protocol (e.g: SOCKS5) and enter the proxy address (e.g: <kbd>127.0.0.1:1080</kbd> or <kbd>username:password@127.0.0.1:1080</kbd>)
 		'reset_favicon' => 'Reset to default',	// TODO
 		'selector_preview' => array(
 			'show_raw' => 'Zobraziť zdrojový kód',

+ 1 - 1
app/i18n/tr/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Yayın kanalı',
 			'edge' => 'Sürekli yayın (“edge”)',
-			'latest' => 'Kararlı yayın (“latest”)',	// DIRTY
+			'latest' => 'Kararlı yayın (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'FreshRSS’yi Güncelle',
 		'viaGit' => 'Git ve GitHub.com üzerinden güncelleme başlatıldı',

+ 2 - 2
app/i18n/tr/conf.php

@@ -308,8 +308,8 @@ return array(
 			'when' => 'Bir makaleyi favori olarak işaretle…',
 		),
 		'sticky_post' => 'Makale açıldığında üstte sabitle',
-		'sticky_sort' => 'Gezinme sırasında el ile belirlenen sıralama düzenini koru',	// DIRTY
-		'sticky_sort_help' => 'Son el ile belirlenen sıralama düzeninin etkin kalıp kalmayacağını ya da her kategori veya beslemenin her zaman kendi varsayılan veya genel ayarını kullanacağını belirler.',	// DIRTY
+		'sticky_sort' => 'Gezinme sırasında el ile belirlenen sıralama düzenini koru',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Son el ile belirlenen sıralama düzeninin etkin kalıp kalmayacağını ya da her kategori veya beslemenin her zaman kendi varsayılan veya genel ayarını kullanacağını belirler.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Okuma',
 		'view' => array(
 			'default' => 'Varsayılan görünüm',

+ 5 - 5
app/i18n/tr/gen.php

@@ -174,12 +174,12 @@ return array(
 		'confirm_exit_slider' => 'Kaydedilmemiş ayarları atmak istediğinizden emin misiniz?',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => 'FreshRSS’de okunacak %d yeni makale var.',	// DIRTY
-				1 => 'FreshRSS’de okunacak %d yeni makale var.',	// DIRTY
+				0 => 'FreshRSS’de okunacak %d yeni makale var.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'FreshRSS’de okunacak %d yeni makale var.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(okunmamış: %d)',	// DIRTY
-				1 => '(okunmamış: %d)',	// DIRTY
+				0 => '(okunmamış: %d)',	// DIRTY - (unread: %d)
+				1 => '(okunmamış: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Bir istek başarısız oldu, bu internet bağlantı sorunlarından kaynaklanmış olabilir.',
 			'title_new_articles' => 'FreshRSS: yeni makaleler!',
@@ -307,7 +307,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Yer imleri',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Yer imleri',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 1 - 1
app/i18n/uk/admin.php

@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => 'Канал випусків',
 			'edge' => 'Крайній випуск («edge»)',
-			'latest' => 'Стабільний випуск («latest»)',	// DIRTY
+			'latest' => 'Стабільний випуск («latest»)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => 'Оновити FreshRSS',
 		'viaGit' => 'Розпочато оновлення за допомогою git і GitHub.com',

+ 2 - 2
app/i18n/uk/conf.php

@@ -308,8 +308,8 @@ return array(
 			'when' => 'Вподобати статтю…',
 		),
 		'sticky_post' => 'Закріплювати статтю вгорі при відкритті',
-		'sticky_sort' => 'Зберігати ручний порядок сортування під час навігації',	// DIRTY
-		'sticky_sort_help' => 'Визначає, чи зберігається останній ручний порядок сортування, чи кожна категорія або стрічка завжди використовує власне типове або глобальне налаштування.',	// DIRTY
+		'sticky_sort' => 'Зберігати ручний порядок сортування під час навігації',	// DIRTY - Keep custom sort order during navigation
+		'sticky_sort_help' => 'Визначає, чи зберігається останній ручний порядок сортування, чи кожна категорія або стрічка завжди використовує власне типове або глобальне налаштування.',	// DIRTY - Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.
 		'title' => 'Читання',
 		'view' => array(
 			'default' => 'Типовий показ',

+ 7 - 7
app/i18n/uk/gen.php

@@ -180,14 +180,14 @@ return array(
 		'confirm_exit_slider' => 'Точно відкинути незбережені параметри?',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY
-				1 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY
-				2 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY
+				0 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY - There is %d new article to read on FreshRSS.
+				1 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY - There are %d new articles to read on FreshRSS.
+				2 => 'Наявні нові статті (%d) у FreshRSS.',	// DIRTY - There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(непрочитано: %d)',	// DIRTY
-				1 => '(непрочитано: %d)',	// DIRTY
-				2 => '(непрочитано: %d)',	// DIRTY
+				0 => '(непрочитано: %d)',	// DIRTY - (unread: %d)
+				1 => '(непрочитано: %d)',	// DIRTY - (unread: %d)
+				2 => '(непрочитано: %d)',	// DIRTY - (unread: %d)
 			),
 			'request_failed' => 'Не вдалося виконати запит. Можливо, інтернет-зʼєднання нестабільне.',
 			'title_new_articles' => 'FreshRSS: нові статті!',
@@ -315,7 +315,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud Закладки',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud Закладки',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 3 - 3
app/i18n/zh-CN/admin.php

@@ -31,7 +31,7 @@ return array(
 		'empty_list' => '没有已安装的扩展',
 		'empty_list_help' => '检查日志以确定扩展列表为空的原因。',
 		'enabled' => '已启用',
-		'is_compatible' => '兼容',	// DIRTY
+		'is_compatible' => '兼容',	// DIRTY - Is compatible
 		'latest' => '已安装',
 		'name' => '名称',
 		'no_configure_view' => '此扩展无法配置。',
@@ -67,7 +67,7 @@ return array(
 		'number_entries' => '%d 篇文章',
 		'overview' => '概览',
 		'percent_of_total' => '%',
-		'repartition' => '文章分布: %s',	// DIRTY
+		'repartition' => '文章分布: %s',	// DIRTY - Articles repartition: %s
 		'status_favorites' => '收藏',
 		'status_read' => '已读',
 		'status_total' => '总计',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => '发布通道',
 			'edge' => '滚动发布 (“edge”)',
-			'latest' => '稳定版本 (“latest”)',	// DIRTY
+			'latest' => '稳定版本 (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => '更新系统',
 		'viaGit' => '开始通过 git 和 GitHub.com 更新',

+ 2 - 2
app/i18n/zh-CN/api.php

@@ -15,7 +15,7 @@ return array(
 		'address' => '你的 API 地址:',
 		'output' => array(
 			'encoding-support' => '⚠️ 警告:<code>%2F</code> 支持缺失,部分客户端可能无法正常工作!',
-			'invalid-configuration' => '⚠️ 警告:./data/config.php 中可能存在无效的 base URL',	// DIRTY
+			'invalid-configuration' => '⚠️ 警告:./data/config.php 中可能存在无效的 base URL',	// DIRTY - ⚠️ WARN: Probable invalid base URL in ./data/config.php
 			'pass' => '✔️ 通过',
 			'unknown-error' => '❌ ',	// IGNORE
 		),
@@ -24,7 +24,7 @@ return array(
 			'greader' => 'Google Reader API 配置测试',
 		),
 		'title' => array(
-			'_' => 'FreshRSS API 端点',	// DIRTY
+			'_' => 'FreshRSS API 端点',	// DIRTY - FreshRSS API endpoints
 			'extension' => '供拓展使用的 API',
 			'fever' => 'Fever 兼容的 API',
 			'greader' => 'Google Reader 兼容的 API',

+ 1 - 1
app/i18n/zh-CN/conf.php

@@ -238,7 +238,7 @@ return array(
 				'_' => '已禁用',
 				'title' => '分享',
 			),
-			'greader' => 'GReader JSON 的分享链接',	// DIRTY
+			'greader' => 'GReader JSON 的分享链接',	// DIRTY - Shareable link to the GReader JSON
 			'help' => '获取此自定义查询的分享链接',
 			'html' => 'HTML 页面的分享链接',
 			'opml' => '订阅源 OPML 的分享链接',

+ 1 - 1
app/i18n/zh-CN/feedback.php

@@ -62,7 +62,7 @@ return array(
 		'feeds_imported_with_errors' => '你的订阅源已导入,但发生错误。你可以点击 <i>更新订阅</i> 按钮以完成导入。',
 		'file_cannot_be_uploaded' => '文件未能上传!',
 		'no_zip_extension' => '服务器未启用 ZIP 扩展。',
-		'zip_error' => '导入 ZIP 文件时出错',	// DIRTY
+		'zip_error' => '导入 ZIP 文件时出错',	// DIRTY - An error occurred during ZIP processing.
 	),
 	'profile' => array(
 		'error' => '你的帐户无法修改',

+ 5 - 5
app/i18n/zh-CN/gen.php

@@ -168,10 +168,10 @@ return array(
 		'confirm_exit_slider' => '您确定要放弃未保存的设置吗?',
 		'feedback' => array(
 			'body_new_articles' => array(
-				0 => 'FreshRSS 中有 %d 篇文章等待阅读。',	// DIRTY
+				0 => 'FreshRSS 中有 %d 篇文章等待阅读。',	// DIRTY - Singular: There is %d new article to read on FreshRSS. | Plural: There are %d new articles to read on FreshRSS.
 			),
 			'body_unread_articles' => array(
-				0 => '(未读: %d)',	// DIRTY
+				0 => '(未读: %d)',	// DIRTY - Singular: (unread: %d) | Plural: (unread: %d)
 			),
 			'request_failed' => '请求失败,这可能是因为网络连接问题。',
 			'title_new_articles' => 'FreshRSS: 新文章!',
@@ -258,14 +258,14 @@ return array(
 		'content' => '内容',
 		'date_from' => '从',
 		'date_modified' => 'Server Modification Date',	// TODO
-		'date_past' => '过去',	// DIRTY
+		'date_past' => '过去',	// DIRTY - In the past
 		'date_published' => '发布日期',
 		'date_range' => '日期范围',
 		'date_received' => '接收日期',
 		'date_to' => '到',
 		'date_user' => '用户修改日期',
 		'feeds' => '订阅源',
-		'free_text' => '自由文本',	// DIRTY
+		'free_text' => '自由文本',	// DIRTY - Free Text
 		'free_text_help' => '在标题和内容中搜索',
 		'full_documentation' => '查看 <a href="https://freshrss.github.io/FreshRSS/en/users/10_filter.html#with-the-search-field" target="_blank">完整搜索文档</a>',
 		'labels' => '我的标签',
@@ -299,7 +299,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud 书签',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud 书签',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 6 - 6
app/i18n/zh-CN/sub.php

@@ -70,7 +70,7 @@ return array(
 		),
 		'description' => '描述',
 		'empty' => '此源为空。请确认它是否正常更新。',
-		'error' => '此源遇到一些问题。请在确认是否能正常访问后重试。',	// DIRTY
+		'error' => '此源遇到一些问题。请在确认是否能正常访问后重试。',	// DIRTY - This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
 		'export-as-opml' => array(
 			'download' => '下载',
 			'help' => 'XML 文件(数据子集。<a href="https://freshrss.github.io/FreshRSS/en/developers/OPML.html" target="_blank">查看文档</a>)',
@@ -93,9 +93,9 @@ return array(
 		'kind' => array(
 			'_' => '订阅源类型',
 			'html_json' => array(
-				'_' => 'HTML + XPath + JSON 点表示法(HTML 中的 JSON)',	// DIRTY
+				'_' => 'HTML + XPath + JSON 点表示法(HTML 中的 JSON)',	// DIRTY - HTML + XPath + JSON dot notation (JSON in HTML)
 				'xpath' => array(
-					'_' => '用于 HTML 中 JSON 的 XPath',	// DIRTY
+					'_' => '用于 HTML 中 JSON 的 XPath',	// DIRTY - XPath for JSON in HTML
 					'help' => '示例:<code>normalize-space(//script[@type="application/json"])</code>(单个 JSON)<br />或:<code>//script[@type="application/ld+json"]</code>(每篇文章一个 JSON 对象)',
 				),
 			),
@@ -155,7 +155,7 @@ return array(
 				'help' => 'JSON 点表达式(JSON 路径)在对象之间使用点,在数组中使用中括号 (例如 <code>data.items[0].title</code>)',
 				'item' => array(
 					'_' => '寻找新的 <strong>文章</strong><br /><small>(最重要的参数)</small>',
-					'help' => '包含文章数组的 JSON 路径,例如 <code>$</code> 或 <code>newsItems</code>',	// DIRTY
+					'help' => '包含文章数组的 JSON 路径,例如 <code>$</code> 或 <code>newsItems</code>',	// DIRTY - JSON path to the array containing the items, e.g. <code>$</code> or <code>newsItems</code>
 				),
 				'item_author' => '文章作者',
 				'item_categories' => '文章标签',
@@ -209,7 +209,7 @@ return array(
 		'moved_category_deleted' => '删除分类时,其中的订阅源会自动归类到 <em>%s</em>',
 		'mute' => array(
 			'_' => '暂停',
-			'state_is_muted' => '此订阅源已静音',	// DIRTY
+			'state_is_muted' => '此订阅源已静音',	// DIRTY - This feed is muted
 		),
 		'no_selected' => '未选择订阅源',
 		'number_entries' => '%d 篇文章',
@@ -218,7 +218,7 @@ return array(
 		'priority' => array(
 			'_' => '可见性',
 			'category' => '在分类中显示',
-			'feed' => '在其订阅源中显示',	// DIRTY
+			'feed' => '在其订阅源中显示',	// DIRTY - Show in its feed
 			'hidden' => '不显示',
 			'important' => '在“重要的订阅”中显示',
 			'main_stream' => '在首页中显示',

+ 2 - 2
app/i18n/zh-TW/admin.php

@@ -15,7 +15,7 @@ return array(
 		'allow_anonymous' => '允許匿名閱讀預設使用者的文章 (%s)',
 		'allow_anonymous_refresh' => '允許匿名刷新文章',
 		'api_enabled' => '允許 <abbr>API</abbr> 存取 <small>(行動應用程式與分享使用者查詢需要)</small>',
-		'form' => 'Web 表單 (傳統方式,需要 JavaScript)',	// DIRTY
+		'form' => 'Web 表單 (傳統方式,需要 JavaScript)',	// DIRTY - Web form (traditional)
 		'http' => 'HTTP (進階: 由 Web 伺服器、OIDC、SSO 等管理)',
 		'none' => '無 (危險)',
 		'title' => '身份驗證',
@@ -137,7 +137,7 @@ return array(
 		'releaseChannel' => array(
 			'_' => '發行方式',
 			'edge' => '滾動發行 (“edge”)',
-			'latest' => '穩定發行 (“latest”)',	// DIRTY
+			'latest' => '穩定發行 (“latest”)',	// DIRTY - Versioned release (“latest”)
 		),
 		'title' => '更新 FreshRSS',
 		'viaGit' => '透過 git 和 GitHub.com 開始更新',

+ 1 - 1
app/i18n/zh-TW/gen.php

@@ -301,7 +301,7 @@ return array(
 		'linkedin' => 'LinkedIn',	// IGNORE
 		'mastodon' => 'Mastodon',	// IGNORE
 		'movim' => 'Movim',	// IGNORE
-		'nextcloud-bookmarks' => 'Nextcloud 書籤',	// DIRTY
+		'nextcloud-bookmarks' => 'Nextcloud 書籤',	// DIRTY - Nextcloud Bookmarks
 		'omnivore' => 'Omnivore',	// IGNORE
 		'pinboard' => 'Pinboard',	// IGNORE
 		'pinterest' => 'Pinterest',	// IGNORE

+ 1 - 1
cli/check.translation.php

@@ -141,7 +141,7 @@ if ($cliOptions->generateReadme) {
 		$uncompleted = intval(ceil((100 - $percentageInt) / 10));
 		$progressBar = str_repeat('■', $completed) . str_repeat('・', $uncompleted);
 
-		$ghSearchUrl = 'https://github.com/search?q=' . urlencode("repo:FreshRSS/FreshRSS path:app/i18n/$lang /(TODO|DIRTY)$/");
+		$ghSearchUrl = 'https://github.com/search?q=' . urlencode("repo:FreshRSS/FreshRSS path:app/i18n/$lang /(TODO|DIRTY)( - .*)?$/");
 
 		$markdownTable .= '| ' . implode(' | ', [
 			_t('gen.lang.' . $lang) . " ($lang)",

+ 29 - 4
cli/i18n/I18nFile.php

@@ -55,7 +55,8 @@ class I18nFile {
 			}
 			foreach ($file as $name => $content) {
 				$filename = $dir . DIRECTORY_SEPARATOR . $name;
-				file_put_contents($filename, $this->format($content));
+				$reference = $language === 'en' ? [] : ($i18n['en'][$name] ?? []);
+				file_put_contents($filename, $this->format($content, $reference));
 			}
 		}
 	}
@@ -145,6 +146,10 @@ class I18nFile {
 				$normalisedKey = ctype_digit($key) ? (int)$key : $key;
 				if ($index === $lastIndex) {
 					$current[$normalisedKey] = $value->__toString();
+					if ($value->isDirty()) {
+						// Carry the key through var_export, including when several keys share the same translation.
+						$current[$normalisedKey] .= ':' . base64_encode($compoundKey);
+					}
 					continue;
 				}
 				if (!isset($current[$normalisedKey]) || !is_array($current[$normalisedKey])) {
@@ -166,12 +171,13 @@ class I18nFile {
 	 * formatting regexes are applied to match the original content.
 	 *
 	 * @param array<string,I18nValue> $translation
+	 * @param array<string,I18nValue> $reference
 	 */
-	private function format(array $translation): string {
+	private function format(array $translation, array $reference = []): string {
+		$translationKeys = array_fill_keys(array_keys($translation), true);
 		$translation = var_export($this->unflatten($translation), true);
 		$patterns = [
 			'/ -> todo\',/',
-			'/ -> dirty\',/',
 			'/ -> ignore\',/',
 			'/array \(/',
 			'/=>\s*array/',
@@ -180,7 +186,6 @@ class I18nFile {
 		];
 		$replacements = [
 			"',\t// TODO", // Double quoting is mandatory to have a tab instead of the \t string
-			"',\t// DIRTY", // Double quoting is mandatory to have a tab instead of the \t string
 			"',\t// IGNORE", // Double quoting is mandatory to have a tab instead of the \t string
 			'array(',
 			'=> array',
@@ -188,6 +193,26 @@ class I18nFile {
 			"\t", // Double quoting is mandatory to have a tab instead of the \t string
 		];
 		$translation = preg_replace($patterns, $replacements, $translation);
+		$translation = preg_replace_callback('/ -> dirty:([A-Za-z0-9+\/=]+)\',/', static function (array $matches) use ($reference, $translationKeys): string {
+			$key = base64_decode($matches[1], true);
+			$original = $key === false ? null : ($reference[$key] ?? null);
+			if ($original === null && $key !== false && preg_match('/^(.+)\.\d+$/', $key, $parts) === 1) {
+				$original = $reference[$parts[1] . '.1'] ?? $reference[$parts[1] . '.0'] ?? null;
+			}
+			if ($original === null) {
+				return "',\t// DIRTY";
+			}
+
+			$comment = $original->getValue();
+			if ($key !== false && preg_match('/^(.+)\.0$/', $key, $parts) === 1
+				&& !isset($translationKeys[$parts[1] . '.1']) && isset($reference[$key], $reference[$parts[1] . '.1'])) {
+				$comment = 'Singular: ' . $comment . ' | Plural: ' . $reference[$parts[1] . '.1']->getValue();
+			}
+			// Keep the reference inside its line comment, including when it contains a PHP closing tag.
+			$comment = trim(preg_replace('/\s+/', ' ', $comment) ?? '');
+			$comment = str_replace('?>', '? >', $comment);
+			return "',\t// DIRTY" . ($comment === '' ? '' : ' - ' . $comment);
+		}, $translation ?? '');
 
 		return <<<PHP
 <?php

+ 4 - 0
cli/i18n/I18nValue.php

@@ -44,6 +44,10 @@ class I18nValue implements \Stringable {
 		return $this->state === self::STATE_IGNORE;
 	}
 
+	public function isDirty(): bool {
+		return $this->state === self::STATE_DIRTY;
+	}
+
 	public function isTodo(): bool {
 		return $this->state === self::STATE_TODO;
 	}

+ 4 - 0
docs/en/internationalization.md

@@ -69,6 +69,10 @@ make i18n-format
 
 It will remove the comments on the lines that you’ve changed, and will reformat the file correctly. If you’ve made any mistakes, it will fix them automatically or it will tell you it can’t (well… the command will dramatically fail without any damage, don’t worry).
 
+Entries marked `// DIRTY` need review. Formatting adds the current English text after the marker, for example `// DIRTY - Save your changes`, so you can compare it with the translation on the same line. Remove the marker once you have reviewed the translation.
+
+For translations with a single plural form, the comment includes both English forms, labelled `Singular:` and `Plural:`.
+
 The strings to translate can be easily found in the translations files thanks to the tag we spoke about at the end of the previous section. Indeed, it indicates to our tools that the strings are not translated yet. This means you can find them with Git. For instance for the Greek language:
 
 ```sh

+ 101 - 0
tests/cli/i18n/I18nFileTest.php

@@ -3,6 +3,107 @@ declare(strict_types=1);
 require_once dirname(__DIR__, 3) . '/cli/i18n/I18nFile.php';
 
 final class I18nFileTest extends \PHPUnit\Framework\TestCase {
+	public function testDirtyCommentsContainTheMatchingEnglishText(): void {
+		$file = new I18nFile();
+		$format = new ReflectionMethod(I18nFile::class, 'format');
+		$translation = [
+			'example.second' => new I18nValue('Identique -> dirty'),
+			'example.first' => new I18nValue('Identique -> dirty'),
+			'example.missing' => new I18nValue('Absent -> dirty'),
+			'example.empty' => new I18nValue('Vide -> dirty'),
+			'example.todo' => new I18nValue('Not translated -> todo'),
+			'example.ignore' => new I18nValue('Ignored -> ignore'),
+			'example.reviewed' => new I18nValue('Reviewed'),
+		];
+		$reference = [
+			'example.first' => new I18nValue('First English string'),
+			'example.second' => new I18nValue('Second English string'),
+			'example.empty' => new I18nValue(" \t\r\n"),
+			'example.todo' => new I18nValue('Not translated'),
+			'example.ignore' => new I18nValue('Ignored'),
+			'example.reviewed' => new I18nValue('Reviewed English string'),
+		];
+		$output = $format->invoke($file, $translation, $reference);
+		self::assertIsString($output);
+		self::assertStringContainsString("'first' => 'Identique',\t// DIRTY - First English string", $output);
+		self::assertStringContainsString("'second' => 'Identique',\t// DIRTY - Second English string", $output);
+		self::assertStringContainsString("'missing' => 'Absent',\t// DIRTY\n", $output);
+		self::assertStringContainsString("'empty' => 'Vide',\t// DIRTY\n", $output);
+		self::assertStringContainsString("'todo' => 'Not translated',\t// TODO\n", $output);
+		self::assertStringContainsString("'ignore' => 'Ignored',\t// IGNORE\n", $output);
+		self::assertStringContainsString("'reviewed' => 'Reviewed',\n", $output);
+	}
+
+	public function testDirtyCommentsAreSafeAndIdempotent(): void {
+		$file = new I18nFile();
+		$format = new ReflectionMethod(I18nFile::class, 'format');
+		$process = new ReflectionMethod(I18nFile::class, 'process');
+		$flatten = new ReflectionMethod(I18nFile::class, 'flatten');
+		$translation = ['example.key' => new I18nValue("L’apostrophe ' et \\ -> dirty")];
+		$reference = ['example.key' => new I18nValue("English ' and \\ %s <b>HTML</b>\r\nnext\tline ?> trailing  ")];
+		$output = $format->invoke($file, $translation, $reference);
+		self::assertIsString($output);
+		self::assertStringContainsString("// DIRTY - English ' and \\ %s <b>HTML</b> next line ? > trailing\n", $output);
+		self::assertStringNotContainsString('?>', $output);
+
+		$filename = tempnam(sys_get_temp_dir(), 'freshrss-i18n-');
+		self::assertIsString($filename);
+		try {
+			file_put_contents($filename, $output);
+			$values = include $filename;
+			self::assertSame(['key' => "L’apostrophe ' et \\"], $values);
+			$loaded = $process->invoke($file, $filename);
+			self::assertIsArray($loaded);
+			$roundTrip = $flatten->invoke($file, $loaded, 'example');
+			self::assertSame($output, $format->invoke($file, $roundTrip, $reference));
+		} finally {
+			unlink($filename);
+		}
+
+		$reference['example.key'] = new I18nValue('Updated English');
+		$updated = $format->invoke($file, $translation, $reference);
+		self::assertIsString($updated);
+		self::assertStringContainsString('// DIRTY - Updated English', $updated);
+		self::assertStringNotContainsString('trailing', $updated);
+	}
+
+	public function testDirtyCommentsUseEnglishFallbackForAdditionalPluralForms(): void {
+		$format = new ReflectionMethod(I18nFile::class, 'format');
+		$output = $format->invoke(new I18nFile(), [
+			'example.count.0' => new I18nValue('Un article -> dirty'),
+			'example.count.1' => new I18nValue('Des articles -> dirty'),
+			'example.count.2' => new I18nValue('Plusieurs articles -> dirty'),
+			'example.only.2' => new I18nValue('Autre forme -> dirty'),
+		], [
+			'example.count.0' => new I18nValue('One article'),
+			'example.count.1' => new I18nValue('Many articles'),
+			'example.only.0' => new I18nValue('One form'),
+		]);
+		self::assertIsString($output);
+		self::assertStringContainsString("0 => 'Un article',\t// DIRTY - One article", $output);
+		self::assertStringContainsString("1 => 'Des articles',\t// DIRTY - Many articles", $output);
+		self::assertStringContainsString("2 => 'Plusieurs articles',\t// DIRTY - Many articles", $output);
+		self::assertStringContainsString("2 => 'Autre forme',\t// DIRTY - One form", $output);
+	}
+
+	public function testDirtyCommentsShowBothEnglishFormsForSingleFormTranslations(): void {
+		$format = new ReflectionMethod(I18nFile::class, 'format');
+		$output = $format->invoke(new I18nFile(), [
+			'example.count.0' => new I18nValue('記事が %d 件あります -> dirty'),
+			'example.only.0' => new I18nValue('一つの形 -> dirty'),
+			'example.fallback.0' => new I18nValue('別の形 -> dirty'),
+		], [
+			'example.count.0' => new I18nValue("One article\n?>"),
+			'example.count.1' => new I18nValue("Many articles\t?>"),
+			'example.only.0' => new I18nValue('One form'),
+			'example.fallback.1' => new I18nValue('Plural only'),
+		]);
+		self::assertIsString($output);
+		self::assertStringContainsString("0 => '記事が %d 件あります',\t// DIRTY - Singular: One article ? > | Plural: Many articles ? >\n", $output);
+		self::assertStringContainsString("0 => '一つの形',\t// DIRTY - One form\n", $output);
+		self::assertStringContainsString("0 => '別の形',\t// DIRTY - Plural only\n", $output);
+	}
+
 	public function test(): void {
 		$before = $this->computeFilesHash();