summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Echo/.gitignore7
-rw-r--r--Echo/.gitreview6
-rw-r--r--Echo/.jshintignore2
-rw-r--r--Echo/.jshintrc31
-rw-r--r--Echo/.rubocop.yml25
-rw-r--r--Echo/.rubocop_todo.yml16
-rw-r--r--Echo/COPYING21
-rw-r--r--Echo/Echo.alias.php250
-rw-r--r--Echo/Echo.php472
-rwxr-xr-xEcho/Gemfile10
-rw-r--r--Echo/Gemfile.lock107
-rw-r--r--Echo/Hooks.php1049
-rw-r--r--Echo/Makefile74
-rw-r--r--Echo/Notifier.php106
-rw-r--r--Echo/RELEASE_NOTES7
-rw-r--r--Echo/Resources.php118
-rw-r--r--Echo/api/ApiEchoMarkRead.php131
-rw-r--r--Echo/api/ApiEchoNotifications.php313
-rw-r--r--Echo/autoload.php102
-rw-r--r--Echo/controller/NotificationController.php418
-rw-r--r--Echo/db_patches/echo_email_batch.sql9
-rw-r--r--Echo/db_patches/echo_target_page.sql8
-rw-r--r--Echo/db_patches/patch-add-echo_event-event_page_id.sql1
-rw-r--r--Echo/db_patches/patch-alter-event_type-index.sql3
-rw-r--r--Echo/db_patches/patch-alter-type_page-index.sql3
-rw-r--r--Echo/db_patches/patch-alter-user_timestamp-index.sql2
-rw-r--r--Echo/db_patches/patch-drop-echo_event-event_page_namespace.sql3
-rw-r--r--Echo/db_patches/patch-drop-echo_event-event_page_title.sql3
-rw-r--r--Echo/db_patches/patch-drop-echo_event-event_timestamp.sql1
-rw-r--r--Echo/db_patches/patch-drop-echo_subscription.sql2
-rw-r--r--Echo/db_patches/patch-email_batch-new-field.sql7
-rw-r--r--Echo/db_patches/patch-event_agent-split.sql4
-rw-r--r--Echo/db_patches/patch-event_agent-split.sqlite.sql35
-rw-r--r--Echo/db_patches/patch-event_agent_ip-size.sql2
-rw-r--r--Echo/db_patches/patch-event_extra-size.sql2
-rw-r--r--Echo/db_patches/patch-event_variant_nullability.sql1
-rw-r--r--Echo/db_patches/patch-event_variant_nullability.sqlite.sql33
-rw-r--r--Echo/db_patches/patch-multiple_target_pages.sql3
-rw-r--r--Echo/db_patches/patch-multiple_target_pages.sqlite.sql27
-rw-r--r--Echo/db_patches/patch-notification-bundling-field.sql8
-rw-r--r--Echo/echo.sql53
-rw-r--r--Echo/formatters/BasicFormatter.php943
-rw-r--r--Echo/formatters/CommentFormatter.php34
-rw-r--r--Echo/formatters/EditFormatter.php75
-rw-r--r--Echo/formatters/EditUserTalkFormatter.php42
-rw-r--r--Echo/formatters/MentionFormatter.php27
-rw-r--r--Echo/formatters/NotificationFormatter.php154
-rw-r--r--Echo/formatters/PageLinkFormatter.php199
-rw-r--r--Echo/formatters/UserRightsFormatter.php72
-rw-r--r--Echo/i18n/af.json53
-rw-r--r--Echo/i18n/am.json60
-rw-r--r--Echo/i18n/ar.json128
-rw-r--r--Echo/i18n/arq.json8
-rw-r--r--Echo/i18n/as.json10
-rw-r--r--Echo/i18n/ast.json116
-rw-r--r--Echo/i18n/av.json8
-rw-r--r--Echo/i18n/awa.json8
-rw-r--r--Echo/i18n/ay.json31
-rw-r--r--Echo/i18n/az.json74
-rw-r--r--Echo/i18n/azb.json35
-rw-r--r--Echo/i18n/ba.json13
-rw-r--r--Echo/i18n/bbc-latn.json10
-rw-r--r--Echo/i18n/bcc.json11
-rw-r--r--Echo/i18n/be-tarask.json111
-rw-r--r--Echo/i18n/be.json114
-rw-r--r--Echo/i18n/bg.json80
-rw-r--r--Echo/i18n/bgn.json26
-rw-r--r--Echo/i18n/bho.json8
-rw-r--r--Echo/i18n/bn.json121
-rw-r--r--Echo/i18n/br.json96
-rw-r--r--Echo/i18n/bs.json117
-rw-r--r--Echo/i18n/ca.json116
-rw-r--r--Echo/i18n/cdo.json108
-rw-r--r--Echo/i18n/ce.json117
-rw-r--r--Echo/i18n/ckb.json111
-rw-r--r--Echo/i18n/cs.json121
-rw-r--r--Echo/i18n/cu.json11
-rw-r--r--Echo/i18n/cv.json8
-rw-r--r--Echo/i18n/cy.json110
-rw-r--r--Echo/i18n/da.json117
-rw-r--r--Echo/i18n/de-formal.json16
-rw-r--r--Echo/i18n/de.json135
-rw-r--r--Echo/i18n/diq.json65
-rw-r--r--Echo/i18n/dsb.json110
-rw-r--r--Echo/i18n/el.json106
-rw-r--r--Echo/i18n/en-gb.json7
-rw-r--r--Echo/i18n/en.json139
-rw-r--r--Echo/i18n/eo.json121
-rw-r--r--Echo/i18n/es.json151
-rw-r--r--Echo/i18n/et.json118
-rw-r--r--Echo/i18n/eu.json31
-rw-r--r--Echo/i18n/fa.json132
-rw-r--r--Echo/i18n/fi.json124
-rw-r--r--Echo/i18n/fo.json29
-rw-r--r--Echo/i18n/fr.json154
-rw-r--r--Echo/i18n/frp.json28
-rw-r--r--Echo/i18n/frr.json135
-rw-r--r--Echo/i18n/fy.json12
-rw-r--r--Echo/i18n/gd.json114
-rw-r--r--Echo/i18n/gl.json126
-rw-r--r--Echo/i18n/gn.json32
-rw-r--r--Echo/i18n/gom-deva.json8
-rw-r--r--Echo/i18n/gu.json101
-rw-r--r--Echo/i18n/haw.json28
-rw-r--r--Echo/i18n/he.json125
-rw-r--r--Echo/i18n/hi.json115
-rw-r--r--Echo/i18n/hr.json93
-rw-r--r--Echo/i18n/hsb.json113
-rw-r--r--Echo/i18n/hu.json122
-rw-r--r--Echo/i18n/hy.json78
-rw-r--r--Echo/i18n/ia.json110
-rw-r--r--Echo/i18n/id.json139
-rw-r--r--Echo/i18n/ig.json9
-rw-r--r--Echo/i18n/ilo.json112
-rw-r--r--Echo/i18n/is.json106
-rw-r--r--Echo/i18n/it.json131
-rw-r--r--Echo/i18n/ja.json120
-rw-r--r--Echo/i18n/jv.json109
-rw-r--r--Echo/i18n/ka.json72
-rw-r--r--Echo/i18n/kk-cyrl.json115
-rw-r--r--Echo/i18n/kn.json75
-rw-r--r--Echo/i18n/ko.json125
-rw-r--r--Echo/i18n/krc.json108
-rw-r--r--Echo/i18n/ksh.json136
-rw-r--r--Echo/i18n/ku-latn.json8
-rw-r--r--Echo/i18n/la.json77
-rw-r--r--Echo/i18n/lad.json15
-rw-r--r--Echo/i18n/lb.json116
-rw-r--r--Echo/i18n/lrc.json97
-rw-r--r--Echo/i18n/lt.json59
-rw-r--r--Echo/i18n/lv.json114
-rw-r--r--Echo/i18n/lzh.json13
-rw-r--r--Echo/i18n/mai.json8
-rw-r--r--Echo/i18n/mg.json60
-rw-r--r--Echo/i18n/min.json8
-rw-r--r--Echo/i18n/mk.json136
-rw-r--r--Echo/i18n/ml.json138
-rw-r--r--Echo/i18n/mn.json9
-rw-r--r--Echo/i18n/mr.json113
-rw-r--r--Echo/i18n/ms.json114
-rw-r--r--Echo/i18n/mt.json110
-rw-r--r--Echo/i18n/nap.json104
-rw-r--r--Echo/i18n/nb.json138
-rw-r--r--Echo/i18n/nds-nl.json107
-rw-r--r--Echo/i18n/nds.json10
-rw-r--r--Echo/i18n/ne.json110
-rw-r--r--Echo/i18n/nl-informal.json13
-rw-r--r--Echo/i18n/nl.json129
-rw-r--r--Echo/i18n/nn.json108
-rw-r--r--Echo/i18n/oc.json107
-rw-r--r--Echo/i18n/or.json69
-rw-r--r--Echo/i18n/pa.json110
-rw-r--r--Echo/i18n/pfl.json8
-rw-r--r--Echo/i18n/pl.json131
-rw-r--r--Echo/i18n/pms.json136
-rw-r--r--Echo/i18n/ps.json59
-rw-r--r--Echo/i18n/pt-br.json120
-rw-r--r--Echo/i18n/pt.json123
-rw-r--r--Echo/i18n/qqq.json160
-rw-r--r--Echo/i18n/qu.json37
-rw-r--r--Echo/i18n/rm.json8
-rw-r--r--Echo/i18n/ro.json119
-rw-r--r--Echo/i18n/roa-tara.json111
-rw-r--r--Echo/i18n/ru.json144
-rw-r--r--Echo/i18n/rue.json8
-rw-r--r--Echo/i18n/sa.json50
-rw-r--r--Echo/i18n/sah.json13
-rw-r--r--Echo/i18n/scn.json107
-rw-r--r--Echo/i18n/sdh.json10
-rw-r--r--Echo/i18n/sh.json107
-rw-r--r--Echo/i18n/si.json33
-rw-r--r--Echo/i18n/sk.json87
-rw-r--r--Echo/i18n/sl.json116
-rw-r--r--Echo/i18n/so.json39
-rw-r--r--Echo/i18n/sq.json107
-rw-r--r--Echo/i18n/sr-ec.json117
-rw-r--r--Echo/i18n/sr-el.json115
-rw-r--r--Echo/i18n/sv.json147
-rw-r--r--Echo/i18n/ta.json91
-rw-r--r--Echo/i18n/tcy.json8
-rw-r--r--Echo/i18n/te.json112
-rw-r--r--Echo/i18n/th.json103
-rw-r--r--Echo/i18n/tl.json100
-rw-r--r--Echo/i18n/tr.json119
-rw-r--r--Echo/i18n/tt-cyrl.json20
-rw-r--r--Echo/i18n/ug-arab.json12
-rw-r--r--Echo/i18n/uk.json123
-rw-r--r--Echo/i18n/ur.json26
-rw-r--r--Echo/i18n/uz.json113
-rw-r--r--Echo/i18n/vec.json25
-rw-r--r--Echo/i18n/vi.json124
-rw-r--r--Echo/i18n/vo.json12
-rw-r--r--Echo/i18n/yi.json84
-rw-r--r--Echo/i18n/yo.json34
-rw-r--r--Echo/i18n/yue.json67
-rw-r--r--Echo/i18n/zh-hans.json160
-rw-r--r--Echo/i18n/zh-hant.json129
-rw-r--r--Echo/includes/AttributeManager.php247
-rw-r--r--Echo/includes/BatchRowUpdate.php454
-rw-r--r--Echo/includes/ContainmentSet.php242
-rw-r--r--Echo/includes/DataOutputFormatter.php138
-rw-r--r--Echo/includes/DbEmailBatch.php160
-rw-r--r--Echo/includes/DbEmailBundler.php51
-rw-r--r--Echo/includes/DeferredMarkAsReadUpdate.php39
-rw-r--r--Echo/includes/DiffParser.php315
-rw-r--r--Echo/includes/DiscussionParser.php875
-rw-r--r--Echo/includes/EchoDbFactory.php144
-rw-r--r--Echo/includes/EmailBatch.php263
-rw-r--r--Echo/includes/EmailBundler.php292
-rw-r--r--Echo/includes/EmailFormatter.php866
-rw-r--r--Echo/includes/EventLogging.php100
-rw-r--r--Echo/includes/NotifUser.php376
-rw-r--r--Echo/includes/UserLocator.php156
-rw-r--r--Echo/includes/cache/LocalCache.php98
-rw-r--r--Echo/includes/cache/RevisionLocalCache.php68
-rw-r--r--Echo/includes/cache/TitleLocalCache.php49
-rw-r--r--Echo/includes/exception/CatchableFatalErrorException.php12
-rw-r--r--Echo/includes/gateway/UserNotificationGateway.php158
-rw-r--r--Echo/includes/iterator/CallbackFilterIterator.php24
-rw-r--r--Echo/includes/iterator/CallbackIterator.php17
-rw-r--r--Echo/includes/iterator/FilteredSequentialIterator.php125
-rw-r--r--Echo/includes/iterator/IteratorDecorator.php33
-rw-r--r--Echo/includes/iterator/MultipleIterator.php67
-rw-r--r--Echo/includes/iterator/NotRecursiveIterator.php18
-rw-r--r--Echo/includes/mapper/AbstractMapper.php76
-rw-r--r--Echo/includes/mapper/EventMapper.php117
-rw-r--r--Echo/includes/mapper/NotificationMapper.php312
-rw-r--r--Echo/includes/mapper/TargetPageMapper.php152
-rw-r--r--Echo/includes/schemaUpdate.php122
-rw-r--r--Echo/jobs/NotificationDeleteJob.php74
-rw-r--r--Echo/jobs/NotificationEmailBundleJob.php26
-rw-r--r--Echo/jobs/NotificationJob.php37
-rw-r--r--Echo/maintenance/processEchoEmailBatch.php67
-rw-r--r--Echo/maintenance/removeInvalidNotification.php81
-rw-r--r--Echo/maintenance/removeInvalidTargetPage.php113
-rw-r--r--Echo/maintenance/testDiscussionParser.php91
-rw-r--r--Echo/maintenance/updateEchoSchemaForSuppression.php62
-rw-r--r--Echo/model/AbstractEntity.php14
-rw-r--r--Echo/model/Event.php548
-rw-r--r--Echo/model/Notification.php308
-rw-r--r--Echo/model/TargetPage.php139
-rw-r--r--Echo/modules/alert/ext.echo.alert.less12
-rw-r--r--Echo/modules/alert/ext.echo.alert.modern.css4
-rw-r--r--Echo/modules/alert/ext.echo.alert.monobook.css4
-rw-r--r--Echo/modules/badge/ext.echo.badge.less30
-rw-r--r--Echo/modules/badge/ext.echo.badge.modern.css4
-rw-r--r--Echo/modules/badge/ext.echo.badge.monobook.css3
-rw-r--r--Echo/modules/base/ext.echo.base.js84
-rw-r--r--Echo/modules/base/ext.echo.base.less53
-rw-r--r--Echo/modules/hooks.txt7
-rw-r--r--Echo/modules/icons/CrossReferenced.pngbin0 -> 322 bytes
-rw-r--r--Echo/modules/icons/Deletion.pngbin0 -> 291 bytes
-rw-r--r--Echo/modules/icons/Featured.pngbin0 -> 337 bytes
-rw-r--r--Echo/modules/icons/Generic.pngbin0 -> 536 bytes
-rw-r--r--Echo/modules/icons/Gratitude.pngbin0 -> 3231 bytes
-rw-r--r--Echo/modules/icons/NotificationsPage-ltr.pngbin0 -> 235 bytes
-rw-r--r--Echo/modules/icons/NotificationsPage-rtl.pngbin0 -> 305 bytes
-rw-r--r--Echo/modules/icons/Revert.pngbin0 -> 324 bytes
-rw-r--r--Echo/modules/icons/Reviewed.pngbin0 -> 309 bytes
-rw-r--r--Echo/modules/icons/ReviewedWithTags.pngbin0 -> 257 bytes
-rw-r--r--Echo/modules/icons/Settings.pngbin0 -> 349 bytes
-rw-r--r--Echo/modules/icons/Talk.pngbin0 -> 274 bytes
-rw-r--r--Echo/modules/mixins.less20
-rw-r--r--Echo/modules/overlay/Help.pngbin0 -> 3237 bytes
-rw-r--r--Echo/modules/overlay/PokeyNorth.pngbin0 -> 207 bytes
-rw-r--r--Echo/modules/overlay/ext.echo.overlay.init.js74
-rw-r--r--Echo/modules/overlay/ext.echo.overlay.js429
-rw-r--r--Echo/modules/overlay/ext.echo.overlay.less208
-rw-r--r--Echo/modules/overlay/ext.echo.overlay.modern.css37
-rw-r--r--Echo/modules/overlay/ext.echo.overlay.monobook.css18
-rw-r--r--Echo/modules/special/Feedback.pngbin0 -> 435 bytes
-rw-r--r--Echo/modules/special/FeedbackHover.pngbin0 -> 424 bytes
-rw-r--r--Echo/modules/special/Help.pngbin0 -> 457 bytes
-rw-r--r--Echo/modules/special/MoreInfo.pngbin0 -> 303 bytes
-rw-r--r--Echo/modules/special/MoreInfoHover.pngbin0 -> 313 bytes
-rw-r--r--Echo/modules/special/Preferences.pngbin0 -> 3128 bytes
-rw-r--r--Echo/modules/special/ext.echo.special.js173
-rw-r--r--Echo/modules/special/ext.echo.special.less94
-rw-r--r--Echo/package.json8
-rw-r--r--Echo/scripts/gen-autoload.php30
-rwxr-xr-xEcho/scripts/generatecss.php29
-rwxr-xr-xEcho/scripts/qunit.sh14
-rwxr-xr-xEcho/scripts/remotecheck.sh15
-rw-r--r--Echo/special/SpecialNotifications.php169
-rw-r--r--Echo/tests/bootstrap.php19
-rw-r--r--Echo/tests/browser/features/flyout.feature17
-rw-r--r--Echo/tests/browser/features/flyout_nojs.feature12
-rw-r--r--Echo/tests/browser/features/messages.feature15
-rw-r--r--Echo/tests/browser/features/notifications.feature40
-rw-r--r--Echo/tests/browser/features/notifications_userrights.feature10
-rw-r--r--Echo/tests/browser/features/step_definitions/common_steps.rb61
-rw-r--r--Echo/tests/browser/features/step_definitions/flyout_steps.rb18
-rw-r--r--Echo/tests/browser/features/step_definitions/messages_steps.rb17
-rw-r--r--Echo/tests/browser/features/step_definitions/notifications_steps.rb91
-rw-r--r--Echo/tests/browser/features/support/env.rb12
-rw-r--r--Echo/tests/browser/features/support/hooks.rb3
-rw-r--r--Echo/tests/browser/features/support/pages/article_page.rb16
-rw-r--r--Echo/tests/echo.suite.xml30
-rw-r--r--Echo/tests/externals/phantomjs-qunit-runner.js127
-rw-r--r--Echo/tests/phpunit/api/ApiEchoMarkReadTest.php112
-rw-r--r--Echo/tests/phpunit/api/ApiEchoNotificationsTest.php71
-rw-r--r--Echo/tests/phpunit/controller/NotificationControllerTest.php220
-rw-r--r--Echo/tests/phpunit/formatters/NotificationFormatterTest.php250
-rw-r--r--Echo/tests/phpunit/includes/AttributeManagerTest.php330
-rw-r--r--Echo/tests/phpunit/includes/BatchRowUpdateTest.php244
-rw-r--r--Echo/tests/phpunit/includes/ContainmentSetTest.php73
-rw-r--r--Echo/tests/phpunit/includes/DiffParserTest.php190
-rw-r--r--Echo/tests/phpunit/includes/DiscussionParserTest.php1084
-rw-r--r--Echo/tests/phpunit/includes/EchoDbFactoryTest.php29
-rw-r--r--Echo/tests/phpunit/includes/EmailFormatterTest.php89
-rw-r--r--Echo/tests/phpunit/includes/NotifUserTest.php210
-rw-r--r--Echo/tests/phpunit/includes/TalkPageFunctionalTest.php90
-rw-r--r--Echo/tests/phpunit/includes/UserLocatorTest.php270
-rw-r--r--Echo/tests/phpunit/includes/cache/TitleLocalCacheTest.php89
-rw-r--r--Echo/tests/phpunit/includes/gateway/UserNotificationGatewayTest.php120
-rw-r--r--Echo/tests/phpunit/includes/iterator/FilteredSequentialIteratorTest.php104
-rw-r--r--Echo/tests/phpunit/includes/mapper/AbstractMapperTest.php75
-rw-r--r--Echo/tests/phpunit/includes/mapper/EventMapperTest.php167
-rw-r--r--Echo/tests/phpunit/includes/mapper/NotificationMapperTest.php262
-rw-r--r--Echo/tests/phpunit/includes/mapper/TargetPageMapperTest.php177
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/138274875.txt78
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/138275105.txt80
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/40608353.txt145
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/40610292.txt146
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/637637213.txt824
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/637638133.txt828
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/646790570.txt69
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/646792804.txt70
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/647258025.txt473
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/647260329.txt474
-rw-r--r--Echo/tests/phpunit/includes/revision_txt/README4
-rw-r--r--Echo/tests/phpunit/maintenance/SupressionMaintenanceTest.php130
-rw-r--r--Echo/tests/phpunit/model/NotificationTest.php88
-rw-r--r--Echo/tests/phpunit/model/TargetPageTest.php99
-rw-r--r--Echo/tests/qunit/overlay/test_ext.echo.overlay.js307
-rw-r--r--Echo/version4
336 files changed, 34895 insertions, 0 deletions
diff --git a/Echo/.gitignore b/Echo/.gitignore
new file mode 100644
index 00000000..c71739dd
--- /dev/null
+++ b/Echo/.gitignore
@@ -0,0 +1,7 @@
+.svn
+*~
+*.kate-swp
+.*.swp
+node_modules/
+scripts/remotes/
+tests/browser/screenshots
diff --git a/Echo/.gitreview b/Echo/.gitreview
new file mode 100644
index 00000000..5aff4ca6
--- /dev/null
+++ b/Echo/.gitreview
@@ -0,0 +1,6 @@
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/extensions/Echo.git
+defaultbranch=master
+defaultrebase=0
diff --git a/Echo/.jshintignore b/Echo/.jshintignore
new file mode 100644
index 00000000..f1f4c6ac
--- /dev/null
+++ b/Echo/.jshintignore
@@ -0,0 +1,2 @@
+tests/externals/
+modules/hooks.txt
diff --git a/Echo/.jshintrc b/Echo/.jshintrc
new file mode 100644
index 00000000..dfe6f43b
--- /dev/null
+++ b/Echo/.jshintrc
@@ -0,0 +1,31 @@
+{
+ /* Common */
+
+ // Enforcing
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "immed": true,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "noempty": true,
+ "nonew": true,
+ "quotmark": "single",
+ "trailing": true,
+ "undef": true,
+ "unused": true,
+ // Legacy
+ "onevar": true,
+
+ /* Local */
+
+ // Environment
+ "browser": true,
+
+ "predef": [
+ "jQuery",
+ "QUnit",
+ "mediaWiki"
+ ]
+}
diff --git a/Echo/.rubocop.yml b/Echo/.rubocop.yml
new file mode 100644
index 00000000..7ce21af2
--- /dev/null
+++ b/Echo/.rubocop.yml
@@ -0,0 +1,25 @@
+inherit_from: .rubocop_todo.yml
+
+Metrics/AbcSize:
+ Enabled: false
+
+Metrics/ClassLength:
+ Enabled: false
+
+Metrics/CyclomaticComplexity:
+ Enabled: false
+
+Metrics/MethodLength:
+ Enabled: false
+
+Metrics/ParameterLists:
+ Enabled: false
+
+Metrics/PerceivedComplexity:
+ Enabled: false
+
+Style/Alias:
+ Enabled: false
+
+Style/SignalException:
+ Enabled: false
diff --git a/Echo/.rubocop_todo.yml b/Echo/.rubocop_todo.yml
new file mode 100644
index 00000000..0649914a
--- /dev/null
+++ b/Echo/.rubocop_todo.yml
@@ -0,0 +1,16 @@
+# This configuration was generated by `rubocop --auto-gen-config`
+# on 2015-02-23 09:43:04 -0700 using RuboCop version 0.29.0.
+# The point is for the user to remove these configuration records
+# one by one as the offenses are removed from the code base.
+# Note that changes in the inspected code, or installation of new
+# versions of RuboCop, may require this file to be generated again.
+
+# Offense count: 2
+# Configuration parameters: AllowURI, URISchemes.
+Metrics/LineLength:
+ Max: 113
+
+# Offense count: 1
+# Configuration parameters: AllowedVariables.
+Style/GlobalVars:
+ Enabled: false
diff --git a/Echo/COPYING b/Echo/COPYING
new file mode 100644
index 00000000..abc69709
--- /dev/null
+++ b/Echo/COPYING
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012-2014
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Echo/Echo.alias.php b/Echo/Echo.alias.php
new file mode 100644
index 00000000..67b05875
--- /dev/null
+++ b/Echo/Echo.alias.php
@@ -0,0 +1,250 @@
+<?php
+/**
+ * Aliases for special pages for extension Echo
+ *
+ * @file
+ * @ingroup Extensions
+ */
+// @codingStandardsIgnoreFile
+
+$specialPageAliases = array();
+
+/** English (English) */
+$specialPageAliases['en'] = array(
+ 'Notifications' => array( 'Notifications' ),
+);
+
+/** Arabic (العربية) */
+$specialPageAliases['ar'] = array(
+ 'Notifications' => array( 'إشعارات' ),
+);
+
+/** Egyptian Spoken Arabic (مصرى) */
+$specialPageAliases['arz'] = array(
+ 'Notifications' => array( 'اخطارات' ),
+);
+
+/** Avaric (авар) */
+$specialPageAliases['av'] = array(
+ 'Notifications' => array( 'Уведомления' ),
+);
+
+/** Western Balochi (بلوچی رخشانی) */
+$specialPageAliases['bgn'] = array(
+ 'Notifications' => array( 'آگاه_کورتینۆک_ئان' ),
+);
+
+/** Min Dong Chinese (Mìng-dĕ̤ng-ngṳ̄) */
+$specialPageAliases['cdo'] = array(
+ 'Notifications' => array( '提醒' ),
+);
+
+/** Chechen (нохчийн) */
+$specialPageAliases['ce'] = array(
+ 'Notifications' => array( 'ДӀахаийтар' ),
+);
+
+/** German (Deutsch) */
+$specialPageAliases['de'] = array(
+ 'Notifications' => array( 'Benachrichtigungen' ),
+);
+
+/** Zazaki (Zazaki) */
+$specialPageAliases['diq'] = array(
+ 'Notifications' => array( 'Mengeneyi' ),
+);
+
+/** Greek (Ελληνικά) */
+$specialPageAliases['el'] = array(
+ 'Notifications' => array( 'Ειδοποιήσεις' ),
+);
+
+/** Esperanto (Esperanto) */
+$specialPageAliases['eo'] = array(
+ 'Notifications' => array( 'Atentigoj' ),
+);
+
+/** Spanish (español) */
+$specialPageAliases['es'] = array(
+ 'Notifications' => array( 'Notificaciones' ),
+);
+
+/** Estonian (eesti) */
+$specialPageAliases['et'] = array(
+ 'Notifications' => array( 'Teavitused' ),
+);
+
+/** Persian (فارسی) */
+$specialPageAliases['fa'] = array(
+ 'Notifications' => array( 'آگاه‌سازی‌ها' ),
+);
+
+/** Finnish (suomi) */
+$specialPageAliases['fi'] = array(
+ 'Notifications' => array( 'Ilmoitukset' ),
+);
+
+/** Galician (galego) */
+$specialPageAliases['gl'] = array(
+ 'Notifications' => array( 'Notificacións' ),
+);
+
+/** Hawaiian (Hawai`i) */
+$specialPageAliases['haw'] = array(
+ 'Notifications' => array( 'Notikala' ),
+);
+
+/** Hebrew (עברית) */
+$specialPageAliases['he'] = array(
+ 'Notifications' => array( 'הודעות', 'כל_ההודעות' ),
+);
+
+/** Upper Sorbian (hornjoserbsce) */
+$specialPageAliases['hsb'] = array(
+ 'Notifications' => array( 'Zdźělenja' ),
+);
+
+/** Indonesian (Bahasa Indonesia) */
+$specialPageAliases['id'] = array(
+ 'Notifications' => array( 'Notifikasi' ),
+);
+
+/** Italian (italiano) */
+$specialPageAliases['it'] = array(
+ 'Notifications' => array( 'Notifiche' ),
+);
+
+/** Japanese (日本語) */
+$specialPageAliases['ja'] = array(
+ 'Notifications' => array( '通知' ),
+);
+
+/** Korean (한국어) */
+$specialPageAliases['ko'] = array(
+ 'Notifications' => array( '알림' ),
+);
+
+/** Cornish (kernowek) */
+$specialPageAliases['kw'] = array(
+ 'Notifications' => array( 'Argemynow' ),
+);
+
+/** Luxembourgish (Lëtzebuergesch) */
+$specialPageAliases['lb'] = array(
+ 'Notifications' => array( 'Notifikatiounen' ),
+);
+
+/** Macedonian (македонски) */
+$specialPageAliases['mk'] = array(
+ 'Notifications' => array( 'Известувања' ),
+);
+
+/** Malayalam (മലയാളം) */
+$specialPageAliases['ml'] = array(
+ 'Notifications' => array( 'അറിയിപ്പുകൾ' ),
+);
+
+/** Marathi (मराठी) */
+$specialPageAliases['mr'] = array(
+ 'Notifications' => array( 'संदेश' ),
+);
+
+/** Malay (Bahasa Melayu) */
+$specialPageAliases['ms'] = array(
+ 'Notifications' => array( 'Pemberitahuan' ),
+);
+
+/** Maltese (Malti) */
+$specialPageAliases['mt'] = array(
+ 'Notifications' => array( 'Notifiki' ),
+);
+
+/** Norwegian Bokmål (norsk bokmål) */
+$specialPageAliases['nb'] = array(
+ 'Notifications' => array( 'Varsler' ),
+);
+
+/** Dutch (Nederlands) */
+$specialPageAliases['nl'] = array(
+ 'Notifications' => array( 'Meldingen' ),
+);
+
+/** Punjabi (ਪੰਜਾਬੀ) */
+$specialPageAliases['pa'] = array(
+ 'Notifications' => array( 'ਇਤਲਾਹਾਂ' ),
+);
+
+/** Polish (polski) */
+$specialPageAliases['pl'] = array(
+ 'Notifications' => array( 'Powiadomienia' ),
+);
+
+/** Portuguese (português) */
+$specialPageAliases['pt'] = array(
+ 'Notifications' => array( 'Notificações' ),
+);
+
+/** Brazilian Portuguese (português do Brasil) */
+$specialPageAliases['pt-br'] = array(
+ 'Notifications' => array( 'Notificações' ),
+);
+
+/** Quechua (Runa Simi) */
+$specialPageAliases['qu'] = array(
+ 'Notifications' => array( 'Willaykuykuna' ),
+);
+
+/** Russian (русский) */
+$specialPageAliases['ru'] = array(
+ 'Notifications' => array( 'Уведомления' ),
+);
+
+/** Sicilian (sicilianu) */
+$specialPageAliases['scn'] = array(
+ 'Notifications' => array( 'Notifiche' ),
+);
+
+/** Serbian (Cyrillic script) (српски (ћирилица)‎) */
+$specialPageAliases['sr-ec'] = array(
+ 'Notifications' => array( 'Обавештења' ),
+);
+
+/** Swedish (svenska) */
+$specialPageAliases['sv'] = array(
+ 'Notifications' => array( 'Meddelanden' ),
+);
+
+/** Ukrainian (українська) */
+$specialPageAliases['uk'] = array(
+ 'Notifications' => array( 'Сповіщення' ),
+);
+
+/** Urdu (اردو) */
+$specialPageAliases['ur'] = array(
+ 'Notifications' => array( 'اطلاعات' ),
+);
+
+/** Venetian (vèneto) */
+$specialPageAliases['vec'] = array(
+ 'Notifications' => array( 'Notifiche' ),
+);
+
+/** Vietnamese (Tiếng Việt) */
+$specialPageAliases['vi'] = array(
+ 'Notifications' => array( 'Thông_báo' ),
+);
+
+/** Chinese (中文) */
+$specialPageAliases['zh'] = array(
+ 'Notifications' => array( '通知' ),
+);
+
+/** Simplified Chinese (中文(简体)‎) */
+$specialPageAliases['zh-hans'] = array(
+ 'Notifications' => array( '通知' ),
+);
+
+/** Traditional Chinese (中文(繁體)‎) */
+$specialPageAliases['zh-hant'] = array(
+ 'Notifications' => array( '通知' ),
+); \ No newline at end of file
diff --git a/Echo/Echo.php b/Echo/Echo.php
new file mode 100644
index 00000000..083ad353
--- /dev/null
+++ b/Echo/Echo.php
@@ -0,0 +1,472 @@
+<?php
+/**
+ * MediaWiki Extension: Echo
+ * http://www.mediawiki.org/wiki/Extension:Echo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY.
+ */
+
+/**
+ *
+ * @file
+ * @ingroup Extensions
+ * @author Andrew Garrett, Benny Situ, Ryan Kaldari, Erik Bernhardson
+ * @licence MIT License
+ */
+
+# Alert the user that this is not a valid entry point to MediaWiki if they try to access the special pages file directly.
+if ( !defined( 'MEDIAWIKI' ) ) {
+ echo <<<EOT
+To install this extension, put the following line in LocalSettings.php:
+require_once( "$IP/extensions/Echo/Echo.php" );
+EOT;
+ exit( 1 );
+}
+
+// Extension credits that will show up on Special:Version
+$wgExtensionCredits['specialpage'][] = array(
+ 'path' => __FILE__,
+ 'name' => 'Echo',
+ 'url' => 'https://www.mediawiki.org/wiki/Extension:Echo',
+ 'author' => array( 'Andrew Garrett', 'Ryan Kaldari', 'Benny Situ', 'Luke Welling' ),
+ 'descriptionmsg' => 'echo-desc',
+ 'license-name' => 'MIT',
+);
+
+$dir = dirname( __FILE__ ) . '/';
+$wgMessagesDirs['Echo'] = __DIR__ . '/i18n';
+$wgExtensionMessagesFiles['EchoAliases'] = $dir . 'Echo.alias.php';
+
+// This file is autogenerated by scripts/gen-autoload.php
+require __DIR__ . "/autoload.php";
+
+// Queable jobs
+$wgJobClasses['EchoNotificationJob'] = 'EchoNotificationJob';
+$wgJobClasses['MWEchoNotificationEmailBundleJob'] = 'MWEchoNotificationEmailBundleJob';
+// Job to delete older notifications
+$wgJobClasses['EchoNotificationDeleteJob'] = 'EchoNotificationDeleteJob';
+
+// API
+$wgAPIMetaModules['notifications'] = 'ApiEchoNotifications';
+$wgAPIModules['echomarkread'] = 'ApiEchoMarkRead';
+
+// Special page
+$wgSpecialPages['Notifications'] = 'SpecialNotifications';
+$wgSpecialPageGroups['Notifications'] = 'users';
+
+// Housekeeping hooks
+$wgHooks['LoadExtensionSchemaUpdates'][] = 'EchoHooks::getSchemaUpdates';
+$wgHooks['GetPreferences'][] = 'EchoHooks::getPreferences';
+$wgHooks['PersonalUrls'][] = 'EchoHooks::onPersonalUrls';
+$wgHooks['BeforePageDisplay'][] = 'EchoHooks::beforePageDisplay';
+$wgHooks['MakeGlobalVariablesScript'][] = 'EchoHooks::makeGlobalVariablesScript';
+$wgHooks['UnitTestsList'][] = 'EchoHooks::getUnitTests';
+$wgHooks['ResourceLoaderRegisterModules'][] = 'EchoHooks::onResourceLoaderRegisterModules';
+$wgHooks['ResourceLoaderTestModules'][] = 'EchoHooks::onResourceLoaderTestModules';
+$wgHooks['UserRights'][] = 'EchoHooks::onUserRights';
+$wgHooks['UserLoadOptions'][] = 'EchoHooks::onUserLoadOptions';
+$wgHooks['UserSaveOptions'][] = 'EchoHooks::onUserSaveOptions';
+$wgHooks['UserClearNewTalkNotification'][] = 'EchoHooks::onUserClearNewTalkNotification';
+$wgHooks['ParserTestTables'][] = 'EchoHooks::onParserTestTables';
+
+// Extension:UserMerge support
+$wgHooks['UserMergeAccountFields'][] = 'EchoHooks::onUserMergeAccountFields';
+$wgHooks['MergeAccountFromTo'][] = 'EchoHooks::onMergeAccountFromTo';
+$wgHooks['UserMergeAccountDeleteTables'][] = 'EchoHooks::onUserMergeAccountDeleteTables';
+
+// Extension initialization
+$wgExtensionFunctions[] = 'EchoHooks::initEchoExtension';
+
+include __DIR__ . '/Resources.php';
+
+/**
+ * This Echo hook can be used to define users who are by default interested in
+ * certain events.
+ * For example, it can be used to say that users are by default interested in
+ * their own user talk page being edited. In fact, that is what it is used for
+ * internally.
+ */
+$wgHooks['EchoGetDefaultNotifiedUsers'][] = 'EchoHooks::getDefaultNotifiedUsers';
+$wgHooks['EchoGetNotificationTypes'][] = 'EchoHooks::getNotificationTypes';
+$wgHooks['EchoGetBundleRules'][] = 'EchoHooks::onEchoGetBundleRules';
+$wgHooks['EchoAbortEmailNotification'][] = 'EchoHooks::onEchoAbortEmailNotification';
+$wgHooks['EchoCreateNotificationComplete'][] = 'EchoHooks::onEchoCreateNotificationComplete';
+
+// Hook appropriate events
+$wgHooks['ArticleSaveComplete'][] = 'EchoHooks::onArticleSaved';
+$wgHooks['AddNewAccount'][] = 'EchoHooks::onAccountCreated';
+$wgHooks['ArticleRollbackComplete'][] = 'EchoHooks::onRollbackComplete';
+$wgHooks['UserSaveSettings'][] = 'EchoHooks::onUserSaveSettings';
+
+// Disable ordinary user talk page email notifications
+$wgHooks['AbortTalkPageEmailNotification'][] = 'EchoHooks::onAbortTalkPageEmailNotification';
+$wgHooks['SendWatchlistEmailNotification'][] = 'EchoHooks::onSendWatchlistEmailNotification';
+// Disable the yellow bar of death
+$wgHooks['GetNewMessagesAlert'][] = 'EchoHooks::abortNewMessagesAlert';
+$wgHooks['LinksUpdateAfterInsert'][] = 'EchoHooks::onLinksUpdateAfterInsert';
+
+// Configuration
+
+// The name of the backend to use for Echo email bundling and digest, it should
+// be always Db
+// @deprecated
+// @todo remove it from code base
+$wgEchoBackendName = 'Db';
+
+// Whether to turn on email batch function
+$wgEchoEnableEmailBatch = true;
+
+// URL for more information about the Echo notification system
+$wgEchoHelpPage = '//www.mediawiki.org/wiki/Special:MyLanguage/Help:Notifications';
+
+// Whether to use job queue to process web and email notifications, bypass the queue for now
+// since it's taking more than an hour to run in mediawiki.org, this is not acceptable for the
+// purpose of testing notification.
+// Todo - Abstract this into classes like: JobQueueNone, JobQueueMySQL, JobQueueRedis
+$wgEchoUseJobQueue = false;
+
+// The organization address, the value should be defined in LocalSettings.php
+$wgEchoEmailFooterAddress = '';
+
+// The email address for both "from" and "reply to" on email notifications.
+// Should be defined in LocalSettings.php
+$wgNotificationSender = $wgPasswordSender;
+// Name for "from" on email notifications. Should be defined in LocalSettings.php
+// if null, uses 'emailsender' message
+$wgNotificationSenderName = null;
+// Name for "reply to" on email notifications. Should be defined in LocalSettings.php
+$wgNotificationReplyName = 'No Reply';
+
+// Use the main db if this is set to false, to use a specific external db, just
+// use any key defined in $wgExternalServers
+$wgEchoCluster = false;
+
+// The max notification count showed in badge
+// The max number showed in bundled message, eg, <user> and 99+ others <action>
+$wgEchoMaxNotificationCount = 99;
+
+// The max number of notifications allowed for a user to do a live update,
+// this is also the number of max notifications allowed for a user to have
+// @FIXME - the name is not intuitive, probably change it when the deleteJob patch
+// is deployed to both deployment branches
+$wgEchoMaxUpdateCount = 2000;
+
+// The time interval between each bundle email in seconds
+// set a small number for test wikis, should set this to 0 to disable email bundling
+// if there is no delay queue support
+$wgEchoBundleEmailInterval = 0;
+
+// Whether or not to enable a new talk page message alert for logged in users
+$wgEchoNewMsgAlert = true;
+
+// Cohort study period. This array should consist of 3 TS_MW format timestamps
+// in ascending order, the 1st one is when the bucketing and study start, the 2nd
+// one is when the bucketing ends, the 3rd one is when the study ends. Set this
+// to empty array to disable Cohort study, this should be defined in LocalSettings.php
+$wgEchoCohortInterval = array();
+
+// Define which output formats are available for each notification category
+$wgEchoDefaultNotificationTypes = array(
+ 'all' => array(
+ 'web' => true,
+ 'email' => true,
+ ),
+ // Only send web notification for welcome event
+ 'welcome' => array(
+ 'email' => false,
+ ),
+);
+
+// Definitions of the different types of notification delivery that are possible.
+// Each definition consists of a class name and a function name.
+// See also: EchoNotificationController class.
+$wgEchoNotifiers = array(
+ 'web' => array( 'EchoNotifier', 'notifyWithNotification' ), // web-based notification
+ 'email' => array( 'EchoNotifier', 'notifyWithEmail' ),
+);
+
+// List of usernames that will not trigger notification creation. This is initially
+// for bots that perform automated edits that are not important enough to regularly
+// spam people with notifications. Set to empty array when not in use.
+$wgEchoAgentBlacklist = array();
+
+// Page location of community maintained blacklist within NS_MEDIAWIKI. Set to null to disable.
+$wgEchoOnWikiBlacklist = 'Echo-blacklist';
+
+// sprintf format of per-user notification agent whitelists. Set to null to disable.
+$wgEchoPerUserWhitelistFormat = '%s/Echo-whitelist';
+
+// Define the categories that notifications can belong to. Categories can be
+// assigned the following parameters: priority, nodismiss, tooltip, and usergroups.
+// All parameters are optional.
+// If a notifications type doesn't have a category parameter, it is
+// automatically assigned to the 'other' category which is lowest priority and
+// has no preferences or dismissibility.
+// The priority parameter controls the order in which notifications are
+// displayed in preferences and batch emails. Priority ranges from 1 to 10. If
+// the priority is not specified, it defaults to 10, which is the lowest.
+// The usergroups param specifies an array of usergroups eligible to recieve the
+// notifications in the category. If no usergroups parameter is specified, all
+// groups are eligible.
+// The nodismiss parameter disables the dismissability of notifications in the
+// category. It can either be set to an array of output formats (see
+// $wgEchoNotifiers) or an array containing 'all'.
+$wgEchoNotificationCategories = array(
+ 'system' => array(
+ 'priority' => 9,
+ 'no-dismiss' => array( 'all' ),
+ ),
+ 'user-rights' => array( // bug 55337
+ 'priority' => 9,
+ 'tooltip' => 'echo-pref-tooltip-user-rights',
+ ),
+ 'other' => array(
+ 'no-dismiss' => array( 'all' ),
+ ),
+ 'edit-user-talk' => array(
+ 'priority' => 1,
+ 'no-dismiss' => array( 'web' ),
+ 'tooltip' => 'echo-pref-tooltip-edit-user-talk',
+ ),
+ 'reverted' => array(
+ 'priority' => 9,
+ 'tooltip' => 'echo-pref-tooltip-reverted',
+ ),
+ 'article-linked' => array(
+ 'priority' => 5,
+ 'tooltip' => 'echo-pref-tooltip-article-linked',
+ ),
+ 'mention' => array(
+ 'priority' => 4,
+ 'tooltip' => 'echo-pref-tooltip-mention',
+ ),
+);
+
+$echoIconPath = "Echo/modules/icons";
+
+// Defines icons, which are 30x30 images. This is passed to BeforeCreateEchoEvent so
+// extensions can define their own icons with the same structure. It is recommended that
+// extensions prefix their icon key. An example is myextension-name. This will help
+// avoid namespace conflicts.
+//
+// You can use either a path or a url, but not both.
+// The value of 'path' is relative to $wgExtensionAssetsPath.
+//
+// The value of 'url' should be a URL.
+//
+// You should customize the site icon URL, which is:
+// $wgEchoNotificationIcons['site']['url']
+$wgEchoNotificationIcons = array(
+ 'placeholder' => array(
+ 'path' => "$echoIconPath/Generic.png",
+ ),
+ 'trash' => array(
+ 'path' => "$echoIconPath/Deletion.png",
+ ),
+ 'chat' => array(
+ 'path' => "$echoIconPath/Talk.png",
+ ),
+ 'linked' => array(
+ 'path' => "$echoIconPath/CrossReferenced.png",
+ ),
+ 'featured' => array(
+ 'path' => "$echoIconPath/Featured.png",
+ ),
+ 'reviewed' => array(
+ 'path' => "$echoIconPath/Reviewed.png",
+ ),
+ 'tagged' => array(
+ 'path' => "$echoIconPath/ReviewedWithTags.png",
+ ),
+ 'revert' => array(
+ 'path' => "$echoIconPath/Revert.png",
+ ),
+ 'checkmark' => array(
+ 'path' => "$echoIconPath/Reviewed.png",
+ ),
+ 'gratitude' => array(
+ 'path' => "$echoIconPath/Gratitude.png",
+ ),
+ 'site' => array(
+ 'url' => false
+ ),
+);
+
+// Definitions of the notification event types built into Echo.
+// If formatter-class isn't specified, defaults to EchoBasicFormatter.
+$wgEchoNotifications = array(
+ 'welcome' => array(
+ 'user-locators' => array(
+ 'EchoUserLocator::locateEventAgent'
+ ),
+ 'category' => 'system',
+ 'group' => 'positive',
+ 'section' => 'alert',
+ 'title-message' => 'notification-new-user',
+ 'title-params' => array( 'agent' ),
+ 'icon' => 'site',
+ ),
+ 'edit-user-talk' => array(
+ 'user-locators' => array(
+ 'EchoUserLocator::locateTalkPageOwner',
+ ),
+ 'primary-link' => array( 'message' => 'notification-link-text-view-message', 'destination' => 'section' ),
+ 'secondary-link' => array( 'message' => 'notification-link-text-view-changes', 'destination' => 'diff' ),
+ 'category' => 'edit-user-talk',
+ 'group' => 'interactive',
+ 'section' => 'alert',
+ 'bundle' => array( 'web' => true, 'email' => false ),
+ 'formatter-class' => 'EchoEditUserTalkFormatter',
+ 'title-message' => 'notification-edit-talk-page2',
+ 'title-params' => array( 'agent', 'user', 'subject-anchor' ),
+ 'bundle-message' => 'notification-edit-talk-page-bundle',
+ 'bundle-params' => array( 'agent', 'user', 'agent-other-display', 'agent-other-count' ),
+ 'flyout-message' => 'notification-edit-talk-page-flyout2',
+ 'flyout-params' => array( 'agent', 'user', 'subject-anchor' ),
+ 'email-subject-message' => 'notification-edit-talk-page-email-subject2',
+ 'email-subject-params' => array( 'agent' ),
+ 'email-body-batch-message' => 'notification-edit-talk-page-email-batch-body2',
+ 'email-body-batch-params' => array( 'agent' ),
+ 'email-body-batch-bundle-message' => 'notification-edit-user-talk-email-batch-bundle-body',
+ 'email-body-batch-bundle-params' => array( 'agent', 'agent-other-display', 'agent-other-count' ),
+ 'icon' => 'chat',
+ ),
+ 'reverted' => array(
+ 'user-locators' => array(
+ array( 'EchoUserLocator::locateFromEventExtra', array( 'reverted-user-id' ) ),
+ ),
+ 'primary-link' => array( 'message' => 'notification-link-text-view-edit', 'destination' => 'diff' ),
+ 'category' => 'reverted',
+ 'group' => 'negative',
+ 'section' => 'alert',
+ 'formatter-class' => 'EchoEditFormatter',
+ 'title-message' => 'notification-reverted2',
+ 'title-params' => array( 'agent', 'title', 'difflink', 'number' ),
+ 'flyout-message' => 'notification-reverted-flyout2',
+ 'flyout-params' => array( 'agent', 'title', 'difflink', 'number' ),
+ 'email-subject-message' => 'notification-reverted-email-subject2',
+ 'email-subject-params' => array( 'agent', 'title', 'number' ),
+ 'email-body-batch-message' => 'notification-reverted-email-batch-body2',
+ 'email-body-batch-params' => array( 'agent', 'title', 'number' ),
+ 'icon' => 'revert',
+ ),
+ 'page-linked' => array(
+ 'user-locators' => array(
+ 'EchoUserLocator::locateArticleCreator',
+ ),
+ 'primary-link' => array( 'message' => 'notification-link-text-view-page', 'destination' => 'link-from-page' ),
+ 'category' => 'article-linked',
+ 'group' => 'neutral',
+ 'section' => 'alert',
+ 'bundle' => array( 'web' => true, 'email' => true ),
+ 'formatter-class' => 'EchoPageLinkFormatter',
+ 'title-message' => 'notification-page-linked',
+ 'title-params' => array( 'agent', 'title', 'link-from-page' ),
+ 'bundle-message' => 'notification-page-linked-bundle',
+ 'bundle-params' => array( 'agent', 'title', 'link-from-page', 'link-from-page-other-display', 'link-from-page-other-count' ),
+ 'flyout-message' => 'notification-page-linked-flyout',
+ 'flyout-params' => array( 'agent', 'title', 'link-from-page' ),
+ 'email-subject-message' => 'notification-page-linked-email-subject',
+ 'email-subject-params' => array(),
+ 'email-body-batch-message' => 'notification-page-linked-email-batch-body',
+ 'email-body-batch-params' => array( 'agent', 'title', 'link-from-page' ),
+ 'email-body-batch-bundle-message' => 'notification-page-linked-email-batch-bundle-body',
+ 'email-body-batch-bundle-params' => array( 'agent', 'title', 'link-from-page', 'link-from-page-other-display', 'link-from-page-other-count' ),
+ 'icon' => 'linked',
+ ),
+ 'mention' => array(
+ 'user-locators' => array(
+ array( 'EchoUserLocator::locateFromEventExtra', array( 'mentioned-users' ) ),
+ ),
+ 'primary-link' => array( 'message' => 'notification-link-text-view-mention', 'destination' => 'section' ),
+ 'secondary-link' => array( 'message' => 'notification-link-text-view-changes', 'destination' => 'diff' ),
+ 'category' => 'mention',
+ 'group' => 'interactive',
+ 'section' => 'alert',
+ 'formatter-class' => 'EchoMentionFormatter',
+ 'title-message' => 'notification-mention',
+ 'title-params' => array( 'agent', 'subject-anchor', 'title', 'section-title', 'main-title-text' ),
+ 'flyout-message' => 'notification-mention-flyout',
+ 'flyout-params' => array( 'agent', 'subject-anchor', 'title', 'section-title', 'main-title-text' ),
+ 'email-subject-message' => 'notification-mention-email-subject',
+ 'email-subject-params' => array( 'agent' ),
+ 'email-body-batch-message' => 'notification-mention-email-batch-body',
+ 'email-body-batch-params' => array( 'agent', 'title', 'section-title', 'main-title-text' ),
+ 'icon' => 'chat',
+ ),
+ 'user-rights' => array(
+ 'user-locators' => array(
+ array( 'EchoUserLocator::locateFromEventExtra', array( 'user' ) ),
+ ),
+ 'primary-link' => array( 'message' => 'echo-learn-more', 'destination' => 'user-rights-list' ),
+ 'category' => 'user-rights',
+ 'group' => 'neutral',
+ 'section' => 'alert',
+ 'formatter-class' => 'EchoUserRightsFormatter',
+ 'title-message' => 'notification-user-rights',
+ 'title-params' => array( 'agent', 'user-rights-list' ),
+ 'flyout-message' => 'notification-user-rights-flyout',
+ 'flyout-params' => array( 'agent', 'user-rights-list' ),
+ 'email-subject-message' => 'notification-user-rights-email-subject',
+ 'email-subject-params' => array(),
+ 'email-body-batch-message' => 'notification-user-rights-email-batch-body',
+ 'email-body-batch-params' => array( 'agent', 'user-rights-list' ),
+ 'icon' => 'site',
+ ),
+);
+
+// Enable notifications for all logged in users by default
+$wgDefaultUserOptions['echo-notify-show-link'] = true;
+
+// Enable new talk page messages alert for all logged in users by default
+$wgDefaultUserOptions['echo-show-alert'] = true;
+
+// By default, send emails for each notification as they come in
+$wgDefaultUserOptions['echo-email-frequency'] = 0; /*EchoHooks::EMAIL_IMMEDIATELY*/
+
+if ( $wgAllowHTMLEmail ) {
+ $wgDefaultUserOptions['echo-email-format'] = 'html'; /*EchoHooks::EMAIL_FORMAT_HTML*/
+} else {
+ $wgDefaultUserOptions['echo-email-format'] = 'plain-text'; /*EchoHooks::EMAIL_FORMAT_PLAIN_TEXT*/
+}
+
+// Set all of the events to notify by web but not email by default (won't affect events that don't email)
+foreach ( $wgEchoNotificationCategories as $category => $categoryData ) {
+ $wgDefaultUserOptions["echo-subscriptions-email-{$category}"] = false;
+ $wgDefaultUserOptions["echo-subscriptions-web-{$category}"] = true;
+}
+
+// most settings default to web on, email off, but override these
+$wgDefaultUserOptions['echo-subscriptions-email-system'] = true;
+$wgDefaultUserOptions['echo-subscriptions-email-user-rights'] = true;
+$wgDefaultUserOptions['echo-subscriptions-web-article-linked'] = false;
+
+// Echo Configuration for EventLogging
+$wgEchoConfig = array(
+ 'version' => '1.5',
+ // default all eventlogging off, overwrite them in site configuration
+ 'eventlogging' => array (
+ 'Echo' => array (
+ 'enabled' => false,
+ 'revision' => 7572295,
+ ),
+ 'EchoMail' => array (
+ 'enabled' => false,
+ 'revision' => 5467650
+ ),
+ 'EchoInteraction' => array (
+ 'enabled' => false,
+ 'revision' => 5782287
+ ),
+ )
+);
diff --git a/Echo/Gemfile b/Echo/Gemfile
new file mode 100755
index 00000000..abeac307
--- /dev/null
+++ b/Echo/Gemfile
@@ -0,0 +1,10 @@
+# ruby=ruby-2.1.1
+# ruby-gemset=Echo
+
+source 'https://rubygems.org'
+
+gem 'chunky_png'
+gem 'csscss'
+gem 'mediawiki_api'
+gem 'mediawiki_selenium'
+gem 'rubocop', require: false
diff --git a/Echo/Gemfile.lock b/Echo/Gemfile.lock
new file mode 100644
index 00000000..56ba4b31
--- /dev/null
+++ b/Echo/Gemfile.lock
@@ -0,0 +1,107 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ ast (2.0.0)
+ astrolabe (1.3.0)
+ parser (>= 2.2.0.pre.3, < 3.0)
+ blankslate (3.1.3)
+ builder (3.2.2)
+ childprocess (0.5.5)
+ ffi (~> 1.0, >= 1.0.11)
+ chunky_png (1.3.3)
+ colorize (0.7.5)
+ csscss (1.3.3)
+ colorize
+ parslet (>= 1.6.1, < 2.0)
+ cucumber (1.3.18)
+ builder (>= 2.1.2)
+ diff-lcs (>= 1.1.3)
+ gherkin (~> 2.12)
+ multi_json (>= 1.7.5, < 2.0)
+ multi_test (>= 0.1.1)
+ data_magic (0.20)
+ faker (>= 1.1.2)
+ yml_reader (>= 0.4)
+ diff-lcs (1.2.5)
+ domain_name (0.5.23)
+ unf (>= 0.0.5, < 1.0.0)
+ faker (1.4.3)
+ i18n (~> 0.5)
+ faraday (0.9.1)
+ multipart-post (>= 1.2, < 3)
+ faraday-cookie_jar (0.0.6)
+ faraday (>= 0.7.4)
+ http-cookie (~> 1.0.0)
+ ffi (1.9.6)
+ gherkin (2.12.2)
+ multi_json (~> 1.3)
+ headless (1.0.2)
+ http-cookie (1.0.2)
+ domain_name (~> 0.5)
+ i18n (0.7.0)
+ json (1.8.2)
+ mediawiki_api (0.3.0)
+ faraday (~> 0.9, >= 0.9.0)
+ faraday-cookie_jar (~> 0.0, >= 0.0.6)
+ mediawiki_selenium (0.4.2)
+ cucumber (~> 1.3, >= 1.3.10)
+ headless (~> 1.0, >= 1.0.1)
+ json (~> 1.8, >= 1.8.1)
+ mediawiki_api (~> 0.2, >= 0.2.1)
+ page-object (~> 1.0)
+ rest-client (~> 1.6, >= 1.6.7)
+ rspec-expectations (~> 2.14, >= 2.14.4)
+ syntax (~> 1.2, >= 1.2.0)
+ mime-types (2.4.3)
+ multi_json (1.10.1)
+ multi_test (0.1.1)
+ multipart-post (2.0.0)
+ netrc (0.10.2)
+ page-object (1.0.3)
+ page_navigation (>= 0.9)
+ selenium-webdriver (>= 2.44.0)
+ watir-webdriver (>= 0.6.11)
+ page_navigation (0.9)
+ data_magic (>= 0.14)
+ parser (2.2.0.2)
+ ast (>= 1.1, < 3.0)
+ parslet (1.6.2)
+ blankslate (>= 2.0, <= 4.0)
+ powerpack (0.1.0)
+ rainbow (2.0.0)
+ rest-client (1.7.2)
+ mime-types (>= 1.16, < 3.0)
+ netrc (~> 0.7)
+ rspec-expectations (2.99.2)
+ diff-lcs (>= 1.1.3, < 2.0)
+ rubocop (0.29.0)
+ astrolabe (~> 1.3)
+ parser (>= 2.2.0.1, < 3.0)
+ powerpack (~> 0.1)
+ rainbow (>= 1.99.1, < 3.0)
+ ruby-progressbar (~> 1.4)
+ ruby-progressbar (1.7.1)
+ rubyzip (1.1.7)
+ selenium-webdriver (2.44.0)
+ childprocess (~> 0.5)
+ multi_json (~> 1.0)
+ rubyzip (~> 1.0)
+ websocket (~> 1.0)
+ syntax (1.2.0)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.6)
+ watir-webdriver (0.6.11)
+ selenium-webdriver (>= 2.18.0)
+ websocket (1.2.1)
+ yml_reader (0.5)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ chunky_png
+ csscss
+ mediawiki_api
+ mediawiki_selenium
+ rubocop
diff --git a/Echo/Hooks.php b/Echo/Hooks.php
new file mode 100644
index 00000000..6e9334a1
--- /dev/null
+++ b/Echo/Hooks.php
@@ -0,0 +1,1049 @@
+<?php
+
+class EchoHooks {
+ const EMAIL_NEVER = -1; // Never send email notifications
+ const EMAIL_IMMEDIATELY = 0; // Send email notificaitons immediately as they come in
+ const EMAIL_DAILY_DIGEST = 1; // Send daily email digests
+ const EMAIL_WEEKLY_DIGEST = 7; // Send weekly email digests
+ const EMAIL_FORMAT_HTML = 'html';
+ const EMAIL_FORMAT_PLAIN_TEXT = 'plain-text';
+
+ /**
+ * Initialize Echo extension with necessary data, this function is invoked
+ * from $wgExtensionFunctions
+ */
+ public static function initEchoExtension() {
+ global $wgEchoNotifications, $wgEchoNotificationCategories, $wgEchoNotificationIcons,
+ $wgEchoConfig;
+
+ // allow extensions to define their own event
+ wfRunHooks( 'BeforeCreateEchoEvent', array( &$wgEchoNotifications, &$wgEchoNotificationCategories, &$wgEchoNotificationIcons ) );
+
+ // turn schema off if eventLogging is not enabled
+ if ( !class_exists( 'EventLogging' ) ) {
+ foreach ( $wgEchoConfig['eventlogging'] as $schema => $property ) {
+ if ( $property['enabled'] ) {
+ $wgEchoConfig['eventlogging'][$schema]['enabled'] = false;
+ }
+ }
+ }
+ }
+
+ public static function getNotificationSenderName() {
+ global $wgNotificationSenderName;
+ if ( $wgNotificationSenderName === null ) {
+ $wgNotificationSenderName = wfMessage( 'emailsender' )->inContentLanguage()->text();
+ }
+
+ return $wgNotificationSenderName;
+ }
+
+ /**
+ * ResourceLoaderTestModules hook handler
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderTestModules
+ *
+ * @param array $testModules
+ * @param ResourceLoader $resourceLoader
+ * @return bool
+ */
+ public static function onResourceLoaderTestModules( array &$testModules,
+ ResourceLoader $resourceLoader
+ ) {
+ global $wgResourceModules;
+
+ $testModuleBoilerplate = array(
+ 'localBasePath' => __DIR__,
+ 'remoteExtPath' => 'Echo',
+ );
+
+ // find test files for every RL module
+ $prefix = 'ext.echo';
+ foreach ( $wgResourceModules as $key => $module ) {
+ if ( substr( $key, 0, strlen( $prefix ) ) === $prefix && isset( $module['scripts'] ) ) {
+ $testFiles = array();
+ foreach ( $module['scripts'] as $script ) {
+ $testFile = 'tests/qunit/' . dirname( $script ) . '/test_' . basename( $script );
+ // if a test file exists for a given JS file, add it
+ if ( file_exists( $testModuleBoilerplate['localBasePath'] . '/' . $testFile ) ) {
+ $testFiles[] = $testFile;
+ }
+ }
+ // if test files exist for given module, create a corresponding test module
+ if ( count( $testFiles ) > 0 ) {
+ $testModules['qunit']["$key.tests"] = $testModuleBoilerplate + array(
+ 'dependencies' => array( $key ),
+ 'scripts' => $testFiles,
+ );
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for ResourceLoaderRegisterModules hook
+ */
+ public static function onResourceLoaderRegisterModules( ResourceLoader &$resourceLoader ) {
+ global $wgResourceModules, $wgEchoConfig;
+
+ foreach ( $wgEchoConfig['eventlogging'] as $schema => $property ) {
+ if ( $property['enabled'] ) {
+ $wgResourceModules[ 'schema.' . $schema ] = array(
+ 'class' => 'ResourceLoaderSchemaModule',
+ 'schema' => $schema,
+ 'revision' => $property['revision'],
+ );
+ $wgResourceModules['ext.echo.base']['dependencies'][] = 'schema.' . $schema;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param $updater DatabaseUpdater object
+ * @return bool true in all cases
+ */
+ public static function getSchemaUpdates( $updater ) {
+ $dir = __DIR__;
+ $baseSQLFile = "$dir/echo.sql";
+ $updater->addExtensionTable( 'echo_event', $baseSQLFile );
+ $updater->addExtensionTable( 'echo_email_batch', "$dir/db_patches/echo_email_batch.sql" );
+ $updater->addExtensionTable( 'echo_target_page', "$dir/db_patches/echo_target_page.sql" );
+
+ if ( $updater->getDB()->getType() === 'sqlite' ) {
+ $updater->modifyExtensionField( 'echo_event', 'event_agent', "$dir/db_patches/patch-event_agent-split.sqlite.sql" );
+ $updater->modifyExtensionField( 'echo_event', 'event_variant', "$dir/db_patches/patch-event_variant_nullability.sqlite.sql" );
+ $updater->addExtensionField( 'echo_target_page', 'etp_id', "$dir/db_patches/patch-multiple_target_pages.sqlite.sql" );
+ // There is no need to run the patch-event_extra-size or patch-event_agent_ip-size because
+ // sqlite ignores numeric arguments in parentheses that follow the type name (ex: VARCHAR(255))
+ // see http://www.sqlite.org/datatype3.html Section 2.2 for more info
+ } else {
+ $updater->modifyExtensionField( 'echo_event', 'event_agent', "$dir/db_patches/patch-event_agent-split.sql" );
+ $updater->modifyExtensionField( 'echo_event', 'event_variant', "$dir/db_patches/patch-event_variant_nullability.sql" );
+ $updater->modifyExtensionField( 'echo_event', 'event_extra', "$dir/db_patches/patch-event_extra-size.sql" );
+ $updater->modifyExtensionField( 'echo_event', 'event_agent_ip', "$dir/db_patches/patch-event_agent_ip-size.sql" );
+ $updater->addExtensionField( 'echo_target_page', 'etp_id', "$dir/db_patches/patch-multiple_target_pages.sql" );
+ }
+
+ $updater->addExtensionField( 'echo_notification', 'notification_bundle_base',
+ "$dir/db_patches/patch-notification-bundling-field.sql" );
+ // This index was renamed twice, first from type_page to event_type and later from event_type to echo_event_type
+ if ( $updater->getDB()->indexExists( 'echo_event', 'type_page', __METHOD__ ) ) {
+ $updater->addExtensionIndex( 'echo_event', 'event_type', "$dir/db_patches/patch-alter-type_page-index.sql" );
+ }
+ $updater->dropTable( 'echo_subscription' );
+ $updater->dropExtensionField( 'echo_event', 'event_timestamp', "$dir/db_patches/patch-drop-echo_event-event_timestamp.sql" );
+ $updater->addExtensionField( 'echo_email_batch', 'eeb_event_hash',
+ "$dir/db_patches/patch-email_batch-new-field.sql" );
+ $updater->addExtensionField( 'echo_event', 'event_page_id', "$dir/db_patches/patch-add-echo_event-event_page_id.sql" );
+ $updater->addExtensionIndex( 'echo_event', 'echo_event_type', "$dir/db_patches/patch-alter-event_type-index.sql" );
+ $updater->addExtensionIndex( 'echo_notification', 'echo_user_timestamp', "$dir/db_patches/patch-alter-user_timestamp-index.sql" );
+
+ return true;
+ }
+
+ /**
+ * Handler for EchoGetBundleRule hook, which defines the bundle rule for each notification
+ *
+ * @param $event EchoEvent
+ * @param $bundleString string Determines how the notification should be bundled, for example,
+ * talk page notification is bundled based on namespace and title, the bundle string would be
+ * 'edit-user-talk-' + namespace + title, email digest/email bundling would use this hash as
+ * a key to identify bundle-able event. For web bundling, we bundle further based on user's
+ * visit to the overlay, we would generate a display hash based on the hash of $bundleString
+ *
+ * @return bool
+ */
+ public static function onEchoGetBundleRules( $event, &$bundleString ) {
+ switch ( $event->getType() ) {
+ case 'edit-user-talk':
+ $bundleString = 'edit-user-talk';
+ if ( $event->getTitle() ) {
+ $bundleString .= '-' . $event->getTitle()->getNamespace()
+ . '-' . $event->getTitle()->getDBkey();
+ }
+ break;
+ case 'page-linked':
+ $bundleString = 'page-linked';
+ if ( $event->getTitle() ) {
+ $bundleString .= '-' . $event->getTitle()->getNamespace()
+ . '-' . $event->getTitle()->getDBkey();
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Handler for EchoGetDefaultNotifiedUsers hook.
+ * @param $event EchoEvent to get implicitly subscribed users for
+ * @param &$users Array to append implicitly subscribed users to.
+ * @return bool true in all cases
+ */
+ public static function getDefaultNotifiedUsers( $event, &$users ) {
+ switch ( $event->getType() ) {
+ // AFAICT these two are unused?
+ case 'add-comment':
+ case 'add-talkpage-topic':
+ // Handled by EchoDiscussionParser
+ $extraData = $event->getExtra();
+
+ if ( !isset( $extraData['revid'] ) || !$extraData['revid'] ) {
+ break;
+ }
+
+ $revision = Revision::newFromId( $extraData['revid'] );
+ break;
+ if ( $revision ) {
+ $users += EchoDiscussionParser::getNotifiedUsersForComment( $revision );
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for EchoGetNotificationTypes hook, Adjust the notify types (e.g. web, email) which
+ * are applicable to this event and user based on various user options. In other words, allow
+ * certain non-echo user options to override the echo notification options.
+ * @param $user User
+ * @param $event EchoEvent
+ * @param $notifyTypes
+ * @return bool
+ */
+ public static function getNotificationTypes( $user, $event, &$notifyTypes ) {
+ if ( !$user->getOption( 'enotifminoredits' ) ) {
+ $extra = $event->getExtra();
+ if ( !empty( $extra['revid'] ) ) {
+ $rev = Revision::newFromID( $extra['revid'], Revision::READ_LATEST );
+
+ if ( $rev->isMinor() ) {
+ $notifyTypes = array_diff( $notifyTypes, array( 'email' ) );
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Handler for GetPreferences hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/GetPreferences
+ *
+ * @param $user User to get preferences for
+ * @param &$preferences Preferences array
+ *
+ * @throws MWException
+ * @return bool true in all cases
+ */
+ public static function getPreferences( $user, &$preferences ) {
+ global $wgEchoDefaultNotificationTypes, $wgAuth, $wgEchoEnableEmailBatch,
+ $wgEchoNotifiers, $wgEchoNotificationCategories, $wgEchoNotifications,
+ $wgEchoNewMsgAlert, $wgAllowHTMLEmail;
+
+ // Don't show echo preference page if echo is disabled for this user
+ if ( self::isEchoDisabled( $user ) ) {
+ return true;
+ }
+
+ // Show email frequency options
+ $never = wfMessage( 'echo-pref-email-frequency-never' )->plain();
+ $immediately = wfMessage( 'echo-pref-email-frequency-immediately' )->plain();
+ $freqOptions = array(
+ $never => self::EMAIL_NEVER,
+ $immediately => self::EMAIL_IMMEDIATELY,
+ );
+ // Only show digest options if email batch is enabled
+ if ( $wgEchoEnableEmailBatch ) {
+ $daily = wfMessage( 'echo-pref-email-frequency-daily' )->plain();
+ $weekly = wfMessage( 'echo-pref-email-frequency-weekly' )->plain();
+ $freqOptions += array(
+ $daily => self::EMAIL_DAILY_DIGEST,
+ $weekly => self::EMAIL_WEEKLY_DIGEST
+ );
+ }
+ $preferences['echo-email-frequency'] = array(
+ 'type' => 'select',
+ 'label-message' => 'echo-pref-send-me',
+ 'section' => 'echo/emailsettings',
+ 'options' => $freqOptions
+ );
+
+ // Display information about the user's currently set email address
+ $prefsTitle = SpecialPage::getTitleFor( 'Preferences', false, 'mw-prefsection-echo' );
+ $link = Linker::link(
+ SpecialPage::getTitleFor( 'ChangeEmail' ),
+ wfMessage( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->escaped(),
+ array(),
+ array( 'returnto' => $prefsTitle->getFullText() )
+ );
+ $emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
+ if ( $wgAuth->allowPropChange( 'emailaddress' ) ) {
+ if ( $emailAddress === '' ) {
+ $emailAddress .= $link;
+ } else {
+ $emailAddress .= wfMessage( 'word-separator' )->escaped()
+ . wfMessage( 'parentheses' )->rawParams( $link )->escaped();
+ }
+ }
+ $preferences['echo-emailaddress'] = array(
+ 'type' => 'info',
+ 'raw' => true,
+ 'default' => $emailAddress,
+ 'label-message' => 'echo-pref-send-to',
+ 'section' => 'echo/emailsettings'
+ );
+
+ // Only show this option if html email is allowed, otherwise it is always plain text format
+ if ( $wgAllowHTMLEmail ) {
+ // Email format
+ $preferences['echo-email-format'] = array(
+ 'type' => 'select',
+ 'label-message' => 'echo-pref-email-format',
+ 'section' => 'echo/emailsettings',
+ 'options' => array (
+ wfMessage( 'echo-pref-email-format-html' )->plain() => self::EMAIL_FORMAT_HTML,
+ wfMessage( 'echo-pref-email-format-plain-text' )->plain() => self::EMAIL_FORMAT_PLAIN_TEXT
+ )
+ );
+ }
+
+ // Sort notification categories by priority
+ $categoriesAndPriorities = array();
+ foreach ( $wgEchoNotificationCategories as $category => $categoryData ) {
+ // See if the category is not dismissable at all. Must do strict
+ // comparison to true since no-dismiss can also be an array
+ if ( isset( $categoryData['no-dismiss'] ) && in_array( 'all' , $categoryData['no-dismiss'] ) ) {
+ continue;
+ }
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ // See if user is eligible to recieve this notification (per user group restrictions)
+ if ( $attributeManager->getCategoryEligibility( $user, $category ) ) {
+ $categoriesAndPriorities[$category] = $attributeManager->getCategoryPriority( $category );
+ }
+ }
+ asort( $categoriesAndPriorities );
+ $validSortedCategories = array_keys( $categoriesAndPriorities );
+
+ // Show subscription options. IMPORTANT: 'echo-subscriptions-email-edit-user-talk' is a
+ // virtual option, its value is saved to existing talk page notification option
+ // 'enotifusertalkpages', see onUserLoadOptions() and onUserSaveOptions() for more
+ // information on how it is handled. Doing it in this way, we can avoid keeping running
+ // massive data migration script to keep these two options synced when echo is enabled on
+ // new wikis or Echo is disabled and re-enabled for some reason. We can update the name
+ // if Echo is ever merged to core
+
+ // Build the columns (output formats)
+ $columns = array();
+ foreach ( $wgEchoNotifiers as $notifierType => $notifierData ) {
+ $formatMessage = wfMessage( 'echo-pref-' . $notifierType )->escaped();
+ $columns[$formatMessage] = $notifierType;
+ }
+
+ // Build the rows (notification categories)
+ $rows = array();
+ $tooltips = array();
+ foreach ( $validSortedCategories as $category ) {
+ $categoryMessage = wfMessage( 'echo-category-title-' . $category )->numParams( 1 )->escaped();
+ $rows[$categoryMessage] = $category;
+ if ( isset( $wgEchoNotificationCategories[$category]['tooltip'] ) ) {
+ $tooltips[$categoryMessage] = wfMessage( $wgEchoNotificationCategories[$category]['tooltip'] )->text();
+ }
+ }
+
+ // Figure out the individual exceptions in the matrix and make them disabled
+ $forceOptionsOff = $forceOptionsOn = array();
+ foreach ( $wgEchoNotifiers as $notifierType => $notifierData ) {
+ foreach ( $validSortedCategories as $category ) {
+ // See if this output format is non-dismissable
+ if ( isset( $wgEchoNotificationCategories[$category]['no-dismiss'] )
+ && in_array( $notifierType, $wgEchoNotificationCategories[$category]['no-dismiss'] ) )
+ {
+ $forceOptionsOn[] = "$notifierType-$category";
+ }
+
+ // Make sure this output format is possible for this notification category
+ if ( isset( $wgEchoDefaultNotificationTypes[$category] ) ) {
+ if ( !$wgEchoDefaultNotificationTypes[$category][$notifierType] ) {
+ $forceOptionsOff[] = "$notifierType-$category";
+ }
+ } elseif ( !$wgEchoDefaultNotificationTypes['all'][$notifierType] ) {
+ $forceOptionsOff[] = "$notifierType-$category";
+ }
+ }
+ }
+
+ $invalid = array_intersect( $forceOptionsOff, $forceOptionsOn );
+ if ( $invalid ) {
+ throw new MWException( sprintf(
+ 'The following notifications are both forced and removed: %s',
+ implode( ', ', $invalid )
+ ) );
+ }
+ $preferences['echo-subscriptions'] = array(
+ 'class' => 'HTMLCheckMatrix',
+ 'section' => 'echo/echosubscriptions',
+ 'rows' => $rows,
+ 'columns' => $columns,
+ 'prefix' => 'echo-subscriptions-',
+ 'force-options-off' => $forceOptionsOff,
+ 'force-options-on' => $forceOptionsOn,
+ 'tooltips' => $tooltips,
+ );
+
+ if ( $wgEchoNewMsgAlert ) {
+ $preferences['echo-show-alert'] = array(
+ 'type' => 'toggle',
+ 'label-message' => 'echo-pref-new-message-indicator',
+ 'section' => 'echo/newmessageindicator',
+ );
+ }
+
+ // If we're using Echo to handle user talk page post notifications,
+ // hide the old (non-Echo) preference for this. If Echo is moved to core
+ // we'll want to remove this old user option entirely. For now, though,
+ // we need to keep it defined in case Echo is ever uninstalled.
+ // Otherwise, that preference could be lost entirely. This hiding logic
+ // is not abstracted since there is only a single preference in core
+ // that is potentially made obsolete by Echo.
+ if ( isset( $wgEchoNotifications['edit-user-talk'] ) ) {
+ $preferences['enotifusertalkpages']['type'] = 'hidden';
+ unset( $preferences['enotifusertalkpages']['section'] );
+ }
+
+ // Show fly-out display prefs
+ // Per bug 47562, we're going to hide this pref for now until we see
+ // what the community reaction to Echo is on en.wiki.
+ $preferences['echo-notify-show-link'] = array(
+ 'type' => 'hidden',
+ 'label-message' => 'echo-pref-notify-show-link',
+ //'section' => 'echo/displaynotifications',
+ );
+ return true;
+ }
+
+ /**
+ * Handler for ArticleSaveComplete hook
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/ArticleSaveComplete
+ * @param $article Article edited
+ * @param $user User who edited
+ * @param $text string New article text
+ * @param $summary string Edit summary
+ * @param $minoredit bool Minor edit or not
+ * @param $watchthis bool Watch this article?
+ * @param $sectionanchor string Section that was edited
+ * @param $flags int Edit flags
+ * @param $revision Revision that was created
+ * @param $status Status
+ * @return bool true in all cases
+ */
+ public static function onArticleSaved( &$article, &$user, $text, $summary, $minoredit, $watchthis, $sectionanchor, &$flags, $revision, &$status ) {
+ global $wgEchoNotifications, $wgRequest;
+
+ if ( $revision ) {
+ EchoDiscussionParser::generateEventsForRevision( $revision );
+
+ // Handle the case of someone undoing an edit, either through the
+ // 'undo' link in the article history or via the API.
+ if ( isset( $wgEchoNotifications['reverted'] ) ) {
+ $title = $article->getTitle();
+ $undidRevId = $wgRequest->getVal( 'wpUndidRevision' );
+ if ( $undidRevId ) {
+ $undidRevision = Revision::newFromId( $undidRevId );
+ if ( $undidRevision && $undidRevision->getTitle()->equals( $title ) ) {
+ $victimId = $undidRevision->getUser();
+ if ( $victimId ) { // No notifications for anonymous users
+ EchoEvent::create( array(
+ 'type' => 'reverted',
+ 'title' => $title,
+ 'extra' => array(
+ 'revid' => $revision->getId(),
+ 'reverted-user-id' => $victimId,
+ 'reverted-revision-id' => $undidRevId,
+ 'method' => 'undo',
+ ),
+ 'agent' => $user,
+ ) );
+ }
+ }
+ }
+ }
+
+ }
+ return true;
+ }
+
+ /**
+ * Handler for EchoAbortEmailNotification hook
+ * @param $user User
+ * @param $event EchoEvent
+ * @return bool true - send email, false - do not send email
+ */
+ public static function onEchoAbortEmailNotification( $user, $event ) {
+ if ( $event->getType() === 'edit-user-talk' ) {
+ $extra = $event->getExtra();
+ if ( !empty( $extra['minoredit'] ) ) {
+ global $wgEnotifMinorEdits;
+ if ( !$wgEnotifMinorEdits || !$user->getOption( 'enotifminoredits' ) ) {
+ // Do not send talk page notification email
+ return false;
+ }
+ }
+ }
+
+ // Proceed to send talk page notification email
+ return true;
+ }
+
+ /**
+ * Handler for AddNewAccount hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/AddNewAccount
+ * @param $user User object that was created.
+ * @param $byEmail bool True when account was created "by email".
+ * @return bool
+ */
+ public static function onAccountCreated( $user, $byEmail ) {
+
+ // new users get echo preferences set that are not the default settings for existing users
+ $user->setOption( 'echo-subscriptions-web-reverted', false );
+ $user->setOption( 'echo-subscriptions-email-reverted', false );
+ $user->setOption( 'echo-subscriptions-web-article-linked', true );
+ $user->setOption( 'echo-subscriptions-email-mention', true );
+ $user->setOption( 'echo-subscriptions-email-article-linked', true );
+ $user->saveSettings();
+
+ EchoEvent::create( array(
+ 'type' => 'welcome',
+ 'agent' => $user,
+ // welcome email is sent to agent
+ 'extra' => array (
+ 'notifyAgent' => true
+ )
+ ) );
+
+ return true;
+ }
+
+ /**
+ * Handler for UserRights hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/UserRights
+ *
+ * @param $user User User object that was changed
+ * @param $add array Array of strings corresponding to groups added
+ * @param $remove array Array of strings corresponding to groups removed
+ *
+ * @return bool
+ */
+ public static function onUserRights( &$user, $add, $remove ) {
+ global $wgUser;
+
+ if ( $user instanceof User && !$user->isAnon() && $wgUser->getId() != $user->getId() && ( $add || $remove ) ) {
+ EchoEvent::create(
+ array(
+ 'type' => 'user-rights',
+ 'title' => Title::newMainPage(),
+ 'extra' => array(
+ 'user' => $user->getID(),
+ 'add' => $add,
+ 'remove' => $remove
+ ),
+ 'agent' => $wgUser,
+ )
+ );
+ }
+ return true;
+ }
+
+ /**
+ * Handler for LinksUpdateAfterInsert hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/LinksUpdateAfterInsert
+ * @param $linksUpdate LinksUpdate
+ * @param $table string
+ * @param $insertions array
+ * @return bool
+ */
+ public static function onLinksUpdateAfterInsert( $linksUpdate, $table, $insertions ) {
+ global $wgRequest, $wgUser;
+
+ // Rollback or undo should not trigger link notification
+ // @Todo Implement a better solution so it doesn't depend on the checking of
+ // a specific set of request variables
+ if ( $wgRequest->getVal( 'wpUndidRevision' ) || $wgRequest->getVal( 'action' ) == 'rollback' ) {
+ return true;
+ }
+
+ // Handle only
+ // 1. inserts to pagelinks table &&
+ // 2. content namespace pages &&
+ // 3. non-transcluding pages &&
+ // 4. non-redirect pages
+ if ( $table !== 'pagelinks' || !MWNamespace::isContent( $linksUpdate->mTitle->getNamespace() )
+ || !$linksUpdate->mRecursive || $linksUpdate->mTitle->isRedirect() )
+ {
+ return true;
+ }
+
+ // link notification is boundless as you can include infinite number of links in a page
+ // db insert is expensive, limit it to a reasonable amount, we can increase this limit
+ // once the storage is on Redis
+ $max = 10;
+ // Only create notifications for links to content namespace pages
+ // @Todo - use one big insert instead of individual insert inside foreach loop
+ foreach ( $insertions as $page ) {
+ if ( MWNamespace::isContent( $page['pl_namespace'] ) ) {
+ $title = Title::makeTitle( $page['pl_namespace'], $page['pl_title'] );
+ if ( $title->isRedirect() ) {
+ continue;
+ }
+
+ EchoEvent::create( array(
+ 'type' => 'page-linked',
+ 'title' => $title,
+ 'agent' => $wgUser,
+ 'extra' => array(
+ 'link-from-page-id' => $linksUpdate->mTitle->getArticleId(),
+ )
+ ) );
+ $max--;
+ }
+ if ( $max < 0 ) {
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for BeforePageDisplay hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/BeforePageDisplay
+ * @param $out OutputPage object
+ * @param $skin Skin being used.
+ * @return bool true in all cases
+ */
+ static function beforePageDisplay( $out, $skin ) {
+ $user = $out->getUser();
+
+ // Don't show the alert message and badge if echo is disabled for this user
+ if ( self::isEchoDisabled( $user ) ) {
+ return true;
+ }
+
+ if ( $user->isLoggedIn() && $user->getOption( 'echo-notify-show-link' ) ) {
+ // Load the module for the Notifications flyout
+ $out->addModules( array( 'ext.echo.overlay.init' ) );
+ // Load the styles for the Notifications badge
+ $out->addModuleStyles( 'ext.echo.badge' );
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for PersonalUrls hook.
+ * Add a "Notifications" item to the user toolbar ('personal URLs').
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/PersonalUrls
+ * @param &$personal_urls Array of URLs to append to.
+ * @param &$title Title of page being visited.
+ * @param SkinTemplate $sk
+ * @return bool true in all cases
+ */
+ static function onPersonalUrls( &$personal_urls, &$title, $sk ) {
+ global $wgEchoNewMsgAlert;
+ $user = $sk->getUser();
+ if ( $user->isAnon() || self::isEchoDisabled( $user ) ) {
+ return true;
+ }
+
+ // Attempt to mark a notification as read when visiting a page,
+ // ideally this should be deferred to end of request and update
+ // the notification count accordingly
+ // @Fixme - Find a better place to put this code
+ if ( $title->getArticleID() ) {
+ $mapper = new EchoTargetPageMapper();
+ $targetPages = $mapper->fetchByUserPageId( $user, $title->getArticleID() );
+ if ( $targetPages ) {
+ $eventIds = array_keys( $targetPages );
+ $notifUser = MWEchoNotifUser::newFromUser( $user );
+ $notifUser->markRead( $eventIds );
+ }
+ }
+
+ // Add a "My notifications" item to personal URLs
+ if ( $user->getOption( 'echo-notify-show-link' ) ) {
+ $notificationCount = MWEchoNotifUser::newFromUser( $user )->getNotificationCount();
+ $text = EchoNotificationController::formatNotificationCount( $notificationCount );
+ $url = SpecialPage::getTitleFor( 'Notifications' )->getLocalURL();
+ if ( $notificationCount == 0 ) {
+ $linkClasses = array( 'mw-echo-notifications-badge' );
+ } else {
+ $linkClasses = array( 'mw-echo-unread-notifications', 'mw-echo-notifications-badge' );
+ }
+ $notificationsLink = array(
+ 'href' => $url,
+ 'text' => $text,
+ 'active' => ( $url == $title->getLocalUrl() ),
+ 'class' => $linkClasses,
+ );
+
+ $insertUrls = array( 'notifications' => $notificationsLink );
+ $personal_urls = wfArrayInsertAfter( $personal_urls, $insertUrls, 'userpage' );
+ }
+
+ // If the user has new messages, display a talk page alert
+ if ( $wgEchoNewMsgAlert && $user->getOption( 'echo-show-alert' ) && $user->getNewtalk() ) {
+ $personal_urls['mytalk']['text'] = $sk->msg( 'echo-new-messages' )->text();
+ $personal_urls['mytalk']['class'] = array( 'mw-echo-alert' );
+ $sk->getOutput()->addModuleStyles( 'ext.echo.alert' );
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for AbortTalkPageEmailNotification hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/AbortTalkPageEmailNotification
+ * @param $targetUser User
+ * @param $title Title
+ * @return bool
+ */
+ static function onAbortTalkPageEmailNotification( $targetUser, $title ) {
+ global $wgEchoNotifications;
+
+ // Send legacy talk page email notification if
+ // 1. echo is disabled for them or
+ // 2. echo talk page notification is disabled
+ if ( self::isEchoDisabled( $targetUser ) || !isset( $wgEchoNotifications['edit-user-talk'] ) ) {
+ // Legacy talk page email notification
+ return true;
+ }
+
+ // Echo talk page email notification
+ return false;
+ }
+
+ /**
+ * Handler for AbortWatchlistEmailNotification hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/AbortWatchlistEmailNotification
+ * @param $targetUser User
+ * @param $title Title
+ * @param $emailNotification EmailNotification The email notification object that sends non-echo notifications
+ * @return bool
+ */
+ static function onSendWatchlistEmailNotification( $targetUser, $title, $emailNotification ) {
+ // If a user is watching his/her own talk page, do not send talk page watchlist
+ // email notification if the user is receiving Echo talk page notification
+ if ( $title->isTalkPage() && $targetUser->getTalkPage()->equals( $title ) ) {
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $events = $attributeManager->getUserEnabledEvents( $targetUser, 'email' );
+ if (
+ !self::isEchoDisabled( $targetUser )
+ && in_array( 'edit-user-talk', $events )
+ ) {
+ // Do not send watchlist email notification, the user will receive an Echo notification
+ return false;
+ }
+ }
+ // Proceed to send watchlist email notification
+ return true;
+ }
+
+ /**
+ * Handler for MakeGlobalVariablesScript hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/MakeGlobalVariablesScript
+ * @param &$vars array Variables to be added into the output
+ * @param $outputPage OutputPage instance calling the hook
+ * @return bool true in all cases
+ */
+ public static function makeGlobalVariablesScript( &$vars, OutputPage $outputPage ) {
+ global $wgEchoHelpPage, $wgEchoMaxNotificationCount, $wgEchoConfig;
+ $user = $outputPage->getUser();
+
+ // Provide info for the Overlay
+
+ if ( ! $user->isAnon() ) {
+ $vars['wgEchoOverlayConfiguration'] = array(
+ 'notification-count' => MWEchoNotifUser::newFromUser( $user )->getFormattedNotificationCount(),
+ 'max-notification-count' => $wgEchoMaxNotificationCount,
+ );
+ $vars['wgEchoHelpPage'] = $wgEchoHelpPage;
+ $vars['wgEchoConfig'] = $wgEchoConfig;
+ } else if (
+ $outputPage->getTitle()->equals( SpecialPage::getTitleFor( 'JavaScriptTest', 'qunit' ) ) ||
+ // Also if running from /plain or /export
+ $outputPage->getTitle()->isSubpageOf( SpecialPage::getTitleFor( 'JavaScriptTest', 'qunit' ) )
+ ) {
+ // For testing purposes
+ $vars['wgEchoConfig'] = array(
+ 'eventlogging' => array(
+ 'EchoInteraction' => array(),
+ ),
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for UnitTestsList hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/UnitTestsList
+ * @param &$files Array of unit test files
+ * @return bool true in all cases
+ */
+ static function getUnitTests( &$files ) {
+ // @codeCoverageIgnoreStart
+ $directoryIterator = new RecursiveDirectoryIterator( __DIR__ . '/tests/phpunit/' );
+
+ /**
+ * @var SplFileInfo $fileInfo
+ */
+ $ourFiles = array();
+ foreach ( new RecursiveIteratorIterator( $directoryIterator ) as $fileInfo ) {
+ if ( substr( $fileInfo->getFilename(), -8 ) === 'Test.php' ) {
+ $ourFiles[] = $fileInfo->getPathname();
+ }
+ }
+
+ $files = array_merge( $files, $ourFiles );
+ return true;
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * Handler for GetNewMessagesAlert hook.
+ * We're using the GetNewMessagesAlert hook instead of the
+ * ArticleEditUpdateNewTalk hook since we still want the user_newtalk data
+ * to be updated and availble to client-side tools and the API.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/GetNewMessagesAlert
+ * @param &$newMessagesAlert String An alert that the user has new messages
+ * or an empty string if the user does not (empty by default)
+ * @param $newtalks Array This will be empty if the user has no new messages
+ * or an Array containing links and revisions if there are new messages
+ * @param $user User The user who is loading the page
+ * @param $out Output object
+ * @return bool Should return false to prevent the new messages alert (OBOD)
+ * or true to allow the new messages alert
+ */
+ static function abortNewMessagesAlert( &$newMessagesAlert, $newtalks, $user, $out ) {
+ global $wgEchoNotifications;
+
+ // If the user has the notifications flyout turned on and is receiving
+ // notifications for talk page messages, disable the new messages alert.
+ if ( $user->isLoggedIn()
+ && $user->getOption( 'echo-notify-show-link' )
+ && isset( $wgEchoNotifications['edit-user-talk'] )
+ ) {
+ // Show the new messages alert for users with echo disabled
+ if ( self::isEchoDisabled( $user ) ) {
+ return true;
+ }
+ // hide new messages alert
+ return false;
+ } else {
+ // show new messages alert
+ return true;
+ }
+ }
+
+ /**
+ * Handler for ArticleRollbackComplete hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/ArticleRollbackComplete
+ * @param $page WikiPage The article that was edited
+ * @param $agent User The user who did the rollback
+ * @param $newRevision Revision The revision the page was reverted back to
+ * @param $oldRevision Revision The revision of the top edit that was reverted
+ * @return bool true in all cases
+ */
+ static function onRollbackComplete( $page, $agent, $newRevision, $oldRevision ) {
+ $victimId = $oldRevision->getUser();
+
+ if (
+ $victimId && // No notifications for anonymous users
+ !$oldRevision->getContent()->equals( $newRevision->getContent() ) // No notifications for null rollbacks
+ ) {
+ EchoEvent::create( array(
+ 'type' => 'reverted',
+ 'title' => $page->getTitle(),
+ 'extra' => array(
+ 'revid' => $page->getRevision()->getId(),
+ 'reverted-user-id' => $victimId,
+ 'reverted-revision-id' => $oldRevision->getId(),
+ 'method' => 'rollback',
+ ),
+ 'agent' => $agent,
+ ) );
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for UserSaveSettings hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/UserSaveSettings
+ * @param $user User whose settings were saved
+ * @return bool true in all cases
+ */
+ static function onUserSaveSettings( $user ) {
+ // Extensions like AbuseFilter might create an account, but
+ // the tables we need might not exist. Bug 57335
+ if ( !defined( 'MW_UPDATER' ) ) {
+ // Reset the notification count since it may have changed due to user
+ // option changes. This covers both explicit changes in the preferences
+ // and changes made through the options API (since both call this hook).
+ MWEchoNotifUser::newFromUser( $user )->resetNotificationCount();
+ }
+ return true;
+ }
+
+ /**
+ * Handler for UserLoadOptions hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/UserLoadOptions
+ * @param $user User whose options were loaded
+ * @param $options Options can be modified
+ * @return bool true in all cases
+ */
+ public static function onUserLoadOptions( $user, &$options ) {
+ // Use existing enotifusertalkpages option for echo-subscriptions-email-edit-user-talk
+ if ( isset( $options['enotifusertalkpages'] ) ) {
+ $options['echo-subscriptions-email-edit-user-talk'] = $options['enotifusertalkpages'];
+ }
+ return true;
+ }
+
+ /**
+ * Handler for UserSaveOptions hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/UserSaveOptions
+ * @param $user User whose options are being saved
+ * @param $options Options can be modified
+ * @return bool true in all cases
+ */
+ public static function onUserSaveOptions( $user, &$options ) {
+ // echo-subscriptions-email-edit-user-talk is just a virtual option,
+ // save the value in the real option enotifusertalkpages
+ if ( isset( $options['echo-subscriptions-email-edit-user-talk'] ) ) {
+ $options['enotifusertalkpages'] = $options['echo-subscriptions-email-edit-user-talk'];
+ unset( $options['echo-subscriptions-email-edit-user-talk'] );
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for UserClearNewTalkNotification hook.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/UserClearNewTalkNotification
+ * @param $user User whose talk page notification should be marked as read
+ * @return bool true in all cases
+ */
+ public static function onUserClearNewTalkNotification( User $user ) {
+ if ( !$user->isAnon() ) {
+ MWEchoNotifUser::newFromUser( $user )->clearTalkNotification();
+ }
+ return true;
+ }
+
+ /**
+ * Handler for EchoCreateNotificationComplete hook, this will allow some
+ * extra stuff to be done upon creating a new notification
+ * @param $notif EchoNotification
+ * @return bool true in all cases
+ */
+ public static function onEchoCreateNotificationComplete( EchoNotification $notif ) {
+ if ( $notif->getEvent() && $notif->getUser() ) {
+ // Extra stuff for talk page notification
+ if ( $notif->getEvent()->getType() === 'edit-user-talk' ) {
+ $notifUser = MWEchoNotifUser::newFromUser( $notif->getUser() );
+ $notifUser->flagCacheWithNewTalkNotification();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler for ParserTestTables hook, makes sure that Echo's tables are present during tests
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/UserClearNewTalkNotification
+ * @param array $tables List of DB tables to be used for parser tests
+ * @return bool true in all cases
+ */
+ public static function onParserTestTables( &$tables ) {
+ $tables[] = 'echo_event';
+ $tables[] = 'echo_notification';
+ $tables[] = 'echo_email_batch';
+ return true;
+ }
+
+ /**
+ * Echo should be disabled for users who are under cohort study
+ * @param $user User
+ * @return bool
+ */
+ public static function isEchoDisabled( User $user ) {
+ global $wgEchoCohortInterval;
+
+ // Make sure the user has an id and cohort study timestamp is specified
+ if ( !$wgEchoCohortInterval || !$user->getId() ) {
+ return false;
+ }
+
+ list( $start, $bucketEnd, $cohortEnd ) = $wgEchoCohortInterval;
+
+ $regTimestamp = $user->getRegistration();
+
+ // Cohort study is for user with a registration timestamp
+ if ( !$regTimestamp ) {
+ return false;
+ }
+
+ // Cohort study is for even user_id
+ if ( $user->getId() % 2 === 1 ) {
+ return false;
+ }
+
+ $now = wfTimestampNow();
+
+ // Make sure the user is registered during the bucketing period
+ // and the cohort study doesn't end yet
+ if ( $start <= $regTimestamp && $regTimestamp <= $bucketEnd
+ && $start <= $now && $now <= $cohortEnd
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * For integration with the UserMerge extension.
+ *
+ * @param array $updateFields
+ * @return bool
+ */
+ public static function onUserMergeAccountFields( &$updateFields ) {
+ // array( tableName, idField, textField )
+ $dbw = MWEchoDbFactory::newFromDefault()->getEchoDb( DB_MASTER );
+ $updateFields[] = array( 'echo_event', 'event_agent_id', 'db' => $dbw );
+ $updateFields[] = array( 'echo_notification', 'notification_user', 'db' => $dbw, 'options' => array( 'IGNORE' ) );
+ $updateFields[] = array( 'echo_email_batch', 'eeb_user_id', 'db' => $dbw, 'options' => array( 'IGNORE' ) );
+ $updateFields[] = array( 'echo_target_page', 'etp_user', 'db' => $dbw, 'options' => array( 'IGNORE' ) );
+
+ return true;
+ }
+
+ public static function onMergeAccountFromTo( User &$oldUser, User &$newUser ) {
+ MWEchoNotifUser::newFromUser( $oldUser )->resetNotificationCount( DB_MASTER );
+ MWEchoNotifUser::newFromUser( $newUser )->resetNotificationCount( DB_MASTER );
+
+ return true;
+ }
+
+ public static function onUserMergeAccountDeleteTables( &$tables ) {
+ $dbw = MWEchoDbFactory::newFromDefault()->getEchoDb( DB_MASTER );
+ $tables['echo_notification'] = array( 'notification_user', 'db' => $dbw );
+ $tables['echo_email_batch'] = array( 'eeb_user_id', 'db' => $dbw );
+ $tables['echo_target_page'] = array( 'etp_user', 'db' => $dbw );
+
+ return true;
+ }
+}
diff --git a/Echo/Makefile b/Echo/Makefile
new file mode 100644
index 00000000..67f6c723
--- /dev/null
+++ b/Echo/Makefile
@@ -0,0 +1,74 @@
+MW_INSTALL_PATH ?= ../..
+MEDIAWIKI_LOAD_URL ?= http://localhost:8080/w/load.php
+
+# mediawiki-vagrant default to hhvm rather than php5, which is mostly
+# fine but really slow for commands like phplint
+PHP=/usr/bin/php5
+
+###
+# Meta stuff
+###
+
+remotes:
+ @scripts/remotecheck.sh
+
+# code review/pull patches/etc from command line
+gerrit: remotes
+ @scripts/remotes/gerrit.py --project 'mediawiki/extensions/Echo' --gtscore -1 --ignorepattern 'WIP'
+
+# interactively make sure en.json and qqq.json have all the
+# same message keys
+message: remotes
+ @python scripts/remotes/message.py
+
+# non-interactive version of message outputs result via exit code
+messagecheck: remotes
+ @python scripts/remotes/message.py check
+
+###
+# Lints
+###
+lint: jshint phplint checkless messagecheck
+
+# Verify all php in the project has valid syntax
+phplint:
+ @find ./ -type f -iname '*.php' -print0 | xargs -0 -P 12 -L 1 ${PHP} -l
+
+# Install nodejs dependencies for jshint
+nodecheck:
+ @which npm > /dev/null && npm install \
+ || (echo "You need to install Node.JS! See http://nodejs.org/" && false)
+
+# Verify all javascript in the project has valid syntax and follows jshint rules
+jshint: nodecheck
+ @node_modules/.bin/jshint modules/ tests/qunit --config .jshintrc
+
+# Verify all less files are compilable
+checkless:
+ @${PHP} ../../maintenance/checkLess.php
+
+# Check compiled less files for duplicated rules
+csscss: gems
+ echo "Generating CSS file..."
+ php scripts/generatecss.php ${MEDIAWIKI_LOAD_URL} /tmp/foo.css
+ csscss -v /tmp/foo.css --num 2 --no-match-shorthand --ignore-properties=display,position,top,bottom,left,right
+
+###
+# Testing
+###
+test: phpunit qunit
+
+# Run the projects phpunit tests
+phpunit:
+ cd ${MW_INSTALL_PATH}/tests/phpunit && ${PHP} phpunit.php --configuration ${MW_INSTALL_PATH}/extensions/Echo/tests/echo.suite.xml --group=Echo
+
+# Run the projects qunit tests
+qunit:
+ @scripts/qunit.sh
+
+###
+# Update this repository for csscss dependencies
+###
+gems:
+ bundle install
+
diff --git a/Echo/Notifier.php b/Echo/Notifier.php
new file mode 100644
index 00000000..53c6e747
--- /dev/null
+++ b/Echo/Notifier.php
@@ -0,0 +1,106 @@
+<?php
+
+// @todo Fill in
+class EchoNotifier {
+ /**
+ * Record an EchoNotification for an EchoEvent
+ * Currently used for web-based notifications.
+ *
+ * @param $user User to notify.
+ * @param $event EchoEvent to notify about.
+ */
+ public static function notifyWithNotification( $user, $event ) {
+ // Only create the notification if the user wants to recieve that type
+ // of notification and they are eligible to recieve it. See bug 47664.
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $userWebNotifications = $attributeManager->getUserEnabledEvents( $user, 'web' );
+ if ( !in_array( $event->getType(), $userWebNotifications ) ) {
+ return;
+ }
+
+ EchoNotification::create( array( 'user' => $user, 'event' => $event ) );
+
+ MWEchoEventLogging::logSchemaEcho( $user, $event, 'web' );
+ }
+
+ /**
+ * Send a Notification to a user by email
+ *
+ * @param $user User to notify.
+ * @param $event EchoEvent to notify about.
+ * @return bool
+ */
+ public static function notifyWithEmail( $user, $event ) {
+ // No valid email address or email notification
+ if ( !$user->isEmailConfirmed() || $user->getOption( 'echo-email-frequency' ) < 0 ) {
+ return false;
+ }
+
+ // Final check on whether to send email for this user & event
+ if ( !wfRunHooks( 'EchoAbortEmailNotification', array( $user, $event ) ) ) {
+ return false;
+ }
+
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $userEmailNotifications = $attributeManager->getUserEnabledEvents( $user, 'email' );
+ // See if the user wants to receive emails for this category or the user is eligible to receive this email
+ if ( in_array( $event->getType(), $userEmailNotifications ) ) {
+ global $wgEchoEnableEmailBatch, $wgEchoNotifications, $wgNotificationSender, $wgNotificationReplyName, $wgEchoBundleEmailInterval;
+
+ $priority = $attributeManager->getNotificationPriority( $event->getType() );
+
+ $bundleString = $bundleHash = '';
+
+ // We should have bundling for email digest as long as either web or email bundling is on, for example, talk page
+ // email bundling is off, but if a user decides to receive email digest, we should bundle those messages
+ if ( !empty( $wgEchoNotifications[$event->getType()]['bundle']['web'] ) || !empty( $wgEchoNotifications[$event->getType()]['bundle']['email'] ) ) {
+ wfRunHooks( 'EchoGetBundleRules', array( $event, &$bundleString ) );
+ }
+ if ( $bundleString ) {
+ $bundleHash = md5( $bundleString );
+ }
+
+ MWEchoEventLogging::logSchemaEcho( $user, $event, 'email' );
+
+ // email digest notification ( weekly or daily )
+ if ( $wgEchoEnableEmailBatch && $user->getOption( 'echo-email-frequency' ) > 0 ) {
+ // always create a unique event hash for those events don't support bundling
+ // this is mainly for group by
+ if ( !$bundleHash ) {
+ $bundleHash = md5( $event->getType() . '-' . $event->getId() );
+ }
+ MWEchoEmailBatch::addToQueue( $user->getId(), $event->getId(), $priority, $bundleHash );
+ return true;
+ }
+
+ $addedToQueue = false;
+
+ // only send bundle email if email bundling is on
+ if ( $wgEchoBundleEmailInterval && $bundleHash && !empty( $wgEchoNotifications[$event->getType()]['bundle']['email'] ) ) {
+ $bundler = MWEchoEmailBundler::newFromUserHash( $user, $bundleHash );
+ if ( $bundler ) {
+ $addedToQueue = $bundler->addToEmailBatch( $event->getId(), $priority );
+ }
+ }
+
+ // send single notification if the email wasn't added to queue for bundling
+ if ( !$addedToQueue ) {
+ // instant email notification
+ $toAddress = MailAddress::newFromUser( $user );
+ $fromAddress = new MailAddress( $wgNotificationSender, EchoHooks::getNotificationSenderName() );
+ $replyAddress = new MailAddress( $wgNotificationSender, $wgNotificationReplyName );
+ // Since we are sending a single email, should set the bundle hash to null
+ // if it is set with a value from somewhere else
+ $event->setBundleHash( null );
+ $email = EchoNotificationController::formatNotification( $event, $user, 'email', 'email' );
+ $subject = $email['subject'];
+ $body = $email['body'];
+
+ UserMailer::send( $toAddress, $fromAddress, $subject, $body, $replyAddress );
+ MWEchoEventLogging::logSchemaEchoMail( $user, 'single' );
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/Echo/RELEASE_NOTES b/Echo/RELEASE_NOTES
new file mode 100644
index 00000000..c6d0fcf4
--- /dev/null
+++ b/Echo/RELEASE_NOTES
@@ -0,0 +1,7 @@
+March, 2015
+-----------
+
+* Echo events now support multiple target pages. As a result The api output of individual
+ notifications within api.php?action=query&meta=notifications no longer has a 'targetpage'
+ property. This has been replaced with a 'targetpages' property which is the same as
+ 'targetpage' was, but now as an array.
diff --git a/Echo/Resources.php b/Echo/Resources.php
new file mode 100644
index 00000000..4eea249e
--- /dev/null
+++ b/Echo/Resources.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * MediaWiki Extension: Echo
+ * http://www.mediawiki.org/wiki/Extension:Echo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY.
+ */
+
+/**
+ *
+ * @file
+ * @ingroup Extensions
+ * @author Andrew Garrett, Benny Situ, Ryan Kaldari, Erik Bernhardson
+ * @licence MIT License
+ */
+
+$echoResourceTemplate = array(
+ 'localBasePath' => __DIR__ . '/modules',
+ 'remoteExtPath' => 'Echo/modules',
+);
+
+$mobileReadyTemplate = array(
+ 'targets' => array( 'desktop', 'mobile' ),
+);
+
+$wgResourceModules += array(
+ // ext.echo.base is used by mobile notifications as well, so be sure not to add any
+ // dependencies that do not target mobile.
+ 'ext.echo.base' => $echoResourceTemplate + $mobileReadyTemplate + array(
+ 'styles' => 'base/ext.echo.base.less',
+ 'scripts' => array(
+ 'base/ext.echo.base.js',
+ ),
+ 'messages' => array(
+ 'echo-error-preference',
+ 'echo-error-token',
+ ),
+ ),
+ 'ext.echo.overlay' => $echoResourceTemplate + $mobileReadyTemplate + array(
+ 'scripts' => array(
+ 'overlay/ext.echo.overlay.js',
+ ),
+ 'skinStyles' => array(
+ 'modern' => 'overlay/ext.echo.overlay.modern.css',
+ 'monobook' => 'overlay/ext.echo.overlay.monobook.css',
+ ),
+ 'dependencies' => array(
+ 'mediawiki.util',
+ 'mediawiki.language',
+ 'mediawiki.ui.anchor',
+ 'ext.echo.base',
+ 'mediawiki.api',
+ 'mediawiki.jqueryMsg',
+ ),
+ 'messages' => array(
+ 'echo-overlay-link',
+ 'echo-mark-all-as-read',
+ 'echo-more-info',
+ 'echo-feedback',
+ 'echo-notification-alert',
+ 'echo-notification-message',
+ 'echo-notification-alert-text-only',
+ 'echo-notification-message-text-only',
+ 'echo-email-batch-bullet'
+ ),
+ ),
+ 'ext.echo.overlay.init' => $echoResourceTemplate + array(
+ 'styles' => array(
+ 'overlay/ext.echo.overlay.less',
+ ),
+ 'dependencies' => array(
+ 'ext.echo.overlay',
+ ),
+ 'scripts' => array(
+ 'overlay/ext.echo.overlay.init.js',
+ ),
+ ),
+ 'ext.echo.special' => $echoResourceTemplate + array(
+ 'scripts' => array(
+ 'special/ext.echo.special.js',
+ ),
+ 'styles' => 'special/ext.echo.special.less',
+ 'dependencies' => array(
+ 'mediawiki.ui.button',
+ 'ext.echo.base',
+ ),
+ 'messages' => array(
+ 'echo-load-more-error',
+ 'echo-more-info',
+ 'echo-feedback',
+ ),
+ 'position' => 'top',
+ ),
+ 'ext.echo.alert' => $echoResourceTemplate + array(
+ 'styles' => 'alert/ext.echo.alert.less',
+ 'skinStyles' => array(
+ 'modern' => 'alert/ext.echo.alert.modern.css',
+ 'monobook' => 'alert/ext.echo.alert.monobook.css',
+ ),
+ ),
+ 'ext.echo.badge' => $echoResourceTemplate + array(
+ 'styles' => 'badge/ext.echo.badge.less',
+ 'skinStyles' => array(
+ 'modern' => 'badge/ext.echo.badge.modern.css',
+ 'monobook' => 'badge/ext.echo.badge.monobook.css',
+ ),
+ ),
+);
diff --git a/Echo/api/ApiEchoMarkRead.php b/Echo/api/ApiEchoMarkRead.php
new file mode 100644
index 00000000..1a70f236
--- /dev/null
+++ b/Echo/api/ApiEchoMarkRead.php
@@ -0,0 +1,131 @@
+<?php
+
+class ApiEchoMarkRead extends ApiBase {
+
+ public function execute() {
+ // To avoid API warning, register the parameter used to bust browser cache
+ $this->getMain()->getVal( '_' );
+
+ $user = $this->getUser();
+ if ( $user->isAnon() ) {
+ $this->dieUsage( 'Login is required', 'login-required' );
+ }
+
+ $notifUser = MWEchoNotifUser::newFromUser( $user );
+
+ $params = $this->extractRequestParams();
+
+ // There is no need to trigger markRead if all notifications are read
+ if ( $notifUser->getNotificationCount() > 0 ) {
+ if ( count( $params['list'] ) ) {
+ // Make sure there is a limit to the update
+ $notifUser->markRead( array_slice( $params['list'], 0, ApiBase::LIMIT_SML2 ) );
+ // Mark all as read
+ } elseif ( $params['all'] ) {
+ $notifUser->markAllRead();
+ // Mark all as read for sections
+ } elseif ( $params['sections'] ) {
+ $notifUser->markAllRead( $params['sections'] );
+ }
+ }
+
+ $rawCount = $notifUser->getNotificationCount();
+
+ $result = array(
+ 'result' => 'success'
+ );
+ $rawCount = 0;
+ foreach ( EchoAttributeManager::$sections as $section ) {
+ $rawSectionCount = $notifUser->getNotificationCount( /* $tryCache = */true, DB_SLAVE, $section );
+ $result[$section]['rawcount'] = $rawSectionCount;
+ $result[$section]['count'] = EchoNotificationController::formatNotificationCount( $rawSectionCount );
+ $rawCount += $rawSectionCount;
+ }
+
+ $result += array(
+ 'rawcount' => $rawCount,
+ 'count' => EchoNotificationController::formatNotificationCount( $rawCount ),
+ );
+ $this->getResult()->addValue( 'query', $this->getModuleName(), $result );
+ }
+
+ public function getAllowedParams() {
+ return array(
+ 'list' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ ),
+ 'all' => array(
+ ApiBase::PARAM_REQUIRED => false,
+ ApiBase::PARAM_TYPE => 'boolean'
+ ),
+ 'sections' => array(
+ ApiBase::PARAM_TYPE => EchoAttributeManager::$sections,
+ ApiBase::PARAM_ISMULTI => true,
+ ),
+ 'token' => array(
+ ApiBase::PARAM_REQUIRED => true,
+ ),
+ );
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getParamDescription() {
+ return array(
+ 'list' => 'A list of notification IDs to mark as read',
+ 'all' => "If set to true, marks all of a user's notifications as read",
+ 'sections' => 'A list of sections to mark as read',
+ 'token' => 'edit token',
+ );
+ }
+
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function getTokenSalt() {
+ return '';
+ }
+
+ public function mustBePosted() {
+ return true;
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getDescription() {
+ return 'Mark notifications as read for the current user';
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getExamples() {
+ return array(
+ 'api.php?action=echomarkread&list=8',
+ 'api.php?action=echomarkread&all=true'
+ );
+ }
+
+ /**
+ * @see ApiBase::getExamplesMessages()
+ */
+ protected function getExamplesMessages() {
+ return array(
+ 'action=echomarkread&list=8'
+ => 'apihelp-echomarkread-example-1',
+ 'action=echomarkread&all=true'
+ => 'apihelp-echomarkread-example-2',
+ );
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/Echo_(Notifications)/API';
+ }
+}
diff --git a/Echo/api/ApiEchoNotifications.php b/Echo/api/ApiEchoNotifications.php
new file mode 100644
index 00000000..4614ce9b
--- /dev/null
+++ b/Echo/api/ApiEchoNotifications.php
@@ -0,0 +1,313 @@
+<?php
+
+class ApiEchoNotifications extends ApiQueryBase {
+
+ public function __construct( $query, $moduleName ) {
+ parent::__construct( $query, $moduleName, 'not' );
+ }
+
+ public function execute() {
+ // To avoid API warning, register the parameter used to bust browser cache
+ $this->getMain()->getVal( '_' );
+
+ $user = $this->getUser();
+ if ( $user->isAnon() ) {
+ $this->dieUsage( 'Login is required', 'login-required' );
+ }
+
+ $params = $this->extractRequestParams();
+ $prop = $params['prop'];
+
+ $result = array();
+ if ( in_array( 'list', $prop ) ) {
+ // Group notification results by section
+ if ( $params['groupbysection'] ) {
+ wfProfileIn( __METHOD__ . '-group-by-section' );
+ foreach ( $params['sections'] as $section ) {
+ $result[$section] = $this->getSectionPropList(
+ $user, $section, $params['limit'],
+ $params[$section . 'continue'], $params['format'], $params[$section . 'unreadfirst']
+ );
+ $this->getResult()->setIndexedTagName( $result[$section]['list'], 'notification' );
+ // 'index' is built on top of 'list'
+ if ( in_array( 'index', $prop ) ) {
+ $result[$section]['index'] = $this->getPropIndex( $result[$section]['list'] );
+ $this->getResult()->setIndexedTagName( $result[$section]['index'], 'id' );
+ }
+ }
+ wfProfileOut( __METHOD__ . '-group-by-section' );
+ } else {
+ wfProfileIn( __METHOD__ . '-group-by-none' );
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $result = $this->getPropList(
+ $user,
+ $attributeManager->getUserEnabledEventsbySections( $user, 'web', $params['sections'] ),
+ $params['limit'], $params['continue'], $params['format']
+ );
+ $this->getResult()->setIndexedTagName( $result['list'], 'notification' );
+ // 'index' is built on top of 'list'
+ if ( in_array( 'index', $prop ) ) {
+ $result['index'] = $this->getPropIndex( $result['list'] );
+ $this->getResult()->setIndexedTagName( $result['index'], 'id' );
+ }
+ wfProfileOut( __METHOD__ . '-group-by-none' );
+ }
+ }
+
+ if ( in_array( 'count', $prop ) ) {
+ wfProfileIn( __METHOD__ . '-count' );
+ $result = array_merge_recursive(
+ $result,
+ $this->getPropcount( $user, $params['sections'], $params['groupbysection'] )
+ );
+ wfProfileOut( __METHOD__ . '-count' );
+ }
+
+ $this->getResult()->setIndexedTagName( $result, 'notification' );
+ $this->getResult()->addValue( 'query', $this->getModuleName(), $result );
+ }
+
+ /**
+ * Internal method for getting the property 'list' data for individual section
+ * @param User $user
+ * @param string $section
+ * @param int $limit
+ * @param string $continue
+ * @param string $format
+ * @param boolean $unreadFirst
+ * @return array
+ */
+ protected function getSectionPropList( User $user, $section, $limit, $continue, $format, $unreadFirst = false ) {
+ $notifUser = MWEchoNotifUser::newFromUser( $user );
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $sectionEvents = $attributeManager->getUserEnabledEventsbySections( $user, 'web', array( $section ) );
+ // Some section like 'message' only has flow notifications, which most wikis and
+ // users don't have, we should skip the query in such case
+ if ( !$sectionEvents || !$notifUser->shouldQuerySectionData( $section ) ) {
+ $result = array(
+ 'list' => array(),
+ 'continue' => null
+ );
+ } else {
+ $result = $this->getPropList(
+ $user, $sectionEvents, $limit, $continue, $format, $unreadFirst
+ );
+ // If events exist for applicable section we should set the section status
+ // in cache to check whether a query should be triggered in later request.
+ // This is mostly for users who don't have 'message' notifications
+ if ( $sectionEvents ) {
+ $notifUser->setSectionStatusCache( $section, count( $result['list'] ) );
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Internal helper method for getting property 'list' data, this is based
+ * on the event types specified in the arguments and it could be event types
+ * of a set of sections or a single section
+ * @param User $user
+ * @param string[] $eventTypes
+ * @param int $limit
+ * @param string $continue
+ * @param string $format
+ * @param boolean $unreadFirst
+ * @return array
+ */
+ protected function getPropList( User $user, array $eventTypes, $limit, $continue, $format, $unreadFirst = false ) {
+ $result = array(
+ 'list' => array(),
+ 'continue' => null
+ );
+
+ $notifMapper = new EchoNotificationMapper();
+
+ // Prefer unread notifications. We don't care about next offset in this case
+ if ( $unreadFirst ) {
+ wfProfileIn( __METHOD__ . '-fetch-data-unread-first' );
+ $notifs = $notifMapper->fetchUnreadByUser( $user, $limit, $eventTypes );
+ // If there are less unread notifications than we requested,
+ // then fill the result with some read notifications
+ $count = count( $notifs );
+ if ( $count < $limit ) {
+ // Query planner should be smart enough that passing a short list of ids to exclude
+ // will only visit at most that number of extra rows.
+ $mixedNotifs = $notifMapper->fetchByUser(
+ $user,
+ $limit - $count,
+ null,
+ $eventTypes,
+ array_keys( $notifs )
+ );
+ foreach ( $mixedNotifs as $notif ) {
+ $notifs[$notif->getEvent()->getId()] = $notif;
+ }
+ }
+ wfProfileOut( __METHOD__ . '-fetch-data-unread-first' );
+ } else {
+ wfProfileIn( __METHOD__ . '-fetch-data' );
+ $notifs = $notifMapper->fetchByUser( $user, $limit + 1, $continue, $eventTypes );
+ wfProfileOut( __METHOD__ . '-fetch-data' );
+ }
+
+ wfProfileIn( __METHOD__ . '-formatting' );
+ foreach ( $notifs as $notif ) {
+ $result['list'][$notif->getEvent()->getID()] = EchoDataOutputFormatter::formatOutput( $notif, $format, $user );
+ }
+ wfProfileOut( __METHOD__ . '-formatting' );
+
+ // Generate offset if necessary
+ if ( !$unreadFirst ) {
+ if ( count( $result['list'] ) > $limit ) {
+ $lastItem = array_pop( $result['list'] );
+ $result['continue'] = $lastItem['timestamp']['utcunix'] . '|' . $lastItem['id'];
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Internal helper method for getting property 'count' data
+ * @param User $user
+ * @param string[] $sections
+ * @param boolean $groupBySection
+ * @return aray
+ */
+ protected function getPropCount( User $user, array $sections, $groupBySection ) {
+ $result = array();
+ $notifUser = MWEchoNotifUser::newFromUser( $user );
+ // Always get total count
+ $rawCount = $notifUser->getNotificationCount();
+ $result['rawcount'] = $rawCount;
+ $result['count'] = EchoNotificationController::formatNotificationCount( $rawCount );
+
+ if ( $groupBySection ) {
+ foreach ( $sections as $section ) {
+ $rawCount = $notifUser->getNotificationCount( /* $tryCache = */true, DB_SLAVE, $section );
+ $result[$section]['rawcount'] = $rawCount;
+ $result[$section]['count'] = EchoNotificationController::formatNotificationCount( $rawCount );
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Internal helper method for getting property 'index' data
+ * @param array $list
+ * @return array
+ */
+ protected function getPropIndex( $list ) {
+ $result = array();
+ foreach ( array_keys( $list ) as $key ) {
+ // Don't include the XML tag name ('_element' key)
+ if ( $key != '_element' ) {
+ $result[] = $key;
+ }
+ }
+ return $result;
+ }
+
+ public function getAllowedParams() {
+ $sections = EchoAttributeManager::$sections;
+ $params = array(
+ 'prop' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => array(
+ 'list',
+ 'count',
+ 'index',
+ ),
+ ApiBase::PARAM_DFLT => 'list',
+ ),
+ 'sections' => array(
+ ApiBase::PARAM_DFLT => implode( '|', $sections ),
+ ApiBase::PARAM_TYPE => $sections,
+ ApiBase::PARAM_ISMULTI => true,
+ ),
+ 'groupbysection' => array(
+ ApiBase::PARAM_TYPE => 'boolean',
+ ApiBase::PARAM_DFLT => false,
+ ),
+ 'format' => array(
+ ApiBase::PARAM_TYPE => array(
+ 'text',
+ 'flyout',
+ 'html',
+ ),
+ ),
+ 'limit' => array(
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_DFLT => 20,
+ ApiBase::PARAM_MIN => 1,
+ ApiBase::PARAM_MAX => ApiBase::LIMIT_SML1,
+ ApiBase::PARAM_MAX2 => ApiBase::LIMIT_SML2,
+ ),
+ 'index' => false,
+ 'continue' => array(
+ /** @todo Once support for MediaWiki < 1.25 is dropped, just use ApiBase::PARAM_HELP_MSG directly */
+ constant( 'ApiBase::PARAM_HELP_MSG' ) ?: '' => 'api-help-param-continue',
+ ),
+ );
+ foreach ( $sections as $section ) {
+ $params[$section . 'continue'] = null;
+ $params[$section . 'unreadfirst'] = array(
+ ApiBase::PARAM_TYPE => 'boolean',
+ ApiBase::PARAM_DFLT => false,
+ );
+ }
+ return $params;
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getParamDescription() {
+ return array(
+ 'prop' => 'Details to request.',
+ 'sections' => 'The notification sections to query.',
+ 'groupbysection' => 'Whether to group the result by section, each section is fetched separately if set',
+ 'format' => 'If specified, notifications will be returned formatted this way.',
+ 'index' => 'If specified, a list of notification IDs, in order, will be returned.',
+ 'limit' => 'The maximum number of notifications to return.',
+ 'continue' => 'When more results are available, use this to continue, this is used only when groupbysection is not set.',
+ 'alertcontinue' => 'When more alert results are available, use this to continue.',
+ 'messagecontinue' => 'When more message results are available, use this to continue.',
+ 'alertunreadfirst' => 'Whether to show unread message notifications first',
+ 'messageunreadfirst' => 'Whether to show unread alert notifications first'
+ );
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getDescription() {
+ return 'Get notifications waiting for the current user';
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getExamples() {
+ return array(
+ 'api.php?action=query&meta=notifications',
+ 'api.php?action=query&meta=notifications&notprop=count&notsections=alert|message&notgroupbysection=1',
+ );
+ }
+
+ /**
+ * @see ApiBase::getExamplesMessages()
+ */
+ protected function getExamplesMessages() {
+ return array(
+ 'action=query&meta=notifications'
+ => 'apihelp-query+notifications-example-1',
+ 'action=query&meta=notifications&notprop=count&notsections=alert|message&notgroupbysection=1'
+ => 'apihelp-query+notifications-example-2',
+ );
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/Echo_(Notifications)/API';
+ }
+}
diff --git a/Echo/autoload.php b/Echo/autoload.php
new file mode 100644
index 00000000..092d347e
--- /dev/null
+++ b/Echo/autoload.php
@@ -0,0 +1,102 @@
+<?php
+// This file is generated by scripts/gen-autoload.php, do not adjust manually
+
+global $wgAutoloadClasses;
+
+$wgAutoloadClasses += array(
+ 'ApiEchoMarkRead' => __DIR__ . '/api/ApiEchoMarkRead.php',
+ 'ApiEchoMarkReadTest' => __DIR__ . '/tests/phpunit/api/ApiEchoMarkReadTest.php',
+ 'ApiEchoNotifications' => __DIR__ . '/api/ApiEchoNotifications.php',
+ 'ApiEchoNotificationsTest' => __DIR__ . '/tests/phpunit/api/ApiEchoNotificationsTest.php',
+ 'BatchRowUpdateTest' => __DIR__ . '/tests/phpunit/includes/BatchRowUpdateTest.php',
+ 'CallbackFilterIterator' => __DIR__ . '/includes/iterator/CallbackFilterIterator.php',
+ 'ContainmentSetTest' => __DIR__ . '/tests/phpunit/includes/ContainmentSetTest.php',
+ 'EchoAbstractEntity' => __DIR__ . '/model/AbstractEntity.php',
+ 'EchoAbstractMapper' => __DIR__ . '/includes/mapper/AbstractMapper.php',
+ 'EchoAbstractMapperStub' => __DIR__ . '/tests/phpunit/includes/mapper/AbstractMapperTest.php',
+ 'EchoAbstractMapperTest' => __DIR__ . '/tests/phpunit/includes/mapper/AbstractMapperTest.php',
+ 'EchoArrayList' => __DIR__ . '/includes/ContainmentSet.php',
+ 'EchoAttributeManager' => __DIR__ . '/includes/AttributeManager.php',
+ 'EchoAttributeManagerTest' => __DIR__ . '/tests/phpunit/includes/AttributeManagerTest.php',
+ 'EchoBasicFormatter' => __DIR__ . '/formatters/BasicFormatter.php',
+ 'EchoBatchRowIterator' => __DIR__ . '/includes/BatchRowUpdate.php',
+ 'EchoBatchRowUpdate' => __DIR__ . '/includes/BatchRowUpdate.php',
+ 'EchoBatchRowWriter' => __DIR__ . '/includes/BatchRowUpdate.php',
+ 'EchoCachedList' => __DIR__ . '/includes/ContainmentSet.php',
+ 'EchoCallbackIterator' => __DIR__ . '/includes/iterator/CallbackIterator.php',
+ 'EchoCatchableFatalErrorException' => __DIR__ . '/includes/exception/CatchableFatalErrorException.php',
+ 'EchoCommentFormatter' => __DIR__ . '/formatters/CommentFormatter.php',
+ 'EchoContainmentList' => __DIR__ . '/includes/ContainmentSet.php',
+ 'EchoContainmentSet' => __DIR__ . '/includes/ContainmentSet.php',
+ 'EchoDataOutputFormatter' => __DIR__ . '/includes/DataOutputFormatter.php',
+ 'EchoDeferredMarkAsReadUpdate' => __DIR__ . '/includes/DeferredMarkAsReadUpdate.php',
+ 'EchoDiffGroup' => __DIR__ . '/includes/DiffParser.php',
+ 'EchoDiffParser' => __DIR__ . '/includes/DiffParser.php',
+ 'EchoDiffParserTest' => __DIR__ . '/tests/phpunit/includes/DiffParserTest.php',
+ 'EchoDiscussionParser' => __DIR__ . '/includes/DiscussionParser.php',
+ 'EchoDiscussionParserTest' => __DIR__ . '/tests/phpunit/includes/DiscussionParserTest.php',
+ 'EchoEditFormatter' => __DIR__ . '/formatters/EditFormatter.php',
+ 'EchoEditUserTalkFormatter' => __DIR__ . '/formatters/EditUserTalkFormatter.php',
+ 'EchoEmailDecorator' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoEmailDigest' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoEmailFormatter' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoEmailFormatterTest' => __DIR__ . '/tests/phpunit/includes/EmailFormatterTest.php',
+ 'EchoEmailMode' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoEmailSingle' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoEvent' => __DIR__ . '/model/Event.php',
+ 'EchoEventMapper' => __DIR__ . '/includes/mapper/EventMapper.php',
+ 'EchoEventMapperTest' => __DIR__ . '/tests/phpunit/includes/mapper/EventMapperTest.php',
+ 'EchoExecuteFirstArgumentStub' => __DIR__ . '/tests/phpunit/includes/mapper/NotificationMapperTest.php',
+ 'EchoFilteredSequentialIterator' => __DIR__ . '/includes/iterator/FilteredSequentialIterator.php',
+ 'EchoHTMLEmailDecorator' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoHTMLEmailFormatter' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoHooks' => __DIR__ . '/Hooks.php',
+ 'EchoIteratorDecorator' => __DIR__ . '/includes/iterator/IteratorDecorator.php',
+ 'EchoLocalCache' => __DIR__ . '/includes/cache/LocalCache.php',
+ 'EchoMentionFormatter' => __DIR__ . '/formatters/MentionFormatter.php',
+ 'EchoMultipleIterator' => __DIR__ . '/includes/iterator/MultipleIterator.php',
+ 'EchoNotRecursiveIterator' => __DIR__ . '/includes/iterator/NotRecursiveIterator.php',
+ 'EchoNotification' => __DIR__ . '/model/Notification.php',
+ 'EchoNotificationController' => __DIR__ . '/controller/NotificationController.php',
+ 'EchoNotificationDeleteJob' => __DIR__ . '/jobs/NotificationDeleteJob.php',
+ 'EchoNotificationFormatter' => __DIR__ . '/formatters/NotificationFormatter.php',
+ 'EchoNotificationFormatterTest' => __DIR__ . '/tests/phpunit/formatters/NotificationFormatterTest.php',
+ 'EchoNotificationJob' => __DIR__ . '/jobs/NotificationJob.php',
+ 'EchoNotificationMapper' => __DIR__ . '/includes/mapper/NotificationMapper.php',
+ 'EchoNotificationMapperTest' => __DIR__ . '/tests/phpunit/includes/mapper/NotificationMapperTest.php',
+ 'EchoNotificationTest' => __DIR__ . '/tests/phpunit/model/NotificationTest.php',
+ 'EchoNotifier' => __DIR__ . '/Notifier.php',
+ 'EchoOnWikiList' => __DIR__ . '/includes/ContainmentSet.php',
+ 'EchoPageLinkFormatter' => __DIR__ . '/formatters/PageLinkFormatter.php',
+ 'EchoRevisionLocalCache' => __DIR__ . '/includes/cache/RevisionLocalCache.php',
+ 'EchoRowUpdateGenerator' => __DIR__ . '/includes/BatchRowUpdate.php',
+ 'EchoSuppressionRowUpdateGenerator' => __DIR__ . '/includes/schemaUpdate.php',
+ 'EchoTalkPageFunctionalTest' => __DIR__ . '/tests/phpunit/includes/TalkPageFunctionalTest.php',
+ 'EchoTargetPage' => __DIR__ . '/model/TargetPage.php',
+ 'EchoTargetPageMapper' => __DIR__ . '/includes/mapper/TargetPageMapper.php',
+ 'EchoTargetPageMapperTest' => __DIR__ . '/tests/phpunit/includes/mapper/TargetPageMapperTest.php',
+ 'EchoTargetPageTest' => __DIR__ . '/tests/phpunit/model/TargetPageTest.php',
+ 'EchoTextEmailDecorator' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoTextEmailFormatter' => __DIR__ . '/includes/EmailFormatter.php',
+ 'EchoTitleLocalCache' => __DIR__ . '/includes/cache/TitleLocalCache.php',
+ 'EchoTitleLocalCacheTest' => __DIR__ . '/tests/phpunit/includes/cache/TitleLocalCacheTest.php',
+ 'EchoUserLocator' => __DIR__ . '/includes/UserLocator.php',
+ 'EchoUserLocatorTest' => __DIR__ . '/tests/phpunit/includes/UserLocatorTest.php',
+ 'EchoUserNotificationGateway' => __DIR__ . '/includes/gateway/UserNotificationGateway.php',
+ 'EchoUserNotificationGatewayTest' => __DIR__ . '/tests/phpunit/includes/gateway/UserNotificationGatewayTest.php',
+ 'EchoUserRightsFormatter' => __DIR__ . '/formatters/UserRightsFormatter.php',
+ 'FilteredSequentialIteratorTest' => __DIR__ . '/tests/phpunit/includes/iterator/FilteredSequentialIteratorTest.php',
+ 'MWDbEchoEmailBatch' => __DIR__ . '/includes/DbEmailBatch.php',
+ 'MWDbEchoEmailBundler' => __DIR__ . '/includes/DbEmailBundler.php',
+ 'MWEchoDbFactory' => __DIR__ . '/includes/EchoDbFactory.php',
+ 'MWEchoDbFactoryTest' => __DIR__ . '/tests/phpunit/includes/EchoDbFactoryTest.php',
+ 'MWEchoEmailBatch' => __DIR__ . '/includes/EmailBatch.php',
+ 'MWEchoEmailBundler' => __DIR__ . '/includes/EmailBundler.php',
+ 'MWEchoEventLogging' => __DIR__ . '/includes/EventLogging.php',
+ 'MWEchoNotifUser' => __DIR__ . '/includes/NotifUser.php',
+ 'MWEchoNotifUserTest' => __DIR__ . '/tests/phpunit/includes/NotifUserTest.php',
+ 'MWEchoNotificationEmailBundleJob' => __DIR__ . '/jobs/NotificationEmailBundleJob.php',
+ 'NotificationControllerTest' => __DIR__ . '/tests/phpunit/controller/NotificationControllerTest.php',
+ 'SpecialNotifications' => __DIR__ . '/special/SpecialNotifications.php',
+ 'SuppressionMaintenanceTest' => __DIR__ . '/tests/phpunit/maintenance/SupressionMaintenanceTest.php',
+);
diff --git a/Echo/controller/NotificationController.php b/Echo/controller/NotificationController.php
new file mode 100644
index 00000000..6ab197d3
--- /dev/null
+++ b/Echo/controller/NotificationController.php
@@ -0,0 +1,418 @@
+<?php
+/**
+ * This class represents the controller for notifications
+ */
+class EchoNotificationController {
+
+ /**
+ * Echo event agent per wiki blacklist
+ *
+ * @var string[]
+ */
+ static protected $blacklist;
+
+ /**
+ * Echo event agent per user whitelist, this overwrites $blacklist
+ *
+ * @param string[]
+ */
+ static protected $userWhitelist;
+
+ /**
+ * Queue's that failed formatting and marks them as read at end of request.
+ *
+ * @var DeferredMarkAsReadUpdate|null
+ */
+ static protected $markAsRead;
+
+ /**
+ * Format the notification count with Language::formatNum(). In addition, for large count,
+ * return abbreviated version, e.g. 99+
+ *
+ * @param int $count
+ * @return string
+ */
+ public static function formatNotificationCount( $count ) {
+ global $wgLang, $wgEchoMaxNotificationCount;
+
+ if ( $count > $wgEchoMaxNotificationCount ) {
+ $count = wfMessage(
+ 'echo-notification-count',
+ $wgLang->formatNum( $wgEchoMaxNotificationCount )
+ )->escaped();
+ } else {
+ $count = $wgLang->formatNum( $count );
+ }
+
+ return $count;
+ }
+
+ /**
+ * Processes notifications for a newly-created EchoEvent
+ *
+ * @param EchoEvent $event
+ * @param boolean $defer Defer to job queue or not
+ */
+ public static function notify( $event, $defer = true ) {
+ // Defer to job queue if defer to job queue is requested and
+ // this event should use job queue
+ if ( $defer && $event->getUseJobQueue() ) {
+ // defer job insertion till end of request when all primary db transactions
+ // have been committed
+ DeferredUpdates::addCallableUpdate( function() use ( $event ) {
+ // can't use self::, php 5.3 doesn't inherit class scope
+ EchoNotificationController::enqueueEvent( $event );
+ } );
+ return;
+ }
+
+ // Check if the event object has valid event type. Events with invalid
+ // event types left in the job queue should not be processed
+ if ( !$event->isEnabledEvent() ) {
+ return;
+ }
+
+ $type = $event->getType();
+ $notifyTypes = self::getEventNotifyTypes( $type );
+ $userIds = array();
+ $userIdsCount = 0;
+ foreach ( self::getUsersToNotifyForEvent( $event ) as $user ) {
+ $userIds[$user->getId()] = $user->getId();
+ $userNotifyTypes = $notifyTypes;
+ wfRunHooks( 'EchoGetNotificationTypes', array( $user, $event, &$userNotifyTypes ) );
+
+ // types such as web, email, etc
+ foreach ( $userNotifyTypes as $type ) {
+ self::doNotification( $event, $user, $type );
+ }
+
+ $userIdsCount++;
+ // Process 1000 users per NotificationDeleteJob
+ if ( $userIdsCount > 1000 ) {
+ self::enqueueDeleteJob( $userIds, $event );
+ $userIds = array();
+ $userIdsCount = 0;
+ }
+ }
+
+ // process the userIds left in the array
+ if ( $userIds ) {
+ self::enqueueDeleteJob( $userIds, $event );
+ }
+ }
+
+ /**
+ * Schedule a job to check and delete older notifications
+ *
+ * @param int $userIds
+ * @param EchoEvent $event
+ */
+ public static function enqueueDeleteJob( array $userIds, EchoEvent $event ) {
+ // Do nothing if there is no user
+ if ( !$userIds ) {
+ return;
+ }
+
+ $job = new EchoNotificationDeleteJob(
+ $event->getTitle() ?: Title::newMainPage(),
+ array(
+ 'userIds' => $userIds
+ )
+ );
+ JobQueueGroup::singleton()->push( $job );
+ }
+
+ /**
+ * @param string $type Event type
+ * @return string[] List of notification types to send for
+ * this event type
+ */
+ public static function getEventNotifyTypes( $type ) {
+ // Get the notification types for this event, eg, web/email
+ global $wgEchoDefaultNotificationTypes;
+
+ $notifyTypes = $wgEchoDefaultNotificationTypes['all'];
+ if ( isset( $wgEchoDefaultNotificationTypes[$type] ) ) {
+ $notifyTypes = array_merge(
+ $notifyTypes,
+ $wgEchoDefaultNotificationTypes[$type]
+ );
+ }
+
+ return array_keys( array_filter( $notifyTypes ) );
+ }
+
+ /**
+ * Push $event onto the mediawiki job queue
+ *
+ * @param EchoEvent $event
+ */
+ public static function enqueueEvent( EchoEvent $event ) {
+ $job = new EchoNotificationJob(
+ $event->getTitle() ?: Title::newMainPage(),
+ array(
+ 'event' => $event,
+ 'masterPos' => MWEchoDbFactory::newFromDefault()
+ ->getMasterPosition(),
+ )
+ );
+ JobQueueGroup::singleton()->push( $job );
+ }
+
+
+ /**
+ * Implements blacklist per active wiki expected to be initialized
+ * from InitializeSettings.php
+ *
+ * @param EchoEvent $event The event to test for exclusion via global blacklist
+ * @return boolean True when the event agent is in the global blacklist
+ */
+ protected static function isBlacklisted( EchoEvent $event ) {
+ if ( !$event->getAgent() ) {
+ return false;
+ }
+
+ if ( self::$blacklist === null ) {
+ global $wgEchoAgentBlacklist, $wgEchoOnWikiBlacklist,
+ $wgMemc;
+
+ self::$blacklist = new EchoContainmentSet;
+ self::$blacklist->addArray( $wgEchoAgentBlacklist );
+ if ( $wgEchoOnWikiBlacklist !== null ) {
+ self::$blacklist->addOnWiki(
+ NS_MEDIAWIKI,
+ $wgEchoOnWikiBlacklist,
+ $wgMemc,
+ wfMemcKey( "echo_on_wiki_blacklist")
+ );
+ }
+ }
+
+ return self::$blacklist->contains( $event->getAgent()->getName() );
+ }
+
+ /**
+ * Implements per-user whitelist sourced from a user wiki page
+ *
+ * @param EchoEvent $event The event to test for inclusion in whitelist
+ * @param User $user The user that owns the whitelist
+ * @return boolean True when the event agent is in the user whitelist
+ */
+ public static function isWhitelistedByUser( EchoEvent $event, User $user ) {
+ global $wgEchoPerUserWhitelistFormat, $wgMemc;
+
+
+ if ( $wgEchoPerUserWhitelistFormat === null || !$event->getAgent() ) {
+ return false;
+ }
+
+ $userId = $user->getID();
+ if ( $userId === 0 ) {
+ return false; // anonymous user
+ }
+
+ if ( !isset( self::$userWhitelist[$userId] ) ) {
+ self::$userWhitelist[$userId] = new EchoContainmentSet;
+ self::$userWhitelist[$userId]->addOnWiki(
+ NS_USER,
+ sprintf( $wgEchoPerUserWhitelistFormat, $user->getName() ),
+ $wgMemc,
+ wfMemcKey( "echo_on_wiki_whitelist_" . $userId )
+ );
+ }
+
+ return self::$userWhitelist[$userId]
+ ->contains( $event->getAgent()->getName() );
+ }
+
+ /**
+ * Processes a single notification for an EchoEvent
+ *
+ * @param EchoEvent $event
+ * @param User $user The user to be notified.
+ * @param string $type The type of notification delivery to process, e.g. 'email'.
+ * @throws MWException
+ */
+ public static function doNotification( $event, $user, $type ) {
+ global $wgEchoNotifiers;
+
+ if ( !isset( $wgEchoNotifiers[$type] ) ) {
+ throw new MWException( "Invalid notification type $type" );
+ }
+
+ // Don't send any notification if Echo is disabled
+ if ( EchoHooks::isEchoDisabled( $user ) ) {
+ return;
+ }
+
+ call_user_func_array( $wgEchoNotifiers[$type], array( $user, $event ) );
+ }
+
+ /**
+ * Returns an array each element of which is the result of a
+ * user-locator attached to the event type.
+ *
+ * @param EchoEvent $event
+ * @return array
+ */
+ public static function evaluateUserLocators( EchoEvent $event ) {
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $type = $event->getType();
+ $result = array();
+ foreach ( $attributeManager->getUserLocators( $type ) as $callable ) {
+ // locator options can be set per-event by using an array with
+ // name as first parameter.
+ if ( is_array( $callable ) ) {
+ $options = $callable;
+ $spliced = array_splice( $options, 0, 1, array( $event ) );
+ $callable = reset( $spliced );
+ } else {
+ $options = array( $event );
+ }
+ if ( is_callable( $callable ) ) {
+ $result[] = call_user_func_array( $callable, $options );
+ } else {
+ wfDebugLog( __CLASS__, __FUNCTION__ . ": Invalid user-locator returned for $type" );
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Retrieves an array of User objects to be notified for an EchoEvent.
+ *
+ * @param EchoEvent $event
+ * @return Iterator values are User objects
+ */
+ public static function getUsersToNotifyForEvent( EchoEvent $event ) {
+ $notify = new EchoFilteredSequentialIterator;
+ foreach ( self::evaluateUserLocators( $event ) as $users ) {
+ $notify->add( $users );
+ }
+
+ // Hook for injecting more users.
+ // @deprecated
+ $users = array();
+ wfRunHooks( 'EchoGetDefaultNotifiedUsers', array( $event, &$users ) );
+ if ( $users ) {
+ $notify->add( $users );
+ }
+
+ // Filter non-User, anon and duplicate users
+ $seen = array();
+ $notify->addFilter( function( $user ) use( &$seen ) {
+ if ( !$user instanceof User ) {
+ wfDebugLog( __METHOD__, 'Expected all User instances, received:' .
+ ( is_object( $user ) ? get_class( $user ) : gettype( $user ) )
+ );
+ return false;
+ }
+ if ( $user->isAnon() || isset( $seen[$user->getId()] ) ) {
+ return false;
+ }
+ $seen[$user->getId()] = true;
+ return true;
+ } );
+
+ // Don't notify the person who initiated the event unless the event extra says to do so
+ $extra = $event->getExtra();
+ if ( ( !isset( $extra['notifyAgent'] ) || !$extra['notifyAgent'] ) && $event->getAgent() ) {
+ $agentId = $event->getAgent()->getId();
+ $notify->addFilter( function( $user ) use( $agentId ) {
+ return $user->getId() != $agentId;
+ } );
+ }
+
+ // Apply per-wiki event blacklist and per-user whitelists
+ // of that blacklist.
+ if ( self::isBlacklisted( $event ) ) {
+ $notify->addFilter( function( $user ) use( $event ) {
+ // don't use self:: - PHP5.3 closures don't inherit class scope
+ return EchoNotificationController::isWhitelistedByUser( $event, $user );
+ } );
+ }
+
+ return $notify->getIterator();
+ }
+
+ /**
+ * Formats a notification
+ *
+ * @param EchoEvent $event The event for a notification.
+ * @param User $user The user to format the notification for.
+ * @param string $format The format to show the notification in: text, html, or email
+ * @param string $type The type of notification being distributed (e.g. email, web)
+ * @return string|array The formatted notification, or an array of subject
+ * and body (for emails), or an error message
+ */
+ public static function formatNotification( $event, $user, $format = 'text', $type = 'web' ) {
+ global $wgEchoNotifications;
+
+ $eventType = $event->getType();
+
+ $res = '';
+ if ( isset( $wgEchoNotifications[$eventType] ) ) {
+ set_error_handler( array( __CLASS__, 'formatterErrorHandler' ), -1 );
+ try {
+ $params = $wgEchoNotifications[$eventType];
+ $notifier = EchoNotificationFormatter::factory( $params );
+ $notifier->setOutputFormat( $format );
+
+ $res = $notifier->format( $event, $user, $type );
+ } catch ( Exception $e ) {
+ $meta = array(
+ 'id' => $event->getId(),
+ 'eventType' => $eventType,
+ 'format' => $format,
+ 'type' => $type,
+ 'user' => $user ? $user->getName() : 'no user',
+ 'exceptionName' => get_class( $e ),
+ 'exceptionMessage' => $e->getMessage(),
+ );
+ wfDebugLog( 'Echo', __FUNCTION__ . ": Error formatting " . FormatJson::encode( $meta ) );
+ MWExceptionHandler::logException( $e );
+ }
+ restore_error_handler();
+ }
+
+ if ( $res === '' ) {
+ self::failFormatting( $event, $user );
+ }
+
+ return $res;
+ }
+
+ /**
+ * Event has failed to format for the given user. Mark it as read so
+ * we do not continue to notify them about this broken event.
+ *
+ * @param EchoEvent $event
+ * @param User $user
+ */
+ protected static function failFormatting( EchoEvent $event, $user ) {
+ // FIXME: The only issue is that the badge count won't be up to date
+ // till you refresh the page. Probably we could do this in the browser
+ // so that if the formatting is empty and the notif is unread, put it
+ // in the auto-mark-read API
+ if ( self::$markAsRead === null ) {
+ self::$markAsRead = new EchoDeferredMarkAsReadUpdate();
+ DeferredUpdates::addUpdate( self::$markAsRead );
+ }
+ self::$markAsRead->add( $event, $user );
+ }
+
+ /**
+ * INTERNAL. Must be public to be callable by the php error handling methods.
+ *
+ * Converts E_RECOVERABLE_ERROR, such as passing null to a method expecting
+ * a non-null object, into exceptions.
+ */
+ public static function formatterErrorHandler( $errno, $errstr, $errfile, $errline ) {
+ if ( $errno !== E_RECOVERABLE_ERROR ) {
+ return false;
+ }
+
+ throw new EchoCatchableFatalErrorException( $errno, $errstr, $errfile, $errline );
+ }
+}
diff --git a/Echo/db_patches/echo_email_batch.sql b/Echo/db_patches/echo_email_batch.sql
new file mode 100644
index 00000000..825eec00
--- /dev/null
+++ b/Echo/db_patches/echo_email_batch.sql
@@ -0,0 +1,9 @@
+CREATE TABLE /*_*/echo_email_batch (
+ eeb_id int unsigned not null primary key auto_increment,
+ eeb_user_id int unsigned not null,
+ eeb_event_priority tinyint unsigned not null default 10, -- event priority
+ eeb_event_id int unsigned not null
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/echo_email_batch_user_event ON /*_*/echo_email_batch (eeb_user_id,eeb_event_id);
+CREATE UNIQUE INDEX /*i*/echo_email_batch_user_priority_event ON /*_*/echo_email_batch (eeb_user_id,eeb_event_priority,eeb_event_id);
diff --git a/Echo/db_patches/echo_target_page.sql b/Echo/db_patches/echo_target_page.sql
new file mode 100644
index 00000000..f6e5c4a2
--- /dev/null
+++ b/Echo/db_patches/echo_target_page.sql
@@ -0,0 +1,8 @@
+CREATE TABLE /*_*/echo_target_page (
+ etp_user int unsigned not null default 0,
+ etp_page int unsigned not null default 0,
+ etp_event int unsigned not null default 0
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/echo_target_page_user_event ON /*_*/echo_target_page (etp_user, etp_event);
+CREATE INDEX /*i*/echo_target_page_user_page_event ON /*_*/echo_target_page (etp_user, etp_page, etp_event);
diff --git a/Echo/db_patches/patch-add-echo_event-event_page_id.sql b/Echo/db_patches/patch-add-echo_event-event_page_id.sql
new file mode 100644
index 00000000..3c4ae714
--- /dev/null
+++ b/Echo/db_patches/patch-add-echo_event-event_page_id.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/echo_event ADD event_page_id int unsigned;
diff --git a/Echo/db_patches/patch-alter-event_type-index.sql b/Echo/db_patches/patch-alter-event_type-index.sql
new file mode 100644
index 00000000..2bfb2b0b
--- /dev/null
+++ b/Echo/db_patches/patch-alter-event_type-index.sql
@@ -0,0 +1,3 @@
+DROP INDEX /*i*/event_type ON /*_*/echo_event;
+
+CREATE INDEX /*i*/echo_event_type ON /*_*/echo_event (event_type);
diff --git a/Echo/db_patches/patch-alter-type_page-index.sql b/Echo/db_patches/patch-alter-type_page-index.sql
new file mode 100644
index 00000000..e43b4519
--- /dev/null
+++ b/Echo/db_patches/patch-alter-type_page-index.sql
@@ -0,0 +1,3 @@
+DROP INDEX /*i*/type_page ON /*_*/echo_event;
+
+CREATE INDEX /*i*/event_type ON /*_*/echo_event (event_type);
diff --git a/Echo/db_patches/patch-alter-user_timestamp-index.sql b/Echo/db_patches/patch-alter-user_timestamp-index.sql
new file mode 100644
index 00000000..e5710c4f
--- /dev/null
+++ b/Echo/db_patches/patch-alter-user_timestamp-index.sql
@@ -0,0 +1,2 @@
+CREATE INDEX /*i*/echo_user_timestamp ON /*_*/echo_notification (notification_user, notification_timestamp);
+DROP INDEX /*i*/user_timestamp ON /*_*/echo_notification;
diff --git a/Echo/db_patches/patch-drop-echo_event-event_page_namespace.sql b/Echo/db_patches/patch-drop-echo_event-event_page_namespace.sql
new file mode 100644
index 00000000..95244ff9
--- /dev/null
+++ b/Echo/db_patches/patch-drop-echo_event-event_page_namespace.sql
@@ -0,0 +1,3 @@
+-- Patch to drop unused event_page_namespace
+alter table /*_*/echo_event drop event_page_namespace;
+
diff --git a/Echo/db_patches/patch-drop-echo_event-event_page_title.sql b/Echo/db_patches/patch-drop-echo_event-event_page_title.sql
new file mode 100644
index 00000000..34451c4d
--- /dev/null
+++ b/Echo/db_patches/patch-drop-echo_event-event_page_title.sql
@@ -0,0 +1,3 @@
+-- Patch to drop unused event_page_title
+alter table /*_*/echo_event drop event_page_title;
+
diff --git a/Echo/db_patches/patch-drop-echo_event-event_timestamp.sql b/Echo/db_patches/patch-drop-echo_event-event_timestamp.sql
new file mode 100644
index 00000000..57f6331a
--- /dev/null
+++ b/Echo/db_patches/patch-drop-echo_event-event_timestamp.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/echo_event DROP event_timestamp;
diff --git a/Echo/db_patches/patch-drop-echo_subscription.sql b/Echo/db_patches/patch-drop-echo_subscription.sql
new file mode 100644
index 00000000..f04a4f0a
--- /dev/null
+++ b/Echo/db_patches/patch-drop-echo_subscription.sql
@@ -0,0 +1,2 @@
+-- drop this table because subscription is not supported
+DROP TABLE /*_*/echo_subscription;
diff --git a/Echo/db_patches/patch-email_batch-new-field.sql b/Echo/db_patches/patch-email_batch-new-field.sql
new file mode 100644
index 00000000..f25f913b
--- /dev/null
+++ b/Echo/db_patches/patch-email_batch-new-field.sql
@@ -0,0 +1,7 @@
+ALTER TABLE /*_*/echo_email_batch ADD COLUMN eeb_event_hash varchar(32) binary not null default '';
+
+DROP INDEX /*i*/echo_email_batch_user_priority_event ON /*_*/echo_email_batch;
+
+CREATE INDEX /*i*/echo_email_batch_user_hash_priority ON /*_*/echo_email_batch (eeb_user_id, eeb_event_hash, eeb_event_priority);
+
+
diff --git a/Echo/db_patches/patch-event_agent-split.sql b/Echo/db_patches/patch-event_agent-split.sql
new file mode 100644
index 00000000..b543e858
--- /dev/null
+++ b/Echo/db_patches/patch-event_agent-split.sql
@@ -0,0 +1,4 @@
+-- 2012-05-06: Split event_agent field to allow anonymous agents.
+
+ALTER TABLE echo_event CHANGE COLUMN event_agent event_agent_id int unsigned null;
+ALTER TABLE echo_event ADD COLUMN event_agent_ip varchar(255) binary null; \ No newline at end of file
diff --git a/Echo/db_patches/patch-event_agent-split.sqlite.sql b/Echo/db_patches/patch-event_agent-split.sqlite.sql
new file mode 100644
index 00000000..505af06a
--- /dev/null
+++ b/Echo/db_patches/patch-event_agent-split.sqlite.sql
@@ -0,0 +1,35 @@
+-- Split event_agent field to allow anonymous agents
+ALTER TABLE echo_event ADD COLUMN event_agent_id int unsigned null;
+ALTER TABLE echo_event ADD COLUMN event_agent_ip varchar binary null;
+UPDATE echo_event SET event_agent_id = event_agent;
+
+-- Rename current table to temporary name
+ALTER TABLE /*_*/echo_event RENAME TO /*_*/temp_echo_event_split_event_agent;
+
+-- Recreate table using the proper nullability constraint for event_variant
+CREATE TABLE /*_*/echo_event (
+ event_id int unsigned not null primary key auto_increment,
+ event_type varchar(64) binary not null,
+ event_variant varchar(64) binary null,
+ event_agent_id int unsigned null, -- The user who triggered it, if any
+ event_agent_ip varchar(39) binary null, -- IP address who triggered it, if any
+ event_page_namespace int unsigned null,
+ event_page_title varchar(255) binary null,
+ event_extra BLOB NULL
+) /*$wgDBTableOptions*/;
+
+-- Copy over all the old data into the new table
+INSERT INTO /*_*/echo_event
+ (event_id, event_type, event_variant, event_agent_id, event_page_namespace, event_page_title, event_extra)
+SELECT
+ event_id, event_type, event_variant, event_agent, event_page_namespace, event_page_title, event_extra
+FROM
+ /*_*/temp_echo_event_split_event_agent;
+
+-- Drop the original table
+DROP TABLE /*_*/temp_echo_event_split_event_agent;
+
+-- recreate indexes
+CREATE INDEX /*i*/echo_event_type ON /*_*/echo_event (event_type);
+
+
diff --git a/Echo/db_patches/patch-event_agent_ip-size.sql b/Echo/db_patches/patch-event_agent_ip-size.sql
new file mode 100644
index 00000000..5ba0bb2c
--- /dev/null
+++ b/Echo/db_patches/patch-event_agent_ip-size.sql
@@ -0,0 +1,2 @@
+-- Patch to update ip size from varbinary(255) to varbinary(39)
+ALTER TABLE /*_*/echo_event CHANGE COLUMN event_agent_ip event_agent_ip varchar(39) binary NULL;
diff --git a/Echo/db_patches/patch-event_extra-size.sql b/Echo/db_patches/patch-event_extra-size.sql
new file mode 100644
index 00000000..0f67672f
--- /dev/null
+++ b/Echo/db_patches/patch-event_extra-size.sql
@@ -0,0 +1,2 @@
+-- Patch to add extra space to event_extra
+alter table /*_*/echo_event change column event_extra event_extra BLOB NULL; \ No newline at end of file
diff --git a/Echo/db_patches/patch-event_variant_nullability.sql b/Echo/db_patches/patch-event_variant_nullability.sql
new file mode 100644
index 00000000..4a1d5e0c
--- /dev/null
+++ b/Echo/db_patches/patch-event_variant_nullability.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/echo_event CHANGE COLUMN event_variant event_variant varchar(64) binary null; \ No newline at end of file
diff --git a/Echo/db_patches/patch-event_variant_nullability.sqlite.sql b/Echo/db_patches/patch-event_variant_nullability.sqlite.sql
new file mode 100644
index 00000000..126e36cc
--- /dev/null
+++ b/Echo/db_patches/patch-event_variant_nullability.sqlite.sql
@@ -0,0 +1,33 @@
+-- Sqlites alter table statement can NOT change existing columns. The only
+-- option since we need to change the nullability of event_variant is to
+-- recreate the table and copy the data over.
+
+-- Rename current table to temporary name
+ALTER TABLE /*_*/echo_event RENAME TO /*_*/temp_echo_event_variant_nullability;
+
+-- Recreate table using the proper nullability constraint for event_variant
+CREATE TABLE /*_*/echo_event (
+ event_id int unsigned not null primary key auto_increment,
+ event_type varchar(64) binary not null,
+ event_variant varchar(64) binary null,
+ event_agent_id int unsigned null, -- The user who triggered it, if any
+ event_agent_ip varchar(39) binary null, -- IP address who triggered it, if any
+ event_page_namespace int unsigned null,
+ event_page_title varchar(255) binary null,
+ event_extra BLOB NULL
+) /*$wgDBTableOptions*/;
+
+-- Copy over all the old data into the new table
+INSERT INTO /*_*/echo_event
+ (event_id, event_type, event_variant, event_agent_id, event_agent_ip, event_page_namespace, event_page_title, event_extra)
+SELECT
+ event_id, event_type, event_variant, event_agent_id, event_agent_ip, event_page_namespace, event_page_title, event_extra
+FROM
+ /*_*/temp_echo_event_variant_nullability;
+
+-- Drop the original table
+DROP TABLE /*_*/temp_echo_event_variant_nullability;
+
+-- recreate indexes
+CREATE INDEX /*i*/echo_event_type ON /*_*/echo_event (event_type);
+
diff --git a/Echo/db_patches/patch-multiple_target_pages.sql b/Echo/db_patches/patch-multiple_target_pages.sql
new file mode 100644
index 00000000..5d574f95
--- /dev/null
+++ b/Echo/db_patches/patch-multiple_target_pages.sql
@@ -0,0 +1,3 @@
+ALTER TABLE /*_*/echo_target_page ADD etp_id int unsigned not null primary key auto_increment;
+DROP INDEX /*i*/echo_target_page_user_event ON /*_*/echo_target_page;
+CREATE INDEX /*i*/echo_target_page_user_event ON /*_*/echo_target_page (etp_user, etp_event);
diff --git a/Echo/db_patches/patch-multiple_target_pages.sqlite.sql b/Echo/db_patches/patch-multiple_target_pages.sqlite.sql
new file mode 100644
index 00000000..0943bca2
--- /dev/null
+++ b/Echo/db_patches/patch-multiple_target_pages.sqlite.sql
@@ -0,0 +1,27 @@
+-- Sqlite can't add a primary key to an existing table
+
+-- give current table temporary name
+ALTER TABLE /*_*/echo_target_page RENAME TO /*_*/temp_echo_target_page;
+
+-- recreate table with our new setup
+CREATE TABLE /*_*/echo_target_page (
+ etp_id int unsigned not null primary key auto_increment,
+ etp_user int unsigned not null default 0,
+ etp_page int unsigned not null default 0,
+ etp_event int unsigned not null default 0
+) /*$wgDBTableOptions*/;
+
+-- copy over old data into new table
+INSERT INTO /*_*/echo_target_page
+ (etp_user, etp_page, etp_event)
+SELECT
+ etp_user, etp_page, etp_event
+FROM
+ /*_*/temp_echo_target_page;
+
+-- drop the original table
+DROP TABLE /*_*/temp_echo_target_page;
+
+-- recreate indexes
+CREATE INDEX /*i*/echo_target_page_user_event ON /*_*/echo_target_page (etp_user, etp_event);
+CREATE INDEX /*i*/echo_target_page_user_page_event ON /*_*/echo_target_page (etp_user, etp_page, etp_event);
diff --git a/Echo/db_patches/patch-notification-bundling-field.sql b/Echo/db_patches/patch-notification-bundling-field.sql
new file mode 100644
index 00000000..f6d5938e
--- /dev/null
+++ b/Echo/db_patches/patch-notification-bundling-field.sql
@@ -0,0 +1,8 @@
+ALTER TABLE /*_*/echo_notification ADD COLUMN notification_bundle_base boolean not null default 1;
+ALTER TABLE /*_*/echo_notification ADD COLUMN notification_bundle_hash varchar(32) binary not null default '';
+ALTER TABLE /*_*/echo_notification ADD COLUMN notification_bundle_display_hash varchar(32) binary not null default '';
+
+CREATE INDEX /*i*/echo_notification_user_base_read_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_base, notification_read_timestamp);
+CREATE INDEX /*i*/echo_notification_user_base_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_base, notification_timestamp, notification_event);
+CREATE INDEX /*i*/echo_notification_user_hash_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_hash, notification_timestamp);
+CREATE INDEX /*i*/echo_notification_user_hash_base_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_display_hash, notification_bundle_base, notification_timestamp);
diff --git a/Echo/echo.sql b/Echo/echo.sql
new file mode 100644
index 00000000..910203ad
--- /dev/null
+++ b/Echo/echo.sql
@@ -0,0 +1,53 @@
+-- Database Schema for Echo notification system
+
+CREATE TABLE /*_*/echo_event (
+ event_id int unsigned not null primary key auto_increment,
+ event_type varchar(64) binary not null,
+ event_variant varchar(64) binary null,
+ event_agent_id int unsigned null, -- The user who triggered it, if any
+ event_agent_ip varchar(39) binary null, -- IP address who triggered it, if any
+ event_page_namespace int unsigned null,
+ event_page_title varchar(255) binary null,
+ event_extra BLOB NULL,
+ event_page_id int unsigned null
+) /*$wgDBTableOptions*/;
+
+CREATE INDEX /*i*/echo_event_type ON /*_*/echo_event (event_type);
+
+CREATE TABLE /*_*/echo_notification (
+ notification_event int unsigned not null,
+ notification_user int unsigned not null,
+ notification_timestamp binary(14) not null,
+ notification_read_timestamp binary(14) null,
+ notification_bundle_base boolean not null default 1,
+ notification_bundle_hash varchar(32) binary not null, -- The hash for bundling notifications regardless of timestamp
+ notification_bundle_display_hash varchar(32) binary not null -- The hash for displaying bundle notifications with regard to timestamp, this is is a subset of notification_bundle_hash
+) /*$wgDBTableOptions*/;
+
+CREATE INDEX /*i*/echo_user_timestamp ON /*_*/echo_notification (notification_user,notification_timestamp);
+CREATE UNIQUE INDEX /*i*/user_event ON /*_*/echo_notification (notification_user,notification_event);
+CREATE INDEX /*i*/echo_notification_user_base_read_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_base, notification_read_timestamp);
+CREATE INDEX /*i*/echo_notification_user_base_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_base, notification_timestamp, notification_event);
+CREATE INDEX /*i*/echo_notification_user_hash_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_hash, notification_timestamp);
+CREATE INDEX /*i*/echo_notification_user_hash_base_timestamp ON /*_*/echo_notification (notification_user, notification_bundle_display_hash, notification_bundle_base, notification_timestamp);
+
+CREATE TABLE /*_*/echo_email_batch (
+ eeb_id int unsigned not null primary key auto_increment,
+ eeb_user_id int unsigned not null,
+ eeb_event_priority tinyint unsigned not null default 10, -- event priority
+ eeb_event_id int unsigned not null,
+ eeb_event_hash varchar(32) binary not null
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/echo_email_batch_user_event ON /*_*/echo_email_batch (eeb_user_id,eeb_event_id);
+CREATE INDEX /*i*/echo_email_batch_user_hash_priority ON /*_*/echo_email_batch (eeb_user_id, eeb_event_hash, eeb_event_priority);
+
+CREATE TABLE /*_*/echo_target_page (
+ etp_id int unsigned not null primary key auto_increment,
+ etp_user int unsigned not null default 0,
+ etp_page int unsigned not null default 0,
+ etp_event int unsigned not null default 0
+) /*$wgDBTableOptions*/;
+
+CREATE INDEX /*i*/echo_target_page_user_event ON /*_*/echo_target_page (etp_user, etp_event);
+CREATE INDEX /*i*/echo_target_page_user_page_event ON /*_*/echo_target_page (etp_user, etp_page, etp_event);
diff --git a/Echo/formatters/BasicFormatter.php b/Echo/formatters/BasicFormatter.php
new file mode 100644
index 00000000..761c2745
--- /dev/null
+++ b/Echo/formatters/BasicFormatter.php
@@ -0,0 +1,943 @@
+<?php
+
+/**
+ * @Todo - Consider having $event/$user as class properties since the formatter is
+ * always tied to these two entities, in this case, we won't have to pass it around
+ * in all the internal method
+ * @Todo - Instance variable $distributionType has been added, the local distribution
+ * type variable $type passed along all the protected/private method should be removed
+ * from all formatters
+ */
+class EchoBasicFormatter extends EchoNotificationFormatter {
+
+ /**
+ * Notification title data for archive page
+ * @param array
+ */
+ protected $title;
+
+ /**
+ * Notification title data for flyout
+ * @param array
+ */
+ protected $flyoutTitle;
+
+ /**
+ * Notification title data for bundling ( flyout and archive page )
+ */
+ protected $bundleTitle;
+
+ /**
+ * Notification email data
+ * @param array
+ */
+ protected $email;
+
+ /**
+ * Notification icon for each type
+ * @param string
+ */
+ protected $icon;
+
+ /**
+ * The language to format a message, default language
+ * is the current language
+ * @param mixed Language code or Language object
+ */
+ protected $language;
+
+ /**
+ * Required parameters
+ * @param array
+ */
+ protected $requiredParameters = array (
+ 'title-message'
+ );
+
+ /**
+ * Data for constructing bundle message, data in this array
+ * should be used in function processParams()
+ * @var array
+ */
+ protected $bundleData = array (
+ 'use-bundle' => false,
+ 'raw-data-count' => 1
+ );
+
+ /**
+ * Max number of raw bundle data to query for each bundle event
+ */
+ protected static $maxRawBundleData = 250;
+
+ /**
+ * @param array
+ */
+ public function __construct( $params ) {
+ parent::__construct( $params );
+
+ // Set up default params if any are missing
+ $params = $this->setDefaultParams( $params );
+
+ // Title for archive page
+ $this->title = array(
+ 'message' => $params['title-message'],
+ 'params' => $params['title-params']
+ );
+
+ // Title for the flyout
+ $this->flyoutTitle = array(
+ 'message' => $params['flyout-message'],
+ 'params' => $params['flyout-params']
+ );
+
+ // Bundle title for both archive page and flyout
+ $this->bundleTitle = array(
+ 'message' => $params['bundle-message'],
+ 'params' => $params['bundle-params']
+ );
+
+ // Notification payload data, eg, summary
+ $this->payload = $params['payload'];
+
+ // Notification email subject and body
+ $this->email = array(
+ 'subject' => array(
+ 'message' => $params['email-subject-message'],
+ 'params' => $params['email-subject-params']
+ ),
+ 'batch-body' => array(
+ 'message' => $params['email-body-batch-message'],
+ 'params' => $params['email-body-batch-params']
+ ),
+ 'batch-bundle-body' => array(
+ 'message' => $params['email-body-batch-bundle-message'],
+ 'params' => $params['email-body-batch-bundle-params']
+ )
+ );
+
+ // Notification icon for the event type
+ $this->icon = $params['icon'];
+ }
+
+ /**
+ * Internal function for setting notification default params
+ * @param $params array
+ * @return array
+ */
+ protected function setDefaultParams( $params ) {
+ $params += array(
+ 'title-params' => array(),
+ 'bundle-message' => '',
+ 'bundle-params' => array(),
+ 'payload' => array(),
+ 'email-subject-message' => 'echo-email-subject-default',
+ 'email-subject-params' => array(),
+ 'email-body-batch-message' => 'echo-email-batch-body-default',
+ 'email-body-batch-params' => array(),
+ 'email-body-batch-bundle-message' => '',
+ 'email-body-batch-bundle-params' => array(),
+ 'icon' => 'placeholder'
+ );
+
+ // default flyout-message to title-message if not defined
+ $params += array ( 'flyout-message' => $params['title-message'], 'flyout-params' => $params['title-params'] );
+
+ return $params;
+ }
+
+ /**
+ * Apply some custom change before formatting, child class overwriting this method
+ * should always invoke a call to the parent method unless child class wants to overwrite
+ * the default completely
+ *
+ * @param $event EchoEvent that the notification is for.
+ * @param $user User to format the notification for.
+ * @param $type string deprecated
+ */
+ protected function applyChangeBeforeFormatting( EchoEvent $event, User $user, $type ) {
+ // Use the bundle message if use-bundle is true and there is a bundle message
+ $this->generateBundleData( $event, $user, $type );
+ if ( $this->bundleData['use-bundle'] && $this->bundleTitle['message'] ) {
+ $this->title = $this->flyoutTitle = $this->bundleTitle;
+ }
+ }
+
+ /**
+ * Formats a notification
+ *
+ * @param $event EchoEvent that the notification is for.
+ * @param $user User to format the notification for.
+ * @param $type string The type of notification being distributed (e.g. email, web)
+ * @return array|string
+ */
+ public function format( $event, $user, $type ) {
+ global $wgExtensionAssetsPath, $wgEchoNotificationIcons, $wgLang;
+
+ $this->setDistributionType( $type );
+ $this->applyChangeBeforeFormatting( $event, $user, $type );
+
+ if ( $this->outputFormat === 'email' ) {
+ return $this->formatEmail( $event, $user, $type );
+ }
+
+ if ( $this->outputFormat === 'text' ) {
+ return $this->formatNotificationTitle( $event, $user )->text();
+ }
+
+ $iconInfo = $wgEchoNotificationIcons[$this->icon];
+ if ( isset( $iconInfo['url'] ) && $iconInfo['url'] ) {
+ $iconUrl = $iconInfo['url'];
+ } else {
+ if ( !isset( $iconInfo['path'] ) || !$iconInfo['path'] ) {
+ // Fallback in case icon is not configured; mainly intended for 'site'
+ $iconInfo = $wgEchoNotificationIcons['placeholder'];
+ }
+ if ( is_array( $iconInfo['path'] ) ) {
+ $dir = $wgLang->getDir();
+ if ( isset( $iconInfo['path'][$dir] ) ) {
+ $path = $iconInfo['path'][$dir];
+ } else {
+ wfDebugLog( 'Echo', "The \"{$this->icon}\" icon does not have anything set for $dir direction." );
+ $path = $wgEchoNotificationIcons['placeholder']['path']; // Fallback
+ }
+ } else {
+ $path = $iconInfo['path'];
+ }
+ $iconUrl = "$wgExtensionAssetsPath/$path";
+ }
+
+ // Assume html as the format for the notification
+ $output = Html::element(
+ 'img',
+ array(
+ 'class' => "mw-echo-icon",
+ 'src' => $iconUrl,
+ )
+ );
+
+ // Build the notification title
+ $content = Xml::tags(
+ 'div',
+ array( 'class' => 'mw-echo-title' ),
+ $this->formatNotificationTitle( $event, $user )->parse()
+ ) . "\n";
+
+ // Build the notification payload
+ $payload = '';
+ foreach ( $this->payload as $payloadComponent ) {
+ $payload .= $this->formatPayload( $payloadComponent, $event, $user );
+ }
+
+ if ( $payload !== '' ) {
+ $content .= Xml::tags( 'div', array( 'class' => 'mw-echo-payload' ), $payload ) . "\n";
+ }
+
+ // Add footer (timestamp and secondary link)
+ $content .= $this->formatFooter( $event, $user );
+
+ // Add the primary link (hidden)
+ if ( $this->outputFormat === 'flyout' ) {
+ $content .= $this->getLink( $event, $user, 'primary' );
+ }
+
+ $output .= Xml::tags( 'div', array( 'class' => 'mw-echo-content' ), $content ) . "\n";
+
+ // The state div is used to visually indicate read or unread status. This is
+ // handled in a separate element than the notification element so that things
+ // like the close box won't inherit the greyed out opacity (which can't be reset).
+ $output = Xml::tags( 'div', array( 'class' => 'mw-echo-state' ), $output ) . "\n";
+
+ return $output;
+ }
+
+ /**
+ * @param $event EchoEvent
+ * @param $user User
+ * @return string
+ */
+ protected function formatNotificationTitle( $event, $user ) {
+ if ( $this->outputFormat === 'flyout' ) {
+ return $this->formatFragment( $this->flyoutTitle, $event, $user );
+ } else {
+ return $this->formatFragment( $this->title, $event, $user );
+ }
+ }
+
+ /**
+ * Create text version and/or html version for email notification
+ *
+ * @param $event EchoEvent
+ * @param $user User
+ * @param $type string deprecated
+ * @return array
+ */
+ protected function formatEmail( $event, $user, $type ) {
+ // Email should be always sent in user language
+ $this->language = $user->getOption( 'language' );
+
+ // Email digest
+ if ( $this->distributionType === 'emaildigest' ) {
+ return $this->formatEmailDigest( $event, $user );
+ }
+
+ // Echo single email
+ $emailSingle = new EchoEmailSingle( $this, $event, $user );
+ $textEmailFormatter = new EchoTextEmailFormatter( $emailSingle );
+ // Update the distribution type to emailsubject when formatting
+ // email subject
+ // @FIXME - Find a better way to do this
+ $distributionType = $this->distributionType;
+ $this->setDistributionType( 'emailsubject' );
+ $subject = $this->formatFragment( $this->email['subject'], $event, $user )->text();
+ $this->setDistributionType( $distributionType );
+
+ $content = array(
+ // Single email subject, there is no need to to escape it for either html
+ // or text email since it's always treated as plain text by mail client
+ 'subject' => $subject,
+ // Single email text body
+ 'body' => $textEmailFormatter->formatEmail(),
+ );
+
+ $format = MWEchoNotifUser::newFromUser( $user )->getEmailFormat();
+ if ( $format == EchoHooks::EMAIL_FORMAT_HTML ) {
+ $htmlEmailFormatter = new EchoHTMLEmailFormatter( $emailSingle );
+ $outputFormat = $this->outputFormat;
+ $this->setOutputFormat( 'htmlemail' );
+ // Add single email html body if user prefers html format
+ $content['body'] = array (
+ 'text' => $content['body'],
+ 'html' => $htmlEmailFormatter->formatEmail()
+ );
+ $this->setOutputFormat( $outputFormat );
+ }
+
+ return $content;
+ }
+
+ /**
+ * Format text and/or html verion of email digest fragment for this event
+ * @param $event EchoEvent
+ * @param $user User
+ * @return array
+ */
+ protected function formatEmailDigest( $event, $user ) {
+ if ( $this->bundleData['use-bundle'] && $this->email['batch-bundle-body'] ) {
+ $key = $this->email['batch-bundle-body'];
+ } else {
+ $key = $this->email['batch-body'];
+ }
+
+ // Email digest text body
+ $content = array( 'batch-body' => $this->formatFragment( $key, $event, $user )->text() );
+ $format = MWEchoNotifUser::newFromUser( $user )->getEmailFormat();
+ if ( $format == EchoHooks::EMAIL_FORMAT_HTML ) {
+ $outputFormat = $this->outputFormat;
+ $this->setOutputFormat( 'htmlemail' );
+ $content['batch-body-html'] = $this->formatFragment( $key, $event, $user )->parse();
+ $content['icon'] = $this->icon;
+ $this->setOutputFormat( $outputFormat );
+ }
+ return $content;
+ }
+
+ /**
+ * Get Message object in the desired language, use this method instead
+ * of wfMessage() if a message would be used in either web or email
+ * @param $msgStr string message string
+ * @return Message
+ */
+ public function getMessage( $msgStr ) {
+ $message = wfMessage( $msgStr );
+ if ( $this->language ) {
+ $message->inLanguage( $this->language );
+ }
+ return $message;
+ }
+
+ /**
+ * Creates a notification fragment based on a message and parameters
+ *
+ * @param $details array An i18n message and parameters to pass to the message
+ * @param $event EchoEvent that the notification is for.
+ * @param $user User to format the notification for.
+ * @return Message
+ */
+ public function formatFragment( $details, $event, $user ) {
+ $message = $this->getMessage( $details['message'] );
+ $this->processParams( $details['params'], $event, $message, $user );
+
+ return $message;
+ }
+
+ /**
+ * Formats the payload of a notification, child method overwriting this method should
+ * always call this method in default case so they can use the payload defined in this
+ * function as well
+ * @param $payload string
+ * @param $event EchoEvent
+ * @param $user User
+ * @return string
+ */
+ protected function formatPayload( $payload, $event, $user ) {
+ switch ( $payload ) {
+ case 'summary':
+ $revisionSnippet = $this->getRevisionSnippet( $event, $user );
+ if ( $revisionSnippet ) {
+ return Xml::tags(
+ 'div',
+ array( 'class' => 'mw-echo-edit-summary' ),
+ Xml::tags(
+ 'span', array( 'class' => 'comment' ),
+ htmlspecialchars( $revisionSnippet )
+ )
+ );
+ } else {
+ return '';
+ }
+ break;
+ case 'comment-text':
+ return $this->formatCommentText( $event, $user );
+ break;
+ default:
+ return '';
+ }
+ }
+
+ /**
+ * Extract the comment left by a user on a talk page from the event.
+ * @param $event EchoEvent The event to format the comment of
+ * @param $user User The user to format content for
+ * @return string Up to the first 200 characters of the comment
+ */
+ protected function formatCommentText( EchoEvent $event, $user ) {
+ if ( !$event->userCan( Revision::DELETED_TEXT, $user ) ) {
+ return $this->getMessage( 'echo-rev-deleted-text-view' )->text();
+ }
+ $extra = $event->getExtra();
+ if ( !isset( $extra['content'] ) ) {
+ return '';
+ }
+ $content = EchoDiscussionParser::stripHeader( $extra['content'] );
+ $content = EchoDiscussionParser::stripSignature( $content );
+ $content = EchoDiscussionParser::stripIndents( $content );
+ return EchoDiscussionParser::getTextSnippet( $content, 200 );
+ }
+
+ /**
+ * Extract the subject anchor (linkable portion of the edited page) from
+ * the event.
+ *
+ * @param $event EchoEvent The event to format the subject anchor of
+ * @return string The anchor on page, or an empty string
+ */
+ protected function formatSubjectAnchor( EchoEvent $event ) {
+ global $wgParser, $wgUser;
+
+ if ( !$event->userCan( Revision::DELETED_TEXT, $wgUser ) ) {
+ return $this->getMessage( 'echo-rev-deleted-text-view' )->text();
+ }
+ $extra = $event->getExtra();
+ if ( empty( $extra['section-title'] ) ) {
+ return '';
+ }
+
+ // Strip out #, keeping # in the i18n message makes it look more clear
+ return substr( $wgParser->guessLegacySectionNameFromWikiText( $extra['section-title'] ), 1 );
+ }
+
+ /**
+ * Build the footer for the notification (timestamp and secondary link)
+ * @param EchoEvent $event
+ * @param User $user The user to format the notification for.
+ * @return String HTML
+ */
+ protected function formatFooter( $event, $user ) {
+ global $wgLang;
+
+ // Default footer is timestamp
+ $footer = $this->formatTimestamp( $event->getTimestamp() );
+ $secondaryLink = $this->getLink( $event, $user, 'secondary' );
+ if ( $secondaryLink ) {
+ $footer = $wgLang->pipeList( array( $footer, $secondaryLink ) );
+ }
+ return Xml::tags( 'div', array( 'class' => 'mw-echo-notification-footer' ), $footer ) . "\n";
+ }
+
+ /**
+ * Generate links based on output format and passed properties
+ * $event EchoEvent
+ * $message Message
+ * $props array
+ */
+ protected function setTitleLink( $event, $message, $props = array() ) {
+ $title = $event->getTitle();
+ if ( !$title ) {
+ $message->params( $this->getMessage( 'echo-no-title' )->text() );
+ return;
+ }
+
+ if ( !isset( $props['fragment'] ) ) {
+ $props['fragment'] = $this->formatSubjectAnchor( $event );
+ }
+
+ $link = $this->buildLinkParam( $title, $props );
+ $message->params( $link );
+ }
+
+ /**
+ * Build a link, to be used as message parameter, based on output format and
+ * passed properties. Return value of this function can be used as parameter
+ * for Message::params()
+ * $title Title
+ * $props array
+ */
+ protected function buildLinkParam( $title, $props = array() ) {
+ $param = array();
+ if ( isset( $props['param'] ) ) {
+ $param = (array)$props['param'];
+ }
+
+ if ( isset( $props['fragment'] ) ) {
+ $fragment = $props['fragment'];
+ $title->setFragment( "#$fragment" );
+ }
+
+ if ( in_array( $this->outputFormat, array( 'html', 'flyout', 'htmlemail' ) ) ) {
+ $attribs = array();
+ if ( isset( $props['attribs'] ) ) {
+ $attribs = (array)$props['attribs'];
+ }
+
+ if ( isset( $props['linkText'] ) ) {
+ $linkText = $props['linkText'];
+ } else {
+ $linkText = htmlspecialchars( $title->getPrefixedText() );
+ }
+
+ $options = array();
+ if ( $this->outputFormat === 'htmlemail' ) {
+ $options = array( 'https' );
+ }
+
+ return array( Message::rawParam( Linker::link( $title, $linkText, $attribs, $param, $options ) ) );
+ } elseif ( $this->outputFormat === 'email' ) {
+ $url = $title->getFullURL( $param, false, PROTO_HTTPS );
+ return $this->sanitizeEmailLink( $url );
+ } else {
+ return $title->getFullURL( $param );
+ }
+ }
+
+ /**
+ * Plain text email in some mail client is misinterpreting the ending
+ * punctuation, this function would encode the last character
+ *
+ * @param $url string
+ *
+ * @return string
+ */
+ public function sanitizeEmailLink( $url ) {
+ // $url should contain all ascii characters now, it's safe to use substr()
+ $lastChar = substr( $url, -1 );
+ if ( $lastChar && !ctype_alnum( $lastChar ) ) {
+ $lastChar = str_replace(
+ array( '.', '-', '(', ';', '!', ':', ',' ),
+ array( '%2E', '%2D', '%28', '%3B', '%21', '%3A', '%2C' ),
+ $lastChar
+ );
+ $url = substr( $url, 0, -1 ) . $lastChar;
+ }
+ return $url;
+ }
+
+ /**
+ * Get raw bundle data for an event so it can be manipulated
+ * @param EchoEvent
+ * @param User
+ * @param string deprecated
+ * @return EchoEvent[]|bool
+ */
+ protected function getRawBundleData( $event, $user, $type ) {
+ // We should keep bundling for events as long as it has bundle hash
+ // even for events with bundling switched to off, this is mainly for
+ // historical data
+ if ( !$event->getBundleHash() ) {
+ return false;
+ }
+
+ $eventMapper = new EchoEventMapper();
+ $events = $eventMapper->fetchByUserBundleHash(
+ $user, $event->getBundleHash(), $this->distributionType, 'DESC', self::$maxRawBundleData
+ );
+
+ if ( $events ) {
+ $this->bundleData['raw-data-count'] += count( $events );
+ // Distribution types other than web include the base event
+ // in the result already, decrement it by one
+ if ( $this->distributionType !== 'web' ) {
+ $this->bundleData['raw-data-count']--;
+ }
+ }
+
+ return $events;
+ }
+
+ /**
+ * Construct the bundle data for an event, by default, the group iterator
+ * is agent, eg, by user A and x others. custom formatter can overwrite
+ * this function to use a differnt group iterator such as title, namespace
+ *
+ * @param EchoEvent
+ * @param User
+ * @param string deprecated
+ * @throws MWException
+ */
+ protected function generateBundleData( $event, $user, $type ) {
+ $data = $this->getRawBundleData( $event, $user, $type );
+
+ // Default the last raw data to false, which means there is no
+ // bundle data other than the base
+ $this->bundleData['last-raw-data'] = false;
+
+ if ( !$data ) {
+ return;
+ }
+
+ $agents = array();
+ $agent = $event->getAgent();
+ if ( $agent ) {
+ if ( $agent->isAnon() ) {
+ $agents[$agent->getName()] = $agent->getName();
+ } else {
+ $agents[$agent->getId()] = $agent->getId();
+ }
+ } else {
+ throw new MWException( "Agent is required for bundling notification!" );
+ }
+
+ // Initialize with 1 for the agent of current event
+ $count = 1;
+ foreach ( $data as $evt ) {
+ if ( $evt->getAgent() ) {
+ if ( $evt->getAgent()->isAnon() ) {
+ $key = $evt->getAgent()->getName();
+ } else {
+ $key = $evt->getAgent()->getId();
+ }
+ if ( !isset( $agents[$key] ) ) {
+ $agents[$key] = $key;
+ $count++;
+ }
+ }
+ $this->bundleData['last-raw-data'] = $evt;
+ }
+
+ $this->bundleData['agent-other-count'] = $count - 1;
+ if ( $count > 1 ) {
+ $this->bundleData['use-bundle'] = true;
+ }
+
+ // If there is more raw data than we requested, that means we have not
+ // retrieved the very last raw record, set the key back to null
+ if ( count( $data ) >= self::$maxRawBundleData ) {
+ $this->bundleData['last-raw-data'] = null;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function getBundleData() {
+ return $this->bundleData;
+ }
+
+ /**
+ * Convert the parameters into real values and pass them into the message
+ *
+ * @param $params array
+ * @param $event EchoEvent
+ * @param $message Message
+ * @param $user User
+ */
+ protected function processParams( $params, $event, $message, $user ) {
+ foreach ( $params as $param ) {
+ $this->processParam( $event, $param, $message, $user );
+ }
+ }
+
+ /**
+ * Process a parameter that should be escaped for display except for use
+ * cases like plain text email and email subject
+ *
+ * @param $message Message
+ * @param $paramContent string
+ */
+ protected function processParamEscaped( $message, $paramContent ) {
+ // Plain text email and email subject do not need to be escaped
+ if ( $this->outputFormat !== 'email' && $this->distributionType !== 'emailsubject' ) {
+ $paramContent = htmlspecialchars( $paramContent );
+ }
+
+ $message->rawParams( $paramContent );
+ }
+
+ /**
+ * Get the URL for the primary or secondary link for an event
+ *
+ * @param EchoEvent $event
+ * @param User $user The user receiving the notification
+ * @param String $rank 'primary' or 'secondary' (default is 'primary')
+ * @param boolean $local True to return a local (relative) URL, false to
+ * return a full URL (for email for example) (default is true)
+ * @param boolean $urlOnly True to return only the URL without the <a> tag,
+ * false to return a full anchor link (default is false)
+ * @param String $style A style attribute to apply to the anchor, e.g.
+ * 'border: 1px solid green; text-decoration: none;' (optional)
+ * @return String URL for link, or HTML for anchor tag, or empty string
+ */
+ public function getLink( $event, $user, $rank = 'primary', $local = true, $urlOnly = false, $style = '' ) {
+ $destination = $event->getLinkDestination( $rank );
+ if ( !$destination ) {
+ return '';
+ }
+
+ // Get link parameters based on the destination
+ list( $target, $query ) = $this->getLinkParams( $event, $user, $destination );
+ // Note that $target can be a Title object or a raw url
+ if ( !$target ) {
+ return '';
+ }
+ if ( $urlOnly ) {
+ if ( is_string( $target ) ) {
+ // A raw url was passed back
+ return $target;
+ }
+ if ( $local ) {
+ return $target->getLinkURL( $query );
+ } else {
+ return $target->getFullURL( $query, false, PROTO_HTTPS );
+ }
+ } else {
+ $message = $this->getMessage( $event->getLinkMessage( $rank ) )->text();
+ $attribs = array( 'class' => "mw-echo-notification-{$rank}-link" );
+ if ( $style ) {
+ $attribs['style'] = $style;
+ }
+ $options = array();
+ // If local is false, return an absolute url using HTTP protocol
+ if ( !$local ) {
+ $options[] = 'https';
+ }
+ if ( is_string( $target ) ) {
+ $attribs['href'] = wfAppendQuery( $target, $query );
+ return Html::element( 'a', $attribs, $message );
+ } else {
+ return Linker::link( $target, $message, $attribs, $query, $options );
+ }
+
+ }
+ }
+
+ /**
+ * Helper function for getLink()
+ *
+ * @param EchoEvent $event
+ * @param User $user The user receiving the notification
+ * @param String $destination The destination type for the link, e.g. 'agent'
+ * @return Array including target and query parameters. Note that target can
+ * be either a Title or a full url
+ */
+ protected function getLinkParams( $event, $user, $destination ) {
+ $target = null;
+ $query = array();
+ $title = $event->getTitle();
+ // Set up link parameters based on the destination
+ switch ( $destination ) {
+ case 'agent':
+ if ( $event->getAgent() ) {
+ $target = $event->getAgent()->getUserPage();
+ }
+ break;
+ case 'title':
+ $target = $title;
+ break;
+ case 'section':
+ $target = $title;
+ if ( $target ) {
+ $fragment = $this->formatSubjectAnchor( $event );
+ if ( $fragment ) {
+ $target->setFragment( "#$fragment" );
+ }
+ }
+ break;
+ case 'diff':
+ $eventData = $event->getExtra();
+ if ( isset( $eventData['revid'] ) && $title ) {
+ $target = $title;
+ // Explicitly set fragment to empty string for diff links, $title is
+ // passed around by reference, it may end up using fragment set from
+ // other parameters
+ $target->setFragment( '#' );
+ $query = array(
+ 'oldid' => 'prev',
+ 'diff' => $eventData['revid'],
+ );
+
+ $data = $this->getBundleLastRawData( $event, $user );
+ if ( $data ) {
+ $extra = $data->getExtra();
+ if ( isset( $extra['revid'] ) ) {
+ $oldId = $target->getPreviousRevisionID( $extra['revid'] );
+ // The diff engine doesn't provide a way to diff against a null revision.
+ // In this case, just fall back old id to the first revision
+ if ( !$oldId ) {
+ $oldId = $extra['revid'];
+ }
+ if ( $oldId < $eventData['revid'] ) {
+ $query['oldid'] = $oldId;
+ }
+ }
+ }
+ }
+ break;
+ }
+ return array( $target, $query );
+ }
+
+ /**
+ * Get the last echo event in a set of bundling data. When bundling notifications,
+ * we mostly only need the very first notification, which is the bundle base.
+ * In some cases, like talk notification diff, Flow notificaiton first unread post,
+ * we need data from the very last notification.
+ *
+ * @param EchoEvent
+ * @param User
+ * @return EchoEvent|boolean false for none
+ */
+ protected function getBundleLastRawData( EchoEvent $event, User $user ) {
+ if ( $event->getBundleHash() ) {
+ // First try cache data from preivous query
+ if ( isset( $this->bundleData['last-raw-data'] ) ) {
+ $data = $this->bundleData['last-raw-data'];
+ // Then try to query the storage
+ } else {
+ $eventMapper = new EchoEventMapper();
+ $data = $eventMapper->fetchByUserBundleHash(
+ $user, $event->getBundleHash(), $this->distributionType, 'ASC', 1
+ );
+ if ( $data ) {
+ $data = reset( $data );
+ }
+ }
+
+ if ( $data ) {
+ return $data;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the style for standard links in html email
+ * @return string
+ */
+ public function getHTMLLinkStyle() {
+ return 'text-decoration: none; color: #3A68B0;';
+ }
+
+ /**
+ * Helper function for processParams()
+ *
+ * @param $event EchoEvent
+ * @param $param string
+ * @param $message Message
+ * @param $user User
+ * @throws MWException
+ */
+ protected function processParam( $event, $param, $message, $user ) {
+ if ( $param === 'agent' ) {
+ $agent = $event->getAgent();
+ if ( !$agent ) {
+ $message->params( $this->getMessage( 'echo-no-agent' )->text() );
+ } elseif ( !$event->userCan( Revision::DELETED_USER, $user ) ) {
+ $message->params( $this->getMessage( 'rev-deleted-user' )->text() );
+ } else {
+ if ( $this->outputFormat === 'htmlemail' ) {
+ $message->rawParams(
+ Linker::link(
+ $agent->getUserPage(),
+ $agent->getName(),
+ array( 'style' => $this->getHTMLLinkStyle() ),
+ array(),
+ array( 'https' )
+ )
+ );
+ } else {
+ $message->params( $agent->getName() );
+ }
+ }
+ // example: {7} others, {99+} others
+ } elseif ( $param === 'agent-other-display' ) {
+ global $wgEchoMaxNotificationCount;
+
+ if ( $this->bundleData['agent-other-count'] > $wgEchoMaxNotificationCount ) {
+ $message->params(
+ $this->getMessage( 'echo-notification-count' )
+ ->numParams( $wgEchoMaxNotificationCount )
+ ->text()
+ );
+ } else {
+ $message->numParams( $this->bundleData['agent-other-count'] );
+ }
+ // the number used for plural support
+ } elseif ( $param === 'agent-other-count' ) {
+ $message->params( $this->bundleData['agent-other-count'] );
+ } elseif ( $param === 'user' ) {
+ $message->params( $user->getName() );
+ } elseif ( $param === 'title' ) {
+ $title = $event->getTitle();
+ if ( !$title ) {
+ $message->params( $this->getMessage( 'echo-no-title' )->text() );
+ } else {
+ if ( $this->outputFormat === 'htmlemail' ) {
+ $props = array (
+ 'attribs' => array( 'style' => $this->getHTMLLinkStyle() )
+ );
+ $this->setTitleLink( $event, $message, $props );
+ } else {
+ $message->params( $this->formatTitle( $title ) );
+ }
+ }
+ } elseif ( $param === 'titlelink' ) {
+ $this->setTitleLink( $event, $message );
+ } elseif ( $param === 'text-notification' ) {
+ $oldOutputFormat = $this->outputFormat;
+ $this->setOutputFormat( 'text' );
+ // $type is ignored in this class
+ $textNotification = $this->format( $event, $user, '' );
+ $this->setOutputFormat( $oldOutputFormat );
+
+ $message->params( $textNotification );
+ } else {
+ throw new MWException( "Unrecognised parameter $param" );
+ }
+ }
+
+ /**
+ * Getter method
+ *
+ * @param $key string
+ *
+ * @throws MWException
+ * @return mixed
+ */
+ public function getValue( $key ) {
+ if ( !property_exists( $this, $key ) ) {
+ throw new MWException( "Call to non-existing property $key in " . get_class( $this ) );
+ }
+ return $this->$key;
+ }
+
+}
diff --git a/Echo/formatters/CommentFormatter.php b/Echo/formatters/CommentFormatter.php
new file mode 100644
index 00000000..c789d524
--- /dev/null
+++ b/Echo/formatters/CommentFormatter.php
@@ -0,0 +1,34 @@
+<?php
+
+class EchoCommentFormatter extends EchoEditFormatter {
+ public function __construct( $params ) {
+ parent::__construct( $params );
+ }
+
+ /**
+ * @param EchoEvent $event
+ * @param $param
+ * @param Message $message
+ * @param User $user
+ */
+ protected function processParam( $event, $param, $message, $user ) {
+ if ( $param === 'content-page' ) {
+ if ( $event->getTitle() ) {
+ $message->params( $event->getTitle()->getSubjectPage()->getPrefixedText() );
+ } else {
+ $message->params( '' );
+ }
+ } elseif ( $param === 'subject-link' ) {
+ $this->setTitleLink( $event, $message );
+ // The title text without namespace
+ } elseif ( $param === 'main-title-text' ) {
+ if ( !$event->getTitle() ) {
+ $message->params( $this->getMessage( 'echo-no-title' )->text() );
+ } else {
+ $message->params( $event->getTitle()->getText() );
+ }
+ } else {
+ parent::processParam( $event, $param, $message, $user );
+ }
+ }
+}
diff --git a/Echo/formatters/EditFormatter.php b/Echo/formatters/EditFormatter.php
new file mode 100644
index 00000000..f2826ef2
--- /dev/null
+++ b/Echo/formatters/EditFormatter.php
@@ -0,0 +1,75 @@
+<?php
+
+class EchoEditFormatter extends EchoBasicFormatter {
+
+ /**
+ * @param EchoEvent $event
+ * @param $param
+ * @param $message Message
+ * @param $user User
+ */
+ protected function processParam( $event, $param, $message, $user ) {
+ if ( $param === 'subject-anchor' ) {
+ $message->params( $this->formatSubjectAnchor( $event ) );
+ } elseif ( $param === 'section-title' ) {
+ $message->params( $this->getSectionTitle( $event, $user ) );
+ } elseif ( $param === 'difflink' ) {
+ $revid = $event->getExtraParam( 'revid' );
+ if ( !$revid ) {
+ $message->params( '' );
+ return;
+ }
+ $diff = $event->getExtraParam( 'diffid', 'prev' );
+ $props = array(
+ 'attribs' => array( 'class' => 'mw-echo-diff' ),
+ 'linkText' => $this->getMessage( 'parentheses' )
+ ->params(
+ $this->getMessage( 'showdiff' )->text()
+ )->escaped(),
+ 'param' => array(
+ 'oldid' => $revid,
+ 'diff' => $diff,
+ ),
+ // Set fragment to empty string for diff links
+ 'fragment' => ''
+ );
+ $this->setTitleLink( $event, $message, $props );
+ } elseif ( $param === 'summary' ) {
+ $message->params( $this->getRevisionSnippet( $event, $user ) );
+ } elseif ( $param === 'number' ) {
+ $eventData = $event->getExtra();
+ // The folliwing is a bit of a hack...
+ // If the edit is a rollback, we want to say 'your edits' in the
+ // notification. If the edit is an undo, we want to say 'your edit'
+ // in the notification. To accomplish this, we pass a 'number' param
+ // to the message which is set to 1 or 2 and formatted with {{PLURAL}}.
+ if ( isset( $eventData['method'] ) && $eventData['method'] === 'rollback' ) {
+ $message->params( 2 );
+ } else {
+ $message->params( 1 );
+ }
+ } else {
+ parent::processParam( $event, $param, $message, $user );
+ }
+ }
+
+ /**
+ * Get the section title for a talk page post
+ * @param $event EchoEvent
+ * @param $user User
+ * @return string
+ */
+ protected function getSectionTitle( $event, $user ) {
+ $extra = $event->getExtra();
+
+ if ( !empty( $extra['section-title'] ) ) {
+ if ( $event->userCan( Revision::DELETED_TEXT, $user ) ) {
+ return EchoDiscussionParser::getTextSnippet( $extra['section-title'], 30 );
+ } else {
+ return $this->getMessage( 'echo-rev-deleted-text-view' )->text();
+ }
+ }
+
+ return '';
+ }
+}
diff --git a/Echo/formatters/EditUserTalkFormatter.php b/Echo/formatters/EditUserTalkFormatter.php
new file mode 100644
index 00000000..2b5aaa24
--- /dev/null
+++ b/Echo/formatters/EditUserTalkFormatter.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Custom formatter for 'edit-user-talk' notifications
+ */
+class EchoEditUserTalkFormatter extends EchoEditFormatter {
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function applyChangeBeforeFormatting( EchoEvent $event, User $user, $type ) {
+ parent::applyChangeBeforeFormatting( $event, $user, $type );
+
+ // Replace default generic notification message with 'Someone left a message
+ // on your talk page in "xxxx"' if
+ // * the message is not bundled and
+ // * there is a section title
+ //
+ // We could go with the approach of creating a new notification type, but
+ // * this is variant is too small to introduce a new type
+ // * may not fall back to default for talk page post with oversighted content
+ // * message bundling is supposed to bundle the same notfication type, creating
+ // a new type will not be able to bundle them together
+ if ( !$this->bundleData['use-bundle'] && $this->getSectionTitle( $event, $user ) ) {
+ $this->title = array(
+ 'message' => 'notification-edit-talk-page-with-section',
+ 'params' => array( 'agent', 'user', 'subject-anchor', 'section-title' )
+ );
+ $this->flyoutTitle = array(
+ 'message' => 'notification-edit-talk-page-flyout-with-section',
+ 'params' => array( 'agent', 'user', 'subject-anchor', 'section-title' )
+ );
+ $this->email['batch-body'] = array(
+ 'message' => 'notification-edit-talk-page-email-batch-body-with-section',
+ 'params' => array( 'agent', 'section-title' )
+ );
+ // Display the summary if there is a section title
+ $this->payload = array( 'summary' );
+ }
+ }
+
+}
diff --git a/Echo/formatters/MentionFormatter.php b/Echo/formatters/MentionFormatter.php
new file mode 100644
index 00000000..2bd98ae2
--- /dev/null
+++ b/Echo/formatters/MentionFormatter.php
@@ -0,0 +1,27 @@
+<?php
+
+class EchoMentionFormatter extends EchoCommentFormatter {
+ /**
+ * {@inheritDoc}
+ */
+ protected function applyChangeBeforeFormatting( EchoEvent $event, User $user, $type ) {
+ parent::applyChangeBeforeFormatting( $event, $user, $type );
+
+ // If we can't find a section title for the mention,
+ // fall back to `notification-mention-nosection`.
+ if ( !$this->getSectionTitle( $event, $user ) ) {
+ $this->title = array(
+ 'message' => 'notification-mention-nosection',
+ 'params' => array( 'agent', 'main-title-text', 'title' )
+ );
+ $this->flyoutTitle = array(
+ 'message' => 'notification-mention-nosection-flyout',
+ 'params' => array( 'agent', 'main-title-text', 'title' )
+ );
+ $this->email['batch-body'] = array(
+ 'message' => 'notification-mention-nosection-email-batch-body',
+ 'params' => array( 'agent', 'main-title-text' )
+ );
+ }
+ }
+}
diff --git a/Echo/formatters/NotificationFormatter.php b/Echo/formatters/NotificationFormatter.php
new file mode 100644
index 00000000..2604ea36
--- /dev/null
+++ b/Echo/formatters/NotificationFormatter.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * Abstract class for constructing a notification message, this class includes
+ * only the most generic formatting functionality as it may be extended by
+ * notification formatters for other extensions with unique content or
+ * requirements.
+ */
+abstract class EchoNotificationFormatter {
+
+ /**
+ * List of valid output format
+ * @var array
+ */
+ protected $validOutputFormats = array( 'text', 'flyout', 'html', 'email', 'htmlemail' );
+
+ /**
+ * List of valid distribution type
+ */
+ protected $validDistributionType = array( 'web', 'email', 'emaildigest', 'emailsubject' );
+
+ /**
+ * Current output format, default is 'text'
+ * @var string
+ */
+ protected $outputFormat = 'text';
+
+ /**
+ * Distribution type, default is 'web'
+ * @var string
+ */
+ protected $distributionType = 'web';
+
+ /**
+ * List of parameters for constructing messages
+ * @var array
+ */
+ protected $parameters;
+
+ /**
+ * List of parameters that must exist in $this->$parameters
+ */
+ protected $requiredParameters = array();
+
+ /**
+ * Creates an instance of the given class with the given parameters.
+ * @param $parameters array Associative array of parameters
+ * @throws MWException
+ */
+ public function __construct( array $parameters ) {
+ $this->parameters = $parameters;
+
+ $missingParameters = array_diff( $this->requiredParameters, array_keys( $parameters ) );
+
+ if ( $missingParameters ) {
+ throw new MWException(
+ "Missing required parameters for " .
+ get_class( $this ) . ":" .
+ implode( " ", $missingParameters )
+ );
+ }
+ }
+
+ /**
+ * Shows a notification in human-readable format.
+ * @param $event EchoEvent being notified about.
+ * @param $user User being notified.
+ * @param $type string The notification type (e.g. notify, email)
+ * @return Mixed; depends on output format
+ * @see EchoNotificationFormatter::setOutputFormat
+ */
+ public abstract function format( $event, $user, $type );
+
+ /**
+ * Set the output format that the notification will be displayed in.
+ * @param $format string A valid output format (by default, 'text', 'html', 'flyout', and 'email' are allowed)
+ * @throws MWException
+ */
+ public function setOutputFormat( $format ) {
+ if ( !in_array( $format, $this->validOutputFormats, true ) ) {
+ throw new MWException( "Invalid output format $format" );
+ }
+
+ $this->outputFormat = $format;
+ }
+
+ public function setDistributionType( $type ) {
+ if ( !in_array( $type, $this->validDistributionType, true ) ) {
+ throw new Exception( "Invalid distribution type $type" );
+ }
+
+ $this->distributionType = $type;
+ }
+
+ /**
+ * Create an EchoNotificationFormatter from the supplied parameters.
+ * @param $parameters array Associative array.
+ * Select the class of formatter to use with the 'class' field.
+ * For other parameters, see the appropriate class' constructor.
+ * @throws MWException
+ * @return EchoNotificationFormatter object.
+ */
+ public static function factory( $parameters ) {
+ $class = null;
+ if ( isset( $parameters['formatter-class'] ) ) {
+ $class = $parameters['formatter-class'];
+ }
+
+ // Default to basic formatter
+ if ( !$class || !class_exists( $class ) ) {
+ $class = 'EchoBasicFormatter';
+ }
+
+ return new $class( $parameters );
+ }
+
+ /**
+ * Returns a link to a title, or the title itself.
+ * @param $title Title object
+ * @return string Text suitable for output format
+ */
+ protected function formatTitle( Title $title ) {
+ return $title->getPrefixedText();
+ }
+
+ /**
+ * Formats a timestamp in a human-readable format
+ * @param $ts string Timestamp in some format compatible with wfTimestamp()
+ * @return string Human-readable timestamp
+ */
+ protected function formatTimestamp( $ts ) {
+ $timestamp = new MWTimestamp( $ts );
+ $ts = $timestamp->getHumanTimestamp();
+ return $ts;
+ }
+
+ /**
+ * Returns a revision snippet
+ * @param EchoEvent $event The event that the notification is for.
+ * @param User $user The user to format the notification for.
+ * @return String The revision snippet (or empty string)
+ */
+ public function getRevisionSnippet( $event, $user ) {
+ $extra = $event->getExtra();
+ if ( !isset( $extra['section-text'] ) || !$event->userCan( Revision::DELETED_TEXT, $user ) ) {
+ return '';
+ }
+
+ $snippet = trim( $extra['section-text'] );
+
+ return $snippet;
+ }
+
+}
diff --git a/Echo/formatters/PageLinkFormatter.php b/Echo/formatters/PageLinkFormatter.php
new file mode 100644
index 00000000..80fbc456
--- /dev/null
+++ b/Echo/formatters/PageLinkFormatter.php
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * Custom formatter for 'page-link' notifications
+ */
+class EchoPageLinkFormatter extends EchoBasicFormatter {
+
+ /**
+ * This is a workaround for backwards compatibility.
+ * In https://gerrit.wikimedia.org/r/#/c/63076 we changed
+ * the schema to save link-from-page-id instead of
+ * link-from-namespace & link-from-title
+ */
+ protected function extractExtra( $extra ) {
+ if ( isset( $extra['link-from-namespace'], $extra['link-from-title'] )
+ && !isset( $extra['link-from-page-id'] )
+ ) {
+ $title = Title::makeTitleSafe(
+ $extra['link-from-namespace'],
+ $extra['link-from-title']
+ );
+ if ( $title ) {
+ $extra['link-from-page-id'] = $title->getArticleId();
+ unset(
+ $extra['link-from-namespace'],
+ $extra['link-from-title']
+ );
+ }
+ }
+
+ return $extra;
+ }
+
+ /**
+ * This method overwrite parent method and construct the bundle iterator
+ * based on link from, it will be used in a message like this: Page A was
+ * link from Page B and X other pages
+ *
+ * @param $event EchoEvent
+ * @param $user User
+ * @param $type string deprecated
+ */
+ protected function generateBundleData( $event, $user, $type ) {
+ global $wgEchoMaxNotificationCount;
+
+ $data = $this->getRawBundleData( $event, $user, $type );
+
+ if ( !$data ) {
+ return;
+ }
+ $extra = self::extractExtra( $event->getExtra() );
+
+ if ( !$this->isTitleSet( $extra ) ) {
+ // Link from title is required for bundling notification
+ return;
+ }
+
+ $count = 1;
+ $linkFrom = array(
+ $extra['link-from-page-id'] => true
+ );
+ foreach ( $data as $bundledEvent ) {
+ $extra = $bundledEvent->getExtra();
+ if ( !$extra ) {
+ continue;
+ }
+
+ if ( $this->isTitleSet( $extra ) ) {
+ $pageId = $extra['link-from-page-id'];
+
+ if ( !isset( $linkFrom[$pageId] ) ) {
+ $linkFrom[$pageId] = true;
+ $count++;
+ }
+ }
+ if ( $count > $wgEchoMaxNotificationCount + 1 ) {
+ break;
+ }
+ }
+
+ $this->bundleData['link-from-page-other-count'] = $count - 1;
+ if ( $count > 1 ) {
+ $this->bundleData['use-bundle'] = true;
+ }
+ }
+
+ /**
+ * Internal function to check if link from page id key is set
+ * @param $extra array
+ * @return bool
+ */
+ private function isTitleSet( $extra ) {
+ return isset( $extra['link-from-page-id'] ) && $extra['link-from-page-id'];
+ }
+
+ /**
+ * @param $event EchoEvent
+ * @param $param string
+ * @param $message Message
+ * @param $user User
+ */
+ protected function processParam( $event, $param, $message, $user ) {
+ $extra = self::extractExtra( $event->getExtra() );
+ switch ( $param ) {
+ // 'A' part in this message: link from page A and X others
+ case 'link-from-page':
+ $title = null;
+ if ( $this->isTitleSet( $extra ) ) {
+ $title = Title::newFromId( $extra['link-from-page-id'] );
+ // Link-from page could be a brand new page and page_id would not be replicated
+ // to slave db yet. If job queue is enabled to process web and email notification,
+ // the check against master database is not necessary since there is already a
+ // delay in the job queue
+ if ( !$title ) {
+ global $wgEchoUseJobQueue;
+ $diff = wfTimestamp() - wfTimestamp( TS_UNIX, $event->getTimestamp() );
+ if ( !$wgEchoUseJobQueue && $diff < 5 ) {
+ $title = Title::newFromID( $extra['link-from-page-id'], Title::GAID_FOR_UPDATE );
+ }
+ }
+ if ( $title ) {
+ if ( $this->outputFormat === 'htmlemail' ) {
+ $message->rawParams(
+ Linker::link(
+ $title,
+ $this->formatTitle( $title ),
+ array( 'style' => $this->getHTMLLinkStyle() ),
+ array(),
+ array( 'https' )
+ )
+ );
+ } else {
+ $message->params( $this->formatTitle( $title ) );
+ }
+ }
+ }
+
+ if ( !$title ) {
+ $message->params( $this->getMessage( 'echo-no-title' ) );
+ }
+ break;
+
+ // example: {7} other page, {99+} other pages
+ case 'link-from-page-other-display':
+ global $wgEchoMaxNotificationCount;
+
+ if ( $this->bundleData['link-from-page-other-count'] > $wgEchoMaxNotificationCount ) {
+ $message->params(
+ $this->getMessage( 'echo-notification-count' )
+ ->numParams( $wgEchoMaxNotificationCount )
+ ->text()
+ );
+ } else {
+ $message->numParams( $this->bundleData['link-from-page-other-count'] );
+ }
+ break;
+
+ // the number used for plural support
+ case 'link-from-page-other-count':
+ $message->params( $this->bundleData['link-from-page-other-count'] );
+ break;
+
+ default:
+ parent::processParam( $event, $param, $message, $user );
+ break;
+ }
+ }
+
+ /**
+ * Helper function for getLink()
+ *
+ * @param EchoEvent $event
+ * @param User $user The user receiving the notification
+ * @param String $destination The destination type for the link
+ * @return Array including target and query parameters
+ */
+ protected function getLinkParams( $event, $user, $destination ) {
+ $target = null;
+ $query = array();
+ // Set up link parameters based on the destination (or pass to parent)
+ switch ( $destination ) {
+ case 'link-from-page':
+ if ( $this->bundleData['use-bundle'] ) {
+ if ( $event->getTitle() ) {
+ $target = SpecialPage::getTitleFor( 'WhatLinksHere', $event->getTitle()->getPrefixedText() );
+ }
+ } else {
+ $extra = self::extractExtra( $event->getExtra() );
+ if ( $this->isTitleSet( $extra ) ) {
+ $target = Title::newFromId( $extra['link-from-page-id'] );
+ }
+ }
+ break;
+ default:
+ return parent::getLinkParams( $event, $user, $destination );
+ }
+ return array( $target, $query );
+ }
+}
diff --git a/Echo/formatters/UserRightsFormatter.php b/Echo/formatters/UserRightsFormatter.php
new file mode 100644
index 00000000..c59a79a3
--- /dev/null
+++ b/Echo/formatters/UserRightsFormatter.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Formatter for 'user-rights' notifications
+ */
+class EchoUserRightsFormatter extends EchoBasicFormatter {
+
+ /**
+ * @param $event EchoEvent
+ * @param $param string
+ * @param $message Message
+ * @param $user User
+ */
+ protected function processParam( $event, $param, $message, $user ) {
+ $extra = $event->getExtra();
+
+ switch ( $param ) {
+ // List of user rights that are granted or revoked
+ case 'user-rights-list':
+ global $wgLang;
+
+ $list = array();
+
+ foreach ( array( 'add', 'remove' ) as $action ) {
+ if ( isset( $extra[$action] ) && $extra[$action] ) {
+
+ // Get the localized group names, bug 55338
+ $groups = array();
+ foreach( $extra[$action] as $group ) {
+ $msg = $this->getMessage( 'group-' . $group );
+ $groups[] = $msg->isBlank() ? $group : $msg->escaped();
+ }
+
+ // Messages that can be used here:
+ // * notification-user-rights-add
+ // * notification-user-rights-remove
+ $list[] = $this->getMessage( 'notification-user-rights-' . $action )
+ ->params( $wgLang->commaList( $groups ), count( $groups ) )
+ ->escaped();
+ }
+ }
+ $message->params( $wgLang->semicolonList( $list ) );
+ break;
+
+ default:
+ parent::processParam( $event, $param, $message, $user );
+ break;
+ }
+ }
+
+ /**
+ * Helper function for getLink()
+ *
+ * @param EchoEvent $event
+ * @param User $user The user receiving the notification
+ * @param String $destination The destination type for the link
+ * @return Array including target and query parameters
+ */
+ protected function getLinkParams( $event, $user, $destination ) {
+ $target = null;
+ $query = array();
+ // Set up link parameters based on the destination (or pass to parent)
+ switch ( $destination ) {
+ case 'user-rights-list':
+ $target = SpecialPage::getTitleFor( 'Listgrouprights' );
+ break;
+ default:
+ return parent::getLinkParams( $event, $user, $destination );
+ }
+ return array( $target, $query );
+ }
+}
diff --git a/Echo/i18n/af.json b/Echo/i18n/af.json
new file mode 100644
index 00000000..02f9caa5
--- /dev/null
+++ b/Echo/i18n/af.json
@@ -0,0 +1,53 @@
+{
+ "@metadata": {
+ "authors": [
+ "Naudefj"
+ ]
+ },
+ "echo-desc": "Kennisgewing-stelsel",
+ "prefs-echo": "Kennisgewings",
+ "prefs-emailsettings": "E-posopsies",
+ "prefs-displaynotifications": "Vertoonopsies",
+ "prefs-echosubscriptions": "Hou my op hoogte oor hierdie gebeurtenisse",
+ "prefs-newmessageindicator": "Nuwe boodskap-indikator",
+ "echo-pref-send-me": "Stuur my:",
+ "echo-pref-send-to": "Stuur na:",
+ "echo-pref-email-format": "E-posformaat:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-pos",
+ "echo-pref-email-frequency-never": "Moenie aan my e-pos stuur nie",
+ "echo-pref-email-frequency-immediately": "Individuele kennisgewings soos hulle inkom",
+ "echo-pref-email-frequency-daily": "Daaglikse opsomming van kennisgewings",
+ "echo-pref-email-frequency-weekly": "Weeklikse opsomming van kennisgewings",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Eenvoudige teks",
+ "echo-pref-notify-show-link": "Wys kennisgewings in my werkbalk",
+ "echo-pref-new-message-indicator": "Wys besprekingsblad-boodskapindikator in my werkbalk",
+ "echo-learn-more": "Leer meer",
+ "echo-new-messages": "U het nuwe boodskappe",
+ "echo-category-title-edit-user-talk": "Boodskap{{PLURAL:$1||pe}} op u besprekingsblad",
+ "echo-category-title-article-linked": "Bladsyskakel{{PLURAL:$1||s}}",
+ "echo-category-title-system": "{{PLURAL:$1|Stelsel}}",
+ "echo-no-agent": "[Niemand]",
+ "echo-no-title": "[Geen bladsy]",
+ "notifications": "Kennisgewings",
+ "tooltip-pt-notifications": "U kennisgewings",
+ "echo-specialpage": "Kennisgewings",
+ "echo-more-info": "Meer inligting",
+ "echo-feedback": "Terugvoer",
+ "notification-link-text-view-message": "Wys boodskap",
+ "notification-link-text-view-mention": "Wys vermelding",
+ "notification-link-text-view-changes": "Wys veranderings",
+ "notification-link-text-view-page": "Wys bladsy",
+ "notification-link-text-view-edit": "Wys wysiging",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|het 'n boodskap}} op u [[User talk:$2#$3|besprekingsblad]] geplaas.",
+ "echo-email-subject-default": "Nuwe kennisgewing op {{SITENAME}}",
+ "echo-email-body-default": "U het 'n nuwe kennisgewing op {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "U het 'n nuwe kennisgewing.",
+ "echo-overlay-link": "Alle kennisgewings",
+ "echo-overlay-title": "<b>Kennisgewings</b>",
+ "echo-mark-all-as-read": "Merk alles as gelees",
+ "echo-date-today": "Vandag",
+ "echo-date-yesterday": "Gister",
+ "echo-email-batch-link-text-view-all-notifications": "Wys alle kennisgewings"
+}
diff --git a/Echo/i18n/am.json b/Echo/i18n/am.json
new file mode 100644
index 00000000..d3103f3f
--- /dev/null
+++ b/Echo/i18n/am.json
@@ -0,0 +1,60 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Elfalem"
+ ]
+ },
+ "prefs-echo": "ማስታወቂያዎች",
+ "prefs-emailsettings": "የኢ-ሜል ምርጫዎች",
+ "prefs-displaynotifications": "የማሳያ አማራጮች",
+ "echo-pref-email": "ኢ-ሜል",
+ "echo-pref-email-frequency-never": "ማስታወቂያዎችን በኢ-ሜል አትላክልኝ",
+ "echo-pref-email-frequency-immediately": "ለእያንዳንዱ ማስታወቂያ",
+ "echo-pref-email-frequency-daily": "በየቀኑ አንድ ማጠቃለያ",
+ "echo-pref-email-frequency-weekly": "በሳምንቱ አንድ ማጠቃለያ",
+ "echo-pref-email-format-html": "ኤች.ቲ.ኤም.ኤል. (HTML)",
+ "echo-pref-email-format-plain-text": "ጥሬ ጽሁፍ",
+ "echo-learn-more": "የበለጠ ለመረዳት",
+ "echo-new-messages": "አዲስ መልዕክቶች አሉዎት",
+ "echo-category-title-edit-user-talk": "ውይይት ገጽ {{PLURAL:$1|መልዕክት|መልዕክቶች}}",
+ "echo-category-title-article-linked": "የገጽ {{PLURAL:$1|መያያዣ|መያያዣዎች}}",
+ "echo-category-title-reverted": "የ{{PLURAL:$1|ተገለበጠ ለውጥ|ተገለበጡ ለውጦች}}",
+ "echo-category-title-mention": "{{PLURAL:$1|ስም ማንሳት}}",
+ "echo-category-title-other": "{{PLURAL:$1|ሌላ|ሌሎች}}",
+ "echo-pref-tooltip-edit-user-talk": "ማንኛውም ሰው በውይይት ገጼ ላይ ሲጽፍ አስታውቀኝ።",
+ "echo-pref-tooltip-article-linked": "ማንኛው ሰው እኔ ወደ ፈጠርኩት መጣጥፍ በሌላ መጣጥፍ ውስጥ መያያዣ ሲያቀርብ አስታውቀኝ።",
+ "echo-pref-tooltip-reverted": "ማንኛው ሰው የእኔን ለውጦች ሲገለብጥ አስታውቀኝ።",
+ "echo-pref-tooltip-mention": "ማንኛውም ሰው ወደ እኔ ውይይት ገጽ በሌላ ውይይት ገጽ ላይ መያያዣ ሲያቀርብ አስታውቀኝ።",
+ "echo-no-agent": "[Nobody]",
+ "echo-no-title": "[No page]",
+ "notifications": "ማስታወቂያዎች",
+ "tooltip-pt-notifications": "የእርስዎ ማስታወቂያዎች",
+ "echo-specialpage": "ማስታወቂያዎች",
+ "echo-anon": "ማስታወቂያዎችን ለማየት [$1 የብዕር ስም ያውጡ] ወይም [$2 በብዕር ስምዎ ይግቡ]።",
+ "echo-none": "ምንም ማስታወቂያዎች የሎትም።",
+ "echo-more-info": "ተጨማሪ መረጃ",
+ "echo-feedback": "አስተያየት",
+ "notification-link-text-view-message": "መልዕክት ለማየት",
+ "notification-link-text-view-mention": "ስምዎ የተነሳበትን ገጽ ለማየት",
+ "notification-link-text-view-changes": "ማነጻጸሪያ ለማየት",
+ "notification-link-text-view-page": "ገጽ ለማየት",
+ "notification-link-text-view-edit": "ማነጻጸሪያ ለማየት",
+ "notification-edit-talk-page2": "[[User:$1|$1]] [[User talk:$2#$3|በውይይት ገጽዎ]] ላይ መልዕክት {{GENDER:$1|ትቷል|ትታለች|ትተዋል}}።",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] በውይይት ገጽዎ ላይ በ«[[User talk:$2#$3|$4]]» ርዕስ ስር መልዕክት {{GENDER:$1|ትቷል|ትታለች|ትተዋል}}።",
+ "notification-edit-talk-page-flyout2": "$1 [[User talk:$2#$3|በውይይት ገጽዎ]] ላይ መልዕክት {{GENDER:$1|ትቷል|ትታለች|ትተዋል}}።",
+ "notification-edit-talk-page-flyout-with-section": "$1 በውይይት ገጽዎ ላይ በ«[[User talk:$2#$3|$4]]» ርዕስ ስር መልዕክት {{GENDER:$1|ትቷል|ትታለች|ትተዋል}}።",
+ "notification-page-linked": "$1 በ[[:$3]] ላይ ወደ [[:$2]] መያያዣ {{GENDER:$1|ፈጥሯል|ፈጥራለች|ፈጥረዋል}}። [[Special:WhatLinksHere/$2|ወደዚህ ገጽ ያሉት መያያዣዎች ሁሉ ይዩ]]።",
+ "notification-page-linked-flyout": "በ[[:$3]] ላይ ወደ [[:$2]] ገጽ መያያዣ ተፈጥሯል።",
+ "notification-add-comment2": "[[User:$1|$1]] በ$4 ገጽ በ«[[$3|$2]]» ርዕስ ላይ አስተያየት {{GENDER:$1|ሰጥቷል|ስጥታለች|ስጥተዋል}}።",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] በ[[$3]] ላይ አዲስ ውይይት በ«$2» ርዕስ {{GENDER:$1|ጀመረ|ጀመረች|ጀመሩ}}።",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] አዲስ መልዕክት {{GENDER:$1|ልኮሎታል}}፣ «[[$3#$2|$2]]»።",
+ "echo-overlay-link": "ሁሉም ማስታወቂያዎች",
+ "echo-overlay-title": "<b>ማስታወቂያዎች</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|ማስታወቂያ|ማስታወቂያዎች}}</b> (ከ$2 {{PLURAL:$2|ያልታየ|ያልታዩ}} ውስጥ {{PLURAL:$1|ዱ|ቱ}})",
+ "echo-mark-all-as-read": "ሁሉንም ታይተዋል በል",
+ "echo-date-today": "ዛሬ",
+ "echo-date-yesterday": "ትላንትና",
+ "echo-load-more-error": "ተጨማሪ ውጤቶችን ሲያመጣ ስህተት ተከስቷል።",
+ "echo-email-batch-link-text-view-all-notifications": "ሁሉንም ማስታወቂያዎች ለማየት"
+}
diff --git a/Echo/i18n/ar.json b/Echo/i18n/ar.json
new file mode 100644
index 00000000..f4f8b587
--- /dev/null
+++ b/Echo/i18n/ar.json
@@ -0,0 +1,128 @@
+{
+ "@metadata": {
+ "authors": [
+ "Achraf94",
+ "Asaifm",
+ "Ciphers",
+ "Meno25",
+ "Mido",
+ "Zanatos",
+ "زكريا",
+ "مشعل الحربي",
+ "Abanima",
+ "Omda4wady",
+ "Khaled"
+ ]
+ },
+ "echo-desc": "نظام الإشعارات",
+ "prefs-echo": "إشعارات",
+ "prefs-emailsettings": "خيارات البريد الإلكتروني",
+ "prefs-displaynotifications": "خيارات العرض",
+ "prefs-echosubscriptions": "أعلمني بشأن هذه الأحداث",
+ "prefs-newmessageindicator": "مؤشر الرسائل الجديدة",
+ "echo-pref-send-me": "أرسل لي:",
+ "echo-pref-send-to": "أرسل إلى:",
+ "echo-pref-email-format": "صيغة البريد الإلكتروني:",
+ "echo-pref-web": "ويب",
+ "echo-pref-email": "بريد إلكتروني",
+ "echo-pref-email-frequency-never": "لا ترسل لي أي إشعارات بالبريد الإلكتروني",
+ "echo-pref-email-frequency-immediately": "الإشعارات الفردية حال ورودها",
+ "echo-pref-email-frequency-daily": "ملخصا يوميا للإشعارات",
+ "echo-pref-email-frequency-weekly": "ملخصا أسبوعيا للإشعارات",
+ "echo-pref-email-format-html": "إتش تي إم إل",
+ "echo-pref-email-format-plain-text": "نص خام",
+ "echo-pref-notify-show-link": "أظهر الإشعارات في شريط الأدوات",
+ "echo-pref-new-message-indicator": "أظهر مؤشر رسائل صفحة النقاش في شريط الأدوات",
+ "echo-learn-more": "معرفة المزيد",
+ "echo-new-messages": "لديك رسائل جديدة",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|رسالة|رسائل}} صفحة النقاش",
+ "echo-category-title-article-linked": "{{PLURAL:$1|وصلة|وصلات}} صفحة",
+ "echo-category-title-reverted": "إلغاء {{PLURAL:$1|تعديل|تعديلات}}",
+ "echo-category-title-mention": "{{PLURAL:$1|إشارة|إشارات}}",
+ "echo-category-title-other": "{{PLURAL:$1|أخرى}}",
+ "echo-category-title-system": "{{PLURAL:$1|النظام}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1||تغيير صلاحية المستخدم|تغييرات صلاحيات المستخدم}}",
+ "echo-pref-tooltip-edit-user-talk": "أعلمني عندما توضع رسائل أو ردود في صفحة نقاشي.",
+ "echo-pref-tooltip-article-linked": "أعلمني عندما توضع في مقالة ما وصلة لصفحة أنشأتها.",
+ "echo-pref-tooltip-reverted": "أعلمني عندما إلغاء تعديل أجريته.",
+ "echo-pref-tooltip-mention": "أعلمني عندما توضع في صفحة نقاش ما وصلة لصفحتي.",
+ "echo-pref-tooltip-user-rights": "أعلمني عند تغيير صلاحياتي.",
+ "echo-no-agent": "[لا أحد]",
+ "echo-no-title": "[لا صفحة]",
+ "echo-error-no-formatter": "لم يحدد للإشعارات أي تنسيق.",
+ "echo-error-preference": "خطأ: لم تحفظ تفضيلات المستخدم.",
+ "echo-error-token": "خطأ: لم يتوصل إلى مفتاح معطيات المستخدم.",
+ "notifications": "إشعارات",
+ "tooltip-pt-notifications": "إشعاراتك",
+ "echo-specialpage": "إشعاراتي",
+ "echo-anon": "لتلقي الإشعارات، [$1 أنشئ حسابا] أو [$2 سجل الدخول].",
+ "echo-none": "ليس لديك أي إشعارات",
+ "echo-more-info": "المزيد",
+ "echo-feedback": "تعليقات",
+ "notification-link-text-view-message": "اعرض الرسالة",
+ "notification-link-text-view-mention": "اعرض الإشارة",
+ "notification-link-text-view-changes": "اعرض التعديلات",
+ "notification-link-text-view-page": "اعرض الصفحة",
+ "notification-link-text-view-edit": "اعرض التعديل",
+ "notification-edit-talk-page2": "{{GENDER:$1|بعث|بعثت}} لك [[User:$1|$1]] برسالة في [[User talk:$2#$3|صفحة نقاشك]].",
+ "notification-edit-talk-page-with-section": "{{GENDER:$1|بعث|بعثت}} لك [[User:$1|$1]] برسالة في قسم [[User talk:$2#$3|$4]] من [[User talk:$2#$3|صفحة نقاشك]].",
+ "notification-edit-talk-page-flyout2": "{{GENDER:$1|بعث|بعثت}} لك $1 برسالة في [[User talk:$2#$3|صفحة نقاشك]].",
+ "notification-edit-talk-page-flyout-with-section": "{{GENDER:$1|بعث|بعثت}} لك $1 برسالة في قسم [[User talk:$2#$3|$4]] من صفحة نقاشك.",
+ "notification-page-linked": "{{GENDER:$1|وضعت}} وصلة لصفحة [[:$2]] في [[:$3]]. [[Special:WhatLinksHere/$2|انظر جميع وصلات تلك الصفحة]].",
+ "notification-page-linked-flyout": "{{GENDER:$1|وضعت}} وصلة لصفحة [[:$2]] في [[:$3]].",
+ "notification-add-comment2": "{{GENDER:$1|علق|علقت}} [[User:$1|$1]] على \"[[$3|$2]]\" في صفحة نقاش \"$4\".",
+ "notification-add-talkpage-topic2": "{{GENDER:$1|أنشأ|أنشأت}} [[User:$1|$1]] قسما جديدا بعنوان \"$2\" في [[$3]].",
+ "notification-add-talkpage-topic-yours2": "{{GENDER:$1|أرسل|أرسلت}} لك [[User:$1|$1]] رسالة بعنوان \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "{{GENDER:$1|علق|علقت}} [[User:$1|$1]] على \"[[$3#$2|$2]]\" في صفحة نقاشك.",
+ "notification-mention": "{{GENDER:$1|أشار|أشارت}} إليك [[User:$1|$1]] في قسم \"[[:$3#$2|$4]]\" من صفحة نقاش $5.",
+ "notification-mention-flyout": "{{GENDER:$1|أشار|أشارت}} إليك $1 في قسم \"[[:$3#$2|$4]]\" في صفحة نقاش $5.",
+ "notification-mention-nosection": "{{GENDER:$1|أشار|أشارت}} [[User:$1|$1]] إليك على [[:$3|صفحة نقاش $2]].",
+ "notification-mention-nosection-flyout": "{{GENDER:$1|أشار|أشارت}} $1 إليك في [[:$3|صفحة نقاش $2]].",
+ "notification-user-rights": "[[Special:Log/rights/$1|{{GENDER:$1|غير|غيرت}}]] [[User:$1|$1]] صلاحياتك. $2. [[Special:ListGroupRights|المزيد]]",
+ "notification-user-rights-flyout": "{{GENDER:$1|غير|غيرت}} $1 صلاحياتك. $2. [[Special:ListGroupRights|المزيد]]",
+ "notification-user-rights-add": "أنت الآن عضو في {{PLURAL:$2|مجموعة|مجموعات}}: $1",
+ "notification-user-rights-remove": "ألغيت عضويتك في {{PLURAL:$2|مجموعة|مجموعات}}: $1",
+ "notification-new-user": "$1، مرحبا بك في {{SITENAME}}. أسعدنا بلقياك.",
+ "notification-reverted2": "{{GENDER:$1|ألغى|ألغت}} [[User:$1|$1]] {{PLURAL:$4|تعديلك في [[:$2]]|تعديلاتك في [[:$2]]}}. $3",
+ "notification-reverted-flyout2": "{{GENDER:$1|ألغى|ألغت}} $1 {{PLURAL:$4|تعديلك في $2|تعديلاتك في $2}}. $3",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|بعث|بعثت}} لك $1 برسالة في {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|بعث|بعثت}} لك $1 برسالة في صفحة نقاشك:",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|بعث|بعثت}} لك $1 برسالة في صفحة نقاشك في \"$2\".",
+ "notification-page-linked-email-subject": "وضعت وصلة لصفحتك في {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|وضعت}} وصلة إلى $2 في $3.",
+ "notification-reverted-email-subject2": "{{GENDER:$1|ألغي{{PLURAL:$3||ت}}}} {{PLURAL:$3|تعديلك|تعديلاتك}} في {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{GENDER:$1|ألغى|ألغت}} $1 {{PLURAL:$3|تعديلك|تعديلاتك}} في $2.",
+ "notification-mention-email-subject": " {{GENDER:$1|أشار|أشارت}} إليك $1 في {{SITENAME}}",
+ "notification-mention-email-batch-body": " {{GENDER:$1|أشار|أشارت}} إليك $1 في قسم \"$3\" من صفحة نقاش $4.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|أشار|أشارت}} إليك في صفحة نقاش $2.",
+ "notification-user-rights-email-subject": "غيرت صلاحياتك في {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "{{GENDER:$1|غير|غيرت}} $1 صلاحياتك. $2.",
+ "echo-email-subject-default": "إشعار جديد في {{SITENAME}}",
+ "echo-email-body-default": "لديك إشعار جديد في {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "لديك إشعار جديد.",
+ "echo-email-footer-default": "$2\n\nللتحكم في رسائل الإلكترونية التي نرسلها لك، انظر التفضيلات:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "للتحكم في رسائل الإلكترونية التي نرسلها لك، <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">انظر التفضيلات</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|إخطار|إخطاران|إخطارات ($1)|100=إخطارات (أكثر من 99)}}",
+ "echo-notification-alert-text-only": "تنبيهات",
+ "echo-notification-message-text-only": "رسائل",
+ "echo-overlay-link": "كل الإشعارات",
+ "echo-overlay-title": "<b>إشعارات</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|إشعارات}}</b> (عرض $1 من $2 لم تقرأ)",
+ "echo-mark-all-as-read": "اعتبرها كلها مقروءة",
+ "echo-date-today": "اليوم",
+ "echo-date-yesterday": "أمس",
+ "echo-load-more-error": "وقع خطأ في إيراد المزيد من النتائج.",
+ "notification-edit-talk-page-bundle": "{{GENDER:$1|{{PLURAL:$4|بعث}}|{{PLURAL:$4|بعثت}}}} لك $1 و{{PLURAL:$4|مستخدم آخر|مستخدم آخر|مستخدمان آخران|$3 آخرون}} برسائل في [[User talk:$2|صفحة نقاشك]].",
+ "notification-page-linked-bundle": "{{GENDER:$1|وضعت}} وصلة إلى $2 في $3 و{{PLURAL:$5|صفحة أخرى|صفحة أخرى|صفحتين أخريين|$4 صفحات أخرى|$4 صفحة أخرى}}. [[Special:WhatLinksHere/$2|انظر جميع الوصلات إلى هذه الصفحة]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "{{GENDER:$1|{{PLURAL:$3|بعث}}|{{PLURAL:$3|بعثت}}}} لك $1 و{{PLURAL:$3|مستخدم آخر|مستخدم آخر|مستخدمان آخران|$2 مستخدمين آخرين|$2 مستخدما آخر|$2 مستخدم آخر}} برسائل في صفحة نقاشك.",
+ "notification-page-linked-email-batch-bundle-body": "{{GENDER:$1|وضعت}} وصلة إلى $2 في $3 و{{PLURAL:$5|صفحة أخرى|صفحة أخرى|صفحتين أخريين|$4 صفحات أخرى|$4 صفحة أخرى}}.",
+ "echo-email-batch-subject-daily": "لديك {{PLURAL:$2|إشعار جديد|إشعارات جديدة}} في {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "لديك {{PLURAL:$2|إشعار جديد|إشعارات جديدة}} في {{SITENAME}} هذا الأسبوع",
+ "echo-email-batch-body-intro-daily": "سلام $1،\nهذا ملخص لنشاطات اليوم في {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "سلام $1،\nهذا ملخص لنشاطات الأسبوع في {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "اعرض كل الإشعارات",
+ "echo-rev-deleted-text-view": "هذه النسخة من الصفحة قد حذفت.",
+ "apihelp-query+notifications-param-prop": "طلب تفاصيل.",
+ "apihelp-query+notifications-param-limit": "العدد الأقصى للإخطارات في النتائج.",
+ "apihelp-query+notifications-example-1": "قائمة الإشعارات"
+}
diff --git a/Echo/i18n/arq.json b/Echo/i18n/arq.json
new file mode 100644
index 00000000..62491129
--- /dev/null
+++ b/Echo/i18n/arq.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Oldstoneage"
+ ]
+ },
+ "tooltip-pt-notifications": "التعلومات"
+}
diff --git a/Echo/i18n/as.json b/Echo/i18n/as.json
new file mode 100644
index 00000000..dfec5cea
--- /dev/null
+++ b/Echo/i18n/as.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gitartha.bordoloi"
+ ]
+ },
+ "echo-new-messages": "আপোনালৈ নতুন বাৰ্তা আহিছে",
+ "notifications": "জাননী",
+ "tooltip-pt-notifications": "আপোনাৰ জাননীসমূহ"
+}
diff --git a/Echo/i18n/ast.json b/Echo/i18n/ast.json
new file mode 100644
index 00000000..c8d863a9
--- /dev/null
+++ b/Echo/i18n/ast.json
@@ -0,0 +1,116 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "echo-desc": "Sistema d'avisos",
+ "prefs-echo": "Avisos",
+ "prefs-emailsettings": "Opciones de corréu",
+ "prefs-displaynotifications": "Opciones de vista",
+ "prefs-echosubscriptions": "Avisame d'estos socesos",
+ "prefs-newmessageindicator": "Indicador de mensaxe nuevu",
+ "echo-pref-send-me": "Unviame:",
+ "echo-pref-send-to": "Unviar a:",
+ "echo-pref-email-format": "Formatu del corréu:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Corréu",
+ "echo-pref-email-frequency-never": "Nun unviame avisos per corréu electrónicu",
+ "echo-pref-email-frequency-immediately": "Avisos individuales según entren",
+ "echo-pref-email-frequency-daily": "Un resume diariu de los avisos",
+ "echo-pref-email-frequency-weekly": "Un resume selmanal de los avisos",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Testu simple",
+ "echo-pref-notify-show-link": "Amosar los avisos na mio barra de ferramientes",
+ "echo-pref-new-message-indicator": "Amosar un indicador de mensaxe na páxina d'alderique na mio barra de ferramientes",
+ "echo-learn-more": "Más información",
+ "echo-new-messages": "Tien mensaxes nuevos",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mensaxe|Mensaxes}} na páxina d'alderique",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Enllaz|Enllaces}} a páxina",
+ "echo-category-title-reverted": "{{PLURAL:$1|Inversión|Inversiones}} d'edición",
+ "echo-category-title-mention": "{{PLURAL:$1|Mención|Menciones}}",
+ "echo-category-title-other": "{{PLURAL:$1|Otros}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Cambiu de permisos d'usuariu|Cambios de permisos d'usuariu}}",
+ "echo-pref-tooltip-edit-user-talk": "Avisame cuando alguién dexe un mensaxe na mio páxina d'alderique.",
+ "echo-pref-tooltip-article-linked": "Avisame cuando alguién enllace dende un artículu a una páxina que yo creé.",
+ "echo-pref-tooltip-reverted": "Avisame cuando alguién revierta una edición de mió, usando les ferramientes desfacer o revertir.",
+ "echo-pref-tooltip-mention": "Avisame cuando dalguién enllace a la mio páxina d'usuariu.",
+ "echo-pref-tooltip-user-rights": "Avisame cuando dalguién cambie los mios permisos d'usuariu.",
+ "echo-no-agent": "[Naide]",
+ "echo-no-title": "[Ensin páxina]",
+ "echo-error-no-formatter": "Nun se definió formatu dalu pal avisu",
+ "echo-error-preference": "Error: Nun pudo establecese la preferencia d'usuariu",
+ "echo-error-token": "Error: Nun pudo recuperase'l token d'usuariu",
+ "notifications": "Avisos",
+ "tooltip-pt-notifications": "Los sos avisos",
+ "echo-specialpage": "Avisos",
+ "echo-anon": "Pa recibir avisos, [$1 cree una cuenta] o [$2 anicie sesión].",
+ "echo-none": "Nun tien avisos.",
+ "echo-more-info": "Más información",
+ "echo-feedback": "La so opinión",
+ "notification-link-text-view-message": "Ver el mensaxe",
+ "notification-link-text-view-mention": "Ver la mención",
+ "notification-link-text-view-changes": "Ver los cambios",
+ "notification-link-text-view-page": "Ver la páxina",
+ "notification-link-text-view-edit": "Ver la edición",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|dexó}} un mensaxe na so [[User talk:$2#$3|páxina d'alderique]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|dexó}} un mensaxe na so páxina d'alderique en [[User talk:$2#$3|$4]].",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|dexó}} un mensaxe na so [[User talk:$2#$3|páxina d'alderique]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|dexó}} un mensaxe na so páxina d'alderique en «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "[[:$2]] {{GENDER:$1|enllazóse}} dende [[:$3]]. [[Special:WhatLinksHere/$2|Ver tolos enllaces a esta páxina]].",
+ "notification-page-linked-flyout": "[[:$2]] {{GENDER:$1|enllazóse}} dende [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|comentó}} sobro \"[[$3|$2]]\" na páxina d'alderique \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|amestó}} l'asuntu nuevu \"$2\" en [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|unvió-y}} un mensaxe: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|comentó}} sobro \"[[$3#$2|$2]]\" na so páxina d'alderique",
+ "notification-mention": "[[User:$1|$1]] fizo-y una {{GENDER:$1|mención}} nel alderique de $5 en «[[:$3#$2|$4]]».",
+ "notification-mention-flyout": "$1 fizo-y una {{GENDER:$1|mención}} nel alderique de $5 en «[[:$3#$2|$4]]».",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|mentó-y}} na [[:$3|páxina d'alderique de $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|mentó-y}} na [[:$3|páxina d'alderique de $2]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|camudó}}]] los sos permisos d'usuariu. $2. [[Special:ListGroupRights|Más información]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|camudó}} los sos permisos d'usuariu. $2. [[Special:ListGroupRights|Más información]]",
+ "notification-user-rights-add": "Agora ye miembru d'{{PLURAL:$2|esti grupu|estos grupos}}: $1",
+ "notification-user-rights-remove": "Dexó de ser miembru d'{{PLURAL:$2|esti grupu|estos grupos}}: $1",
+ "notification-new-user": "¡Damos-y la bienvenida a {{SITENAME}}, $1! Prestanos que tea equí.",
+ "notification-reverted2": "[[User:$1|$1]] {{GENDER:$1|invertió}} {{PLURAL:$4|la so edición|les sos ediciones}} en [[:$2]] $3",
+ "notification-reverted-flyout2": "$1 {{GENDER:$1|invertió}} {{PLURAL:$4|la so edición|les sos ediciones}} en $2 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|dexó-y}} un mensaxe en {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|dexó}} un mensaxe na to páxina d'alderique:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|dexó}} un mensaxe na so páxina d'alderique en «$2».",
+ "notification-page-linked-email-subject": "La so páxina enllazóse'n {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 {{GENDER:$1|enllazóse}} dende $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Desfizose la so edición|Desficieronse les sos ediciones}} {{GENDER:$1|en}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|desfizo}} {{PLURAL:$3|la so edición|les sos ediciones}} en $2",
+ "notification-mention-email-subject": "$1 fizo-y una {{GENDER:$1|mención}} en {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 fizo-y una {{GENDER:$1|mención}} nel alderique de $4 en «$3».",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|mentó-y}} na páxina d'alderique de $2.",
+ "notification-user-rights-email-subject": "Camudaron los sos permisos d'usuariu en {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|camudó}} los sos permisos d'usuariu. $2",
+ "echo-email-subject-default": "Nuevu avisu en {{SITENAME}}",
+ "echo-email-body-default": "Tien un nuevu avisu en {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Tien un nuevu avisu",
+ "echo-email-footer-default": "$2\n\nPa controlar los correos que-y unviamos, compruebe les sos preferencies:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Pa controlar los correos electrónicos que-y unviamos, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">compruebe les sos preferencies</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|($1) alerta|($1) alertes|100=(99+) alertes}}",
+ "echo-notification-message": "{{PLURAL:$1|($1) mensaxe|($1) mensaxes|100=(99+) mensaxes}}",
+ "echo-notification-alert-text-only": "Alertes",
+ "echo-notification-message-text-only": "Mensaxes",
+ "echo-overlay-link": "Tolos avisos",
+ "echo-overlay-title": "<b>Avisos</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Avisu|Avisos}}</b> (amosando $1 de $2 ensin lleer)",
+ "echo-mark-all-as-read": "Marcar too como lleío",
+ "echo-date-today": "Güei",
+ "echo-date-yesterday": "Ayeri",
+ "echo-load-more-error": "Hubo un error al descargar más resultaos.",
+ "notification-edit-talk-page-bundle": "$1 y {{PLURAL:$4|otra persona|otres $3 persones}} {{GENDER:$1|dexaron}} un mensaxe na so [[User talk:$2|páxina d'alderique]].",
+ "notification-page-linked-bundle": "$2 {{GENDER:$1|enllazóse}} dende $3 y $4 {{PLURAL:$5|páxina|páxines}} más. [[Special:WhatLinksHere/$2|Ver tolos enllaces a esta páxina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 y {{PLURAL:$3|otra persona|otres $2 persones}} {{GENDER:$1|dexaron}} un mensaxe na so páxina d'alderique",
+ "notification-page-linked-email-batch-bundle-body": "$2 {{GENDER:$1|enllazóse}} dende $3 y {{PLURAL:$5|otra páxina|otres $4 páxines}}",
+ "echo-email-batch-subject-daily": "Tien {{PLURAL:$2|un avisu nuevu|avisos nuevos}} en {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Tien {{PLURAL:$2|un avisu nuevu|avisos nuevos}} en {{SITENAME}} esta selmana",
+ "echo-email-batch-body-intro-daily": "Hola, $1:\nEsti ye un resume personal de la actividá de güei en {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Hola, $1:\nEsti ye un resume personal de la actividá selmanal en {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Ver toles notificaciones",
+ "echo-rev-deleted-text-view": "Esta revisión de páxina ta encaboxada"
+}
diff --git a/Echo/i18n/av.json b/Echo/i18n/av.json
new file mode 100644
index 00000000..cc8543e5
--- /dev/null
+++ b/Echo/i18n/av.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazimagomedov"
+ ]
+ },
+ "echo-new-messages": "Духъе цIиял кагътал руго"
+}
diff --git a/Echo/i18n/awa.json b/Echo/i18n/awa.json
new file mode 100644
index 00000000..c3d7f9cc
--- /dev/null
+++ b/Echo/i18n/awa.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "1AnuraagPandey"
+ ]
+ },
+ "notifications": "अधिसूचना"
+}
diff --git a/Echo/i18n/ay.json b/Echo/i18n/ay.json
new file mode 100644
index 00000000..18e20091
--- /dev/null
+++ b/Echo/i18n/ay.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jduranboger"
+ ]
+ },
+ "echo-desc": "Sistema de notificaciones",
+ "prefs-echo": "Notificaciones",
+ "prefs-emailsettings": "Opciones de correo electrónico",
+ "prefs-displaynotifications": "Opciones de visualización",
+ "prefs-echosubscriptions": "Notificarme sobre estos eventos",
+ "prefs-newmessageindicator": "Indicador de mensajes nuevos",
+ "echo-pref-send-me": "Enviarme:",
+ "echo-pref-send-to": "Enviar a:",
+ "echo-pref-email-format": "Formato del mensaje:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Email",
+ "echo-pref-email-frequency-never": "No enviarme notificaciones por correo electrónico",
+ "echo-pref-email-frequency-immediately": "Enviarme notificaciones individuales en cuanto lleguen",
+ "echo-pref-email-frequency-daily": "Resumen diario de notificaciones",
+ "echo-pref-email-frequency-weekly": "Resumen semanal de notificaciones",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Texto sin formato",
+ "echo-pref-notify-show-link": "Mostrar notificaciones en mi barra de herramientas",
+ "echo-pref-new-message-indicator": "Mostrar el indicador de mensajes en la barra de herramientas",
+ "echo-learn-more": "Más información",
+ "echo-new-messages": "Tienes mensajes nuevos",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|mensaje|mensajes}} en la página de discusión",
+ "echo-category-title-article-linked": "{{PLURAL:$1|enlace|enlaces}} de página",
+ "echo-category-title-reverted": "{{PLURAL:$1|reversión|reversiones}} de edición"
+}
diff --git a/Echo/i18n/az.json b/Echo/i18n/az.json
new file mode 100644
index 00000000..8855a5eb
--- /dev/null
+++ b/Echo/i18n/az.json
@@ -0,0 +1,74 @@
+{
+ "@metadata": {
+ "authors": [
+ "Interfase",
+ "Khan27",
+ "Wertuose",
+ "Dağlı95"
+ ]
+ },
+ "echo-desc": "Bildiriş sistemi",
+ "prefs-echo": "Bildirişlər",
+ "prefs-emailsettings": "Elektron poçtun parametrləri",
+ "prefs-displaynotifications": "Displeyin parametrləri",
+ "prefs-echosubscriptions": "Bu hadisələr barədə mənə xəbər verilsin",
+ "prefs-newmessageindicator": "Yeni mesaj göstəricisi",
+ "echo-pref-send-me": "Mənə göndər:",
+ "echo-pref-send-to": "Göndər",
+ "echo-pref-email-format": "Elektron məktub formatı",
+ "echo-pref-web": "Veb",
+ "echo-pref-email": "Elektron məktub",
+ "echo-pref-email-frequency-never": "Bildirişlər mənə elektron məktubla göndərilməsin",
+ "echo-pref-email-frequency-immediately": "Ayrı-ayrılıqda bildirişlər",
+ "echo-pref-email-frequency-daily": "Gündəlik bildirişlər",
+ "echo-pref-email-frequency-weekly": "Həftəlik bildirişlər",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Sadə mətn",
+ "echo-pref-notify-show-link": "Dəyişiklikləri mənim alətlər panelimdə göstər",
+ "echo-pref-new-message-indicator": "Müzakirə səhifəsindəki mesaj indikatorunu alətlər panelimdə göstər",
+ "echo-learn-more": "Daha ətraflı",
+ "echo-new-messages": "Yeni mesajlarınız var",
+ "echo-category-title-edit-user-talk": "Müzakirə səhifəsindəki {{PLURAL:$1|1=mesaj|mesaj}}",
+ "echo-category-title-article-linked": "Səhifəyə {{PLURAL:$1|keçid|keçidlər}}",
+ "echo-category-title-reverted": "Redaktələrin {{PLURAL:$1|1=ləğv|ləğvi}}",
+ "notifications": "Bildirişlər",
+ "tooltip-pt-notifications": "Sizin bildirişləriniz",
+ "echo-specialpage": "Bildirişlər",
+ "echo-none": "Sizə bildiriş yoxdur",
+ "echo-more-info": "Daha ətraflı",
+ "echo-feedback": "Rəy",
+ "notification-link-text-view-message": "Məktuba bax",
+ "notification-link-text-view-mention": "Qeydə bax",
+ "notification-link-text-view-changes": "Dəyişiklərə bax",
+ "notification-link-text-view-page": "Səhifəyə bax",
+ "notification-link-text-view-edit": "Redaktəyə bax",
+ "notification-edit-talk-page2": "[[User:$1|$1]] sizin [[User talk:$2#$3|müzakirə səhifənizdə]] məktub {{GENDER:$1|qoyub}} .",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] sizin müzakirə səhifənizdə \"[[User talk:$2#$3|$4]]\" başlıqlı mesaj {{GENDER:$1|qoyub}}.",
+ "notification-edit-talk-page-flyout2": "Sizin [[User talk:$2#$3|müzakirə səhifənizdə]] mesaj $1 {{GENDER:$1|qoyub}}.",
+ "notification-page-linked": "[[:$2]] səhifəsinə [[:$3]] səhifəsindən {{GENDER:$1|keçid verilib}}. [[Special:WhatLinksHere/$2|Bu səhifəyə olan bütün keçidlərə bax]].",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] [[$3]] səhifəsində yeni \"$2\" başlıqlı mövzu {{GENDER:$1|əlavə edib|əlavə edib}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] tərəfindən sizə mesaj {{GENDER:$1|göndərilib|göndərilib}}: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$2|$2]] sizin müzakirə səhifənizindəki «[[$4#$3|$3]]» başlıqlı mövzuya {{GENDER:$1|fikir bildirdi|fikir bildirdi}}.",
+ "notification-mention": "[[User:$1|$1]] sizin adınızı $5 danışıq səhifəsinin \"[[:$3#$2|$4]]\" bölməsində $1 qeyd edib.",
+ "notification-mention-flyout": "[[User:$1|$1]] sizin adınızı $5 danışıq səhifəsinin \"[[:$3#$2|$4]]\" bölməsində $1 qeyd edib.",
+ "notification-mention-nosection": "[[User:$1|$1]] sizin adınızı [[:$3|müzakirə səhifəsind $2]] qeyd edib.",
+ "notification-new-user": "'''$1''' {{SITENAME}} saytına xoş gəlmisiniz! Sizi burada görməyimizə çox şadıq. Uğurlar!",
+ "notification-edit-talk-page-email-subject2": "İstifadəçi $1 \"{{SITENAME}}\" saytındakı müzakirə səhifənizdə sizə mesaj yazıb",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|İstifadəçi}} sizin müzakirə səhifənizdə məktub $1 {{GENDER:$1|yazıb}}",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|İstifadəçi}} sizin müzakirə səhifənizdə «$2» bölməsində məktub $1 {{GENDER:$1|yazıb}}",
+ "notification-mention-email-subject": "{{GENDER:$1|İstifadəçi}} sizin adınızı «{{SITENAME}}» səhifəsində $1 {{GENDER:$1|qeyd edib}}",
+ "notification-mention-email-batch-body": "Sizin adınız $4 danışıq səhifəsinin $3 bölməsində $1 {{GENDER:$1|qeyd edilib}}",
+ "notification-mention-nosection-email-batch-body": "Sizin adınız $2 danışıq səhifəsinin $1 {{GENDER:$1|qeyd edilib}}",
+ "echo-email-subject-default": "«{{SITENAME}}» saytında yeni bildiriş var",
+ "echo-email-body-default": "Sizə {{SITENAME}} səhifəsində yeni bildiriş var :\n\n$1",
+ "echo-email-batch-body-default": "Sizə yeni bildiriş var",
+ "echo-overlay-link": "Bütün bildirişlər",
+ "echo-overlay-title": "<b>Bildirişlər</b>",
+ "echo-overlay-title-overflow": "<b>Bildirişlər</b> $2 {{PLURAL|$2|oxunmamış|oxunmamışlar}})dan $1 ({{PLURAL|$1|göstərilib|göstəriliblər}}",
+ "echo-mark-all-as-read": "Hamısını oxunmuş kimi qeyd et",
+ "echo-date-today": "Bugün",
+ "echo-date-yesterday": "Dünən",
+ "echo-email-batch-subject-daily": "Sizin {{SITENAME}}-da {{PLURAL:$2|yeni bildiriş|yeni bildirişləriniz|}} var",
+ "echo-email-batch-subject-weekly": "Sizin bu həftə {{SITENAME}}-da {{PLURAL:$2|yeni bildiriş|yeni bildirişləriniz|}} var",
+ "echo-email-batch-link-text-view-all-notifications": "Bütün bildirişlərə bax"
+}
diff --git a/Echo/i18n/azb.json b/Echo/i18n/azb.json
new file mode 100644
index 00000000..6ab18127
--- /dev/null
+++ b/Echo/i18n/azb.json
@@ -0,0 +1,35 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mousa",
+ "Amir a57"
+ ]
+ },
+ "echo-desc": "بیلدیریش سیستِمی",
+ "prefs-echo": "بیلدیریلر",
+ "prefs-displaynotifications": "گؤرونتو سئچَنکلری",
+ "echo-pref-email-frequency-never": "منه هئچ بیلدیری ایمیلی گؤندرمه",
+ "echo-pref-email-frequency-immediately": "آیری آیری هر بیلدیری گلنده",
+ "echo-pref-email-frequency-daily": "گونلوک بیلدیریلرین بیر خولاصه‌سی",
+ "echo-pref-email-frequency-weekly": "هفته‌لیک بیلدیریلرین بیر خولاصه‌سی",
+ "echo-no-agent": "[هئچ کیمسه]",
+ "echo-no-title": "[هئچ صحیفه]",
+ "echo-error-no-formatter": "بیلدیری اوچون بیر فورمت تعریفی یوخدور",
+ "notifications": "بیلدیریلر",
+ "tooltip-pt-notifications": "سیزین بیلدیریشلرینیز",
+ "echo-specialpage": "منیم بیلدیریلریم",
+ "echo-anon": "بیلدیریلری آلماق اوچون، [$1 بیر حساب یارادین] یادا [$2 گیریش ائدین].",
+ "echo-none": "سیزین بیلدیرینیز یوخدور.",
+ "notification-new-user": "{{SITENAME}}-ه خوش گلمیسینیز، $1!",
+ "echo-email-subject-default": "{{SITENAME}}-ده یئنی بیلدیری",
+ "echo-email-body-default": "سیزین {{SITENAME}}-ده یئنی بیلدیرینیز واردیر:\n\n$1",
+ "echo-email-footer-default": "$2\n\nسیزه هانکی ایمیل‌لرین گله بیله‌جگینی دَییشمگه، باخین:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-overlay-link": "بوتون بیلدیریلر",
+ "echo-overlay-title": "منیم بیلدیریلریم",
+ "echo-overlay-title-overflow": "منیم بیلدیریلریم ($2 اوخونمامیشدان $1-ی گؤستریلیر)",
+ "echo-date-today": "بوگون",
+ "echo-date-yesterday": "دونن",
+ "echo-load-more-error": "آرتیق نتیجه‌لری گتیرنده بیر خطا قاباغا گلدی.",
+ "echo-email-batch-subject-daily": "سیزین بوگون $1 {{PLURAL:$2|بیلدیرینیز}} واردیر",
+ "echo-email-batch-subject-weekly": "سیزین بو هفته $1 {{PLURAL:$2|بیلدیرینیز}} واردیر"
+}
diff --git a/Echo/i18n/ba.json b/Echo/i18n/ba.json
new file mode 100644
index 00000000..6067fb7f
--- /dev/null
+++ b/Echo/i18n/ba.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ләйсән"
+ ]
+ },
+ "prefs-echo": "Белдереүҙәр",
+ "notifications": "Белдереүҙәр",
+ "tooltip-pt-notifications": "Һеҙҙең белдереүҙәр",
+ "echo-specialpage": "Минең белдереүҙәр",
+ "echo-overlay-link": "Бөтә белдереүҙәр",
+ "echo-overlay-title": "Минең белдереүҙәр"
+}
diff --git a/Echo/i18n/bbc-latn.json b/Echo/i18n/bbc-latn.json
new file mode 100644
index 00000000..e8b5a7b0
--- /dev/null
+++ b/Echo/i18n/bbc-latn.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "WBT001Erin"
+ ]
+ },
+ "echo-category-title-article-linked": "Alaman pangait",
+ "notification-edit-user-talk-email-batch-bundle-body": "alaman panghataion",
+ "notification-page-linked-email-batch-bundle-body": "alaman/alamanalaman"
+}
diff --git a/Echo/i18n/bcc.json b/Echo/i18n/bcc.json
new file mode 100644
index 00000000..3bbecc2d
--- /dev/null
+++ b/Echo/i18n/bcc.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Baloch Afghanistan"
+ ]
+ },
+ "echo-notification-alert": "{{جمع:$1|هشداران ($1)|هشداران ($1)|100=هشداران (99+)}}",
+ "echo-notification-message": "{{جمع:$1|پیامان ($1)|پیامان ($1)|100=پیامان (99+)}}",
+ "echo-date-today": "مروچی",
+ "echo-date-yesterday": "زئ"
+}
diff --git a/Echo/i18n/be-tarask.json b/Echo/i18n/be-tarask.json
new file mode 100644
index 00000000..3df68f9e
--- /dev/null
+++ b/Echo/i18n/be-tarask.json
@@ -0,0 +1,111 @@
+{
+ "@metadata": {
+ "authors": [
+ "Base",
+ "Renessaince",
+ "Wizardist",
+ "Red Winged Duck"
+ ]
+ },
+ "echo-desc": "Сыстэма апавяшчэньняў",
+ "prefs-echo": "Абвесткі",
+ "prefs-emailsettings": "Налады e-mail",
+ "prefs-displaynotifications": "Налады паказу",
+ "prefs-echosubscriptions": "Паведамляць мне пра гэтыя падзеі",
+ "prefs-newmessageindicator": "Індыкатар новых паведамленьняў",
+ "echo-pref-send-me": "Даслаць мне:",
+ "echo-pref-send-to": "Даслаць да:",
+ "echo-pref-email-format": "Фармат e-mail:",
+ "echo-pref-web": "Праз сайт",
+ "echo-pref-email": "Праз пошту",
+ "echo-pref-email-frequency-never": "Не дасылаць мне абвестак праз e-mail",
+ "echo-pref-email-frequency-immediately": "Асобна кожнае, калі зьяўляецца",
+ "echo-pref-email-frequency-daily": "Штодзённая зборка абвестак",
+ "echo-pref-email-frequency-weekly": "Штотыднёвая зборка абвестак",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Просты тэкст",
+ "echo-pref-notify-show-link": "Паказваць апавяшчэньні ў маёй панэлі",
+ "echo-pref-new-message-indicator": "Паказваць індыкатар паведамленьняў на старонцы гутарак у маёй панэлі",
+ "echo-learn-more": "Даведацца болей",
+ "echo-new-messages": "Вы маеце новыя паведамленьні",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|1=Паведамленьне|Паведамленьні}} ў гутарках",
+ "echo-category-title-article-linked": "{{PLURAL:$1|1=Спасылка|Спасылкі}} на старонку",
+ "echo-category-title-reverted": "{{PLURAL:$1|1=Адкат праўкі|Адкаты правак}}",
+ "echo-category-title-mention": "{{PLURAL:$1|1=Згадваньне|Згадваньні}}",
+ "echo-category-title-other": "{{PLURAL:$1|1=Іншае|Іншыя}}",
+ "echo-category-title-system": "{{PLURAL:$1|1=Сыстэмнае|Сыстэмныя}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|1=Зьмена|Зьмены}} правоў удзельніка",
+ "echo-pref-tooltip-edit-user-talk": "Паведамляць, калі нехта дасылае паведамленьне на маю старонку гутарак.",
+ "echo-pref-tooltip-article-linked": "Паведамляць, калі нехта спасылаецца на створаную мной старонку зь іншага артыкула.",
+ "echo-pref-tooltip-reverted": "Паведамляць, калі нехта адкатвае зробленую мной праўку.",
+ "echo-pref-tooltip-mention": "Паведамляць, калі нехта спасылаецца на маю старонку ўдзельніка.",
+ "echo-no-agent": "[Ніхто]",
+ "echo-no-title": "[Няма старонкі]",
+ "echo-error-no-formatter": "Фарматаваньне для абвестак ня вызначана",
+ "echo-error-preference": "Памылка: не ўдалося захаваць наладу",
+ "echo-error-token": "Памылка: не ўдалося атрымаць токен удзельніка",
+ "notifications": "Абвесткі",
+ "tooltip-pt-notifications": "Вашыя абвесткі",
+ "echo-specialpage": "Абвесткі",
+ "echo-anon": "Для атрыманьня абвестак [$1 стварыце рахунак] або [$2 увайдзіце].",
+ "echo-none": "Вы ня маеце абвестак.",
+ "echo-more-info": "Болей",
+ "echo-feedback": "Водгук",
+ "notification-link-text-view-message": "Праглядзець паведамленьне",
+ "notification-link-text-view-mention": "Праглядзець згадваньне",
+ "notification-link-text-view-changes": "Праглядзець зьмены",
+ "notification-link-text-view-page": "Праглядзець старонку",
+ "notification-link-text-view-edit": "Праглядзець праўку",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|пакінуў|пакінула}} паведамленьне на Вашай [[User talk:$2#$3|старонцы гутарак]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|пакінуў|пакінула}} паведамленьне на вашай старонцы гутарак у «[[User talk:$2#$3|$4]]».",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|пакінуў|пакінула}} паведамленьне на Вашай [[User talk:$2#$3|старонцы гутарак]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|пакінуў|пакінула}} паведамленьне на вашай старонцы гутарак у «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "На [[:$2]] {{GENDER:$1|спаслаліся}} з [[:$3]]. [[Special:WhatLinksHere/$2|усе спасылкі на гэтую старонку]].",
+ "notification-page-linked-flyout": "На [[:$2]] {{GENDER:$1|спаслаліся}} з [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|пакінуў|пакінула}} камэнтар у тэме «[[$3|$2]]» на старонцы абмеркаваньня «$4»",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|стварыў|стварыла}} новую тэму «$2» у [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|даслаў|даслала}} Вам паведамленьне: «[[$3#$2|$2]]»",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|пакінуў|пакінула}} камэнтар у тэме «[[$3#$2|$2]]» на вашай старонцы гутарак",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|згадаў|згадала}} Вас на старонцы размоваў $5 у «[[:$3#$2|$4]]».",
+ "notification-mention-flyout": "$1 {{GENDER:$1|згадаў|згадала}} Вас на старонцы абмеркаваньня $5 у «[[:$3#$2|$4]]».",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|зьмяніў|зьмяніла}}]] Вашыя правы. $2. [[Special:ListGroupRights|Даведайцеся болей]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|зьмяніў|зьмяніла}} вашыя правы. $2. [[Special:ListGroupRights|Даведайцеся больш]]",
+ "notification-user-rights-add": "Цяпер Вы ўваходзіце ў {{PLURAL:$2|1=гэтую групу|гэтыя групы}}: $1",
+ "notification-user-rights-remove": "Цяпер вы не ўваходзіце ў {{PLURAL:$2|1=гэтую групу|гэтыя групы}}: $1",
+ "notification-new-user": "Вітаем у {{GRAMMAR:месны|{{SITENAME}}}}, $1! Мы радыя бачыць Вас.",
+ "notification-reverted2": "{{PLURAL:$4|1=Вашая праўка|Вашыя праўкі}} на старонцы [[:$2]] {{PLURAL:$4|1=была скасавная|былі скасаваныя}} {{GENDER:$1|ўдзельнікам|ўдзельніцай}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "$1 {{GENDER:$1|скасаваў|скасавала}} {{PLURAL:$4|1=Вашую праўку|Вашыя праўкі}} на старонцы $2. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|пакінуў|пакінула}} Вам паведамленьне на {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|пакінуў|пакінула}} Вам паведамленьне на старонцы абмеркаваньня:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|пакінуў|пакінула}} паведамленьне на Вашай старонцы гутарак у «$2».",
+ "notification-page-linked-email-subject": "На вашую старонку спаслаліся ў {{GRAMMAR:месны|{{SITENAME}}}}",
+ "notification-page-linked-email-batch-body": "На $2 {{GENDER:$1|спаслаліся}} з $3.",
+ "notification-reverted-email-subject2": "$1 {{GENDER:$1|скасаваў|скасавала}} {{PLURAL:$3|1=Вашую праўку|Вашыя праўкі}} на сайце {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|скасаваў|скасавала}} {{PLURAL:$3|1=Вашую праўку|Вашыя праўкі}} на старонцы «$2».",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|згадаў|згадала}} Вас у {{GRAMMAR:месны|{{SITENAME}}}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|згадаў|згадала}} Вас на старонцы абмеркаваньня $4 у «$3».",
+ "notification-user-rights-email-subject": "Вашыя правы ў {{GRAMMAR:месны|{{SITENAME}}}} былі зьмененыя",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|зьмяніў|зьмяніла}} Вашыя правы. $2",
+ "echo-email-subject-default": "Новая абвестка ад {{GRAMMAR:родны|{{SITENAME}}}}",
+ "echo-email-body-default": "Для Вас ёсьць новая абвестка ў {{GRAMMAR:месны|{{SITENAME}}}}:\n\n$1",
+ "echo-email-batch-body-default": "Вы маеце новую абвестку",
+ "echo-email-footer-default": "$2\n\nКаб выбраць, якія лісты мы дасылацьмем Вам, наведайце свае налады:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Каб абраць лісты, якія Вы жадаеце атрымліваць, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">праверце свае налады</a>.<br />\n$1",
+ "echo-overlay-link": "Усе абвесткі",
+ "echo-overlay-title": "<b>Абвесткі</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|1=Паведамленьне|Паведамленьні}}</b> ({{PLURAL:$1|1=паказанае|паказаныя}} $1 з $2 {{PLURAL:$2|1=непрачытанага|непрачытаных}})",
+ "echo-mark-all-as-read": "Пазначыць усё як прачытанае",
+ "echo-date-today": "Сёньня",
+ "echo-date-yesterday": "Учора",
+ "echo-load-more-error": "Узьнікла памылка ў час атрыманьня дадатковых вынікаў.",
+ "notification-edit-talk-page-bundle": "$1 і $3 {{PLURAL:$4|іншы ўдзельнік|іншыя ўдзельнікі|іншых удзельнікаў}} пакінулі паведамленьне на Вашай [[User talk:$2|старонцы гутарак]].",
+ "notification-page-linked-bundle": "$1 {{GENDER:$1|дадаў|дадала}} спасылку на $2 на старонцы $3 і {{PLURAL:$5|1=іншай старонцы|$4 іншых старонках}}. [[Special:WhatLinksHere/$2|Глядзіце ўсе спасылкі на гэтую старонку]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 і $2 {{PLURAL:$3|1=іншы|іншых}} пакінулі паведамленьне на Вашай старонцы гутарак.",
+ "notification-page-linked-email-batch-bundle-body": "$1 {{GENDER:$1|дадаў|дадала}} спасылку на $2 на старонцы $3 і яшчэ $4 {{PLURAL:$5|старонцы|старонках}}.",
+ "echo-email-batch-subject-daily": "Вы атрымалі {{PLURAL:$2|новую абвестку|новыя абвесткі|новых абвестак}} на {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "На гэтым тыдні Вы атрымалі {{PLURAL:$2|новую абвестку|новыя абвесткі|новых абвестак}} на {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Вітаем, $1!\nВось агляд сёньняшняй актыўнасьці ў {{GRAMMAR:месны|{{SITENAME}}}} для Вас.",
+ "echo-email-batch-body-intro-weekly": "Вітаем, $1!\nВось тыднёвы агляд актыўнасьці ў {{GRAMMAR:месны|{{SITENAME}}}} для вас.",
+ "echo-email-batch-link-text-view-all-notifications": "Праглядзець усе абвесткі",
+ "echo-rev-deleted-text-view": "Гэтая вэрсія старонкі была схаваная."
+}
diff --git a/Echo/i18n/be.json b/Echo/i18n/be.json
new file mode 100644
index 00000000..307611a9
--- /dev/null
+++ b/Echo/i18n/be.json
@@ -0,0 +1,114 @@
+{
+ "@metadata": {
+ "authors": [
+ "Дзяніс Тутэйшы",
+ "Чаховіч Уладзіслаў",
+ "Mikalai Udodau"
+ ]
+ },
+ "echo-desc": "Сістэма паведамленняў",
+ "prefs-echo": "Паведамленні",
+ "prefs-emailsettings": "Настройкі эл. пошты",
+ "prefs-displaynotifications": "Настройкі адлюстравання",
+ "prefs-echosubscriptions": "Паведамляць мне пра гэтыя падзеі",
+ "prefs-newmessageindicator": "Індыкатар новага паведамлення",
+ "echo-pref-send-me": "Дасылаць мне:",
+ "echo-pref-send-to": "Дасылаць да:",
+ "echo-pref-email-format": "Фармат e-mail:",
+ "echo-pref-web": "Праз сайт",
+ "echo-pref-email": "Эл.пошта",
+ "echo-pref-email-frequency-never": "Не дасылаць мне паведамленні па эл. пошце",
+ "echo-pref-email-frequency-immediately": "Асобныя паведамленні па меры іх паступлення",
+ "echo-pref-email-frequency-daily": "Штодзённы агляд паведамленняў",
+ "echo-pref-email-frequency-weekly": "Штотыдневы агляд паведамленняў",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Просты тэкст",
+ "echo-pref-notify-show-link": "Паказаць паведамленні ў маёй панэлі інструментаў",
+ "echo-pref-new-message-indicator": "Паказаць у маёй панэлі інструментаў індыкатар паведамленняў на старонцы абмеркавання",
+ "echo-learn-more": "Даведацца больш",
+ "echo-new-messages": "У вас ёсць новыя паведамленні",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|паведамленне|паведамленні}} на старонцы размоў",
+ "echo-category-title-article-linked": "{{PLURAL:$1|спасылка|спасылкі}} на старонкі",
+ "echo-category-title-reverted": "{{PLURAL:$1|адмена|адмены}} правак",
+ "echo-category-title-mention": "{{PLURAL:$1|Згадванне|Згадванні}}",
+ "echo-category-title-other": "{{PLURAL:$1|Іншае|Іншыя}}",
+ "echo-category-title-system": "{{PLURAL:$1|Сістэмнае|Сістэмныя}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Змяненне доступаў удзельніка|Змяненні доступаў удзельніка}}",
+ "echo-pref-tooltip-edit-user-talk": "Паведамляць мне, калі хтосьці пакідае паведамленне ці адказвае на маёй старонцы размоў.",
+ "echo-pref-tooltip-article-linked": "Паведамляць мне, калі хтосьці спасылаецца ў артыкулах на створаную мной старонку",
+ "echo-pref-tooltip-reverted": "Паведамляць мне, калі хтосьці адмяніў маю праўку, выкарыстаўшы функцыю адмены ці адкату.",
+ "echo-pref-tooltip-mention": "Паведамляць мне, калі хтосьці высылаецца на маю старонку ўдзельніка.",
+ "echo-pref-tooltip-user-rights": "Паведамляць мне, калі хтосьці змяняе мае правы доступу.",
+ "echo-no-agent": "[Ніхто]",
+ "echo-no-title": "[Няма старонкі]",
+ "echo-error-no-formatter": "Фарматаванне не вызначана для паведамлення",
+ "echo-error-preference": "Памылка: Не ўдалося задаць настройкі ўдзельніка",
+ "echo-error-token": "Памылка: не ўдалося атрымаць маркер удзельніка (user token)",
+ "notifications": "Паведамленні",
+ "tooltip-pt-notifications": "Вашы паведамленні",
+ "echo-specialpage": "Паведамленні",
+ "echo-anon": "Каб атрымліваць паведамленні, [$1 стварыце ўліковы запіс] ці [$2 прадстаўцеся].",
+ "echo-none": "Вы не атрымлівалі паведамленняў.",
+ "echo-more-info": "Больш падрабязна",
+ "echo-feedback": "Зваротная сувязь",
+ "notification-link-text-view-message": "Прагляд паведамленняў",
+ "notification-link-text-view-mention": "Прагляд згадкі",
+ "notification-link-text-view-changes": "Прагляд змен",
+ "notification-link-text-view-page": "Прагляд старонкі",
+ "notification-link-text-view-edit": "Прагляд праўкі",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|пакінуў|пакінула}} паведамленне на вашай [[User talk:$2#$3|старонцы размоў]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|пакінуў|пакінула}} паведамленне на вашай старонцы размоў \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|пакінуў|пакінула}} паведамленне на вашай [[User talk:$2#$3|старонцы размоў]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|пакінуў|пакінула}} паведамленне на вашай старонцы размоў \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] была {{GENDER:$1|звязана}} з [[:$3]]. [[Special:WhatLinksHere/$2|Гл. усе спасылкі на гэту старонку]].",
+ "notification-page-linked-flyout": "[[:$2]] была {{GENDER:$1|звязана}} з [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|пракаментаваў|пракаментавала}} тэму \"[[$3|$2]]\" на старонцы размоў \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|дадаў|дадала}} новую тэму \"$2\" на старонцы [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|адправіў|адправіла}} вам паведамленне: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|пракаментаваў|пракаментавала}} тэму \"[[$3#$2|$2]]\" на вашай старонцы размоў.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|згадаў|згадала}} вас на старонцы размоў $5 у раздзеле \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|згадаў|згадала}} вас на старонцы размоў $5 у раздзеле \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|згадаў|згадала}} вас на [[:$3|$2 старонцы размоў]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|згадаў|згадала}} вас на [[:$3|$2 старонцы размоў]].",
+ "notification-user-rights": "Вашы правы карыстальніка [[Special:Log/rights/$1|{{GENDER:$1|змяніў|змяніла}}]] [[User:$1|$1]]. $2. [[Special:ListGroupRights|Падрабязней]]",
+ "notification-user-rights-flyout": "Вашы правы доступу {{GENDER:$1|змяніў|змяніла}} $1. $2. [[Special:ListGroupRights|Падрабязней]]",
+ "notification-user-rights-add": "Вы цяпер удзельнік {{PLURAL:$2|1=наступнай групы|наступных груп}}: $1",
+ "notification-user-rights-remove": "Вы больш не ўваходзіце ў {{PLURAL:$2|1=наступную групу|наступныя групы}}: $1",
+ "notification-new-user": "Вітаем у {{GRAMMAR:месны|{{SITENAME}}}}, $1! Рады бачыць вас.",
+ "notification-reverted2": "{{PLURAL:$4|1=Вашу праўку на старонцы [[:$2]]|Вашы праўкі на старонцы [[:$2]]}} {{GENDER:$1|скасаваў|скасавала}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|1=Вашу праўку на старонцы $2|Вашы праўкі на старонцы $2}} {{GENDER:$1|скасаваў|скасавала}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|Удзельнік|Удзельніца}} $1 {{GENDER:$1|пакінуў|пакінула}} вам паведамленне на пляцоўцы «{{SITENAME}}»",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|Удзельнік|Удзельніца}} $1 {{GENDER:$1|пакінуў|пакінула}} паведамленне на вашай старонцы размоў:",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|Удзельнік|Удзельніца}} $1 {{GENDER:$1|пакінуў|пакінула}} вам паведамленне на вашай старонцы размоў у раздзеле (тэме) «$2»",
+ "notification-page-linked-email-subject": "На сайце «{{SITENAME}}» з'явілася спасылка на вашу старонку ўдзельніка",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|Удзельнік|удзельніца}} $1 {{GENDER:$1|спаслаўся|спаслалася}} на $2 з $3",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Хтосьці}} адмяніў {{PLURAL:$3|вашу праўку|вашы праўкі}} на сайце «{{SITENAME}}»",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Ваша праўка на старонцы «$2» была адменена|Вашы праўкі на старонцы «$2» былі адменены}} {{GENDER:$1|ўдзельнікам|ўдзельніцай}} $1.",
+ "notification-mention-email-subject": "{{GENDER:$1|Удзельнік|Удзельніца}} $1 {{GENDER:$1|згадаў|згадала}} вас на сайце «{{SITENAME}}»",
+ "notification-mention-email-batch-body": "{{GENDER:$1|Удзельнік|Удзельніца}} $1 {{GENDER:$1|згадаў|згадала}} вас на старонцы размоў $4 на сайце «$3».",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|згадаў|згадала}} вас на старонцы размоў $2.",
+ "notification-user-rights-email-subject": "Вашы правы на сайце «{{SITENAME}}» былі зменены",
+ "notification-user-rights-email-batch-body": "Вашы правы былі зменены {{GENDER:$1|ўдзельнікам|ўдзельніцай}} $1. $2.",
+ "echo-email-subject-default": "Новыя паведамленні на сайце «{{SITENAME}}»",
+ "echo-email-body-default": "У вас ёсць новае паведамленне на сайце «{{SITENAME}}»: $1",
+ "echo-email-batch-body-default": "У вас ёсць новае паведамленне",
+ "echo-email-footer-default": "$2 Для кантролю за тым, якія паведамленні адпраўляюцца вам па эл. пошце, праверце свае персанальныя настройкі: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}} $1",
+ "echo-email-footer-default-html": "Для кантролю за тым, якія паведамленні адпраўляюцца вам па эл. пошце, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">праверце свае персанальныя настройкі</a><br /> $1",
+ "echo-overlay-link": "Усе паведамленні",
+ "echo-overlay-title": "<b>Паведамленні</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Паведамленні}}</b> ({{PLURAL|$1|паказана|паказаны}} $1 з $2 {{PLURAL|$2|непрачытанага|непрачытаных}})",
+ "echo-mark-all-as-read": "Пазначыць усе як прачытаныя",
+ "echo-date-today": "Сёння",
+ "echo-date-yesterday": "Учора",
+ "echo-load-more-error": "Адбылася памылка пры атрыманні дадатковых вынікаў.",
+ "notification-edit-talk-page-bundle": "$1 і $3 {{PLURAL:$4|іншы|іншых}} {{PLURAL:$4|ўдзельнік|удзельнікаў}} пакінулі паведамленне на вашай [[User talk:$2|старонцы размоў]].",
+ "notification-page-linked-bundle": "На старонку «$2» ёсць {{GENDER:$1|спасылка}} са старонкі «$3» і яшчэ $4 {{PLURAL:$5|старонкі|старонак}}. [[Special:WhatLinksHere/$2|Гл. усе спасылкі на гэту старонку]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 і $2 {{PLURAL:$3|іншы|іншых}} {{PLURAL:$3|ўдзельнік|удзельнікаў}} пакінулі паведамленне на вашай старонцы размоў.",
+ "notification-page-linked-email-batch-bundle-body": "На старонку «$2» ёсць {{GENDER:$1|спасылка}} са старонкі «$3» і яшчэ $4 {{PLURAL:$5|старонкі|старонак}}",
+ "echo-email-batch-subject-daily": "Вы атрымалі $2 {{PLURAL:$2|новае паведамленне ў|новых паведамлення ў|новых паведамленняў у}} праекце «{{SITENAME}}»",
+ "echo-email-batch-subject-weekly": "На гэтым тыдні вы атрымалі $2 {{PLURAL:$2|новае паведамленне ў|новых паведамлення ў|новых паведамленняў у}} праекце «{{SITENAME}}»",
+ "echo-email-batch-body-intro-daily": "Прывітанне, $1! Вось кароткі агляд сённяшняй дзейнасці ў {{SITENAME}} для вас.",
+ "echo-email-batch-body-intro-weekly": "Прывітанне, $1! Вось кароткі тыднёвы агляд дзейнасці ў {{SITENAME}} для вас.",
+ "echo-email-batch-link-text-view-all-notifications": "Праглядзець усе паведамленні",
+ "echo-rev-deleted-text-view": "Гэта версія старонкі была схавана"
+}
diff --git a/Echo/i18n/bg.json b/Echo/i18n/bg.json
new file mode 100644
index 00000000..64e0c094
--- /dev/null
+++ b/Echo/i18n/bg.json
@@ -0,0 +1,80 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aceofhearts1968",
+ "DCLXVI",
+ "Termininja",
+ "Borislav"
+ ]
+ },
+ "echo-desc": "Система за известия",
+ "prefs-echo": "Известия",
+ "prefs-emailsettings": "Настройки за е-поща",
+ "prefs-displaynotifications": "Настройки за показване",
+ "prefs-echosubscriptions": "Получаване на известие за следните събития",
+ "prefs-newmessageindicator": "Индикатор за ново съобщение",
+ "echo-pref-send-me": "Съдържание на е-писмата:",
+ "echo-pref-send-to": "Адрес за получаване:",
+ "echo-pref-email-format": "Формат на е-писмата:",
+ "echo-pref-web": "Уеб",
+ "echo-pref-email": "Е-поща",
+ "echo-pref-email-frequency-never": "Без изпращане на известия по е-поща",
+ "echo-pref-email-frequency-immediately": "Известие за всяко отделно събитие",
+ "echo-pref-email-frequency-daily": "Дневно резюме на известията",
+ "echo-pref-email-frequency-weekly": "Седмично резюме на известията",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "обикновен текст",
+ "echo-pref-notify-show-link": "Показване на известията в лентата с моите инструменти",
+ "echo-pref-new-message-indicator": "Показване на индикатор за съобщения на беседата в лентата с моите инструменти",
+ "echo-learn-more": "Повече подробности",
+ "echo-new-messages": "Имате нови съобщения",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Съобщение|Съобщения}} на беседата",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Препратка|Препратки}} към страници",
+ "echo-category-title-reverted": "{{PLURAL:$1|Връщане|Връщания}} на редакция",
+ "echo-category-title-mention": "{{PLURAL:$1|Споменаване|Споменавания}}",
+ "echo-category-title-other": "{{PLURAL:$1|Други}}",
+ "echo-category-title-system": "{{PLURAL:$1|Системни известия}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Промяна|Промени}} на потребителските права",
+ "echo-pref-tooltip-edit-user-talk": "Известяване, когато някой остави съобщение или отговор на беседата ми.",
+ "echo-pref-tooltip-article-linked": "Известяване, когато някой постави препратка в статия към създадена от мен страница.",
+ "echo-pref-tooltip-reverted": "Известяване, когато някой премахне или отмени моя редакция чрез инструмента за връщане.",
+ "echo-pref-tooltip-mention": "Известяване, когато някой постави препратка към потребителската ми страница.",
+ "echo-pref-tooltip-user-rights": "Известяване, когато някой промени потребителските ми права.",
+ "echo-no-agent": "[Никой]",
+ "echo-no-title": "[Няма страница]",
+ "echo-error-no-formatter": "Не е посочено форматиране на известията.",
+ "echo-error-preference": "Грешка: Потребителските предпочитания не бяха съхранени.",
+ "notifications": "Известия",
+ "tooltip-pt-notifications": "Вашите известия",
+ "echo-specialpage": "Известия",
+ "echo-anon": "За получаване на известия е необходимо да [$1 регистрирате сметка] или [$2 влезте] в системата.",
+ "echo-none": "Нямате известия.",
+ "echo-more-info": "Повече информация",
+ "echo-feedback": "Обратна връзка",
+ "notification-link-text-view-message": "Преглед на известието",
+ "notification-link-text-view-mention": "Преглед на споменаването",
+ "notification-link-text-view-changes": "Преглед на промените",
+ "notification-link-text-view-page": "Преглед на страницата",
+ "notification-link-text-view-edit": "Преглед на редакцията",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|остави}} съобщение на Вашата [[User talk:$2#$3|беседа]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|остави}} съобщение на Вашата беседа „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|остави}} съобщение на Вашата [[User talk:$2#$3|беседа]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|остави}} съобщение на Вашата беседа „[[User talk:$2#$3|$4]]“.",
+ "notification-new-user": "Добре дошли в {{SITENAME}}, $1! Радостно е, че сте сред нас.",
+ "notification-user-rights-email-subject": "Потребителските ви права в {{SITENAME}} бяха променени",
+ "echo-email-subject-default": "Ново известие в {{SITENAME}}",
+ "echo-email-body-default": "Имате ново известие в {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Имате ново известие.",
+ "echo-overlay-link": "Всички известия",
+ "echo-overlay-title": "<b>Известия</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Известия}}</b> (показване на $1 от $2 непрочетени))",
+ "echo-mark-all-as-read": "Отбелязване на всички като прочетени",
+ "echo-date-today": "Днес",
+ "echo-date-yesterday": "Вчера",
+ "echo-load-more-error": "Възникна грешка при извличане на още резултати.",
+ "echo-email-batch-subject-daily": "Имате {{PLURAL:$2|ново известие|нови известия}} в {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Имате {{PLURAL:$2|ново известие|нови известия}} в {{SITENAME}} от тази седмица",
+ "echo-email-batch-body-intro-daily": "Здравейте $1,\nПо-долу е показано резюме на активността в {{SITENAME}} за днес.",
+ "echo-email-batch-body-intro-weekly": "Здравейте $1,\nПо-долу е показано резюме на активността в {{SITENAME}} през седмицата.",
+ "echo-email-batch-link-text-view-all-notifications": "Преглед на всички известия"
+}
diff --git a/Echo/i18n/bgn.json b/Echo/i18n/bgn.json
new file mode 100644
index 00000000..443a8424
--- /dev/null
+++ b/Echo/i18n/bgn.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Baloch Afghanistan"
+ ]
+ },
+ "echo-pref-send-me": "په من دیم دئ:",
+ "echo-pref-send-to": "دیم داته بیئت په:",
+ "echo-pref-email-format": "ایمیلئ فرمت:",
+ "echo-pref-web": "ویب",
+ "echo-pref-email": "ایمیل",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "ساده گین متن",
+ "echo-learn-more": "گیشتیر بزانیت",
+ "echo-category-title-other": "{{PLURAL:$1|دیگرین}}",
+ "echo-category-title-system": "{{PLURAL:$1|سیستیم}}",
+ "echo-no-agent": "[هیچ کس]",
+ "echo-no-title": "[بیدون ورق]",
+ "notifications": "نئ مئلوماتان",
+ "tooltip-pt-notifications": "شمی مئلوماتان",
+ "echo-specialpage": "نئ مئلوماتان",
+ "notification-link-text-view-message": "پیامئ دیستین",
+ "notification-link-text-view-page": "تاکدیمی دیستین",
+ "echo-date-today": "مروچی",
+ "echo-date-yesterday": "زئ"
+}
diff --git a/Echo/i18n/bho.json b/Echo/i18n/bho.json
new file mode 100644
index 00000000..11c98fa6
--- /dev/null
+++ b/Echo/i18n/bho.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nepaboy"
+ ]
+ },
+ "tooltip-pt-notifications": "आपके अधिसूचनासब"
+}
diff --git a/Echo/i18n/bn.json b/Echo/i18n/bn.json
new file mode 100644
index 00000000..acce9940
--- /dev/null
+++ b/Echo/i18n/bn.json
@@ -0,0 +1,121 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aftab1995",
+ "Bellayet",
+ "Jayantanth",
+ "Nasir8891",
+ "Sayak Sarkar",
+ "Aftabuzzaman"
+ ]
+ },
+ "echo-desc": "বিজ্ঞপ্তি ব্যবস্থা",
+ "prefs-echo": "বিজ্ঞপ্তি",
+ "prefs-emailsettings": "ইমেইল অপশন",
+ "prefs-displaynotifications": "প্রদর্শনের অপশন",
+ "prefs-echosubscriptions": "এই ঘটনা সম্পর্কে আমাকে অবহিত করো",
+ "prefs-newmessageindicator": "নতুন বার্তা নির্দেশক",
+ "echo-pref-send-me": "আমাকে পাঠাও:",
+ "echo-pref-send-to": "প্রাপক:",
+ "echo-pref-email-format": "ইমেইল ফরমেট:",
+ "echo-pref-web": "ওয়েব",
+ "echo-pref-email": "ইমেইল",
+ "echo-pref-email-frequency-never": "আমাকে কোনো ইমেইল বিজ্ঞপ্তি পাঠিও না",
+ "echo-pref-email-frequency-immediately": "স্বতন্ত্র বিজ্ঞপ্তি আসা মাত্রই",
+ "echo-pref-email-frequency-daily": "দৈনিক বিজ্ঞপ্তির একটি সারাংশ",
+ "echo-pref-email-frequency-weekly": "সাপ্তাহিক বিজ্ঞপ্তির একটি সারাংশ",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "সরল লেখা",
+ "echo-pref-notify-show-link": "আমার টুলবারে বিজ্ঞপ্তি দেখাও",
+ "echo-pref-new-message-indicator": "আমার টুলবারে আলাপ পাতা বার্তা নির্দেশক (বিজ্ঞপ্তি) দেখাও",
+ "echo-learn-more": "আরও জানুন",
+ "echo-new-messages": "আপনার নতুন বার্তা এসেছে",
+ "echo-category-title-edit-user-talk": "আলাপ পাতার {{PLURAL:$1|বার্তা|বার্তাসমূহ}}",
+ "echo-category-title-article-linked": "পাতা {{PLURAL:$1|সংযোগ|সংযোগসমূহ}}",
+ "echo-category-title-reverted": "সম্পাদনা {{PLURAL:$1|ফেরত}}",
+ "echo-category-title-mention": "{{PLURAL:$1|উল্লেখ|উল্লেখসমূহ}}",
+ "echo-category-title-other": "{{PLURAL:$1|অন্য}}",
+ "echo-category-title-system": "{{PLURAL:$1|সিস্টেম}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|ব্যবহারকারীর অধিকার পরিবর্তন}}",
+ "echo-pref-tooltip-edit-user-talk": "আমার আলাপ পাতায় কেউ বার্তা রাখলে বা উত্তর দিলে আমাকে বিজ্ঞপ্তি দাও।",
+ "echo-pref-tooltip-article-linked": "যদি কেউ অন্য পাতায় আমার তৈরি কোনো পাতার লিঙ্ক প্রদান করে তাহলে আমাকে বিজ্ঞপ্তি দাও।",
+ "echo-pref-tooltip-reverted": "আনডু বা রোলব্যাক টুল দিয়ে কেউ আমার সম্পাদনা ফেরত নিলে আমাকে বিজ্ঞপ্তি দাও।",
+ "echo-pref-tooltip-mention": "কেউ আমার ব্যবহারকারী পাতার লিঙ্ক প্রদান করলে আমাকে বিজ্ঞপ্তি দাও।",
+ "echo-pref-tooltip-user-rights": "কেউ আমার ব্যবহারকারীর অধিকার পরিবর্তন করলে আমাকে বিজ্ঞপ্তি দাও।",
+ "echo-no-agent": "[কেউ নাই]",
+ "echo-no-title": "[কোনো পাতা নাই]",
+ "echo-error-no-formatter": "বিজ্ঞপ্তির জন্য কোনো ফরমেটিং নির্ধারিত হয়নি",
+ "echo-error-preference": "ত্রুটি: ব্যবহারকারী পছন্দ ধার্য্য করা যাচ্ছে না",
+ "echo-error-token": "ত্রুটি: ব্যবহারকারী টোকেন উদ্ধার করা যাচ্ছে না",
+ "notifications": "বিজ্ঞপ্তি",
+ "tooltip-pt-notifications": "আপনার বিজ্ঞপ্তি",
+ "echo-specialpage": "বিজ্ঞপ্তি",
+ "echo-anon": "বিজ্ঞপ্তি পেতে, [$1 অ্যাকাউন্ট তৈরি] অথবা [$2 প্রবেশ] করুন।",
+ "echo-none": "আপনার কোন বিজ্ঞপ্তি নাই।",
+ "echo-more-info": "আরও তথ্য",
+ "echo-feedback": "প্রতিক্রিয়া",
+ "notification-link-text-view-message": "বার্তা দেখাও",
+ "notification-link-text-view-mention": "উল্লেখণ দেখাও",
+ "notification-link-text-view-changes": "পরিবর্তনসমূহ দেখাও",
+ "notification-link-text-view-page": "পাতা দেখাও",
+ "notification-link-text-view-edit": "সম্পাদনা দেখাও",
+ "notification-edit-talk-page2": "[[User:$1|$1]] আপনার [[User talk:$2#$3|আলাপ পাতায়]] একটি বার্তা {{GENDER:$1|রেখেছেন}}।",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] আপনার আলাপ পাতার \"[[User talk:$2#$3|$4]]\"-এ একটি বার্তা {{GENDER:$1|রেখেছেন}}।",
+ "notification-edit-talk-page-flyout2": "$1 আপনার [[User talk:$2#$3|আলাপ পাতায়]] একটি বার্তা {{GENDER:$1|রেখেছেন}}।",
+ "notification-edit-talk-page-flyout-with-section": "$1 আপনার আলাপ পাতার \"[[User talk:$2#$3|$4]]\"-এ একটি বার্তা {{GENDER:$1|রেখেছেন}}।",
+ "notification-page-linked": "[[:$3]] থেকে [[:$2]] {{GENDER:$1|সংযুক্ত}} রয়েছে। [[Special:WhatLinksHere/$2|এই পাতার সাথে সকল সংযোগ দেখুন]]।",
+ "notification-page-linked-flyout": "[[:$3]] থেকে [[:$2]] {{GENDER:$1|সংযুক্ত}} রয়েছে।",
+ "notification-add-comment2": "[[User:$1|$1]] \"[[$3|$2]]\" সম্পর্কে \"$4\"-এর আলাপ পাতায় {{GENDER:$1|মন্তব্য করেছেন}}।",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] [[$3]]-এ \"$2\" সম্পর্কে একটি নতুন বিষয় {{GENDER:$1|পোষ্ট করেছেন}}।",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] আপনাকে একটি বার্তা {{GENDER:$1|পাঠিয়েছেন}}: \"[[$3#$2|$2]]\"।",
+ "notification-add-comment-yours2": "[[User:$1|$1]] আপনার আলাপ পাতায় \"[[$3#$2|$2]]\" সম্পর্কে {{GENDER:$1|মন্তব্য করেছেন}}।",
+ "notification-mention": "[[User:$1|$1]] $5-এর আলাপ পাতায় [[:$3#$2|$4]]-এ আপনাকে {{GENDER:$1|উল্লেখ করেছেন}}।",
+ "notification-mention-flyout": "$1 $5-এর আলাপ পাতায় \"[[:$3#$2|$4]]\"-এ আপনাকে {{GENDER:$1|উল্লেখ করেছেন}}।",
+ "notification-mention-nosection": "[[User:$1|$1]] [[:$3|$2-এর আলাপ পাতায়]] আপনাকে {{GENDER:$1|উল্লেখ করেছেন}}।",
+ "notification-mention-nosection-flyout": "$1 [[:$3|$2-এর আলাপ পাতায়]] আপনাকে {{GENDER:$1|উল্লেখ করেছেন}}।",
+ "notification-user-rights": "[[User:$1|$1]] আপনার ব্যবহারকারী অধিকার [[Special:Log/rights/$1|{{GENDER:$1|পরিবর্তন করেছেন}}]]। $2। [[Special:ListGroupRights|আরও জানুন]]",
+ "notification-user-rights-flyout": "$1 আপনার ব্যবহারকারী অধিকার {{GENDER:$1|পরিবর্তন করেছেন}}। $2। [[Special:ListGroupRights|আরও জানুন]]",
+ "notification-user-rights-add": "আপনি এখন থেকে {{PLURAL:$2|এই দলের|এই দলসমূহের}} একজন সদস্য: $1",
+ "notification-user-rights-remove": "আপনি আর {{PLURAL:$2|এই দলের|এই দলসমূহের}} সদস্য নন।: $1",
+ "notification-new-user": "{{SITENAME}} সাইটে স্বাগতম, $1! আপনাকে এখানে পেয়ে আমরা খুব আনন্দিত।",
+ "notification-reverted2": "{{PLURAL:$4[[:$2]]-এ আপনার সম্পাদনা|[[:$2]]-এ আপনার সম্পাদনাগুলো}} [[User:$1|$1]] দ্বারা {{GENDER:$1|পূর্বাবস্থায়}} নেওয়া হয়েছে। $3",
+ "notification-reverted-flyout2": "$2-এ আপনার {{PLURAL:$4|সম্পাদনা|সম্পাদনাগুলো}} $1 দ্বারা {{GENDER:$1|পূর্বাবস্থায়}} নেয়া হয়েছে। $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{SITENAME}} এ আপনার জন্য একটি বার্তা {{GENDER:$1|রেখেছেন}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 আপনার আলাপ পাতায় একটি বার্তা {{GENDER:$1|রেখেছেন}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 আপনার আলাপ পাতায় \"$2\"-এ একটি বার্তা {{GENDER:$1|রেখেছেন}}।",
+ "notification-page-linked-email-subject": "আপনার পাতাটি {{SITENAME}} সাইটে সংযুক্ত রয়েছে।",
+ "notification-page-linked-email-batch-body": "$2 পাতাটি $3 হতে {{GENDER:$1|সংযুক্ত}}।",
+ "notification-reverted-email-subject2": "{{SITENAME}}-এ আপনার {{PLURAL:$3|সম্পাদনা|সম্পাদনাগুলো}} {{GENDER:$1|পূর্বাবস্থায়}} নেয়া হয়েছে",
+ "notification-reverted-email-batch-body2": "$1 দ্বারা {{PLURAL:$3|$2-এ আপনার সম্পাদনা|$2-এ আপনার সম্পাদনাগুলি}} {{GENDER:$1|পূর্বাবস্থায়}} নেয়া হয়েছে।",
+ "notification-mention-email-subject": "$1 আপনাকে {{SITENAME}}-এ {{GENDER:$1|উল্লেখ করেছেন}}",
+ "notification-mention-email-batch-body": "$1 আপনাকে $4-এর আলাপ পাতায় \"$3\"-এ {{GENDER:$1|উল্লেখ করেছেন}}।",
+ "notification-mention-nosection-email-batch-body": "$1 $2-এর আলাপ পাতায় আপনাকে {{GENDER:$1|উল্লেখ করেছেন}}।",
+ "notification-user-rights-email-subject": "{{SITENAME}}-এ আপনার ব্যবহারকারী অধিকার পরবর্তন হয়েছে",
+ "notification-user-rights-email-batch-body": "$1 আপনার অধিকারসমূহ {{GENDER:$1|পরিবর্তন করেছেন}}। $2।",
+ "echo-email-subject-default": "{{SITENAME}} এ নতুন বিজ্ঞপ্তি",
+ "echo-email-body-default": "{{SITENAME}} এ আপনার একটি নতুন বিজ্ঞপ্তি রয়েছে:\n\n$1",
+ "echo-email-batch-body-default": "আপনার নতুন একটি বিজ্ঞপ্তি রয়েছে।",
+ "echo-email-footer-default": "$2\n\nযে ইমেইল আমরা আপনাকে পাঠাই তা নিয়ন্ত্রণ করতে, আপনার পছন্দসমূহ পরীক্ষা করুন:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "যে ইমেইল আমরা আপনাকে পাঠাই তা নিয়ন্ত্রণ করতে, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">আপনার পছন্দসমূহ পরীক্ষা করুন</a>।<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|সতর্কতা ($1)|100=সতর্কতা (৯৯+)}}",
+ "echo-notification-message": "{{PLURAL:$1|বার্তা ($1)|100=বার্তা (৯৯+)}}",
+ "echo-notification-alert-text-only": "সতর্কতা",
+ "echo-notification-message-text-only": "বার্তা",
+ "echo-overlay-link": "সকল বিজ্ঞপ্তি",
+ "echo-overlay-title": "<b>বিজ্ঞপ্তি</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|বিজ্ঞপ্তি}}</b> (অপঠিত $2টির মধ্যে $1টি প্রদর্শিত হচ্ছে)",
+ "echo-mark-all-as-read": "সব পঠিত বলে চিহ্নিত",
+ "echo-date-today": "আজ",
+ "echo-date-yesterday": "গতকাল",
+ "echo-load-more-error": "আরও ফলাফল আনার সময় কোনো ত্রুটি হয়েছে।",
+ "notification-edit-talk-page-bundle": "$1 এবং আরো $3 {{PLURAL:$4|জন}} [[User talk:$2|আপনার আলাপ পাতায়]] একটি {{GENDER:$1|বার্তা}} রেখেছেন।",
+ "notification-page-linked-bundle": "$3 এবং আরো $4টি {{PLURAL:$5|পাতায়}} $2 পাতার {{GENDER:$1|সংযোগ}} রয়েছে।[[Special:WhatLinksHere/$2|সংযোগকারী পাতাগুলিকে দেখুন]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 এবং আরও $2 {{PLURAL:$3|জন}} আপনার আলাপ পাতায় বার্তা {{GENDER:$1|দিয়েছেন}}।",
+ "notification-page-linked-email-batch-bundle-body": "$3 এবং আরো $4টি {{PLURAL:$5|পাতায়}} $2 পাতার {{GENDER:$1|সংযোগ}} রয়েছে।",
+ "echo-email-batch-subject-daily": "আপনি {{SITENAME}}-এ {{PLURAL:$2|একটি নতুন বিজ্ঞপ্তি|নতুন বিজ্ঞপ্তিসমূহ}} পেয়েছেন",
+ "echo-email-batch-subject-weekly": "এই সপ্তাহে আপনি {{SITENAME}}-এ {{PLURAL:$2|একটি নতুন বিজ্ঞপ্তি|নতুন বিজ্ঞপ্তিসমূহ}} পেয়েছেন",
+ "echo-email-batch-body-intro-daily": "প্রিয় $1,\n{{SITENAME}} সাইটে আপনার জন্য দিনের কার্যক্রমের সারাংশ এখানে দেওয়া হল।",
+ "echo-email-batch-body-intro-weekly": "প্রিয় $1,\n{{SITENAME}} সাইটে আপনার জন্য সপ্তাহের কার্যক্রমের সারাংশ এখানে দেওয়া হল।",
+ "echo-email-batch-link-text-view-all-notifications": "সকল বিজ্ঞপ্তি দেখাও",
+ "echo-rev-deleted-text-view": "এই পাতা সংস্করণটি বাতিল করা হয়েছে।"
+}
diff --git a/Echo/i18n/br.json b/Echo/i18n/br.json
new file mode 100644
index 00000000..c539408a
--- /dev/null
+++ b/Echo/i18n/br.json
@@ -0,0 +1,96 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fohanno",
+ "Fulup",
+ "Y-M D"
+ ]
+ },
+ "echo-desc": "Reizhiad kemennoù",
+ "prefs-echo": "Kemennoù",
+ "prefs-emailsettings": "Dibarzhioù postel",
+ "prefs-displaynotifications": "Dibarzhioù diskwel",
+ "prefs-echosubscriptions": "Kemenn din an darvoudoù-mañ",
+ "prefs-newmessageindicator": "Merker kemennadenn nevez",
+ "echo-pref-send-me": "Kas din :",
+ "echo-pref-send-to": "Kas da :",
+ "echo-pref-email-format": "Furmad ar postel :",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Postel",
+ "echo-pref-email-frequency-never": "Arabat kas posteloù kemenn din",
+ "echo-pref-email-frequency-immediately": "Kemennoù hiniennel evel ma teuont",
+ "echo-pref-email-frequency-daily": "Un diverrañ pemdeziek eus ar c'hemennoù",
+ "echo-pref-email-frequency-weekly": "Un diverrañ sizhuniek eus ar c'hemennoù",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Testenn blaen",
+ "echo-pref-notify-show-link": "Diskouez ar c'hemennoù em barrenn ostilhoù",
+ "echo-learn-more": "Gouzout hiroc'h",
+ "echo-new-messages": "Kemennadennoù nevez zo ganeoc'h",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Kemennadenn|Kemennadennoù}} ar bajenn gaozeal",
+ "echo-category-title-article-linked": "Pajenn {{PLURAL:$1|link}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Kemm|Kemmoù}} nullet",
+ "echo-category-title-mention": "{{PLURAL:$1|Meneg}}",
+ "echo-category-title-other": "{{PLURAL:$1|All}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-pref-tooltip-edit-user-talk": "Kemenn din pa vez postet ur gemennadenn gant unan bennak pe pa respont war ma fajenn gaozeal.",
+ "echo-pref-tooltip-article-linked": "Ma c'hemenn pa vez graet ul liamm war-du ur bajennn am eus krouet gant unan bennak adalek pajenn ur pennad.",
+ "echo-pref-tooltip-mention": "Kelaouiñ ac'hanon pa vez menneget va fajenn implijer gant unan bennak.",
+ "echo-pref-tooltip-user-rights": "Kelaouiñ ac'hanon pa vez kemmet va gwirioù implijer gant unan bennak.",
+ "echo-no-agent": "[Den]",
+ "echo-no-title": "[Pajenn ebet]",
+ "echo-error-preference": "Fazi : Dibosubl eo termenniñ an arventenn implijer.",
+ "echo-error-token": "Fazi : N'eus ket bet gallet adtapout jedouer an implijer",
+ "notifications": "Kemennoù",
+ "tooltip-pt-notifications": "Ho kemennoù",
+ "echo-specialpage": "Kemennoù",
+ "echo-anon": "Evit resev kemennoù, [$1 krouit ur gont] pe [$2 kevreit].",
+ "echo-none": "N'ho peus resevet kemenn ebet.",
+ "echo-more-info": "Gouzout hiroc'h",
+ "echo-feedback": "Sonjoù",
+ "notification-link-text-view-message": "Gwelet ar gemennadenn",
+ "notification-link-text-view-mention": "Gwelet ar meneg",
+ "notification-link-text-view-changes": "Diskouez ar c'hemmoù",
+ "notification-link-text-view-page": "Gwelet ar bajenn",
+ "notification-link-text-view-edit": "Gwelet ar c'hemm",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|en deus|he deus}} lezet ur gemennadenn war ho [[User talk:$2#$3|pajenn gaozeal]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|en deus|he deus}} lezet ur gemennadenn war ho pajenn kaozeal e-barzh \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|en deus|he deus}} lezet ur gemennadenn war ho [[User talk:$2#$3|pajenn gaozeal]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|en deus|he deus}} lezet ur gemennadenn war ho pajenn gaozeal e-barzh \"[[User talk:$2#$3|$4]]\".",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|en deus|he deus}} kaset ur gemennadenn deoc'h: \"[[$3#$2|$2]]\".",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|en deus|he deus}} meneget ac'hanoc'h war ar bajenn gaozeal $5 e-barzh \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|en deus|he deus}} meneget ac'hanoc'h war ar bajenn gaozeal $5 e-barzh \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|en deus|he deus}} meneget ac'hanoc'h war [[:$3|pajenn gaozeal $2]].",
+ "notification-user-rights-add": "Bremañ ez oc'h un ezel eus {{PLURAL:$2|ar strollad-mañ|ar strolladoù-mañ}}: $1",
+ "notification-user-rights-remove": "N'oc'h ket ken un ezel eus ar {{PLURAL:$2|strollad|strolladoù}}-mañ : $1",
+ "notification-new-user": "Degemer mat er {{SITENAME}}, $1!",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|en|he}} deus laosket deoc'h ur gemennadenn\nwar {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|en deus|he deus}} lezet ur gemennadenn war ho pajenn gaozeal :",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|en deus|he deus}} embannet ur gemennadenn war ho pajenn gaozeal diwar-benn \"$2\".",
+ "notification-page-linked-email-subject": "Liammet eo bet ho pajenn ouzh {{SITENAME}}",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|en deus|he deus}} ho meneget war {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|en deus|he deus}} meneget ac'hanoc'h war ar bajenn gaozeal $4 e-barzh \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|en deus|he deus}} meneget ac'hanoc'h war ar bajenn gaozeal $2.",
+ "notification-user-rights-email-subject": "Cheñchet eo ho kwirioù implijer war {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Kemmet eo bet ho kwirioù implijer gant $1. $2.",
+ "echo-email-subject-default": "Kemenn nevez e {{SITENAME}}",
+ "echo-email-body-default": "Ur c'hemenn nevez ho peus war {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Ur c'hemenn nevez ho peus resevet.",
+ "echo-email-footer-default": "$2\n\nEvit kontrollañ peseurt posteloù a gasomp deoc'h, gwiriit ho penndibaboù : {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Evit kontrollañ peseurt posteloù a gasomp deoc'h, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">gwiriit ho tibaboù</a>.<br />\n$1",
+ "echo-notification-message": "{{PLURAL:$1|Kemennadenn ($1)|Kemennadennoù ($1)|100=Kemennadennoù (99+)}}",
+ "echo-notification-message-text-only": "Kemennadennoù",
+ "echo-overlay-link": "An holl gemennoù",
+ "echo-overlay-title": "<b>Kemennoù</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Kemennoù}}</b> (o tiskouez $1 diwar $2 nann-lennet)",
+ "echo-mark-all-as-read": "Merkañ an holl evel lennet",
+ "echo-date-today": "Hiziv",
+ "echo-date-yesterday": "Dec'h",
+ "echo-load-more-error": "Ur fazi zo bet en ur glask disoc'hoù all.",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 hag $2 {{PLURAL:$3|unan|re}} all {{GENDER:$1|o deus}} lezet ur gemennadenn war ho pajenn gaozeal.",
+ "echo-email-batch-subject-daily": "{{PLURAL:$2|Ur c'hemenn|Kemennoù}} nevez hoc'h eus war {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "{{PLURAL:$2|Ur c'hemenn|Kemennoù}} nevez hoc'h eus war {{SITENAME}} ar sizhun-mañ",
+ "echo-email-batch-body-intro-daily": "Demat deoc'h $1,\nSetu amañ un diverradur eus obererezh an deiz war {{SITENAME}} evidoc'h.",
+ "echo-email-batch-body-intro-weekly": "Demat deoc'h $1,\nSetu amañ un diverradur eus obererezh ar sizhun-mañ war {{SITENAME}} evidoc'h.",
+ "echo-email-batch-link-text-view-all-notifications": "Gwelet an holl gemennoù",
+ "echo-rev-deleted-text-view": "Lamet eo bet an adwel pajenn-mañ."
+}
diff --git a/Echo/i18n/bs.json b/Echo/i18n/bs.json
new file mode 100644
index 00000000..5800d80d
--- /dev/null
+++ b/Echo/i18n/bs.json
@@ -0,0 +1,117 @@
+{
+ "@metadata": {
+ "authors": [
+ "CERminator",
+ "DzWiki",
+ "Edinwiki",
+ "Palapa",
+ "KWiki"
+ ]
+ },
+ "echo-desc": "Obavještajni sistem",
+ "prefs-echo": "Obavještenja",
+ "prefs-emailsettings": "Email opcije",
+ "prefs-displaynotifications": "Opcije prikaza",
+ "prefs-echosubscriptions": "Obavijesti me o tim događajima",
+ "prefs-newmessageindicator": "Indikator za nove poruke",
+ "echo-pref-send-me": "Pošalji mi:",
+ "echo-pref-send-to": "Pošalji:",
+ "echo-pref-email-format": "Format e-pošte:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-pošta",
+ "echo-pref-email-frequency-never": "Ne šalji mi obavještenja preko e-pošte",
+ "echo-pref-email-frequency-immediately": "Lična obavještenja kako dolaze u",
+ "echo-pref-email-frequency-daily": "Dnevni sažetak obavještenja",
+ "echo-pref-email-frequency-weekly": "Sedmični sažetak obavještenja",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Obični tekst",
+ "echo-pref-notify-show-link": "Pokaži obavještenja u mojoj alatnoj traci",
+ "echo-pref-new-message-indicator": "Pokaži indikator da je dobijena poruka na stranici za razgovor u mojoj alatnoj traci",
+ "echo-learn-more": "Saznajte više",
+ "echo-new-messages": "Imate nove poruke",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Poruke}} na stranici za razgovor",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Linkovi na stranicu}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Vraćanje izmjena}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Spominjanje|Spominjanja}}",
+ "echo-category-title-other": "{{PLURAL:$1|Ostalo}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Promjena korisničkih prava}}",
+ "echo-pref-tooltip-edit-user-talk": "Obavijesti me kad neko ostavi poruku ili odgovor na mojoj stranici za razgovor.",
+ "echo-pref-tooltip-article-linked": "Obavijesti me kada neko linkuje na stranicu koju sam napravio od stranice članaka.",
+ "echo-pref-tooltip-reverted": "Obavijesti me kada neko vrati uređivanje koje sam napravio/la, korištenjem naredbe undo ili alatom za vraćanje.",
+ "echo-pref-tooltip-mention": "Obavijesti me kada me neko spomene na nekoj stranici za razgovor.",
+ "echo-pref-tooltip-user-rights": "Obavijesti me kad neko promijeni moja korisnička prava.",
+ "echo-no-agent": "[Niko]",
+ "echo-no-title": "[Nema stranice]",
+ "echo-error-no-formatter": "Nema formatiranja određenog za obavještavanje.",
+ "echo-error-preference": "Greška: Nemoguće odrediti korisničke postavke.",
+ "echo-error-token": "Greška: Nemoguće ponovo pronaći korisničku oznaku.",
+ "notifications": "Obavještenja",
+ "tooltip-pt-notifications": "Vaša obavještenja",
+ "echo-specialpage": "Obavještenja",
+ "echo-anon": "Da biste primili obaveštenja, morate se [[Special:UserLogin|prijaviti]] ili [[Special:Userlogin/signup|napraviti račun]].",
+ "echo-none": "Nemate obavještenja",
+ "echo-more-info": "Više informacija",
+ "echo-feedback": "Povratna informacija",
+ "notification-link-text-view-message": "Pogledaj poruku",
+ "notification-link-text-view-mention": "Pogledajte spominjanje",
+ "notification-link-text-view-changes": "Pogledaj izmjene",
+ "notification-link-text-view-page": "Pogledaj stranicu",
+ "notification-link-text-view-edit": "Pogledaj uređivanje",
+ "notification-edit-talk-page2": "[[User:$1|$1]] vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj [[User talk:$2#$3|stranici za razgovor]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj [[User talk:$2#$3|stranici za razgovor]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Stranica [[:$2]] je {{GENDER:$1|povezana}} sa stranicom [[:$3]]. [[Special:WhatLinksHere/$2|Pogledajte sve veze prema ovoj stranici]].",
+ "notification-page-linked-flyout": "[[:$2]] je {{GENDER:$1|povezana}} sa [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] je {{GENDER:$1|ostavio|ostavila}} komentar na \"[[$3|$2]]\" na \"$4\" stranici za razgovor.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] je {{GENDER:$1|postavio|postavila}} novu temu \"$2\" na [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vam je {{GENDER:$1|poslao|poslala}} poruku: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] je {{GENDER:$1|komentarisao|komentarisala}} temu \"[[$3#$2|$2]]\" na vašoj stranici za razgovor.",
+ "notification-mention": "[[User:$1|$1]] vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $5 u \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $5 u \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] vas je {{GENDER:$1|spomenuo|spomenula}} na [[:$3|stranici za razgovor $2]].",
+ "notification-mention-nosection-flyout": "$1 vas je {{GENDER:$1|spomenuo|spomenula}} na [[:$3|stranici za razgovor $2]].",
+ "notification-user-rights": "Vaša korisnička prava [[Special:Log/rights/$1|su bila {{GENDER:$1|izmijenjena}}]] od strane [[User:$1|$1]]. $2. [[Special:ListGroupRights|Saznajte više]]",
+ "notification-user-rights-flyout": "Vaša korisnička prava {{GENDER:$1|izmijenjena}} su od strane $1. $2. [[Special:ListGroupRights|Saznajte više]]",
+ "notification-user-rights-add": "Od sada ste član {{PLURAL:$2|ove grupe|ovih grupa}}: $1",
+ "notification-user-rights-remove": "Više niste član {{PLURAL:$2|ove grupe|ovih grupa}}: $1",
+ "notification-new-user": "$1, dobro došli na {{SITENAME}}! Drago nam je što ste ovdje.",
+ "notification-reverted2": "{{PLURAL:$4|Vaša izmjena na [[:$2]] je poništena|Vaše izmjene na [[:$2]] su poništene}} {{GENDER:$1|od}} strane [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Vaša izmjena na $2 je poništena|Vaše izmjene na $2 su poništene}} {{GENDER:$1|od}} strane $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u \"$2\".",
+ "notification-page-linked-email-subject": "Vaša stranica je povezana na {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 je {{GENDER:$1|povezana}} sa $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Vaša izmjena je {{GENDER:$1|poništena}}|Vaše izmjene su {{GENDER:$1|poništene}}}} na {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Vaša izmjena na $2 je poništena|Vaše izmjene na $2 su poništene}} {{GENDER:$1|od}} strane $1.",
+ "notification-mention-email-subject": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $4 u \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 vas je {{GENDER:$1|spomenuo|spomenula}} na stranici za razgovor $2.",
+ "notification-user-rights-email-subject": "Vaša korisnička prava su se promijenila na {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Vaša korisnička prava su {{GENDER:$1|promjenjena}} od strane $1. $2",
+ "echo-email-subject-default": "Novo obavještenje na {{SITENAME}}",
+ "echo-email-body-default": "Imate novo obavještenje na {{SITENAME}}: \n\n$1",
+ "echo-email-batch-body-default": "Imate novo obavještenje.",
+ "echo-email-footer-default": "$2\n\nDa kontrolišete koje vam email poruke šaljemo, provjerite svoje postavke:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Da kontrolišete koje vam email poruke šaljemo, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">provjerite vaše postavke</a>.<br />\n$1",
+ "echo-notification-message-text-only": "Poruke",
+ "echo-overlay-link": "Sva obavještenja",
+ "echo-overlay-title": "<b>Obavještenja</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Obavještenja}}</b> (prikaz $1 od $2 nepročitanih)",
+ "echo-mark-all-as-read": "Označi sve kao pročitano",
+ "echo-date-today": "Danas",
+ "echo-date-yesterday": "Jučer",
+ "echo-load-more-error": "Greška se pojavila za vrijeme dobavljanja više rezultata.",
+ "notification-edit-talk-page-bundle": "$1 i $3 {{PLURAL:$4|ostali|ostale}} {{GENDER:$1|ostavili}} su poruku na vašoj [[User talk:$2|stranici za razgovor]].",
+ "notification-page-linked-bundle": "$2 {{GENDER:$1|povezana}} je sa $3 i $4 {{PLURAL:$5|druge stranice|drugih stranica}}. [[Special:WhatLinksHere/$2|Pogledaj sve linkove na ovu stranicu.]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 i $2 {{PLURAL:$3|ostali|ostalih}} {{GENDER:$1|ostavili}} su poruku na vašoj stranici za razgovor.",
+ "notification-page-linked-email-batch-bundle-body": "Stranica $2 {{GENDER:$1|povezana}} je sa $3 i $4 {{PLURAL:$5|druge stranice|drugih stranica}}.",
+ "echo-email-batch-subject-daily": "Imate {{PLURAL:$2|novo obavještenje|nova obavještenja}} na {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Imate {{PLURAL:$2|novo obavještenje|nova obavještenja}} na {{SITENAME}} ove sedmice",
+ "echo-email-batch-body-intro-daily": "Zdravo $1,\nOvo je sažetak današnjih aktivnosti na {{SITENAME}} za Vas.",
+ "echo-email-batch-body-intro-weekly": "Zdravo $1,\nOvo je sažetak sedmičnih aktivnosti na {{SITENAME}} za Vas.",
+ "echo-email-batch-link-text-view-all-notifications": "Pogledaj sva obavještenja",
+ "echo-rev-deleted-text-view": "Revizija ove stranice je zabranjena."
+}
diff --git a/Echo/i18n/ca.json b/Echo/i18n/ca.json
new file mode 100644
index 00000000..3e1aa24c
--- /dev/null
+++ b/Echo/i18n/ca.json
@@ -0,0 +1,116 @@
+{
+ "@metadata": {
+ "authors": [
+ "Arnaugir",
+ "Papapep",
+ "Pitort",
+ "QuimGil",
+ "Vriullop",
+ "පසිඳු කාවින්ද",
+ "Fitoschido"
+ ]
+ },
+ "echo-desc": "Sistema de notificacions",
+ "prefs-echo": "Notificacions",
+ "prefs-emailsettings": "Opcions de correu electrònic",
+ "prefs-displaynotifications": "Opcions de visualització",
+ "prefs-echosubscriptions": "Notifica'm sobre aquests esdeveniments",
+ "prefs-newmessageindicator": "Indicador de missatges nous",
+ "echo-pref-send-me": "Envia’m:",
+ "echo-pref-send-to": "Envia a:",
+ "echo-pref-email-format": "Format del missatge:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Correu electrònic",
+ "echo-pref-email-frequency-never": "No m’enviïs notificacions per correu electrònic",
+ "echo-pref-email-frequency-immediately": "Notificacions individuals a mesura que arribin",
+ "echo-pref-email-frequency-daily": "Un resum diari de notificacions",
+ "echo-pref-email-frequency-weekly": "Un resum setmanal de notificacions",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Text net",
+ "echo-pref-notify-show-link": "Mostra les notificacions a la meva barra d'eines",
+ "echo-pref-new-message-indicator": "Mostra l'indicador de missatges en pàgina de discussió a la meva barra d'eines",
+ "echo-learn-more": "Més informació",
+ "echo-new-messages": "Teniu nous missatges",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Missatge|Missatges}} de discussió",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Enllaç|Enllaços}} de pàgina",
+ "echo-category-title-reverted": "{{PLURAL:$1|Reversió d'edició|Reversions d'edicions}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Menció|Mencions}}",
+ "echo-category-title-other": "{{PLURAL:$1|Altres}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-pref-tooltip-edit-user-talk": "Avisa'm quan algú envia un missatge o respon a la meva pàgina de discussió.",
+ "echo-pref-tooltip-article-linked": "Avisa'm quan algú enllaça des d'un article a una pàgina que he creat.",
+ "echo-pref-tooltip-reverted": "Avisa'm quan algú reverteix una modificació que he fet, emprant l'eina per a desfer o revocar.",
+ "echo-pref-tooltip-mention": "Avisa'm quan algú enllaça a la meva pàgina d'usuari des de qualsevol pàgina de discussió.",
+ "echo-pref-tooltip-user-rights": "Avisa’m quan algú canviï els meus drets d’usuari.",
+ "echo-no-agent": "[Ningú]",
+ "echo-no-title": "[Cap pàgina]",
+ "echo-error-no-formatter": "Cap format definit per a la notificació.",
+ "echo-error-preference": "Error: No s'ha pogut establir la preferència d'usuari.",
+ "echo-error-token": "Error: No ha pogut recuperar el símbol de l'usuari.",
+ "notifications": "Notificacions",
+ "tooltip-pt-notifications": "Les vostres notificacions",
+ "echo-specialpage": "Notificacions",
+ "echo-anon": "Per a rebre notificacions, [[Special:Userlogin/signup|creeu un compte]] o [[Special:UserLogin|registreu-vos]].",
+ "echo-none": "No teniu cap notificació.",
+ "echo-more-info": "Més informació",
+ "echo-feedback": "Comentaris",
+ "notification-link-text-view-message": "Mostra el missatge",
+ "notification-link-text-view-mention": "Mostra la menció",
+ "notification-link-text-view-changes": "Mostra els canvis",
+ "notification-link-text-view-page": "Mostra la pàgina",
+ "notification-link-text-view-edit": "Mostra la modificació",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|ha deixat}} un missatge a la vostra [[User talk:$2#$3|pàgina de discussió]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|ha deixat}} un missatge a la vostra pàgina de discussió sobre \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|ha deixat}} un missatge a la vostra [[User talk:$2#$3|pàgina de discussió]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|ha deixat}} un missatge a la vostra pàgina de discussió sobre «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "S'ha {{GENDER:$1|enllaçat}} [[:$2]] des de [[:$3]]. [[Special:WhatLinksHere/$2|Vegeu tots els enllaços a aquesta pàgina]].",
+ "notification-page-linked-flyout": "S'ha {{GENDER:$1|enllaçada}} [[:$2]] des de [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|ha fet un comentari}} sobre «[[$3|$2]]» a la pàgina de discussió «$4».",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|ha publicat}} un nou fil de discussió «$2» a [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] us {{GENDER:$1|ha enviat}} un missatge: «[[$3#$2|$2]]».",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|ha fet un comentari}} sobre «[[$3#$2|$2]]» a la vostra pàgina de discussió.",
+ "notification-mention": "[[User:$1|$1]] us {{GENDER:$1|ha mencionat}} a $5 en la seva pàgina de discussió sobre «[[:$3#$2|$4]]».",
+ "notification-mention-flyout": "$1 us {{GENDER:$1|ha mencionat}} en la pàgina de discussió de $5 sobre «[[:$3#$2|$4]]».",
+ "notification-user-rights": "Els vostres drets d'accés [[Special:Log/rights/$1|han estat {{GENDER:$1|canviats}}]] per [[User:$1|$1]]. $2. [[Special:ListGroupRights|Més informació]]",
+ "notification-user-rights-flyout": "Els vostres drets d'accés han estat {{GENDER:$1|canviats}} per $1. $2. [[Special:ListGroupRights|Més informació]]",
+ "notification-user-rights-add": "Ara sou membre d'{{PLURAL:$2|aquest grup|aquests grups}}: $1",
+ "notification-user-rights-remove": "Heu deixat de pertànyer {{PLURAL:$2|al següent grup|als següents grups}}: $1",
+ "notification-new-user": "Benvingut al projecte {{SITENAME}}, $1! Ens alegrem que estiguis aquí.",
+ "notification-reverted2": "{{PLURAL:$4|S'ha revertit la vostra edició a [[:$2]] |S'ha revertit les vostres edicions a [[:$2]]}} {{GENDER:$1|per}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|S'ha revertit la vostra edició a $2|S'ha revertit les vostres edicions a $2}} {{GENDER:$1|per}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 us {{GENDER:$1|ha deixat}} un missatge al projecte {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 us {{GENDER:$1|ha deixat}} un missatge en la vostra pàgina de discussió:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 us {{GENDER:$1|ha deixat}} un missatge en la vostra pàgina de discussió sobre «$2».",
+ "notification-page-linked-email-subject": "S'ha enllaçat la vostra pàgina al projecte {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "S'ha {{GENDER:$1|enllaçada}} $2 des de $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|S'ha revertit la vostra edició|S'han revertit les vostres edicions}} {{GENDER:$1|al projecte}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|S'ha revertit la vostra edició a $2|S'ha revertit les vostres edicions a $2}} {{GENDER:$1|}}per $1.",
+ "notification-mention-email-subject": "$1 us ha {{GENDER:$1|mencionat}} a {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 us ha {{GENDER:$1|mencionat}} a la pàgina de discussió de $4, a \"$3\".",
+ "notification-user-rights-email-subject": "Els vostres permisos d'usuari han canviat a {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Els vostres permisos d'usuari han estat {{GENDER:$1|canviats}} per $1. $2.",
+ "echo-email-subject-default": "Notificació de nou a {{SITENAME}}",
+ "echo-email-body-default": "Teniu una nova notificació a {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Teniu una nova notificació.",
+ "echo-email-footer-default": "$2\n\nPer a controlar quins correus us enviem, reviseu les vostres preferències:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Per a controlar quins correus us enviem, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">reviseu les vostres preferències</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Alertes ($1)|100=Alertes (+99)}}",
+ "echo-notification-message": "{{PLURAL:$1|Missatges ($1)|100=Missatges (+99)}}",
+ "echo-overlay-link": "Totes les notificacions",
+ "echo-overlay-title": "<b>Notificacions</b>",
+ "echo-overlay-title-overflow": "<b>Notificacions</b> (mostrant $1 de $2 no llegides)",
+ "echo-mark-all-as-read": "Marca'ls tots com a llegits",
+ "echo-date-today": "Avui",
+ "echo-date-yesterday": "Ahir",
+ "echo-load-more-error": "S'ha produït un error en obtenir més resultats.",
+ "notification-edit-talk-page-bundle": "$1 i $3 {{PLURAL:$4|més}} {{GENDER:$1|han deixat}} un missatge a la vostra [[User talk:$2|pàgina de discussió]].",
+ "notification-page-linked-bundle": "S'ha {{GENDER:$1|enllaçat}} $2 des de $3 i $4 {{PLURAL:$5|pàgina|pàgines}} més. [[Special:WhatLinksHere/$2|Vegeu tots els enllaços a aquesta pàgina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 i $2 {{PLURAL:$3|més}} {{GENDER:$1|han deixat}} un missatge a la seva pàgina de discussió.",
+ "notification-page-linked-email-batch-bundle-body": "$2 ha {{GENDER:$1|enllaçat}} {{PLURAL:$5|una altra pàgina|altres pàgines}} des de $3 i $4.",
+ "echo-email-batch-subject-daily": "Teniu {{PLURAL:$2|una nova notificació|noves notificacions}} al projecte {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Teniu {{PLURAL:$2|una nova notificació|noves notificacions}} d'aquesta setmana al projecte {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Hola $1,\nAquí teniu un resum de l'activitat d'avui a {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Hola $1,\nAquí teniu un resum de l'activitat d'aquesta setmana a {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Vegeu totes les notificacions",
+ "echo-rev-deleted-text-view": "S'ha suprimit aquesta revisió de pàgina."
+}
diff --git a/Echo/i18n/cdo.json b/Echo/i18n/cdo.json
new file mode 100644
index 00000000..003f54ab
--- /dev/null
+++ b/Echo/i18n/cdo.json
@@ -0,0 +1,108 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Yejianfei"
+ ]
+ },
+ "echo-desc": "通知系統",
+ "prefs-echo": "通知",
+ "prefs-emailsettings": "電子郵件選項",
+ "prefs-displaynotifications": "顯示選項",
+ "prefs-echosubscriptions": "通知我茲幾萆事計",
+ "prefs-newmessageindicator": "新其導航",
+ "echo-pref-send-me": "發送給我:",
+ "echo-pref-send-to": "發送遘:",
+ "echo-pref-email-format": "電子郵件格式:",
+ "echo-pref-web": "網頁",
+ "echo-pref-email": "電子郵件",
+ "echo-pref-email-frequency-never": "伓使發給我任何通知",
+ "echo-pref-email-frequency-immediately": "伊各儂來辰候其个人通知",
+ "echo-pref-email-frequency-daily": "蜀日蜀回其通知總結",
+ "echo-pref-email-frequency-weekly": "蜀禮拜蜀回其通知總結",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "純文本",
+ "echo-pref-notify-show-link": "敆我其工具欄顯示通知",
+ "echo-pref-new-message-indicator": "敆我其工具欄顯示討論頁信息指示",
+ "echo-learn-more": "學習更更価仂囝",
+ "echo-new-messages": "汝有新其信息",
+ "echo-category-title-edit-user-talk": "討論頁 {{PLURAL:$1|條}}信息",
+ "echo-category-title-article-linked": "頁面{{PLURAL:$1|萆鏈接}}",
+ "echo-category-title-reverted": "修改{{PLURAL:$1|回退回}}",
+ "echo-category-title-mention": "提遘{{PLURAL:$1|回}}",
+ "echo-category-title-other": "{{PLURAL:$1|其它}}",
+ "echo-category-title-system": "{{PLURAL:$1|萆系統}}",
+ "echo-pref-tooltip-edit-user-talk": "有儂敆我其用戶頁回覆其辰候通知我。",
+ "echo-pref-tooltip-article-linked": "有儂鏈接我趁論文頁面創建其頁面其辰候通知我。",
+ "echo-pref-tooltip-reverted": "有儂使撤銷或者回滾工具回退我其修改其辰候通知我。",
+ "echo-pref-tooltip-mention": "有儂鏈接遘我其用戶頁其辰候通知我。",
+ "echo-no-agent": "[無儂]",
+ "echo-no-title": "[無頁]",
+ "echo-error-no-formatter": "未規定通知其格式。",
+ "echo-error-preference": "有賺:無辦法設置用戶其喜好。",
+ "echo-error-token": "有賺:無辦法得遘用戶其標誌。",
+ "notifications": "通知",
+ "tooltip-pt-notifications": "汝其通知",
+ "echo-specialpage": "通知",
+ "echo-anon": "卜收通知,[$1 開賬戶]或者[$2 躒底]。",
+ "echo-none": "汝無通知。",
+ "echo-more-info": "更更価其信息",
+ "echo-feedback": "反饋",
+ "notification-link-text-view-message": "看蜀看信息",
+ "notification-link-text-view-mention": "看提遘其乇",
+ "notification-link-text-view-changes": "看蜀看改變",
+ "notification-link-text-view-page": "看蜀看頁面",
+ "notification-link-text-view-edit": "看蜀看修改",
+ "notification-edit-talk-page2": "[[User:$1|$1]]敆汝其[[User talk:$2#$3|討論頁]]{{GENDER:$1|留下}}蜀萆信息。",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]]敆汝其討論頁「[[User talk:$2#$3|$4]]」{{GENDER:$1|留下}}蜀萆信息。",
+ "notification-edit-talk-page-flyout2": "$1敆汝其[[User talk:$2#$3|討論頁]]{{GENDER:$1|留下}}蜀條信息。",
+ "notification-edit-talk-page-flyout-with-section": "$1敆汝其討論頁「[[User talk:$2#$3|$4]]」{{GENDER:$1|留下}}蜀條信息。",
+ "notification-page-linked": "[[:$2]]趁[[:$3]]𡅏{{GENDER:$1|鏈}}過來。[[Special:WhatLinksHere/$2|看全部鏈遘茲蜀頁其鏈接]]。",
+ "notification-page-linked-flyout": "[[:$2]]是趁[[:$3]]𡅏{{GENDER:$1|鏈}}過來。",
+ "notification-add-comment2": "[[User:$1|$1]]敆「$4」其討論頁𡅏{{GENDER:$1|評論}}「[[$3|$2]]」。",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]]敆[[$3]]𡅏{{GENDER:$1|發表}}蜀萆新其话題「$2」。",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]]{{GENDER:$1|發}}給汝蜀條信息:「[[$3#$2|$2]]」。",
+ "notification-add-comment-yours2": "[[User:$1|$1]]敆汝其討論頁𡅏{{GENDER:$1|評論}}「[[$3#$2|$2]]」。",
+ "notification-mention": "[[User:$1|$1]]敆$5其討論頁其「[[:$3#$2|$4]]」𡅏{{GENDER:$1|提遘}}汝。",
+ "notification-mention-flyout": "$1敆$5其討論頁其「[[:$3#$2|$4]]」𡅏{{GENDER:$1|提遘}}汝。",
+ "notification-user-rights": "汝其用戶權利乞[[User:$1|$1]][[Special:Log/rights/$1|{{GENDER:$1|改去}}]]。$2. [[Special:ListGroupRights|學習更更価]]",
+ "notification-user-rights-flyout": "汝其用戶權限乞$1{{GENDER:$1|改去}}。$2。[[Special:ListGroupRights|學習更更価]]",
+ "notification-user-rights-add": "汝現在是{{PLURAL:$2|茲蜀組|茲幾組}}其成頁:$1",
+ "notification-user-rights-remove": "汝不再是{{PLURAL:$2|茲蜀組|茲幾組}}其成員了:$1",
+ "notification-new-user": "歡迎來遘{{SITENAME}},$1!儂家各儂雅高興看見汝敆這塊。",
+ "notification-reverted2": "汝{{PLURAL:$4|敆[[:$2]]上其修改}}已經乞[[User:$1|$1]]{{GENDER:$1|回滾}}了。$3",
+ "notification-reverted-flyout2": "汝{{PLURAL:$4|敆$2上其修改}}已經乞$1{{GENDER:$1|回滾}}。$3",
+ "notification-edit-talk-page-email-subject2": "$1敆{{SITENAME}}𡅏給汝{{GENDER:$1|留下}}蜀條信息",
+ "notification-edit-talk-page-email-batch-body2": "$1敆汝其討論頁𡅏{{GENDER:$1|留下}}蜀條信息:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1敆汝其用戶討論頁其「$2」𡅏{{GENDER:$1|留下}}蜀條信息。",
+ "notification-page-linked-email-subject": "汝其頁面鏈遘{{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2是趁$3𡅏{{GENDER:$1|鏈}}過來。",
+ "notification-reverted-email-subject2": "汝其{{PLURAL:$3|修改}}敆{{SITENAME}}𡅏乞{{GENDER:$1|回滾}}去",
+ "notification-reverted-email-batch-body2": "汝其{{PLURAL:$3|敆$2懸頂其修改已經}}乞$1{{GENDER:$1|回滾}}了。",
+ "notification-mention-email-subject": "$1敆{{SITENAME}}𡅏{{GENDER:$1|提遘}}汝",
+ "notification-mention-email-batch-body": "$1敆$4其討論頁其「$3」𡅏{{GENDER:$1|提遘mentioned}}汝。",
+ "notification-user-rights-email-subject": "汝其用戶權利敆{{SITENAME}}𡅏乞改去了。",
+ "notification-user-rights-email-batch-body": "汝其用戶權利乞$1改去了。$2。",
+ "echo-email-subject-default": "敆{{SITENAME}}懸頂有新其通知",
+ "echo-email-body-default": "汝敆{{SITENAME}}懸頂有新其通知:\n\n$1",
+ "echo-email-batch-body-default": "汝有蜀萆新其通知。",
+ "echo-email-footer-default": "為𡅏控制儂家發給汝其底蜀種電子郵件,檢查汝其喜好:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$2:$1",
+ "echo-email-footer-default-html": "為𡅏控制儂家發給汝底蜀種電子郵件,請<a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">檢查汝其喜好</a>。<br />\n$1",
+ "echo-overlay-link": "全部通知",
+ "echo-overlay-title": "<b>通知</b>",
+ "echo-overlay-title-overflow": "<b>通知</b>(未讀其通知顯示出$1條,共總有$2條)",
+ "echo-mark-all-as-read": "全部標記成已讀",
+ "echo-date-today": "今旦",
+ "echo-date-yesterday": "昨冥",
+ "echo-load-more-error": "獲取更更価其結果辰候發生错误。",
+ "notification-edit-talk-page-bundle": "$1共$3{{PLURAL:$4|其它}}敆汝其[[User talk:$2|討論頁]]𡅏{{GENDER:$1|留下}}蜀條信息。",
+ "notification-page-linked-bundle": "$2是趁$3共其它$4{{PLURAL:$5|頁}}𡅏{{GENDER:$1|鏈}}過其。[[Special:WhatLinksHere/$2|看全部鏈遘茲蜀頁其鏈接]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1其其它$2{{PLURAL:$3|隻}}儂敆汝其討論頁上{{GENDER:$1|留下}}蜀條信息。",
+ "notification-page-linked-email-batch-bundle-body": "$2是趁$3共其它$4{{PLURAL:$5|頁}}𡅏{{GENDER:$1|鏈}}過來。",
+ "echo-email-batch-subject-daily": "汝敆{{SITENAME}}𡅏有{{PLURAL:$2|新其通知}}",
+ "echo-email-batch-subject-weekly": "汝茲蜀禮拜敆{{SITENAME}}𡅏有{{PLURAL:$2|新其通知}}",
+ "echo-email-batch-body-intro-daily": "嘿$1,\n這是汝其今旦敆{{SITENAME}}懸頂其活動。",
+ "echo-email-batch-body-intro-weekly": "嘿$1,\n這是汝其茲蜀禮拜敆{{SITENAME}}懸頂其活動。",
+ "echo-email-batch-link-text-view-all-notifications": "看全部通知",
+ "echo-rev-deleted-text-view": "茲頁其修定已經乞限制了。"
+}
diff --git a/Echo/i18n/ce.json b/Echo/i18n/ce.json
new file mode 100644
index 00000000..9806f548
--- /dev/null
+++ b/Echo/i18n/ce.json
@@ -0,0 +1,117 @@
+{
+ "@metadata": {
+ "authors": [
+ "Умар"
+ ]
+ },
+ "echo-desc": "Хааман система",
+ "prefs-echo": "Хаамаш",
+ "prefs-emailsettings": "Электронан почтан гӀирс нисбар",
+ "prefs-displaynotifications": "Гуш болу гӀирсаш",
+ "prefs-echosubscriptions": "ХӀокху хиларах лаьцна хаийта",
+ "prefs-newmessageindicator": "Керлачу хааман индикатор",
+ "echo-pref-send-me": "Баийта соьга:",
+ "echo-pref-send-to": "Хаам баийта тӀе:",
+ "echo-pref-email-format": "Хааман формат:",
+ "echo-pref-web": "Веб",
+ "echo-pref-email": "Электронан почта",
+ "echo-pref-email-frequency-never": "Сан эл. почте ма баийта хаамаш",
+ "echo-pref-email-frequency-immediately": "Къаьстина хаамаш тӀедаре хьаьжжина",
+ "echo-pref-email-frequency-daily": "ХӀор денна хаам",
+ "echo-pref-email-frequency-weekly": "ХӀор кӀиранах хаам",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Цхьалхе йоза",
+ "echo-pref-notify-show-link": "Сан панелан тӀехь гайта хаам",
+ "echo-pref-new-message-indicator": "Сан панелан тӀехь гайта хааман индикатор",
+ "echo-learn-more": "Цул совнаха хаа",
+ "echo-new-messages": "Хьуна кхаьчна керла хаам",
+ "echo-category-title-edit-user-talk": "Дийцаре агӀонехь {{PLURAL:$1|хаам|хаамаш}}",
+ "echo-category-title-article-linked": "АгӀона тӀе {{PLURAL:$1|хьажорг}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|нисдар юхадаккхар|нисдарш юхадаккхар}}",
+ "echo-category-title-mention": "{{PLURAL:$1|хаам|хаамаш}}",
+ "echo-category-title-other": "{{PLURAL:$1|кхин долу|кхин дерш}}",
+ "echo-category-title-system": "{{PLURAL:$1|Системан}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Декъашхочун бакъо хийцар|Декъашхочун бакъонаш хийцар}}",
+ "echo-pref-tooltip-edit-user-talk": "Хаийта соьга, цхьам хаам баийтача я сан дийцаре агӀорахь жоп делча.",
+ "echo-pref-tooltip-article-linked": "Хаийта соьга, цхьам ас кхоьллина агӀона тӀе хьажорг цхьан агӀонашкахь йитича.",
+ "echo-pref-tooltip-reverted": "Хаийта соьга, цхьам сан нисдар юха даьккхича.",
+ "echo-pref-tooltip-mention": "Хаийта соьга, цхьам сан долара агӀона тӀе хьажорг цхьан дийцаре агӀорахь йитича.",
+ "echo-pref-tooltip-user-rights": "Сан бакъонаш цхьаммо хийцича хаам бе соьга.",
+ "echo-no-agent": "[Цхьа а]",
+ "echo-no-title": "[АгӀо яц]",
+ "echo-error-no-formatter": "Хааман формат билгалйина яц",
+ "echo-error-preference": "ГӀала:Декъашхочун гӀирс нисбан цабелира",
+ "echo-error-token": "ГӀалат:Декъашхочун (user token) маркер схьаэца тар цаделира",
+ "notifications": "Хаамаш",
+ "tooltip-pt-notifications": "Хьан хаамаш",
+ "echo-specialpage": "Хаамаш",
+ "echo-anon": "Хаамаш хилийта, [$1 декъашхочун дӀаяздар кхолла] я [$2 чугӀо].",
+ "echo-none": "Хьуна хаамаш ца беара.",
+ "echo-more-info": "Ма-дарра",
+ "echo-feedback": "ЮхагӀо зӀе",
+ "notification-link-text-view-message": "Хааме хьажар",
+ "notification-link-text-view-mention": "Хааме хьажар",
+ "notification-link-text-view-changes": "Хийцаме хьажар",
+ "notification-link-text-view-page": "Хьажа агӀоне",
+ "notification-link-text-view-edit": "Нисдаре хьажар",
+ "notification-edit-talk-page2": "Декъашхочо [[User:$1|$1]] хьан [[User talk:$2#$3|дийцаре агӀонехь]] {{GENDER:$1|битина}}. хаам.",
+ "notification-edit-talk-page-with-section": "Хьан дийцаре агӀонехь [[User:$1|$1]] {{GENDER:$1|битина}} хаам \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|Декъашхочо}} хьан [[User talk:$2#$3|дийцаре агӀонехь]] битина хаам.",
+ "notification-edit-talk-page-flyout-with-section": "Хьан дийцаре агӀонехь $1 {{GENDER:$1|битина}} хаам \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] и {{GENDER:$1|йихкина}} оцу [[:$3]]. [[Special:WhatLinksHere/$2|Хьажа. ХӀокху агӀона массо хьажоргаш]].",
+ "notification-page-linked-flyout": "[[:$2]] и {{GENDER:$1|йихкина}} оцу [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|хаам биттина}} темехь \"[[$3|$2]]\" \"$4\" дийцаре агӀонехь.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|тӀетоьхна}} керла тем \"$2\" [[$3]] агӀонехь.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] хьога хаам {{GENDER:$1|хьажийна}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|хаам биттина}} темехь \"[[$3#$2|$2]]\" дийцаре агӀонехь.",
+ "notification-mention": "[[User:$1|$1]] хьо {{GENDER:$1|хьахийна}} дийцаре агӀонехь $5 декъехь \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "хьо {{GENDER:$1|хьахийна}} дийцаре агӀонехь $5 декъехь \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] хьо хьахийна [[:$3|дийцаре агӀонехь $2]].",
+ "notification-mention-nosection-flyout": "{{GENDER:$1||декъашхочо}} хьо хьахийна [[:$3|дийцаре агӀонехь $2]].",
+ "notification-user-rights": "Хьан бакъонаш [[Special:Log/rights/$1|{{GENDER:$1|хийцина}}]] [[User:$1|$1]]. $2. [[Special:ListGroupRights|Мадарра]]",
+ "notification-user-rights-flyout": "Декъашхочун бакъонаш {{GENDER:$1|хийцина}} $1. $2. [[Special:ListGroupRights|Мадарра]]",
+ "notification-user-rights-add": "ХӀинца хьо {{PLURAL:$2|1=тобан юкъа эцна|тобанийн юкъа эцна}}: $1",
+ "notification-user-rights-remove": "Хьан хӀокху {{PLURAL:$2|тобан|тобанийн}} бакъо дӀаяьккхина: $1",
+ "notification-new-user": "Марша догӀилла {{SITENAME}}, $1! Хьо кхузахь хиларна даккхийде тхо.",
+ "notification-reverted2": "{{PLURAL:$4|АгӀонехь [[:$2]] хьан нисдар|АгӀонехь [[:$2]] хьан нисдарш}} {{GENDER:$1|юхадаькхина}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|АгӀонехь $2 хьан нисдар|АгӀонехь $2 хьан нисдарш}} {{GENDER:$1|юхадаькхина}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|Декъашхочо}} $1 «{{SITENAME}}» сайтехь хьуна хаам {{GENDER:$1|биттина}}",
+ "notification-edit-talk-page-email-batch-body2": "Хьан дийцаре агӀонехь {{GENDER:$1|декъашхочо}} $1 {{GENDER:$1|битина}} хаам:",
+ "notification-edit-talk-page-email-batch-body-with-section": "Хьан дийцаре агӀонехь {{GENDER:$1|декъашхочо}} $1 {{GENDER:$1|битина}} хаам (темехь) «$2»",
+ "notification-page-linked-email-subject": "«{{SITENAME}}» сайтехь ахьа кхоьллина агӀона тӀе хьажорг хӀоттина",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|Декъашхо}} $1 {{GENDER:$1|тӀетеввжина}} цу $2 $3",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Цхьам}} «{{SITENAME}}» сайтехь хьан {{PLURAL:$3|нисдар юхадаькхина|нисдарш юхадаьхина}}",
+ "notification-reverted-email-batch-body2": "{{GENDER:$1|Декъашхочо}} $1 {{PLURAL:$3|«$2» агӀонехь хьан нисдар юхадаьккхина|«$2» агӀонехь хьан нисдарш юхадаьхина}}.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|Декъашхочо}} «{{SITENAME}}» сайтехь хьо хьахийна",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|хьахийна}} хьо $4 дийцарийн агӀо \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 декъашхочо хьо хьахийна $2 агӀона чохь.",
+ "notification-user-rights-email-subject": "Сайтехь «{{SITENAME}}» хьан бакъонаш хийцина",
+ "notification-user-rights-email-batch-body": "{{GENDER:$1|Декъашхочо}} хьан бакъонаш хийцина $1. $2.",
+ "echo-notification-count": "$1+",
+ "echo-email-subject-default": "Сайтехь «{{SITENAME}}» керла хаам",
+ "echo-email-body-default": "Сайтехь «{{SITENAME}}» хьога керла хаам бу:\n\n$1",
+ "echo-email-batch-body-default": "Хьан керла хаам бу",
+ "echo-email-footer-default": "$2\n\nЭлектронан почте муьлха хаамаш богӀуш бу хьажа а уьш дӀанисбан а декъашхочун гӀирсе хьажа :\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Электронан почте муьлха хаамаш бохуш бу хьажа а уьш дӀанисбан а <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">Википедин почтан гӀирсе хьажа </a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|ДӀахьедар ($1)|100=ДӀахьедар (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Хаам ($1)|100=Хаам (99+)}}",
+ "echo-notification-alert-text-only": "Хаам",
+ "echo-notification-message-text-only": "Хаам",
+ "echo-overlay-link": "Массо хаамаш",
+ "echo-overlay-title": "<b>Хаамаш</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Хаам}}</b> ({{PLURAL:$1|гайтина}} $1 царах $2 {{PLURAL:$2|беша бац}})",
+ "echo-mark-all-as-read": "Массо билгалъе еша сана",
+ "echo-date-today": "Тахана",
+ "echo-date-yesterday": "Селхана",
+ "echo-load-more-error": "Кхин тӀе хилам схьаоьцуш гӀалат хила",
+ "notification-edit-talk-page-bundle": "$1 а $3 {{PLURAL:$4|кхи}} {{GENDER:$1|декъашхоша}} хьан [[User talk:$2|дийцаре агӀонехь хаам битина]].",
+ "notification-page-linked-bundle": "АгӀона тӀе «$2» {{GENDER:$1|хьажорг}} ю «$3» агӀона чура а кхин $4 {{PLURAL:$5|агӀона|агӀонийн}}. [[Special:WhatLinksHere/$2|Хьажа массо хьажоргашка]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 а $2 {{PLURAL:$3|кхин}} {{GENDER:$1|декъашхоша}} хьан дийцаре агӀонехь хаам битина.",
+ "notification-page-linked-email-batch-bundle-body": "АгӀона «$2» тӀе {{GENDER:$1|хьажорг ю}} «$3» агӀона чура а кхин $4 {{PLURAL:$5|агӀона|агӀонийн}} чура а",
+ "echo-email-batch-subject-daily": "Хьоьга кхаьчна $2 {{PLURAL:$2|керла хаам|керла хаамаш}} «{{SITENAME}}» проектехь",
+ "echo-email-batch-subject-weekly": "ХӀокху кӀиран чохь хьоьга кхаьчна $2 {{PLURAL:$2|керла хаам|керла хаамаш}} «{{SITENAME}}» проектехь",
+ "echo-email-batch-body-intro-daily": "Маршалла, $1!\nТахан хилларг {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Маршалла, $1!\nТахан хилларг {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Массо хаамашка хьажар",
+ "echo-rev-deleted-text-view": "Хьара агӀона верси къайлаяьккхина"
+}
diff --git a/Echo/i18n/ckb.json b/Echo/i18n/ckb.json
new file mode 100644
index 00000000..0e17d5c5
--- /dev/null
+++ b/Echo/i18n/ckb.json
@@ -0,0 +1,111 @@
+{
+ "@metadata": {
+ "authors": [
+ "Calak"
+ ]
+ },
+ "echo-desc": "سیستەمی ئاگادارییەکان",
+ "prefs-echo": "ئاگادارییەکان",
+ "prefs-emailsettings": "ھەڵبژاردەکانی ئیمەیل",
+ "prefs-displaynotifications": "ھەڵبژاردەکانی پێشاندان",
+ "prefs-echosubscriptions": "سەبارەت بەم ڕووداوانە ئاگادارم بکە",
+ "prefs-newmessageindicator": "نیشاندەری پەیامی نوێ",
+ "echo-pref-send-me": "بۆم بنێرە:",
+ "echo-pref-send-to": "بنێرە بۆ:",
+ "echo-pref-email-format": "جۆری ئیمەیل:",
+ "echo-pref-web": "وێب",
+ "echo-pref-email": "ئیمەیل",
+ "echo-pref-email-frequency-never": "ھیچ ئاگاداراییەکم بە ئیمەیل بۆ مەنێرە",
+ "echo-pref-email-frequency-immediately": "ئاگادارییە تاکەکەسییەکان ھەر وەکی دێن",
+ "echo-pref-email-frequency-daily": "کورتەیەکی رۆژانەی ئاگادارییەکان",
+ "echo-pref-email-frequency-weekly": "کورتەیەکی حەفتانەی ئاگادارییەکان",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "دەقی ساکار",
+ "echo-pref-notify-show-link": "ئاگادارییەکان لە تووڵامرازەکەمدا نیشان بدە",
+ "echo-pref-new-message-indicator": "نیشاندەری پەیامی پەڕەی لێدوان لە تووڵامرازەکەمدا نیشان بدە",
+ "echo-learn-more": "زۆرتر بزانە",
+ "echo-new-messages": "پەیامی نوێت ھەیە",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|پەیام|پەیامەکان}}ی پەڕەی لێدوان",
+ "echo-category-title-article-linked": "{{PLURAL:$1|بەستەر|بەستەرەکان}}ی پەڕە",
+ "echo-category-title-reverted": "{{PLURAL:$1|گەڕاندنەوە|گەڕاندنەوەکان}}ی دەستکاری",
+ "echo-category-title-mention": "{{PLURAL:$1|ئاماژە|ئاماژەکان}}",
+ "echo-category-title-other": "{{PLURAL:$1|دیکە}}",
+ "echo-category-title-system": "{{PLURAL:$1|سیستەم}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|گۆڕانی مافەکانی بەکارھێنەر}}",
+ "echo-pref-tooltip-edit-user-talk": "کاتێک کەسێک لە پەڕەی لێدوانمدا پەیامێکی نارد یان وەڵامی دامەوە، ئاگادارم بکە.",
+ "echo-pref-tooltip-article-linked": "کاتێک کەسێک لە پەڕەیەکی وتاردا بە پەڕەیەک کە من دروستم کردووە بەستەری دا، ئاگادارم بکە.",
+ "echo-pref-tooltip-reverted": "کاتێک کەسێک دەستکارییەکی من کردوومە بە ئامرازی پووچەڵکردنەوە یان گەڕاندنەوە دەگەڕێنێتەوە، ئاگادارم بکە.",
+ "echo-pref-tooltip-mention": "کاتێک کەسێک لە پەڕەیەکی لێدواندا بە پەڕەی بەکارھێنەریی من بەستەری دا، ئاگادارم بکە.",
+ "echo-no-agent": "[هیچ کەس]",
+ "echo-no-title": "[بێ سەردێڕ]",
+ "echo-error-no-formatter": "ھیچ شێوازێک بۆ ئاگاداری دیاری نەکراوە.",
+ "echo-error-preference": "ھەڵە: ھەڵبژاردەکانی بەکارھێنەر ڕێک ناخرێ.",
+ "echo-error-token": "ھەڵە: نیشانی بەکارھێنەر وەرناگیرێ.",
+ "notifications": "ئاگادارییەکان",
+ "tooltip-pt-notifications": "ئاگادارییەکانت",
+ "echo-specialpage": "ئاگادارییەکان",
+ "echo-anon": "بۆ وەرگرتنی ئاگادارییەکان، [$1 ھەژمارێک دروست بکە] یان [$2 بچۆ ژوورەوە].",
+ "echo-none": "ئاگادارییەکت نییە.",
+ "echo-more-info": "زانیاریی زیاتر",
+ "echo-feedback": "بەردەنگ",
+ "notification-link-text-view-message": "پەیام ببینە",
+ "notification-link-text-view-mention": "ئاماژە ببینە",
+ "notification-link-text-view-changes": "گۆڕانکارییەکان ببینە",
+ "notification-link-text-view-page": "پەڕە ببینە",
+ "notification-link-text-view-edit": "دەستکاری ببینە",
+ "notification-edit-talk-page2": "[[User:$1|$1]] پەیامێکی لە [[User talk:$2#$3|پەڕەی لێدوان]]تدا {{GENDER:$1|نووسی}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] پەیامێکی لە [[User talk:$2#$3|پەڕەی لێدوان]]ت لە \"[[User talk:$2#$3|$4]]\"دا {{GENDER:$1|نووسی}}.",
+ "notification-edit-talk-page-flyout2": "$1 پەیامێکی لە [[User talk:$2#$3|پەڕەی لێدوان]]تدا {{GENDER:$1|نووسی}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1 پەیامێکی لە [[User talk:$2#$3|پەڕەی لێدوان]]ت لە \"[[User talk:$2#$3|$4]]\"دا {{GENDER:$1|نووسی}}.",
+ "notification-page-linked": "[[:$2]] لە [[:$3]]دا {{GENDER:$1|بەستەر درا}}. [[Special:WhatLinksHere/$2|ھەموو بەستەرە بەسراوەکان بەم پەڕەیەوە ببینە]].",
+ "notification-page-linked-flyout": "[[:$2]] لە [[:$3]]دا {{GENDER:$1|بەستەر درا}}.",
+ "notification-add-comment2": "[[User:$1|$1]] لە «[[$3|$2]]»ی پەڕەی لێدوانی «$4»دا بۆچۆنی نووسی.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] بابەتی نوێی «$2»ی لە [[$3]]دا نووسی.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] پەیامێکی بۆ ناردی: «[[$3#$2|$2]]».",
+ "notification-add-comment-yours2": "[[User:$1|$1]] لە «[[$3#$2|$2]]»ی پەڕەی لێدوانتدا بۆچۆنی نووسی.",
+ "notification-mention": "[[User:$1|$1]] لە پەڕەی لێدوانی $5 لە «[[:$3#$2|$4]]»دا ئاماژەی پێ‌کردی.",
+ "notification-mention-flyout": "$1 لە پەڕەی لێدوانی $5 لە «[[:$3#$2|$4]]»دا ئاماژەی پێ‌کردی.",
+ "notification-mention-nosection": "[[User:$1|$1]] لە [[:$3|پەڕەی لێدوانی $2]]دا ئاماژەی {{GENDER:$1| پێ‌کردی}}.",
+ "notification-mention-nosection-flyout": "$1 لە [[:$3|پەڕەی لێدوانی $2]]دا ئاماژەی {{GENDER:$1| پێ‌کردی}}.",
+ "notification-user-rights": "مافەکانی بەکارھێنەریت لە لایەن [[User:$1|$1]]ەوە [[Special:Log/rights/$1|{{GENDER:$1|گۆڕدرا}}]]. $2. [[Special:ListGroupRights|زیاتر بزانە]]",
+ "notification-user-rights-flyout": "مافەکانی بەکارھێنەریت لە لایەن $1ەوە {{GENDER:$1|گۆڕدرا}}. $2. [[Special:ListGroupRights|زیاتر بزانە]]",
+ "notification-user-rights-add": "تۆ ھەر ئێستا ئەندامی ئەم {{PLURAL:$2|گرووپە|گرووپانە}}ی: $1",
+ "notification-user-rights-remove": "تۆ ئیتر ئەندامی ئەم {{PLURAL:$2|گرووپە|گرووپانە}} نی: $1",
+ "notification-new-user": "بەخێرھاتی بۆ {{SITENAME}}، $1! کەیفخۆشین لێرەی.",
+ "notification-reverted2": "{{PLURAL:$4|دەستکارییەکەت|دەستکارییەکانت}} لە [[:$2]]دا لە لایەن [[User:$1|$1]]ەوە {{GENDER:$1|گەڕێنرایەوە}}. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|دەستکارییەکەت|دەستکارییەکانت}} لە $2دا لە لایەن $1ەوە {{GENDER:$1|گەڕێنرایەوە}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 لە {{SITENAME}}دا پەیامێکی بۆ ناردی.",
+ "notification-edit-talk-page-email-batch-body2": "$1 لە پەڕەی لێدوانتدا پەیامێکی نارد.",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 لە پەڕەی لێدوانت لە «$2»دا پەیامێکی نارد.",
+ "notification-page-linked-email-subject": "پەڕەکەت لە {{SITENAME}}دا بەستەر درا.",
+ "notification-page-linked-email-batch-body": "$2 لە $3دا {{GENDER:$1|بەستەر درا}}.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|دەستکارییەکەت|دەستکارییەکانت}} لە {{SITENAME}}دا {{GENDER:$1|گەڕێنرایەوە}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|دەستکارییەکەت|دەستکارییەکانت}} لە $2دا لە لایەن $1ەوە {{GENDER:$1|گەڕێنرایەوە}}.",
+ "notification-mention-email-subject": "$1 لە {{SITENAME}}دا ئاماژەی پێ‌کردی.",
+ "notification-mention-email-batch-body": "$1 لە پەڕەی لێدوانی $4 لە «$3»دا ئاماژەی پێ‌کردی.",
+ "notification-mention-nosection-email-batch-body": "$1 لە پەڕەی لێدوانی $2دا ئاماژەی {{GENDER:$1|پێ‌کردی}}.",
+ "notification-user-rights-email-subject": "مافەکانی بەکارھێنەریت لە {{SITENAME}}دا گۆڕدرا.",
+ "notification-user-rights-email-batch-body": "مافەکانی بەکارھێنەریت لە لایەن $1ەوە گۆڕدرا. $2.",
+ "echo-email-subject-default": "ئاگادارییەکی نوێ لە {{SITENAME}}",
+ "echo-email-body-default": "ئاگادارییەکی نوێت ھەیە لە {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "ئاگادارییەکی نوێت ھەیە.",
+ "echo-email-footer-default": "$2\n\nبۆ کۆنترۆڵی ئەو ئیمەیلانەی بۆت دەنێرین، ھەڵبژاردەکانت تاوتوێ بکە:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "\n\nبۆ کۆنترۆڵی ئەو ئیمەیلانەی بۆت دەنێرین، <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">ھەڵبژاردەکانت تاوتوێ بکە</a>.<br />:\n$1",
+ "echo-overlay-link": "ھەموو ئاگادارییەکان",
+ "echo-overlay-title": "<b>ئاگادارییەکان</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|ئاگادارییەکان}}</b> (نیشاندانی $1 لە $2ی نەخوێنراو)",
+ "echo-mark-all-as-read": "ھەموویان وەک خوێنراوە نیشان بکە",
+ "echo-date-today": "ئەمڕۆ",
+ "echo-date-yesterday": "دوێنێ",
+ "echo-load-more-error": "ھەڵەیەک لە کاتی وەرگرتنی ئاکامی زیاتر ڕووی دا.",
+ "notification-edit-talk-page-bundle": "$1 و $3ی {{PLURAL:$4|تر}} لە [[User talk:$2|پەڕەی لێدوان]]تدا پەیامێکیان ناردووە.",
+ "notification-page-linked-bundle": "$2 لە $3 و $4 {{PLURAL:$5|پەڕە}}ی تردا {{GENDER:$1|بەستەر درا}}. [[Special:WhatLinksHere/$2|ھەموو بەسراوەکان بەم پەڕەیە ببینە]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 و $2ی {{PLURAL:$3|تر}} لە پەڕەی لێدوانتدا پەیامێکیان ناردووە.",
+ "notification-page-linked-email-batch-bundle-body": "$2 لە $3 و $4 {{PLURAL:$5|پەڕە}}ی تردا {{GENDER:$1|بەستەر درا}}.",
+ "echo-email-batch-subject-daily": "لە {{SITENAME}}دا {{PLURAL:$2|ئاگادارییەکی نوێت|ئاگاداریی نوێت}} ھەیە",
+ "echo-email-batch-subject-weekly": "لە {{SITENAME}}دا {{PLURAL:$2|ئاگادارییەکی نوێت|ئاگاداریی نوێت}} لەم حەفتەیەدا ھەیە",
+ "echo-email-batch-body-intro-daily": "سڵاو $1،\nئەمە کۆرتەیەکە لە چالاکییەکانی ئەمرۆی {{SITENAME}} بۆ تۆ.",
+ "echo-email-batch-body-intro-weekly": "سڵاو $1،\nئەمە کۆرتەیەکە لە چالاکییەکانی حەفتانەی {{SITENAME}} بۆ تۆ.",
+ "echo-email-batch-link-text-view-all-notifications": "ھەموو ئاگادارییەکان ببینە",
+ "echo-rev-deleted-text-view": "پێداچوونەوەی ئەم پەڕەیە بێسراوە."
+}
diff --git a/Echo/i18n/cs.json b/Echo/i18n/cs.json
new file mode 100644
index 00000000..bb0e8d59
--- /dev/null
+++ b/Echo/i18n/cs.json
@@ -0,0 +1,121 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chmee2",
+ "Jkjk",
+ "Mormegil",
+ "Vks",
+ "Matěj Suchánek"
+ ]
+ },
+ "echo-desc": "Notifikační systém",
+ "prefs-echo": "Upozornění",
+ "prefs-emailsettings": "Nastavení e-mailu",
+ "prefs-displaynotifications": "Možnosti zobrazení",
+ "prefs-echosubscriptions": "Upozorněte mě na…",
+ "prefs-newmessageindicator": "Indikátor nových zpráv",
+ "echo-pref-send-me": "Posílejte mi:",
+ "echo-pref-send-to": "Posílat na:",
+ "echo-pref-email-format": "Formát e-mailu:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Neposílejte mi žádná upozornění e-mailem",
+ "echo-pref-email-frequency-immediately": "Jednotlivá upozornění, jakmile se objeví",
+ "echo-pref-email-frequency-daily": "Denní souhrn upozornění",
+ "echo-pref-email-frequency-weekly": "Týdenní souhrn upozornění",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Prostý text",
+ "echo-pref-notify-show-link": "Zobrazovat upozornění v panelu nástrojů",
+ "echo-pref-new-message-indicator": "Zobrazit indikátor diskusních zpráv v mém panelu nástrojů",
+ "echo-learn-more": "Další informace",
+ "echo-new-messages": "Máte nové zprávy",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|příspěvek|příspěvky}} v diskusi",
+ "echo-category-title-article-linked": "{{PLURAL:$1|odkaz|odkazy}} na stránku",
+ "echo-category-title-reverted": "{{PLURAL:$1|vrácenou úpravu|vrácené úpravy}}",
+ "echo-category-title-mention": "{{PLURAL:$1|zmínku|zmínky}}",
+ "echo-category-title-other": "{{PLURAL:$1|jinou událost|jiné události}}",
+ "echo-category-title-system": "{{PLURAL:$1|systémovou událost|systémové události}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|změnu|změny}} uživatelských práv",
+ "echo-pref-tooltip-edit-user-talk": "Upozorněte mě, když mi někdo na mé diskusní stránce napíše zprávu nebo odpoví.",
+ "echo-pref-tooltip-article-linked": "Upozorněte mě, když někdo na stránku, kterou jsem založil, odkáže z článku.",
+ "echo-pref-tooltip-reverted": "Upozorněte mě, když někdo úpravu, kterou jsem provedl, vrátí pomocí nástrojů pro zrušení editace nebo vrácení zpět.",
+ "echo-pref-tooltip-mention": "Upozorněte mě, když někdo odkáže na mou uživatelskou stránku.",
+ "echo-pref-tooltip-user-rights": "Upozorněte mě, když někdo změní moje uživatelská práva.",
+ "echo-no-agent": "[Nikdo]",
+ "echo-no-title": "[Žádná stránka]",
+ "echo-error-no-formatter": "Upozornění nemá definováno formátování",
+ "echo-error-preference": "Chyba: Nepodařilo se uložit uživatelské nastavení",
+ "echo-error-token": "Chyba: Nepodařilo se získat uživatelský token",
+ "notifications": "Upozornění",
+ "tooltip-pt-notifications": "Vaše upozornění",
+ "echo-specialpage": "Upozornění",
+ "echo-anon": "Pro zobrazování upozornění je nutné [$1 vytvořit si účet] nebo [$2 se přihlásit].",
+ "echo-none": "Nemáte žádné upozornění.",
+ "echo-more-info": "Více informací",
+ "echo-feedback": "Názor",
+ "echo-quotation-marks": "„$1“",
+ "notification-link-text-view-message": "Zobrazit zprávu",
+ "notification-link-text-view-mention": "Zobrazit zmínku",
+ "notification-link-text-view-changes": "Zobrazit změny",
+ "notification-link-text-view-page": "Zobrazit stránku",
+ "notification-link-text-view-edit": "Zobrazit editaci",
+ "notification-edit-talk-page2": "[[User:$1|$1]] vám {{GENDER:$1|napsal|napsala}} na [[User talk:$2#$3|vaši diskusní stránku]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] vám {{GENDER:$1|napsal|napsala}} na vaši diskusní stránku k „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 vám {{GENDER:$1|napsal|napsala}} na [[User talk:$2#$3|vaši diskusní stránku]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 vám {{GENDER:$1|napsal|napsala}} na vaši diskusní stránku k „[[User talk:$2#$3|$4]]“.",
+ "notification-page-linked": "Do stránky [[:$3]] {{GENDER:$1|byl přidán}} odkaz na stránku [[:$2]]. [[Special:WhatLinksHere/$2|Zobrazit všechny odkazy na tuto stránku]].",
+ "notification-page-linked-flyout": "Do stránky [[:$3]] {{GENDER:$1|byl přidán}} odkaz na stránku [[:$2]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|přidal|přidala}} komentář k „[[$3|$2]]“ na stránce „$4“",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|přidal|přidala}} komentář na nové téma „$2“ na stránce „[[$3]]“",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vám {{GENDER:$1|poslal|poslala}} zprávu: „[[$3#$2|$2]]“",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|přidal|přidala}} komentář k „[[$3#$2|$2]]“ na vaší diskusní stránce",
+ "notification-mention": "[[User:$1|$1]] vás {{GENDER:$1|zmínil|zmínila}} v diskusi k „$5“ u „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 vás {{GENDER:$1|zmínil|zmínila}} v diskusi {{GENDER:$5|uživatele|uživatelky}} $5 u „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] vás {{GENDER:$1|zmínil|zmínila}} v [[:$3|diskusi ke stránce $2]].",
+ "notification-mention-nosection-flyout": "$1 vás {{GENDER:$1|zmínil|zmínila}} v [[:$3|diskusi ke stránce $2]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|změnil|změnila}}]] vaše uživatelská práva. $2. [[Special:ListGroupRights|Více informací]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|změnil|změnila}} vaše uživatelská práva. $2. [[Special:ListGroupRights|Více informací]]",
+ "notification-user-rights-add": "Nyní patříte do {{PLURAL:$2|této skupiny|těchto skupin}}: $1",
+ "notification-user-rights-remove": "Nadále už nepatříte do {{PLURAL:$2|této skupiny|těchto skupin}}: $1",
+ "notification-new-user": "Vítejte na {{grammar:6sg|{{SITENAME}}}}, {{GENDER:$1|uživateli|uživatelko}} $1! Těší nás, že jste tu.",
+ "notification-reverted2": "[[User:$1|$1]] {{GENDER:$1|revertoval|revertovala}} {{PLURAL:$4|vaši editaci|vaše editace}} stránky [[:$2]] $3",
+ "notification-reverted-flyout2": "$1 {{GENDER:$1|revertoval|revertovala}} {{PLURAL:$4|vaši editaci|vaše editace}} stránky $2 $3",
+ "notification-edit-talk-page-email-subject2": "$1 vám na {{grammar:6sg|{{SITENAME}}}} {{GENDER:$1|napsal|napsala}} zprávu.",
+ "notification-edit-talk-page-email-batch-body2": "$1 vám {{GENDER:$1|napsal|napsala}} na vaši diskusní stránku:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 vám {{GENDER:$1|napsal|napsala}} na vaši diskusní stránku k „$2“.",
+ "notification-page-linked-email-subject": "Na {{grammar:6sg|{{SITENAME}}}} někdo odkázal na vaši stránku.",
+ "notification-page-linked-email-batch-body": "Do stránky $3 {{GENDER:$1|byl přidán}} odkaz na stránku $2",
+ "notification-reverted-email-subject2": "$1 {{GENDER:$1|revertoval|revertovala}} {{PLURAL:$3|vaši editaci|vaše editace}} na {{grammar:6sg|{{SITENAME}}}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|revertoval|revertovala}} {{PLURAL:$3|vaši editaci|vaše editace}} stránky $2.",
+ "notification-mention-email-subject": "$1 vás na {{grammar:6sg|{{SITENAME}}}} {{GENDER:$1|zmínil|zmínila}}",
+ "notification-mention-email-batch-body": "$1 vás {{GENDER:$1|zmínil|zmínila}} v diskusi $4 u „$3“.",
+ "notification-mention-nosection-email-batch-body": "$1 vás {{GENDER:$1|zmínil|zmínila}} v diskusi ke stránce $2.",
+ "notification-user-rights-email-subject": "Na {{grammar:6sg|{{SITENAME}}}} byla změněna vaše uživatelská práva",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|změnil|změnila}} vaše uživatelská práva. $2",
+ "echo-email-subject-default": "Nové upozornění na {{grammar:6sg|{{SITENAME}}}}",
+ "echo-email-body-default": "Na {{grammar:6sg|{{SITENAME}}}} máte nové upozornění:\n\n$1",
+ "echo-email-batch-body-default": "Máte nové upozornění",
+ "echo-email-footer-default": "$2\n\nPosílání e-mailů si můžete přizpůsobit v nastavení:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Posílání e-mailů si můžete přizpůsobit <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">v nastavení</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Upozornění ($1)|100=Upozornění (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Zpráva ($1)|Zprávy ($1)|100=Zprávy (99+)}}",
+ "echo-notification-alert-text-only": "Upozornění",
+ "echo-notification-message-text-only": "Zprávy",
+ "echo-overlay-link": "Všechna upozornění",
+ "echo-overlay-title": "<b>Upozornění</b>",
+ "echo-overlay-title-overflow": "<b>Upozornění</b> (zobrazuje se $1 z $2 {{PLURAL:$1|nepřečteného|nepřečtených}})",
+ "echo-mark-all-as-read": "Označit vše jako přečtené",
+ "echo-date-today": "Dnes",
+ "echo-date-yesterday": "Včera",
+ "echo-load-more-error": "Při načítání dalších výsledků došlo k chybě.",
+ "notification-edit-talk-page-bundle": "$1 a $3 {{PLURAL:$4|další}} vám napsali na [[User talk:$2|vaši diskusní stránku]].",
+ "notification-page-linked-bundle": "Do stránky $3 a $4 {{PLURAL:$5|další stránky|dalších stránek}} {{GENDER:$1|byly přidány}} odkazy na stránku $2: [[Special:WhatLinksHere/$2|Zobrazit všechny odkazy na tuto stránku]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 a $2 {{PLURAL:$3|další}} vám napsali na vaši diskusní stránku",
+ "notification-page-linked-email-batch-bundle-body": "Do stránky $3 a $4 {{PLURAL:$5|další stránky|dalších stránek}} {{GENDER:$1|byly přidány}} odkazy na stránku $2",
+ "echo-email-batch-subject-daily": "Na {{grammar:6sg|{{SITENAME}}}} dnes máte {{PLURAL:$2|nové|nová}} upozornění",
+ "echo-email-batch-subject-weekly": "Na {{grammar:6sg|{{SITENAME}}}} máte tento týden {{PLURAL:$2|nové|nová}} upozornění",
+ "echo-email-batch-body-intro-daily": "Ahoj, uživateli $1,\n\nzde pro vás máme shrnutí dnešní aktivity na {{grammar:6sg|{{SITENAME}}}}",
+ "echo-email-batch-body-intro-weekly": "Ahoj, uživateli $1,\n\nzde pro vás máme shrnutí aktivity na {{grammar:6sg|{{SITENAME}}}} za tento týden",
+ "echo-email-batch-link-text-view-all-notifications": "Zobrazit všechna upozornění",
+ "echo-rev-deleted-text-view": "Tato verze stránky byla utajena"
+}
diff --git a/Echo/i18n/cu.json b/Echo/i18n/cu.json
new file mode 100644
index 00000000..d35964fb
--- /dev/null
+++ b/Echo/i18n/cu.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "ОйЛ"
+ ]
+ },
+ "echo-learn-more": "поꙁнаи вѧщє",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|напьсаниѥ|напьсании|напьсаниꙗ}} бєсѣдꙑ страницѣ",
+ "echo-category-title-system": "{{PLURAL:$1|сѷстима}}",
+ "echo-date-yesterday": "вьчєра"
+}
diff --git a/Echo/i18n/cv.json b/Echo/i18n/cv.json
new file mode 100644
index 00000000..8330f539
--- /dev/null
+++ b/Echo/i18n/cv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chuvash2014"
+ ]
+ },
+ "echo-pref-email-format-html": "HTML"
+}
diff --git a/Echo/i18n/cy.json b/Echo/i18n/cy.json
new file mode 100644
index 00000000..b3c7fb57
--- /dev/null
+++ b/Echo/i18n/cy.json
@@ -0,0 +1,110 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lloffiwr"
+ ]
+ },
+ "echo-desc": "Sustem hysbysu",
+ "prefs-echo": "Hysbysiadau",
+ "prefs-emailsettings": "Dewisiadau ebost",
+ "prefs-displaynotifications": "Dewisiadau arddangos",
+ "prefs-echosubscriptions": "Hysbyswch fi am y digwyddiadau hyn",
+ "prefs-newmessageindicator": "Arwyddo negeseuon newydd",
+ "echo-pref-send-me": "Anfon ataf:",
+ "echo-pref-send-to": "Anfon at:",
+ "echo-pref-email-format": "Fformat yr ebost:",
+ "echo-pref-web": "Gwe",
+ "echo-pref-email": "Ebost",
+ "echo-pref-email-frequency-never": "Peidio ag anfon unrhyw hysbysiadau ebost ataf",
+ "echo-pref-email-frequency-immediately": "Hysbysiadau unigol pan ddigwyddant",
+ "echo-pref-email-frequency-daily": "Crynodeb dyddiol o'r hysbysiadau",
+ "echo-pref-email-frequency-weekly": "Crynodeb wythnosol o'r hysbysiadau",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Testun plaen",
+ "echo-pref-notify-show-link": "Dangos hysbysiadau yn fy mar offer",
+ "echo-pref-new-message-indicator": "Dangos arwydd bod neges newydd ar fy nhudalen sgwrs yn fy mar offer",
+ "echo-learn-more": "Darllen mwy",
+ "echo-new-messages": "Mae negeseuon newydd gennych",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|negeseuon}} ar dudalennau sgwrs",
+ "echo-category-title-article-linked": "{{PLURAL:$1|cysylltau i dudalennau}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|dadwneud golygiadau}}",
+ "echo-category-title-mention": "{{PLURAL:$1|cyfeiriadau}}",
+ "echo-category-title-other": "{{PLURAL:$1|Arall}}",
+ "echo-category-title-system": "{{PLURAL:$1|sustem}}",
+ "echo-pref-tooltip-edit-user-talk": "Fy hysbysu pan fo rhywun yn gadael neges neu ateb ar fy nhudalen sgwrs.",
+ "echo-pref-tooltip-article-linked": "Fy hysbysu pan fo rhywun yn gosod cyswllt o ryw erthygl i dudalen a ddechreuais i.",
+ "echo-pref-tooltip-reverted": "Hysbyswch fi pan fo rhywun yn dadwneud golygiad o'm heiddo i, drwy ddefnyddio'r teclynnau dadwneud neu wrthdroi.",
+ "echo-pref-tooltip-mention": "Hysbyswch fi pan fo rhywun yn gosod cyswllt at fy nhudalen defnyddiwr oddi wrth rhyw dudalen sgwrs.",
+ "echo-no-agent": "[Neb]",
+ "echo-no-title": "[Dim tudalen]",
+ "echo-error-no-formatter": "Ni phenwyd unrhyw fformat i'r hysbysiad.",
+ "echo-error-preference": "Gwall: Ni ellid gosod y dewis yn newisiadau'r defnyddiwr.",
+ "echo-error-token": "Gwall: Ni ellid adalw tocyn y defnyddiwr.",
+ "notifications": "Hysbysiadau",
+ "tooltip-pt-notifications": "Eich hysbysiadau",
+ "echo-specialpage": "Hysbysiadau",
+ "echo-anon": "Er mwyn derbyn hysbysiadau, [$1 dechreuwch gyfrif] neu [$2 mewngofnodwch].",
+ "echo-none": "Nid oes unrhyw hysbysiadau gennych.",
+ "echo-more-info": "Mwy o wybodaeth",
+ "echo-feedback": "Adborth",
+ "notification-link-text-view-message": "Gweld y neges",
+ "notification-link-text-view-mention": "Gweld y crybwyll",
+ "notification-link-text-view-changes": "Gweld y newidiadau",
+ "notification-link-text-view-page": "Gweld y dudalen",
+ "notification-link-text-view-edit": "Gweld y golygiad",
+ "notification-edit-talk-page2": "{{GENDER:$1|Gadawodd}} [[User:$1|$1]] neges ar eich [[User talk:$2#$3|tudalen sgwrs]].",
+ "notification-edit-talk-page-with-section": "{{GENDER:$1|Gadawodd}} [[User:$1|$1]] neges ar eich tudalen sgwrs yn yr adran \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "{{GENDER:$1|Gadawodd}} $1 neges ar eich [[User talk:$2#$3|tudalen sgwrs]].",
+ "notification-edit-talk-page-flyout-with-section": "{{GENDER:$1|Gadawodd}} $1 neges ar eich tudalen sgwrs yn yr adran \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "{{GENDER:$1|Cysylltwyd}} [[:$2]] o [[:$3]]. [[Special:WhatLinksHere/$2|Gweler yr holl gysylltau i'r dudalen hon]].",
+ "notification-page-linked-flyout": "{{GENDER:$1|Cysylltwyd}} [[:$2]] o [[:$3]].",
+ "notification-add-comment2": "{{GENDER:$1|Gadawodd}} [[User:$1|$1]] sylw am \"[[$3|$2]]\" ar y dudalen sgwrs \"$4\".",
+ "notification-add-talkpage-topic2": "{{GENDER:$1|Gosododd}} [[User:$1|$1]] sylw ar y pwnc newydd \"$2\" ar [[$3]].",
+ "notification-add-talkpage-topic-yours2": "{{GENDER:$1|Anfonodd}} [[User:$1|$1]] neges atoch: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "{{GENDER:$1|Gosododd}} [[User:$1|$1]] sylw am \"[[$3#$2|$2]]\" ar eich tudalen sgwrs.",
+ "notification-mention": "{{GENDER:$1|Cyfeiriodd}} [[User:$1|$1]] atoch ar dudalen sgwrs $5 yn yr adran \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "{{GENDER:$1|Cyfeiriodd}} $1 atoch ar dudalen sgwrs $5 yn yr adran \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "{{GENDER:$1|Cyfeiriodd}} [[User:$1|$1]] atoch ar [[:$3|dudalen sgwrs $2]].",
+ "notification-mention-nosection-flyout": "{{GENDER:$1|Cyfeiriodd}} $1 atoch ar [[:$3|dudalen sgwrs $2]].",
+ "notification-user-rights": "[[Special:Log/rights/$1|{{GENDER:$1|Newidiwyd}}]] eich galluoedd defnyddiwr gan [[User:$1|$1]]. $2. [[Special:ListGroupRights|Darllen mwy]]",
+ "notification-user-rights-flyout": "{{GENDER:$1|Newidiwyd}} eich galluoedd defnyddiwr gan $1. $2. [[Special:ListGroupRights|Darllen mwy]]",
+ "notification-user-rights-add": "Rydych nawr yn aelod o'r {{PLURAL:$2|grŵp hwn|grŵp hwn|grwpiau hyn}}: $1",
+ "notification-user-rights-remove": "Nid ydych bellach yn aelod o'r {{PLURAL:$2|grŵp hwn|grŵp hwn|grwpiau hyn}}: $1",
+ "notification-new-user": "Croeso i {{SITENAME}}, $1! Rydym yn falch eich bod wedi cyrraedd.",
+ "notification-reverted2": "{{GENDER:$1|Dadwneuthpwyd}} eich {{PLURAL:$4||golygiad ar [[:$2]]|golygiadau ar [[:$2]]}} gan [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{GENDER:$1|Dadwneuthpwyd}} eich {{PLURAL:$4||golygiad ar $2|golygiadau ar $2}} gan $1. $3",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|Gosododd}} $1 neges i chi ar {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|Gosododd}} $1 neges ar eich tudalen sgwrs:",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|Gosododd}} $1 neges ar eich tudalen sgwrs yn \"$2\".",
+ "notification-page-linked-email-subject": "Cysylltwyd i'ch tudalen ar {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|Gosodwyd}} cyswllt o $3 i $2.",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Dadwnaethpwyd}} eich {{PLURAL:$3||golygiad|golygiadau}} ar {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{GENDER:$1|Dadwnaethpwyd}} eich {{PLURAL:$3||golygiad|golygiadau}}ar $2 gan $1.",
+ "notification-mention-email-subject": "{{GENDER:$1|Cyfeiriodd}} $1 atoch ar {{SITENAME}}",
+ "notification-mention-email-batch-body": "{{GENDER:$1|Cyfeiriodd}} $1 atoch ar dudalen sgwrs $4 yn yr adran \"$3\".",
+ "notification-mention-nosection-email-batch-body": "{{GENDER:$1|Cyfeiriodd}} $1 atoch ar y dudalen sgwrs $2.",
+ "notification-user-rights-email-subject": "Newidiodd eich galluoedd fel defnyddiwr ar {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Newidiwyd eich galluoedd {{GENDER:$1|defnyddiwr}} gan $1. $2.",
+ "echo-email-subject-default": "Hysbysiad newydd ar {{SITENAME}}",
+ "echo-email-body-default": "Mae hysbysiad newydd gennych ar {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Mae hysbysiad newydd gennych.",
+ "echo-email-footer-default": "$2\n\nOs am reoli yr ebyst y cewch gennym, ewch i'ch dewisiadau:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "I reoli'r ebyst i'w hanfon atoch, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">ewch i'ch dewisiadau</a>.<br />\n$1",
+ "echo-overlay-link": "Pob hysbysiad",
+ "echo-overlay-title": "<b>Hysbysiadau</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Hysbysiadau}}</b> (yn dangos $1 o $2 heb eu darllen)",
+ "echo-mark-all-as-read": "Marcio bod y cwbl wedi eu darllen",
+ "echo-date-today": "Heddiw",
+ "echo-date-yesterday": "Ddoe",
+ "echo-load-more-error": "Cafwyd gwall wrth nôl rhagor o ganlyniadau.",
+ "notification-edit-talk-page-bundle": "{{GENDER:$1|Gadawodd}} $1 a $3 {{PLURAL:$4|a $3 arall|ac $3 arall|a $3 eraill}} negeseuon ar eich [[User talk:$2|tudalen defnyddiwr]].",
+ "notification-page-linked-bundle": "{{GENDER:$1|Gosodwyd}} cysylltiad at $2 o $3 {{PLURAL:$5||ac $4 dudalen arall|a $4 dudalen arall|a $4 o dudalennau eraill}}. [[Special:WhatLinksHere/$2|Gweler yr holl gysylltiadau i'r dudalen hon]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "{{GENDER:$1|Gadawodd}} $1 {{PLURAL:$3||ac $2 arall||a $2 arall| a $2 eraill}} negeseuon ar eich tudalen sgwrs.",
+ "notification-page-linked-email-batch-bundle-body": "{{GENDER:$1|Gosodwyd}} gyswllt i $2 oddi wrth $3 {{PLURAL:$5||ac $4 dudalen arall|a $2 dudalen arall|a $2 o dudalennau eraill}}.",
+ "echo-email-batch-subject-daily": "Mae {{PLURAL:$2||hysbysiad|hysbysiadau}} newydd gennych ar {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Mae {{PLURAL:$2||hysbysiad|hysbysiadau}} newydd gennych yr wythnos hon ar {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Sut mae $1,\nDyma grynodeb i chi o weithgaredd heddiw ar {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Sut mae $1,\nDyma grynodeb i chi o weithgaredd yr wythnos hon ar {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Gweld yr holl hysbysiadau",
+ "echo-rev-deleted-text-view": "Cuddiwyd y diwygiad hwn o'r dudalen."
+}
diff --git a/Echo/i18n/da.json b/Echo/i18n/da.json
new file mode 100644
index 00000000..89bc95a2
--- /dev/null
+++ b/Echo/i18n/da.json
@@ -0,0 +1,117 @@
+{
+ "@metadata": {
+ "authors": [
+ "Byrial",
+ "Christian List",
+ "Palnatoke",
+ "Sarrus",
+ "Tjernobyl",
+ "Thomsen"
+ ]
+ },
+ "echo-desc": "Meddelelsessystem",
+ "prefs-echo": "Meddelelser",
+ "prefs-emailsettings": "E-mailindstillinger",
+ "prefs-displaynotifications": "Indstillinger for visning",
+ "prefs-echosubscriptions": "Giv mig en meddelelse ved følgende hændelser",
+ "prefs-newmessageindicator": "Indikator for nye meddelelser",
+ "echo-pref-send-me": "Send mig:",
+ "echo-pref-send-to": "Send til:",
+ "echo-pref-email-format": "E-mailformat:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Send mig ikke nogen e-mailmeddelelser",
+ "echo-pref-email-frequency-immediately": "De enkelte meddelelser når de kommer",
+ "echo-pref-email-frequency-daily": "En daglig oversigt over meddelelser",
+ "echo-pref-email-frequency-weekly": "En ugentlig oversigt over meddelelser",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Plain text",
+ "echo-pref-notify-show-link": "Vis meddelelser i min værktøjslinje",
+ "echo-pref-new-message-indicator": "Vis indikator for meddelelser på diskussionssiden i min værktøjslinje",
+ "echo-learn-more": "Find ud af mere",
+ "echo-new-messages": "Du har nye beskeder",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Besked|Beskeder}} på diskussionsside",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Sidehenvisning|Sidehenvisninger}}",
+ "echo-category-title-reverted": "Tilbagestilling af {{PLURAL:$1|redigering|redigeringer}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Omtale|Omtaler}}",
+ "echo-category-title-other": "{{PLURAL:$1|Anden|Andre}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Ændring af brugerrettighed|Ændring af brugerrettigheder}}",
+ "echo-pref-tooltip-edit-user-talk": "Giv mig besked når nogen skriver en besked eller et svar på min diskussionsside.",
+ "echo-pref-tooltip-article-linked": "Giv mig beked når nogen henviser til en side som jeg har oprettet, fra en artikelside.",
+ "echo-pref-tooltip-reverted": "Giv mig besked når nogen tilbagestiller en redigering som jeg lavet, ved at bruge fjern redigering eller rul tilbage.",
+ "echo-pref-tooltip-mention": "Giv mig besked når nogen henviser til min brugerside.",
+ "echo-pref-tooltip-user-rights": "Giv mig besked når nogen ændrer mine brugerrettigheder.",
+ "echo-no-agent": "[Ingen]",
+ "echo-no-title": "[Ingen side]",
+ "echo-error-no-formatter": "Der er ikke defineret et format for meddelelsen",
+ "echo-error-preference": "Fejl: Kunne ikke gemme brugerindstillinger",
+ "echo-error-token": "Fejl: Kunne ikke hente brugertoken",
+ "notifications": "Meddelelser",
+ "tooltip-pt-notifications": "Dine meddelelser",
+ "echo-specialpage": "Meddelelser",
+ "echo-anon": "For at modtage meddelelser skal du [$1 oprette en konto] eller [$2 logge ind].",
+ "echo-none": "Du har ingen meddelelser.",
+ "echo-more-info": "Mere information",
+ "echo-feedback": "Feedback",
+ "notification-link-text-view-message": "Vis besked",
+ "notification-link-text-view-mention": "Se omtale",
+ "notification-link-text-view-changes": "Se ændringer",
+ "notification-link-text-view-page": "Se side",
+ "notification-link-text-view-edit": "Se redigering",
+ "notification-edit-talk-page2": "[[User:$1|$1]] skrev en besked på din [[User talk:$2#$3|diskussionsside]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] lagde en besked på din diskussionsside i \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 skrev et indlæg på din [[User talk:$2#$3|diskussionsside]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 lagde en besked på din diskussionside i \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Der blev {{GENDER:$1|henvist}} til [[:$2]] fra [[:$3]]. [[Special:WhatLinksHere/$2|Se alle henvisninger til siden]].",
+ "notification-page-linked-flyout": "Der blev {{GENDER:$1|henvist}} til [[:$2]] fra [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] kommenterede om \"[[$3|$2]]\" på diskussionssiden \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] skrev et nyt indlæg om \"$2\" på [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] har sendt dig en besked: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] kommenterede om \"[[$3#$2|$2]]\" på din diskussionsside",
+ "notification-mention": "[[User:$1|$1]] omtalte dig på diskussionssiden $5 i \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 omtalte dig på diskussionssiden $5 i \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|nævnte}} dig på [[:$3|diskussionssiden for \"$2\"]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|nævnte}} dig på [[:$3|diskussionssiden for \"$2\"]].",
+ "notification-user-rights": "Dine brugerrettigheder [[Special:Log/rights/$1|blev ændret]] af [[User:$1|$1]]. $2. [[Special:ListGroupRights|Find ud af mere]]",
+ "notification-user-rights-flyout": "Dine brugerrettigheder blev ændret af $1. $2. [[Special:ListGroupRights|Find ud af mere]]",
+ "notification-user-rights-add": "Du er nu medlem af {{PLURAL:$2|denne gruppe|disse grupper}}: $1",
+ "notification-user-rights-remove": "du er ikke længere medlem af {{PLURAL:$2|denne gruppe|disse grupper}}: $1",
+ "notification-new-user": "Velkommen til {{SITENAME}}, $1! Vi er glade for at du er her.",
+ "notification-reverted2": "{{PLURAL:$4|Din redigering af [[:$2]] er blevet tilbagestillet|Dine redigeringer af [[:$2]] er blevet tilbagestillede}} af [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Din redigering af $2 er blevet tilbagestillet|Dine redigeringer af $2 er blevet tilbagestillede}} af $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 lagde en besked til dig på {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 skrev et indlæg på din diskussionsside",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 lagde en besked på din diskussionsside i \"$2\".",
+ "notification-page-linked-email-subject": "En side som du oprettede blev henvist til på {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Der {{GENDER:$1|blev}} henvist til $2 fra $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Din redigering blev|Dine redigeringer blev}} {{GENDER:$1|omgjort}} på {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Din redigering|Dine redigeringer}} på $2 er omgjort af $1.",
+ "notification-mention-email-subject": "$1 omtalte dig på {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 omtalte dig på diskussionssiden $4 i \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|nævnte}} dig på diskussionssiden for \"$2\".",
+ "notification-user-rights-email-subject": "Dine brugerrettigheder er blevet ændret på {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Dine brugerrettigheder er blevet ændret af $1. $2",
+ "echo-email-subject-default": "Ny meddelelse på {{SITENAME}}",
+ "echo-email-body-default": "Der er en ny meddelelse til dig på {{SITENAME}}\n\n$1",
+ "echo-email-batch-body-default": "Der er en ny meddelelse til dig",
+ "echo-email-footer-default": "$2\n\nTjek dine indstillinger for at se hvilke e-mails vi sender til dig:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "For at styre hvilke e-mails, vi sender til dig, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">tjek dine indstillinger</a><br />\n$1",
+ "echo-overlay-link": "Alle meddelelser",
+ "echo-overlay-title": "<b>Meddelelser</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Meddelelser}}<b> (viser $1 af $2 ulæste)",
+ "echo-mark-all-as-read": "Markér alle som læste",
+ "echo-date-today": "I dag",
+ "echo-date-yesterday": "I går",
+ "echo-load-more-error": "Der skete en fejl under hentningen af flere resultater.",
+ "notification-edit-talk-page-bundle": "$1 og $3 {{PLURAL:$4|andre}} lagde en besked på din [[User talk:$2|diskussionsside]].",
+ "notification-page-linked-bundle": "$2 {{GENDER:$1|blev}} henvist til fra $3 og $4 {{PLURAL:$5|anden side|andre sider}}. [[Special:WhatLinksHere/$2|Se alle henvisninger til siden]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 og $2 {{PLURAL:$3|anden|andre}} skrev indlæg på din diskussionsside",
+ "notification-page-linked-email-batch-bundle-body": "$2 {{GENDER:$1|blev}} henvist til fra $3 og $4 {{PLURAL:$5|anden side|andre sider}}",
+ "echo-email-batch-subject-daily": "Du har {{PLURAL:$2|en ny meddelelse|$2 nye meddelelser}} på {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Du har {{PLURAL:$2|en ny meddelelse|$2 nye meddelelser}} på {{SITENAME}} i denne uge",
+ "echo-email-batch-body-intro-daily": "Hej $1,\nHer er en oversigt over dagens aktivitet på {{SITENAME}} for dig.",
+ "echo-email-batch-body-intro-weekly": "Hej $1,\nHer er et resumé af denne uges aktivitet på {{SITENAME}} for dig.",
+ "echo-email-batch-link-text-view-all-notifications": "Se alle meddelelser",
+ "echo-rev-deleted-text-view": "Denne sideversion er skjult."
+}
diff --git a/Echo/i18n/de-formal.json b/Echo/i18n/de-formal.json
new file mode 100644
index 00000000..f0a96f28
--- /dev/null
+++ b/Echo/i18n/de-formal.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln"
+ ]
+ },
+ "echo-new-messages": "Sie haben neue Nachrichten",
+ "echo-none": "Sie haben in letzter Zeit keine Benachrichtigungen erhalten.",
+ "notification-user-rights": "Ihre Benutzerrechte wurden von [[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|geändert}}]]. $2. [[Special:ListGroupRights|Weitere Informationen …]]",
+ "notification-user-rights-flyout": "Ihre Benutzerrechte wurden von $1 {{GENDER:$1|geändert}}. $2. [[Special:ListGroupRights|Weitere Informationen …]]",
+ "notification-user-rights-add": "Sie sind jetzt Mitglied dieser {{PLURAL:$2|Benutzergruppe|Benutzergruppen}}: $1",
+ "notification-user-rights-remove": "Sie sind nicht länger Mitglied dieser {{PLURAL:$2|Benutzergruppe|Benutzergruppen}}: $1",
+ "notification-new-user": "Willkommen bei {{SITENAME}}, $1! Wir freuen uns, dass Sie hier sind.",
+ "notification-user-rights-email-subject": "Ihre Benutzerrechte auf „{{SITENAME}}“ wurden geändert.",
+ "notification-user-rights-email-batch-body": "Ihre Benutzerrechte wurden von $1 {{GENDER:$1|geändert}}. $2"
+}
diff --git a/Echo/i18n/de.json b/Echo/i18n/de.json
new file mode 100644
index 00000000..977db8cb
--- /dev/null
+++ b/Echo/i18n/de.json
@@ -0,0 +1,135 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln",
+ "Metalhead64",
+ "Se4598",
+ "TMg",
+ "ChrisiPK",
+ "Suriyaa Kudo",
+ "Purodha"
+ ]
+ },
+ "echo-desc": "Stellt ein Benachrichtigungssystem bereit",
+ "prefs-echo": "Benachrichtigungen",
+ "prefs-emailsettings": "E-Mail-Optionen",
+ "prefs-displaynotifications": "Anzeigeoptionen",
+ "prefs-echosubscriptions": "Mich bei diesen Ereignissen benachrichtigen",
+ "prefs-newmessageindicator": "Hinweise zu neuen Nachrichten",
+ "echo-pref-send-me": "Sende mir:",
+ "echo-pref-send-to": "Sende an:",
+ "echo-pref-email-format": "E-Mail-Format:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-Mail",
+ "echo-pref-email-frequency-never": "Sende mir keine E-Mail-Benachrichtigungen",
+ "echo-pref-email-frequency-immediately": "Individuelle Benachrichtigung zu jedem Ereignis",
+ "echo-pref-email-frequency-daily": "Tägliche Benachrichtigung zu den Ereignissen",
+ "echo-pref-email-frequency-weekly": "Wöchentliche Benachrichtigung zu den Ereignissen",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Nur Text",
+ "echo-pref-notify-show-link": "Benachrichtigungen in meiner Benutzerleiste anzeigen",
+ "echo-pref-new-message-indicator": "Hinweise zu neuen Nachrichten in meiner Benutzerleiste anzeigen",
+ "echo-learn-more": "Mehr erfahren",
+ "echo-new-messages": "Du hast neue Nachrichten",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Diskussionsseitennachricht|Diskussionsseitennachrichten}}",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Seitenverlinkung|Seitenverlinkungen}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Rückgängigmachung einer Bearbeitung|Rückgängigmachungen von Bearbeitungen}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Erwähnung|Erwähnungen}}",
+ "echo-category-title-other": "{{PLURAL:$1|Andere}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Benutzerrechteänderung|Benutzerrechteänderungen}}",
+ "echo-pref-tooltip-edit-user-talk": "Benachrichtige mich, wenn jemand eine Nachricht oder eine Antwort auf meiner Diskussionsseite hinterlässt.",
+ "echo-pref-tooltip-article-linked": "Benachrichtige mich, wenn jemand in einem Artikel auf eine Seite verlinkt, die ich erstellt habe.",
+ "echo-pref-tooltip-reverted": "Benachrichtige mich, wenn jemand eine von mir gemachte Bearbeitung rückgängig macht oder zurücksetzt.",
+ "echo-pref-tooltip-mention": "Benachrichtige mich, wenn jemand auf meine Benutzerseite verlinkt.",
+ "echo-pref-tooltip-user-rights": "Benachrichtige mich, wenn jemand meine Benutzerrechte ändert.",
+ "echo-no-agent": "[Niemand]",
+ "echo-no-title": "[Keine Seite]",
+ "echo-error-no-formatter": "Keine Formatierung zur Benachrichtigung definiert",
+ "echo-error-preference": "Fehler: Benutzereinstellung konnte nicht festgelegt werden.",
+ "echo-error-token": "Fehler: Benutzertoken konnte nicht abgerufen werden",
+ "notifications": "Benachrichtigungen",
+ "tooltip-pt-notifications": "Deine Benachrichtigungen",
+ "echo-specialpage": "Benachrichtigungen",
+ "echo-anon": "Um Benachrichtigungen erhalten zu können, muss man ein [$1 Benutzerkonto anlegen] oder sich [$2 anmelden].",
+ "echo-none": "Du hast keine Benachrichtigungen.",
+ "echo-more-info": "Mehr Informationen",
+ "echo-feedback": "Rückmeldung",
+ "notification-link-text-view-message": "Nachricht ansehen",
+ "notification-link-text-view-mention": "Erwähnung ansehen",
+ "notification-link-text-view-changes": "Änderungen ansehen",
+ "notification-link-text-view-page": "Seite ansehen",
+ "notification-link-text-view-edit": "Bearbeitung ansehen",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|hinterließ}} eine Nachricht auf deiner [[User talk:$2#$3|Diskussionsseite]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|hinterließ}} eine Nachricht auf deiner Diskussionsseite zum Thema „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|hinterließ}} eine Nachricht auf deiner [[User talk:$2#$3|Diskussionsseite]].",
+ "notification-edit-talk-page-flyout-with-section": "„$1“ {{GENDER:$1|hinterließ}} eine Nachricht auf deiner Diskussionsseite zum Thema „[[User talk:$2#$3|$4]]“.",
+ "notification-page-linked": "[[:$2]] wurde von der Seite [[:$3]] {{GENDER:$1|verlinkt}}. [[Special:WhatLinksHere/$2|Alle Links auf diese Seite ansehen]].",
+ "notification-page-linked-flyout": "[[:$2]] wurde von der Seite [[:$3]] {{GENDER:$1|verlinkt}}.",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|kommentierte}} auf „[[$3|$2]]“ auf der Diskussionsseite von „$4“",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|startete}} das neue Thema „$2“ auf [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] hat dir eine Nachricht {{GENDER:$1|gesandt}}: „[[$3#$2|$2]]“",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|kommentierte}} auf „[[$3#$2|$2]]“ auf deiner Diskussionsseite",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|erwähnte}} dich auf der Seite „$5“ in „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|erwähnte}} dich auf der Seite „$5“ in „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|erwähnte}} dich auf der [[:$3|Seite „$2“]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|erwähnte}} dich auf der [[:$3|Seite „$2“]].",
+ "notification-user-rights": "Deine Benutzerrechte wurden von [[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|geändert}}]]. $2. [[Special:ListGroupRights|Weitere Informationen]]",
+ "notification-user-rights-flyout": "Deine Benutzerrechte wurden von $1 {{GENDER:$1|geändert}}. $2. [[Special:ListGroupRights|Weitere Informationen]]",
+ "notification-user-rights-add": "Du bist jetzt Mitglied dieser {{PLURAL:$2|Benutzergruppe|Benutzergruppen}}: $1",
+ "notification-user-rights-remove": "Du bist nicht länger Mitglied dieser {{PLURAL:$2|Benutzergruppe|Benutzergruppen}}: $1",
+ "notification-new-user": "Willkommen bei {{SITENAME}}, $1! Wir freuen uns, dass du hier bist.",
+ "notification-reverted2": "Deine {{PLURAL:$4|Bearbeitung an der Seite [[:$2]] wurde|Bearbeitungen an der Seite [[:$2]] wurden}} von [[User:$1|$1]] {{GENDER:$1|rückgängig}} gemacht. $3",
+ "notification-reverted-flyout2": "Deine {{PLURAL:$4|Bearbeitung an der Seite $2 wurde|Bearbeitungen an der Seite $2 wurden}} von $1 {{GENDER:$1|rückgängig}} gemacht. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|hinterließ}} dir eine Nachricht auf {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|hinterließ}} eine Nachricht auf deiner Diskussionsseite:",
+ "notification-edit-talk-page-email-batch-body-with-section": "„$1“ {{GENDER:$1|hinterließ}} eine Nachricht auf deiner Diskussionsseite zum Thema „$2“.",
+ "notification-page-linked-email-subject": "Deine Seite wurde auf {{SITENAME}} verlinkt",
+ "notification-page-linked-email-batch-body": "$2 wurde von der Seite $3 {{GENDER:$1|verlinkt}}",
+ "notification-reverted-email-subject2": "Deine {{PLURAL:$3|Bearbeitung wurde|Bearbeitungen wurden}} auf {{SITENAME}} {{GENDER:$1|rückgängig}} gemacht",
+ "notification-reverted-email-batch-body2": "Deine {{PLURAL:$3|Bearbeitung an der Seite $2 wurde|Bearbeitungen an der Seite $2 wurden}} von $1 {{GENDER:$1|rückgängig}} gemacht",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|erwähnte}} dich auf {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|erwähnte}} dich auf der Diskussionsseite von $4 in „$3“.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|erwähnte}} dich auf der Diskussionsseite „$2“.",
+ "notification-user-rights-email-subject": "Deine Benutzerrechte auf „{{SITENAME}}“ wurden geändert.",
+ "notification-user-rights-email-batch-body": "Deine Benutzerrechte wurden von $1 {{GENDER:$1|geändert}}. $2",
+ "echo-email-subject-default": "Neue Benachrichtigung auf {{SITENAME}}",
+ "echo-email-body-default": "Es gibt eine neue Benachrichtigung auf {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Du hast eine neue Benachrichtigung",
+ "echo-email-footer-default": "$2\n\nUm zu steuern, welche E-Mails wir dir senden, nutze deine Einstellungen:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Um zu steuern, welche E-Mails wir dir senden, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">nutze deine Einstellungen</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Eine Benachrichtigung|$1 Benachrichtigungen|100=99+ Benachrichtigungen}}",
+ "echo-notification-message": "{{PLURAL:$1|Eine Nachricht|$1 Nachrichten|100=99+ Nachrichten}}",
+ "echo-notification-alert-text-only": "Benachrichtigungen",
+ "echo-notification-message-text-only": "Nachrichten",
+ "echo-overlay-link": "Alle Benachrichtigungen",
+ "echo-overlay-title": "<b>Benachrichtigungen</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Benachrichtigungen}}</b> ($1 von $2 ungelesenen werden angezeigt)",
+ "echo-mark-all-as-read": "Alle als gelesen markieren",
+ "echo-date-today": "Heute",
+ "echo-date-yesterday": "Gestern",
+ "echo-load-more-error": "Beim Abrufen weiterer Ergebnisse ist ein Fehler aufgetreten.",
+ "notification-edit-talk-page-bundle": "$1 und {{PLURAL:$4|ein weiterer Benutzer|$3 weitere Benutzer}} {{GENDER:$1|hinterließen}} eine Nachricht auf deiner [[User talk:$2|Diskussionsseite]].",
+ "notification-page-linked-bundle": "$2 wurde von $3 und {{PLURAL:$5|einer weiteren Seite|$4 weiteren Seiten}} {{GENDER:$1|verlinkt}}. [[Special:WhatLinksHere/$2|Alle Links auf diese Seite ansehen]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 und {{PLURAL:$3|ein weiterer Benutzer|$2 weitere Benutzer}} {{GENDER:$1|hinterließen}} eine Nachricht auf deiner Diskussionsseite",
+ "notification-page-linked-email-batch-bundle-body": "$2 wurde von $3 und {{PLURAL:$5|einer weiteren Seite|$4 weiteren Seiten}} {{GENDER:$1|verlinkt}}",
+ "echo-email-batch-subject-daily": "Du hast {{PLURAL:$2|eine neue Benachrichtigung|neue Benachrichtigungen}} auf {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Du hast diese Woche {{PLURAL:$2|eine neue Benachrichtigung|neue Benachrichtigungen}} auf {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Hallo $1,\nHier ist für dich eine Zusammenfassung der Aktivitäten auf {{SITENAME}} von heute.",
+ "echo-email-batch-body-intro-weekly": "Hallo $1,\nHier ist für dich eine Zusammenfassung der Aktivitäten auf {{SITENAME}} von dieser Woche.",
+ "echo-email-batch-link-text-view-all-notifications": "Alle Benachrichtigungen ansehen",
+ "echo-rev-deleted-text-view": "Diese Seitenversion wurde unterdrückt",
+ "apihelp-echomarkread-description": "Benachrichtigungen für den aktuellen Benutzer als gelesen markieren.",
+ "apihelp-echomarkread-param-all": "Falls festgelegt, markiert alle Benutzerbenachrichtigungen als gelesen.",
+ "apihelp-echomarkread-param-sections": "Eine Liste der Abschnitte, die als gelesen markiert werden sollen.",
+ "apihelp-echomarkread-example-1": "Benachrichtigung 8 als gelesen markieren",
+ "apihelp-echomarkread-example-2": "Alle Benachrichtigungen als gelesen markieren",
+ "apihelp-query+notifications-param-prop": "Einzelheiten der Anfrage.",
+ "apihelp-query+notifications-param-sections": "Die Abschnitte der Meldungen abfragen.",
+ "apihelp-query+notifications-param-format": "Falls angegeben, werden die zurückgegebenen Benachrichtigungen auf diese Weise formatiert.",
+ "apihelp-query+notifications-param-limit": "Die maximale Anzahl zurückzugebender Benachrichtigungen.",
+ "apihelp-query+notifications-param-messagecontinue": "Falls mehrere Nachrichtenergebnisse verfügbar sind, dies zum Fortfahren verwenden.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Ob ungelesene Benachrichtigungen zuerst angezeigt werden sollen.",
+ "apihelp-query+notifications-example-1": "Benachrichtigungen auflisten",
+ "apihelp-query+notifications-example-2": "Benachrichtigungen auflisten, gruppiert nach Abschnitt, mit Zählern"
+}
diff --git a/Echo/i18n/diq.json b/Echo/i18n/diq.json
new file mode 100644
index 00000000..3ad42014
--- /dev/null
+++ b/Echo/i18n/diq.json
@@ -0,0 +1,65 @@
+{
+ "@metadata": {
+ "authors": [
+ "Asmen",
+ "Erdemaslancan",
+ "Marmase",
+ "Mirzali",
+ "Gorizon",
+ "Sayginer"
+ ]
+ },
+ "echo-desc": "Sistemê tebliğati",
+ "prefs-echo": "Mengeney",
+ "prefs-emailsettings": "Opsiyona e-posta",
+ "prefs-displaynotifications": "Weçinayışa mocnayışi",
+ "prefs-newmessageindicator": "Tebliğê mesacanê neweyan",
+ "echo-pref-send-me": "Mı rê bırışe:",
+ "echo-pref-send-to": "Cı rê bırışe:",
+ "echo-pref-email-format": "Formata E-posta:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-posta",
+ "echo-pref-email-frequency-never": "Mı rê tebliğê e-postey merışe",
+ "echo-pref-email-frequency-immediately": "Tebliğê pela abıryayiye",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Metno pan",
+ "echo-learn-more": "Zewbi",
+ "echo-new-messages": "Şımaré mesaco newe esto",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mesacê|Mesacên}} pela werênayışi",
+ "echo-category-title-article-linked": "Para {{PLURAL:$1|link|linki}}",
+ "echo-category-title-reverted": "Timara {{PLURAL:$1|terknayış|terknayışi}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Bahs kerden|Bahs kerdeni}}",
+ "echo-category-title-other": "{{PLURAL:$1|Zewbi}}",
+ "echo-category-title-system": "{{PLURAL:$1|sistem}}",
+ "echo-no-agent": "[Kesek]",
+ "echo-no-title": "[Pele Çıniya]",
+ "notifications": "Mengene",
+ "tooltip-pt-notifications": "Beyanatê to",
+ "echo-specialpage": "Mengeney",
+ "echo-none": "Beyanatê to çıniyê.",
+ "echo-more-info": "Zêde (vêşi) melumat",
+ "echo-feedback": "Peydrışten",
+ "notification-link-text-view-message": "Qaytê mesaci ke",
+ "notification-link-text-view-mention": "Qayt ke, cao ke qalê to biyo",
+ "notification-link-text-view-changes": "Qaytê vırnayışan ke",
+ "notification-link-text-view-page": "Qaytê pele ke",
+ "notification-link-text-view-edit": "Qaytê vırnayışi ke",
+ "notification-edit-talk-page2": "[[User:$1|$1]], perda [[User talk:$2#$3| mesacande]] to de zew mesaco newe {{GENDER:$1|vırada}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]], Pera masecan de \"[[User talk:$2#$3|$4]]\" de mewzu {{GENDER:$1|vırade}}.",
+ "notification-edit-talk-page-flyout2": "$1, [[User talk:$2#$3|pela werênayışê şıma]] de yew mesac {{GENDER:$1|caverda}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1, pela werênayışê şıma de sernameyê \"[[User talk:$2#$3|$4]]\" rê yew mesac {{GENDER:$1|caverda}}.",
+ "notification-reverted2": "[[User:$1|$1]] {{PLURAL:$4|vurnayışi [[:$2]] |vurnayışê [[:$2]] }} çımraviyarnayışanê $3 {{GENDER:$1|peyser}} gırewti.",
+ "notification-reverted-flyout2": "$1 {{PLURAL:$4|vırnayışa $2 |vırnayışane $2 }} rewizyona $3 {{GENDER:$1|peyser}} grot",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1, pela werênayışê şıma de be sernameyê \"$2\" ra yew mesac {{GENDER:$1|caverda}}.",
+ "echo-email-subject-default": "{{SITENAME}} de beyanato newe",
+ "echo-email-body-default": "{{SITENAME}} de beyanatê do newe esto:\n\n$1",
+ "echo-email-batch-body-default": "Yew beyanatê to esto.",
+ "echo-overlay-link": "Pêro beyanati",
+ "echo-overlay-title": "<b>Tebliği</b>",
+ "echo-mark-all-as-read": "Pêrine wende nışan ke",
+ "echo-date-today": "Ewro",
+ "echo-date-yesterday": "Vızér",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 û $2 {{PLURAL:$3|karberi|karberan}} pela werênayışê şıma de yew mesac {{GENDER:$1|caverda}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Qaytê beyanatan pêrine ke",
+ "echo-rev-deleted-text-view": "Vırnayışê na pele dard we."
+}
diff --git a/Echo/i18n/dsb.json b/Echo/i18n/dsb.json
new file mode 100644
index 00000000..03d4b0a7
--- /dev/null
+++ b/Echo/i18n/dsb.json
@@ -0,0 +1,110 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "echo-desc": "System powěźeńkow",
+ "prefs-echo": "Powěźeńki",
+ "prefs-emailsettings": "E-mailowe nastajenja",
+ "prefs-displaynotifications": "Zwobraznjowańske nastajenja",
+ "prefs-echosubscriptions": "Mě wó toś tych tšojenjach informěrowaś",
+ "prefs-newmessageindicator": "Nowy powěsćowy indikator",
+ "echo-pref-send-me": "Pósćel mě:",
+ "echo-pref-send-to": "Pósłaś na:",
+ "echo-pref-email-format": "E-mailowy format:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Mě žedne e-mailowe powěźeńki njepósłaś",
+ "echo-pref-email-frequency-immediately": "Indiwiduelne powěźeńki ako dochadaju",
+ "echo-pref-email-frequency-daily": "Wšedny pśeglěd powěźeńkow",
+ "echo-pref-email-frequency-weekly": "Tyźeński pśeglěd powěźeńkow",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Lutny tekst",
+ "echo-pref-notify-show-link": "Powěźeńki w symbolowej rědce pokazaś",
+ "echo-pref-new-message-indicator": "Powěsćowy indikator diskusijnego boka w symbolowej rědce pokazaś",
+ "echo-learn-more": "Dalšne informacije",
+ "echo-new-messages": "Maš nowe powěsći",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Powěsć|Powěsći}} na diskusijnem boku",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Wótkaz|Wótkaza|Wótkaze}} boka",
+ "echo-category-title-reverted": "{{PLURAL:$1|Anulěrowanje|Anulěrowani|Anulěrowanja}} změnow",
+ "echo-category-title-mention": "{{PLURAL:$1|Naspomnjenje|Naspomnjeni|Naspomnjenja}}",
+ "echo-category-title-other": "{{PLURAL:$1|Druga|Drugej|Druge}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-pref-tooltip-edit-user-talk": "Informěruj mě gaž něchten zawóstaja powěsć abo wótegrono na mójom diskusijnem boku.",
+ "echo-pref-tooltip-article-linked": "Informěruj mě, gaž něchten wótkazujo na bok, kótaryž som z nastawka napórał.",
+ "echo-pref-tooltip-reverted": "Informěruj mě, gaž něchten z pomocu anulěrowanja abo rěda anulěrujo změnu, kótaruž som cynił.",
+ "echo-pref-tooltip-mention": "Informěruj mě, gaž něchten wótkazujo z někakego diskusijnego boka k mójomu wužywarskemu bokoju.",
+ "echo-no-agent": "[Nichten]",
+ "echo-no-title": "[Žeden bok]",
+ "echo-error-no-formatter": "Za powěźeńku njejo se formatěrowanje definěrowało.",
+ "echo-error-preference": "Zmólka: Wužywarske nastajenje njedajo se stajiś.",
+ "echo-error-token": "Zmólka: Wužywarski token njedajo se wótwołaś.",
+ "notifications": "Powěźeńki",
+ "tooltip-pt-notifications": "Twóje powěźeńki",
+ "echo-specialpage": "Powěźeńki",
+ "echo-anon": "Aby powěźeńki dostał, [$1 napóraj konto] abo [$2 pśizjaw se].",
+ "echo-none": "Njamaš powěźeńki",
+ "echo-more-info": "Dalšne informacije",
+ "echo-feedback": "Komentary",
+ "notification-link-text-view-message": "Powěsć pokazaś",
+ "notification-link-text-view-mention": "Naspomnjenje pokazaś",
+ "notification-link-text-view-changes": "Změny pokazaś",
+ "notification-link-text-view-page": "Bok se woglědaś",
+ "notification-link-text-view-edit": "Změnu pokazaś",
+ "notification-edit-talk-page2": "[[User:$1|$1]] jo powěsć na twójom [[User talk:$2#$3|diskusijnem boku]] {{GENDER:$1|zawóstajił|zawóstajiła}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] jo powěsć na twójom diskusijnem boku w \"[[User talk:$2#$3|$4]]\" {{GENDER:$1|zawóstajił|zawóstajiła}}.",
+ "notification-edit-talk-page-flyout2": "$1 jo powěsć na twójom [[User talk:$2#$3|diskusijnem boku]] {{GENDER:$1|zawóstajił|zawóstajiła}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1 jo powěsć na twójom diskusijnem boku w \"[[User talk:$2#$3|$4]]\" {{GENDER:$1|zawóstajił|zawóstajiła}}.",
+ "notification-page-linked": "[[:$2]] jo se wót [[:$3]] {{GENDER:$1|wótkazał|wótkazała}}. [[Special:WhatLinksHere/$2|Wšykne wótkaze k toś tomu bokoju pokazaś]].",
+ "notification-page-linked-flyout": "[[:$2]] jo se wót [[:$3]] {{GENDER:$1|wótkazał|wótkazała}}.",
+ "notification-add-comment2": "[[User:$1|$1]] jo na \"[[$3|$2]]\" na diskusijnem boku \"$4\" {{GENDER:$1|komentěrował|komentěrowała}}.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] jo nowu temu \"$2\" na [[$3]] {{GENDER:$1|startował|startowała}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] jo śi powěsć {{GENDER:$1|pósłał|pósłała}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] jo na \"[[$3#$2|$2]]\" na twójom diskusijnem boku {{GENDER:$1|komentěrował|komentěrowała}}.",
+ "notification-mention": "[[User:$1|$1]] jo śi na diskusijnem boku $5 w \"[[:$3#$2|$4]]\" {{GENDER:$1|naspomnjeł|naspomnjeła}}.",
+ "notification-mention-flyout": "$1 jo śi na diskusijnem boku $5 w \"[[:$3#$2|$4]]\" {{GENDER:$1|naspomnjeł|naspomnjeła}}.",
+ "notification-mention-nosection": "[[User:$1|$1]] jo śi na [[:$3|diskusijnem boku $2]] {{GENDER:$1|naspomnjeł|naspomnjeła}}.",
+ "notification-mention-nosection-flyout": "$1 jo śi na [[:$3|diskusijnem boku $2]] {{GENDER:$1|naspomnjeł|naspomnjeła}}.",
+ "notification-user-rights": "Twóje wužywarske pšawa [[Special:Log/rights/$1|su se wót [[User:$1|$1]] {{GENDER:$1|změnili}}]] . $2. [[Special:ListGroupRights|Dalšne informacije]]",
+ "notification-user-rights-flyout": "Twóje wužywarske pšawa su se wót $1 {{GENDER:$1|změnili}}. $2. [[Special:ListGroupRights|Dalšne informacije]]",
+ "notification-user-rights-add": "Sy něnto cłonk {{PLURAL:$2|toś teje kupki|toś teju kupkowu|toś tych kupkow}}: $1",
+ "notification-user-rights-remove": "Njejsy wěcej cłonk {{PLURAL:$2|toś teje kupki|toś teju kupkowu|toś tych kupkow}}: $1",
+ "notification-new-user": "Witaj do {{GRAMMAR:genitiw|{{SITENAME}}}}, $1! Wjaselimy se, až sy how.",
+ "notification-reverted2": "[[User:$1|$1]] jo {{PLURAL:$4|změnu na [[:$2]]|změnje na [[:$2]]|změny na [[:$2]]}} {{GENDER:$1|anulěrował|anulěrowała}}. $3",
+ "notification-reverted-flyout2": "$1 jo {{PLURAL:$4|změnu na $2|změnje na $2|změny na $2}} {{GENDER:$1|anulěrował|anulěrowała}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 jo śi powěsć na {{GRAMMAR:lokatiw|{{SITENAME}}}} {{GENDER:$1|zawóstajił|zawóstajiła}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 jo powěsć na twójom diskusijnem boku {{GENDER:$1|zawóstajił|zawóstajiła}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 jo powěsć wó \"$2\" na twójom diskusijnem boku {{GENDER:$1|zawóstajił|zawóstajiła}}.",
+ "notification-page-linked-email-subject": "Twój bok jo se na {{GRAMMAR:lokatiw|{{SITENAME}}}} wótkazał.",
+ "notification-page-linked-email-batch-body": "$2 jo se z $3 {{GENDER:$1|wótkazał}}.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Twója změna jo|Twójej změnje stej|Twóje změny su}} se na {{GRAMMAR:lokatiw|{{SITENAME}}}}{{GENDER:$1|{{PLURAL:$3|anulěrowała|anulěrowałej|anulěrowali}}}}",
+ "notification-reverted-email-batch-body2": "$1 jo {{PLURAL:$3|twóju změnu na $2|twójej změnje na $2|twóje změny na $2}} {{GENDER:$1|anulěrował|anulěrowała}}.",
+ "notification-mention-email-subject": "$1 jo śi na {{GRAMMAR:lokatiw|{{SITENAME}}}} {{GENDER:$1|naspomnjeł|naspomnjeła}}",
+ "notification-mention-email-batch-body": "$1 jo śi na diskusijnem boku $4 w \"$3\" {{GENDER:$1|naspomnjeł|naspomnjeła}}.",
+ "notification-mention-nosection-email-batch-body": "$1 jo śi na diskusijnem boku $2 {{GENDER:$1|naspomnjeł|naspomnjeła}}.",
+ "notification-user-rights-email-subject": "Twóje wužywarske pšawa su se na {{GRAMMAR:lokatiw|{{SITENAME}}}} změnili",
+ "notification-user-rights-email-batch-body": "Twóje wužywarske pšawa su se wót $1 {{GENDER:$1|změnili}}. $2",
+ "echo-email-subject-default": "Nowa powěźeńka na {{GRAMMAR:lokatiw|{{SITENAME}}}}",
+ "echo-email-body-default": "Maš nowu powěźeńku na {{GRAMMAR:lokatiw|{{SITENAME}}}}:\n\n$1",
+ "echo-email-batch-body-default": "Maš nowu powěźeńku.",
+ "echo-email-footer-default": "$2\n\nAby kontrěrolował, kótare e-maile śi sćelomy, pśeglědaj swóje nastajenja:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Aby kontrolěrował, kótare e-maile śi sćelomy, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">pśeglědaj swóje nastajenja</a>.<br />\n$1",
+ "echo-overlay-link": "Wšykne powěźeńki",
+ "echo-overlay-title": "<b>Powěźeńki</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Poěźeńka|Powěźeńce|Powěźeńki}}</b> ($1 z $2 {{PLURAL:$2|njepśecytaneje|njepśecytaneju|njepśecytanych}} se {{PLURAL:$1|pokazujo|pokazujotej|pokazuju|pokazujo}})",
+ "echo-mark-all-as-read": "Wšykne ako pśecytane markěrowaś",
+ "echo-date-today": "Źinsa",
+ "echo-date-yesterday": "Cora",
+ "echo-load-more-error": "Pśi wobstarowanju dalšnych wuslědkow jo zmólka nastała.",
+ "notification-edit-talk-page-bundle": "$1 a {{PLURAL:$4|dalšny wužywaŕ jo|$3 dalšnej wužywarja stej|$3 dalšne wužywarje su|$3 dalšnych wužywarjow jo}} powěsć na twójom [[User talk:$2|diskusijnem boku]] {{PLURAL:$4|zawóstajił|zawóstajiłej|zawóstajili|zawóstajiło}}.",
+ "notification-page-linked-bundle": "$2 jo se z $3 a {{PLURAL:$5|jadnogo dalšnego boka|$4 dalšneju bokowu|$4 dalšnych bokow}} {{GENDER:$1|wotkazał}}. [[Special:WhatLinksHere/$2|Wšykne wótkaze k toś tomu bokoju pokazaś]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 a {{PLURAL:$3|dalšny wužywaŕ stej|$2 dalšnej wužywarja su|$2 dalšne wužywarje su|$2 dalšnych wužywarjow su}} powěsć na twójom diskusijnem boku {{GENDER:$1|zawóstajiłej|zawóstajili}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2 jo se wót $3 a {{PLURAL:$5|jadnogo dalšnego boka|$4 dalšneju bokowu|$4 dalšnych bokow}} {{GENDER:$1|wótkazał}}.",
+ "echo-email-batch-subject-daily": "Maš {{PLURAL:$2|nowu powěźeńku|nowej powěźeńce|nowe powěźeńki}} na {{GRAMMAR:lokatiw|{{SITENAME}}}}",
+ "echo-email-batch-subject-weekly": "Maš {{PLURAL:$2|nowu powěźeńku|nowej powěźeńce|nowe powěźeńki}} na {{GRAMMAR:lokatiw|{{SITENAME}}}} toś ten tyźeń",
+ "echo-email-batch-body-intro-daily": "Witaj $1,\n\nhow jo zespominanje źinsajšnych aktiwitow na {{GRAMMAR:lokatiw|{{SITENAME}}}} za tebje.",
+ "echo-email-batch-body-intro-weekly": "Witja $1,\n\nhow jo zespominanje aktiwitow z toś togo tyźenja na {{GRAMMAR:lokatiw|{{SITENAME}}}} za tebje.",
+ "echo-email-batch-link-text-view-all-notifications": "Wšykne powěźeńki pokazaś",
+ "echo-rev-deleted-text-view": "Toś ta bokowa wersija jo se pódtłocyła."
+}
diff --git a/Echo/i18n/el.json b/Echo/i18n/el.json
new file mode 100644
index 00000000..cb445d5d
--- /dev/null
+++ b/Echo/i18n/el.json
@@ -0,0 +1,106 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aitolos",
+ "Dipa1965",
+ "Geraki",
+ "Glavkos",
+ "Protnet",
+ "Xaris333",
+ "ZaDiak",
+ "Auslaender"
+ ]
+ },
+ "echo-desc": "Σύστημα ειδοποιήσεων",
+ "prefs-echo": "Ειδοποιήσεις",
+ "prefs-emailsettings": "Επιλογές ηλεκτρονικού ταχυδρομείου",
+ "prefs-displaynotifications": "Επιλογές εμφάνισης",
+ "prefs-echosubscriptions": "Να ειδοποιούμαι σχετικά με αυτά τα γεγονότα",
+ "prefs-newmessageindicator": "Δείκτης νέων μηνυμάτων",
+ "echo-pref-send-me": "Στείλτε μου:",
+ "echo-pref-send-to": "Αποστολή σε:",
+ "echo-pref-email-format": "Μορφή ηλεκτρονικού ταχυδρομείου:",
+ "echo-pref-web": "Ιστοσελίδα",
+ "echo-pref-email": "Ηλεκτρονικό ταχυδρομείο",
+ "echo-pref-email-frequency-never": "Μην μου στέλνετε ειδοποιήσεις μέσω ηλεκτρονικού ταχυδρομείου",
+ "echo-pref-email-frequency-immediately": "Μεμονωμένες κοινοποιήσεις, καθώς έρχονται",
+ "echo-pref-email-frequency-daily": "Ημερήσια σύνοψη ειδοποιήσεων",
+ "echo-pref-email-frequency-weekly": "Εβδομαδιαία σύνοψη ειδοποιήσεων",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Απλό κείμενο",
+ "echo-pref-notify-show-link": "Εμφάνιση ειδοποιήσεων στη γραμμή εργαλείων μου",
+ "echo-pref-new-message-indicator": "Να εμφανίζεται, στη γραμμή εργαλείων, ο δείκτης μηνυμάτων της σελίδας συζήτησης",
+ "echo-learn-more": "Μάθετε περισσότερα",
+ "echo-new-messages": "Έχετε νέα μηνύματα",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Μήνυμα|Μηνύματα}} στη σελίδα συζήτησης",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Σύνδεσμος|Σύνδεσμοι}} σελίδας",
+ "echo-category-title-reverted": "{{PLURAL:$1|Επαναφορά|Επαναφορές}} επεξεργασίας",
+ "echo-category-title-mention": "{{PLURAL:$1|Αναφορά|Αναφορές}}",
+ "echo-category-title-other": "{{PLURAL:$1|Άλλα}}",
+ "echo-category-title-system": "{{PLURAL:$1|Σύστημα}}",
+ "echo-pref-tooltip-edit-user-talk": "Να ειδοποιούμαι όταν κάποιος δημοσιεύσει ένα μήνυμα ή απαντήσεις στη σελίδα συζήτησής μου.",
+ "echo-pref-tooltip-article-linked": "Να ειδοποιούμαι όταν κάποιος συνδέει σε σελίδα που δημιούργησα από μια σελίδα λήμματος.",
+ "echo-pref-tooltip-reverted": "Να ειδοποιούμαι όταν κάποιος αναστρέφει μια επεξεργασία που έκανα, χρησιμοποιώντας το εργαλείο αναίρεσης ή επαναφοράς.",
+ "echo-pref-tooltip-mention": "Να ειδοποιούμαι όταν κάποιος προσθέτει σύνδεσμο προς τη σελίδα χρήστη μου, σε οποιαδήποτε σελίδα συζήτησης.",
+ "echo-no-agent": "[Κανένας]",
+ "echo-no-title": "[Καμία σελίδα]",
+ "echo-error-no-formatter": "Δεν έχει οριστεί μορφοποίηση για την ειδοποίηση",
+ "echo-error-preference": "Σφάλμα: Δεν ήταν δυνατό να οριστεί προτίμηση χρήστη",
+ "echo-error-token": "Σφάλμα: δεν ήταν δυνατή η ανάκτηση διακριτικού χρήστη",
+ "notifications": "Ειδοποιήσεις",
+ "tooltip-pt-notifications": "Οι ειδοποιήσεις σας",
+ "echo-specialpage": "Ειδοποιήσεις",
+ "echo-anon": "Για να λαμβάνετε ειδοποιήσεις, [$1 δημιουργήστε ένα λογαριασμό] ή [$2 συνδεθείτε].",
+ "echo-none": "Δεν έχετε ειδοποιήσεις.",
+ "echo-more-info": "Περισσότερες πληροφορίες",
+ "echo-feedback": "Ανατροφοδότηση",
+ "notification-link-text-view-message": "Προβολή μηνύματος",
+ "notification-link-text-view-mention": "Προβολή αναφοράς",
+ "notification-link-text-view-changes": "Προβολή αλλαγών",
+ "notification-link-text-view-page": "Προβολή σελίδας",
+ "notification-link-text-view-edit": "Προβολή επεξεργασίας",
+ "notification-edit-talk-page2": "{{GENDER:$1|Ο|Η}} [[User:$1|$1]] άφησε μήνυμα στη [[User talk:$2#$3|σελίδα συζήτησής]] σας.",
+ "notification-edit-talk-page-with-section": "{{GENDER:$1|Ο|Η}} [[User:$1|$1]] άφησε μήνυμα στην ενότητα \"[[User talk:$2#$3|$4]] της σελίδας συζήτησης σας.",
+ "notification-edit-talk-page-flyout2": "{{GENDER:$1|Ο|Η}} $1 άφησε μήνυμα στη [[User talk:$2#$3|σελίδα συζήτησής]] σας.",
+ "notification-edit-talk-page-flyout-with-section": "{{GENDER:$1|Ο|Η}} $1 άφησε μήνυμα στη σελίδα συζήτησής στη [[User talk:$2#$3|$4]].",
+ "notification-page-linked": "Η σελίδα [[:$2]] {{GENDER:$1|συνδέθηκε}} από τη σελίδα [[:$3]]. [[Special:WhatLinksHere/$2|Δείτε όλους τους συνδέσμους προς αυτή τη σελίδα]].",
+ "notification-page-linked-flyout": "Η σελίδα [[:$2]] {{GENDER:$1|συνδέθηκε}} από τη σελίδα [[:$3]].",
+ "notification-add-comment2": "{{GENDER:$1|Ο|Η}} [[User:$1|$1]] σχολίασε στο \"[[$3|$2]]\" στην συζήτηση \"$4\".",
+ "notification-mention": "{{GENDER:$1|Ο|Η}} [[User:$1|$1]] {{GENDER:$1|σας ανάφερε}} στην ενότητα \"[[:$3#$2|$4]]\" της σελίδας $5.",
+ "notification-mention-flyout": "{{GENDER:$1|Ο|Η}} [[User:$1|$1]] {{GENDER:$1|σας ανάφερε}} στην ενότητα \"[[:$3#$2|$4]]\" της σελίδας $5.",
+ "notification-new-user": "Καλώς ήρθατε στο {{SITENAME}}, $1! Χαιρόμαστε που είστε εδώ.",
+ "notification-reverted2": "{{PLURAL:$4|Η επεξεργασία σας στην [[:$2]] έχει|Οι επεξεργασίες σας στην [[:$2]] έχουν}} αναστραφεί από {{GENDER:$1|τον|την}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Η επεξεργασία σας στην $2 έχει|Οι επεξεργασίες σας στην $2 έχουν}} αναστραφεί από {{GENDER:$1|τον|την}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|Ο|Η}} $1 σας άφησε ένα μήνυμα στη {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|Ο|Η}} $1 άφησε ένα μήνυμα στην σελίδα συζήτησής σας:",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|Ο|Η}} $1 άφησε ένα μήνυμα στην σελίδα συζήτησής σας στην \"$2\"",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Η επεξεργασία σας στην $2 έχει|Οι επεξεργασίες σας στην $2 έχουν}} αναστραφεί από {{GENDER:$1|τον|την}} $1.",
+ "notification-mention-email-subject": "{{GENDER:$1|Ο|Η}} $1 σας ανέφερε στη {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|σας ανάφερε}} στην ενότητα \"$3\" της σελίδας $4.",
+ "notification-mention-nosection-email-batch-body": "{{GENDER:$1|Ο|Η}} $1 σας ανάφερε στην σελίδα συζήτησης $2.",
+ "notification-user-rights-email-subject": "Τα δικαιώματα χρήστη σας έχουν αλλάξει στη {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Τα δικαιώματα χρήστη σας έχουν αλλάξει από {{GENDER:$1|τον|την}} $1. $2.",
+ "echo-email-subject-default": "Νέα ειδοποίηση στο {{SITENAME}}",
+ "echo-email-body-default": "Έχετε μια νέα ειδοποίηση στη {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Έχετε μια νέα ειδοποίηση.",
+ "echo-email-footer-default": "$2\n\nΓια να ελέγξετε ποια μηνύματα σας στέλνουμε, πηγαίνετε στις προτιμήσεις σας:\n\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Για να ελέγξετε ποια μηνύματα σας στέλνουμε, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">πηγαίνετε στις προτιμήσεις σας</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Ειδοποιήσεις ($1)|Ειδοποιήσεις ($1)|100=Ειδοποιήσεις (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Μήνυμα ($1)|Μηνύματα ($1)|100=Μηνύματα (99+)}}",
+ "echo-overlay-link": "Όλες οι ειδοποιήσεις",
+ "echo-overlay-title": "<b>Ειδοποιήσεις</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Ειδοποιήσεις}}</b> (εμφανίζονται $1 από $2 μη αναγνωσμένες)",
+ "echo-mark-all-as-read": "Σήμανση όλων ως αναγνωσμένες",
+ "echo-date-today": "Σήμερα",
+ "echo-date-yesterday": "Χθες",
+ "echo-load-more-error": "Παρουσιάστηκε σφάλμα κατά την ανάκτηση περισσότερων αποτελέσματων.",
+ "notification-edit-talk-page-bundle": "{{GENDER:$1|Ο|Η}} $1 και $3 {{PLURAL:$4|άλλος|άλλοι}} άφησαν μηνύματα στην [[User talk:$2|σελίδα συζήτησής σας]].",
+ "notification-page-linked-bundle": "Η $2 {{GENDER:$1|συνδέθηκε}} από τη σελίδα $3 και $4 {{PLURAL:$5|άλλη σελίδα|άλλες σελίδες}}. [[Special:WhatLinksHere/$2|Δείτε όλους τους συνδέσμους]] προς αυτή τη σελίδα",
+ "notification-edit-user-talk-email-batch-bundle-body": "Ο χρήστης $1 και $2 {{PLURAL:$3|άλλος χρήστης|άλλοι χρήστες}} {{GENDER:$1|άφησαν}} ένα μήνυμα στη σελίδα συζήτησης σας.",
+ "echo-email-batch-subject-daily": "Έχετε {{PLURAL:$2|μια νέα ειδοποίηση|νέες ειδοποιήσεις}} στη {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Έχετε {{PLURAL:$2|μια νέα ειδοποίηση|νέες ειδοποιήσεις}} στη {{SITENAME}} αυτή την εβδομάδα",
+ "echo-email-batch-body-intro-daily": "Γεια $1,\nΕδώ είναι μια περίληψη της σημερινής δραστηριότητας στη {{SITENAME}} για εσάς.",
+ "echo-email-batch-body-intro-weekly": "Γεια $1,\nΕδώ είναι μια περίληψη της δραστηριότητας αυτής της εβδομάδας στη {{SITENAME}} για εσάς.",
+ "echo-email-batch-link-text-view-all-notifications": "Δείτε όλες τις ειδοποιήσεις",
+ "echo-rev-deleted-text-view": "Αυτή η αναθεώρηση σελίδας έχει καταργηθεί."
+}
diff --git a/Echo/i18n/en-gb.json b/Echo/i18n/en-gb.json
new file mode 100644
index 00000000..3dc7de74
--- /dev/null
+++ b/Echo/i18n/en-gb.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shirayuki"
+ ]
+ }
+}
diff --git a/Echo/i18n/en.json b/Echo/i18n/en.json
new file mode 100644
index 00000000..9d0b73a2
--- /dev/null
+++ b/Echo/i18n/en.json
@@ -0,0 +1,139 @@
+{
+ "@metadata": {
+ "authors": [
+ "Andrew Garrett"
+ ]
+ },
+ "echo-desc": "Notifications system",
+ "prefs-echo": "Notifications",
+ "prefs-emailsettings": "Email options",
+ "prefs-displaynotifications": "Display options",
+ "prefs-echosubscriptions": "Notify me about these events",
+ "prefs-newmessageindicator": "New message indicator",
+ "echo-pref-send-me": "Send me:",
+ "echo-pref-send-to": "Send to:",
+ "echo-pref-email-format": "Email format:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Email",
+ "echo-pref-email-frequency-never": "Do not send me any email notifications",
+ "echo-pref-email-frequency-immediately": "Individual notifications as they come in",
+ "echo-pref-email-frequency-daily": "A daily summary of notifications",
+ "echo-pref-email-frequency-weekly": "A weekly summary of notifications",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Plain text",
+ "echo-pref-notify-show-link": "Show notifications in my toolbar",
+ "echo-pref-new-message-indicator": "Show talk page message indicator in my toolbar",
+ "echo-learn-more": "Learn more",
+ "echo-new-messages": "You have new messages",
+ "echo-category-title-edit-user-talk": "Talk page {{PLURAL:$1|message|messages}}",
+ "echo-category-title-article-linked": "Page {{PLURAL:$1|link|links}}",
+ "echo-category-title-reverted": "Edit {{PLURAL:$1|revert|reverts}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Mention|Mentions}}",
+ "echo-category-title-other": "{{PLURAL:$1|Other}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|User rights change|User rights changes}}",
+ "echo-pref-tooltip-edit-user-talk": "Notify me when someone posts a message or replies on my talk page.",
+ "echo-pref-tooltip-article-linked": "Notify me when someone links to a page I created from an article page.",
+ "echo-pref-tooltip-reverted": "Notify me when someone reverts an edit I made, by using the undo or rollback tool.",
+ "echo-pref-tooltip-mention": "Notify me when someone links to my user page.",
+ "echo-pref-tooltip-user-rights": "Notify me when someone changes my user rights.",
+ "echo-no-agent": "[Nobody]",
+ "echo-no-title": "[No page]",
+ "echo-error-no-formatter": "No formatting defined for notification.",
+ "echo-error-preference": "Error: Could not set user preference.",
+ "echo-error-token": "Error: Could not retrieve user token.",
+ "notifications": "Notifications",
+ "tooltip-pt-notifications": "Your notifications",
+ "echo-specialpage": "Notifications",
+ "echo-anon": "To receive notifications, [$1 create an account] or [$2 log in].",
+ "echo-none": "You have no notifications.",
+ "echo-more-info": "More info",
+ "echo-feedback": "Feedback",
+ "echo-quotation-marks": "\"$1\"",
+ "notification-link-text-view-message": "View message",
+ "notification-link-text-view-mention": "View mention",
+ "notification-link-text-view-changes": "View changes",
+ "notification-link-text-view-page": "View page",
+ "notification-link-text-view-edit": "View edit",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|left}} a message on your [[User talk:$2#$3|talk page]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|left}} a message on your talk page in \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|left}} a message on your [[User talk:$2#$3|talk page]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|left}} a message on your talk page in \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] was {{GENDER:$1|linked}} from [[:$3]]. [[Special:WhatLinksHere/$2|See all links to this page]].",
+ "notification-page-linked-flyout": "[[:$2]] was {{GENDER:$1|linked}} from [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|commented}} on \"[[$3|$2]]\" on the \"$4\" talk page.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|posted}} a new topic \"$2\" on [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|sent}} you a message: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|commented}} on \"[[$3#$2|$2]]\" on your talk page.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|mentioned}} you on the $5 talk page in \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|mentioned}} you on the $5 talk page in \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|mentioned}} you on the [[:$3|$2 talk page]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|mentioned}} you on the [[:$3|$2 talk page]].",
+ "notification-user-rights": "Your user rights [[Special:Log/rights/$1|were {{GENDER:$1|changed}}]] by [[User:$1|$1]]. $2. [[Special:ListGroupRights|Learn more]]",
+ "notification-user-rights-flyout": "Your user rights were {{GENDER:$1|changed}} by $1. $2. [[Special:ListGroupRights|Learn more]]",
+ "notification-user-rights-add": "You are now a member of {{PLURAL:$2|this group|these groups}}: $1",
+ "notification-user-rights-remove": "You are no longer a member of {{PLURAL:$2|this group|these groups}}: $1",
+ "notification-new-user": "Welcome to {{SITENAME}}, $1! We're glad you're here.",
+ "notification-reverted2": "Your {{PLURAL:$4|edit on [[:$2]] has|edits on [[:$2]] have}} been {{GENDER:$1|reverted}} by [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Your {{PLURAL:$4|edit on $2 has|edits on $2 have}} been {{GENDER:$1|reverted}} by $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|left}} you a message on {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|left}} a message on your talk page:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|left}} a message on your talk page in \"$2\".",
+ "notification-page-linked-email-subject": "Your page was linked on {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 was {{GENDER:$1|linked}} from $3.",
+ "notification-reverted-email-subject2": "Your {{PLURAL:$3|edit was|edits were}} {{GENDER:$1|reverted}} on {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "Your {{PLURAL:$3|edit on $2 has been|edits on $2 have been}} {{GENDER:$1|reverted}} by $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|mentioned}} you on {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|mentioned}} you on the $4 talk page in \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|mentioned}} you on the $2 talk page.",
+ "notification-user-rights-email-subject": "Your user rights have changed on {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Your user rights were {{GENDER:$1|changed}} by $1. $2.",
+ "echo-notification-count": "$1+",
+ "echo-email-subject-default": "New notification at {{SITENAME}}",
+ "echo-email-body-default": "You have a new notification at {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "You have a new notification.",
+ "echo-email-footer-default": "$2\n\nTo control which emails we send you, check your preferences:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "To control which emails we send you, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">check your preferences</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Alert ($1)|Alerts ($1)|100=Alerts (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Message ($1)|Messages ($1)|100=Messages (99+)}}",
+ "echo-notification-alert-text-only": "Alerts",
+ "echo-notification-message-text-only": "Messages",
+ "echo-overlay-link": "All notifications",
+ "echo-overlay-title": "<b>Notifications</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notification|Notifications}}</b> (showing $1 of $2 unread)",
+ "echo-mark-all-as-read": "Mark all as read",
+ "echo-date-today": "Today",
+ "echo-date-yesterday": "Yesterday",
+ "echo-load-more-error": "An error occurred while fetching more results.",
+ "notification-edit-talk-page-bundle": "$1 and $3 {{PLURAL:$4|other|others}} {{GENDER:$1|left}} a message on your [[User talk:$2|talk page]].",
+ "notification-page-linked-bundle": "$2 was {{GENDER:$1|linked}} from $3 and $4 other {{PLURAL:$5|page|pages}}. [[Special:WhatLinksHere/$2|See all links to this page]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 and $2 {{PLURAL:$3|other|others}} {{GENDER:$1|left}} a message on your talk page.",
+ "notification-page-linked-email-batch-bundle-body": "$2 was {{GENDER:$1|linked}} from $3 and $4 other {{PLURAL:$5|page|pages}}.",
+ "echo-email-batch-separator": "--",
+ "echo-email-batch-bullet": "•",
+ "echo-email-batch-subject-daily": "You have {{PLURAL:$2|a new notification|new notifications}} at {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "You have {{PLURAL:$2|a new notification|new notifications}} at {{SITENAME}} this week",
+ "echo-email-batch-body-intro-daily": "Hi $1,\nHere's a summary of today's activity on {{SITENAME}} for you.",
+ "echo-email-batch-body-intro-weekly": "Hi $1,\nHere's a summary of this week's activity on {{SITENAME}} for you.",
+ "echo-email-batch-link-text-view-all-notifications": "View all notifications",
+ "echo-rev-deleted-text-view": "This page revision has been suppressed.",
+ "apihelp-echomarkread-description": "Mark notifications as read for the current user.",
+ "apihelp-echomarkread-param-list": "A list of notification IDs to mark as read.",
+ "apihelp-echomarkread-param-all": "If set, marks all of a user's notifications as read.",
+ "apihelp-echomarkread-param-sections": "A list of sections to mark as read.",
+ "apihelp-echomarkread-example-1": "Mark notification 8 as read",
+ "apihelp-echomarkread-example-2": "Mark all notifications as read",
+ "apihelp-query+notifications-description": "Get notifications waiting for the current user.",
+ "apihelp-query+notifications-param-prop": "Details to request.",
+ "apihelp-query+notifications-param-sections": "The notification sections to query.",
+ "apihelp-query+notifications-param-groupbysection": "Whether to group the result by section. Each section is fetched separately if set.",
+ "apihelp-query+notifications-param-format": "If specified, notifications will be returned formatted this way.",
+ "apihelp-query+notifications-param-limit": "The maximum number of notifications to return.",
+ "apihelp-query+notifications-param-index": "If specified, a list of notification IDs, in order, will be returned.",
+ "apihelp-query+notifications-param-alertcontinue": "When more alert results are available, use this to continue.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Whether to show unread message notifications first.",
+ "apihelp-query+notifications-param-messagecontinue": "When more message results are available, use this to continue.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Whether to show unread alert notifications first.",
+ "apihelp-query+notifications-example-1": "List notifications",
+ "apihelp-query+notifications-example-2": "List notifications, grouped by section, with counts"
+}
diff --git a/Echo/i18n/eo.json b/Echo/i18n/eo.json
new file mode 100644
index 00000000..a0470947
--- /dev/null
+++ b/Echo/i18n/eo.json
@@ -0,0 +1,121 @@
+{
+ "@metadata": {
+ "authors": [
+ "KuboF",
+ "Tlustulimu",
+ "Yekrats"
+ ]
+ },
+ "echo-desc": "Sciiga sistemo",
+ "prefs-echo": "Sciigoj",
+ "prefs-emailsettings": "Retpoŝtaj opcioj",
+ "prefs-displaynotifications": "Montraj opcioj",
+ "prefs-echosubscriptions": "Sciigu min pri tiuj ĉi okazaĵoj",
+ "prefs-newmessageindicator": "Indikilo pri novaj mesaĝoj",
+ "echo-pref-send-me": "Sendadi al mi:",
+ "echo-pref-send-to": "Sendadi al:",
+ "echo-pref-email-format": "Formo de retpoŝto:",
+ "echo-pref-web": "Reteje",
+ "echo-pref-email": "Retpoŝte",
+ "echo-pref-email-frequency-never": "Ne sendadi al mi retpoŝtajn sciigojn",
+ "echo-pref-email-frequency-immediately": "Unuopajn sciigojn tuj kiam ili alvenos",
+ "echo-pref-email-frequency-daily": "Tagan resumon de sciigoj",
+ "echo-pref-email-frequency-weekly": "Semajnan resumon de sciigoj",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Ordinara teksto",
+ "echo-pref-notify-show-link": "Montri sciigojn en mia ilobreto",
+ "echo-pref-new-message-indicator": "Montri indikilon pri diskutaj mesaĝoj en mia ilobreto",
+ "echo-learn-more": "Lerni plu",
+ "echo-new-messages": "Vi havas novajn mesaĝojn",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mesaĝo|Mesaĝoj}} en diskutpaĝo",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Ligilo|Ligiloj}} al paĝo",
+ "echo-category-title-reverted": "{{PLURAL:$1|Malfaro|Malfaroj}} de redakto",
+ "echo-category-title-mention": "{{PLURAL:$1|Mencio|Mencioj}}",
+ "echo-category-title-other": "{{PLURAL:$1|Aliaj}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistemo}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Ŝanĝo de uzanto-rajto|Ŝanĝoj de uzanto-rajtoj}}",
+ "echo-pref-tooltip-edit-user-talk": "Sciigu min kiam iu komencas diskuton aŭ respondas en mia diskutpaĝo.",
+ "echo-pref-tooltip-article-linked": "Sciigu min kiam iu ligas al paĝo kiun mi kreis de artikolo.",
+ "echo-pref-tooltip-reverted": "Sciigu min kiam iu malfaras mian redakton per ilo por malfari aŭ amasmalfari.",
+ "echo-pref-tooltip-mention": "Sciigu min kiam iu ligas al mia uzantopaĝo.",
+ "echo-pref-tooltip-user-rights": "Sciigu min, se iu ŝanĝas miajn rajtojn de uzanto.",
+ "echo-no-agent": "[Neniu]",
+ "echo-no-title": "[Sen Paĝo]",
+ "echo-error-no-formatter": "Neniu aranĝo difinita por sciigo.",
+ "echo-error-preference": "Eraro: Konserviĝo de uzanto-preferoj ne sukcesis.",
+ "echo-error-token": "Eraro: Simbolo de uzanto ne povis esti elvokata.",
+ "notifications": "Sciigoj",
+ "tooltip-pt-notifications": "Viaj sciigoj",
+ "echo-specialpage": "Sciigoj",
+ "echo-anon": "Po ricevadi sciigojn oni bezonas [$1 krei konton] aŭ [$2 ensaluti].",
+ "echo-none": "Vi ne havas sciigojn.",
+ "echo-more-info": "Pliaj informoj",
+ "echo-feedback": "Rimarkoj",
+ "notification-link-text-view-message": "Montri mesaĝon",
+ "notification-link-text-view-mention": "Montri mencion",
+ "notification-link-text-view-changes": "Montri ŝanĝojn",
+ "notification-link-text-view-page": "Montri paĝon",
+ "notification-link-text-view-edit": "Montri redakton",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|lasis}} mesaĝon en via [[User talk:$2#$3|diskutpaĝo]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|lasis}} mesaĝon sur via diskutopaĝo en „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|lasis}} mesaĝon sur via [[User talk:$2#$3|diskutopaĝo]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|lasis}} mesaĝon sur via diskutopaĝo en \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] estis {{GENDER:$1|ligata}} de [[:$3]]. [[Special:WhatLinksHere/$2|Ligiloj ĉi tien]].",
+ "notification-page-linked-flyout": "[[:$2]] estis {{GENDER:$1|ligita}} de [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|komentis}} sur \"[[$3|$2]]\" sur la diskutopaĝo de \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|afiŝis}} novan temon \"$2\" sur [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|sendis}} al vi mesaĝon: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|komentis}} sur \"[[$3#$2|$2]]\" sur via diskutopaĝo.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|menciis}} vin sur la diskutopaĝo de $5 en \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|menciis}} vin sur la diskutopaĝo de $5 en \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|menciis}} vin sur la [[:$3|diskutopaĝo „$2“]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|menciis}} vin sur la [[:$3|diskutopaĝo „$2“]].",
+ "notification-user-rights": "Viaj uzantorajtoj [[Special:Log/rights/$1|estis {{GENDER:$1|ŝanĝitaj}}]] de [[User:$1|$1]]. $2. [[Special:ListGroupRights|Pliaj informoj]]",
+ "notification-user-rights-flyout": "Viaj uzantorajtoj estis {{GENDER:$1|ŝanĝitaj}} de $1. $2. [[Special:ListGroupRights|Pliaj informoj]]",
+ "notification-user-rights-add": "Vi estas nun membro de {{PLURAL:$2|ĉi tiu grupo|ĉi tiuj grupoj}}: $1",
+ "notification-user-rights-remove": "Vi ne plu estas membro de {{PLURAL:$2|ĉi tiu grupo|ĉi tiuj grupoj}}: $1",
+ "notification-new-user": "Bonvenon al {{SITENAME}}, $1! Ni ĝojas, ke vi estas ĉi tie.",
+ "notification-reverted2": "{{PLURAL:$4|Via redakto sur [[:$2]] estis {{GENDER:$1|malfarita}}|Viaj redaktoj sur [[:$2]] estis {{GENDER:$1|malfaritaj}}}} de [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Via redakto sur $2 estis {{GENDER:$1|malfarita}}|Viaj redaktoj sur $2 estis {{GENDER:$1|malfaritaj}}}} de $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|lasis}} al vi mesaĝon sur {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|lasis}} mesaĝon sur via diskutopaĝo:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|lasis}} mesaĝon sur via diskutopaĝo pri \"$2\".",
+ "notification-page-linked-email-subject": "Via paĝo estas ligita en {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 estis {{GENDER:$1|ligita}} de $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Via redakto estis {{GENDER:$1|malfarita}}|Viaj redaktoj estis {{GENDER:$1|malfaritaj}}}} sur {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Via redakto sur $2 estis {{GENDER:$1|malfarita}}|Viaj redaktoj sur $2 estis {{GENDER:$1|malfaritaj}}}} de $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|menciis}} vin sur {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|menciis}} vin sur la diskutopaĝo de $4 en \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|menciis}} vin sur la diskutopaĝo „$2“.",
+ "notification-user-rights-email-subject": "Viaj uzantorajtoj estis ŝanĝitaj sur {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Viaj uzantorajtoj estis {{GENDER:$1|ŝanĝitaj}} de $1. $2.",
+ "echo-email-subject-default": "Nova sciigo en {{SITENAME}}",
+ "echo-email-body-default": "Vi havas novan noton ĉe {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Vi havas novajn sciigojn.",
+ "echo-email-footer-default": "$2\n\nPor kontroli kiujn retpoŝtaĵojn ni sendas al vi, kontrolu viajn preferojn:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Por kontroli kiujn retpoŝtaĵojn ni sendas al vi, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">kontrolu viajn preferojn</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Atentigo ($1)|Atentigoj ($1)|100=Atentigoj (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mesaĝo ($1)|Mesaĝoj ($1)|100=Mesaĝoj (99+)}}",
+ "echo-notification-alert-text-only": "Sciigoj",
+ "echo-notification-message-text-only": "Mesaĝoj",
+ "echo-overlay-link": "Ĉiuj sciigoj",
+ "echo-overlay-title": "<b>Sciigoj</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Sciigo|Sciigoj}}</b> (montrante $1 de $2 {{PLURAL:$2|nelegita|nelegitaj}})",
+ "echo-mark-all-as-read": "Marki ĉiujn kiel legitaj",
+ "echo-date-today": "Hodiaŭ",
+ "echo-date-yesterday": "Hieraŭ",
+ "echo-load-more-error": "Okazis eraro dum venigo de pliaj rezultoj.",
+ "notification-edit-talk-page-bundle": "$1 kaj {{PLURAL:$4|alia uzanto|$3 aliaj uzantoj}} {{GENDER:$1|lasis}} mesaĝon sur via [[User talk:$2|diskutopaĝo]].",
+ "notification-page-linked-bundle": "$2 estis {{GENDER:$1|ligita}} de $3 kaj $4 {{PLURAL:$5|plia paĝo|pliaj paĝoj}}. [[Special:WhatLinksHere/$2|Ligiloj ĉi tien]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 kaj {{PLURAL:$3|alia uzanto|$2 aliaj uzantoj}} {{GENDER:$1|lasis}} mesaĝon sur via diskutopaĝo.",
+ "notification-page-linked-email-batch-bundle-body": "$2 estis {{GENDER:$1|ligita}} de $3 kaj $4 {{PLURAL:$5|plia paĝo|pliaj paĝoj}}.",
+ "echo-email-batch-subject-daily": "Vi havas {{PLURAL:$2|novan sciigon|novajn sciigojn}} sur {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Vi ĉisemajne havas {{PLURAL:$2|novan sciigon|novajn sciigojn}} sur {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Saluton $1,\nĈi tie estas resumo de hodiaŭaj aktivaĵoj sur {{SITENAME}} por vi.",
+ "echo-email-batch-body-intro-weekly": "Saluton $1,\nĈi tie estas resumo de la aktivaĵoj de ĉi tiu semajno sur {{SITENAME}} por vi.",
+ "echo-email-batch-link-text-view-all-notifications": "Montri ĉiujn sciigojn",
+ "echo-rev-deleted-text-view": "Ĉi tiu revizio de la paĝo estis subpremita.",
+ "apihelp-echomarkread-description": "Marki sciigojn legitaj por tiu ĉi uzanto.",
+ "apihelp-echomarkread-example-2": "Marki ĉiujn sciigojn legitaj",
+ "apihelp-query+notifications-description": "Ricevi sciigojn atentantajn por tiu ĉi uzanto."
+}
diff --git a/Echo/i18n/es.json b/Echo/i18n/es.json
new file mode 100644
index 00000000..3fec7c0b
--- /dev/null
+++ b/Echo/i18n/es.json
@@ -0,0 +1,151 @@
+{
+ "@metadata": {
+ "authors": [
+ "-jem-",
+ "Armando-Martin",
+ "DJ Nietzsche",
+ "Fitoschido",
+ "Hahc21",
+ "Invadinado",
+ "Jduranboger",
+ "Larjona",
+ "Miguel2706",
+ "PoLuX124",
+ "Ralgis",
+ "The Anonymouse",
+ "TheBITLINK",
+ "Vivaelcelta",
+ "Themasterriot",
+ "Macofe",
+ "Amitie 10g"
+ ]
+ },
+ "echo-desc": "Sistema de notificaciones",
+ "prefs-echo": "Notificaciones",
+ "prefs-emailsettings": "Opciones de correo electrónico",
+ "prefs-displaynotifications": "Opciones de visualización",
+ "prefs-echosubscriptions": "Notificarme sobre estos eventos",
+ "prefs-newmessageindicator": "Indicador de mensajes nuevos",
+ "echo-pref-send-me": "Enviarme:",
+ "echo-pref-send-to": "Enviar a:",
+ "echo-pref-email-format": "Formato del mensaje:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Correo electrónico",
+ "echo-pref-email-frequency-never": "No enviarme notificaciones por correo electrónico",
+ "echo-pref-email-frequency-immediately": "Enviarme las notificaciones individuales en cuanto lleguen",
+ "echo-pref-email-frequency-daily": "Resumen diario de notificaciones",
+ "echo-pref-email-frequency-weekly": "Resumen semanal de las notificaciones",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Texto sin formato",
+ "echo-pref-notify-show-link": "Mostrar las notificaciones en mi barra de herramientas",
+ "echo-pref-new-message-indicator": "Mostrar un indicador de mensajes nuevos en la barra de herramientas",
+ "echo-learn-more": "Más información",
+ "echo-new-messages": "Tienes mensajes nuevos",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mensaje|Mensajes}} en la página de discusión",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Enlace|Enlaces}} de página",
+ "echo-category-title-reverted": "{{PLURAL:$1|Reversión de edición|Reversiones de ediciones}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Mención|Menciones}}",
+ "echo-category-title-other": "{{PLURAL:$1|Otros}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Cambio de permisos de usuario|Cambios de permisos de usuarios}}",
+ "echo-pref-tooltip-edit-user-talk": "Notificarme cuando alguien publique un mensaje o responda en mi página de discusión.",
+ "echo-pref-tooltip-article-linked": "Notificarme cuando alguien enlace en un artículo a una página creada por mí.",
+ "echo-pref-tooltip-reverted": "Notificarme cuando alguien revierta una edición mía mediante las herramientas de deshacer o revertir.",
+ "echo-pref-tooltip-mention": "Notificarme cuando alguien enlace mi página de usuario.",
+ "echo-pref-tooltip-user-rights": "Notificarme cuando alguien cambie mis derechos de usuario.",
+ "echo-no-agent": "[Nadie]",
+ "echo-no-title": "[No hay ninguna página]",
+ "echo-error-no-formatter": "No se definió ningún formato para las notificaciones.",
+ "echo-error-preference": "Error: no se pudo establecer la preferencia del usuario.",
+ "echo-error-token": "Error: no se pudo recuperar la ficha de usuario.",
+ "notifications": "Notificaciones",
+ "tooltip-pt-notifications": "Tus notificaciones",
+ "echo-specialpage": "Notificaciones",
+ "echo-anon": "[$1 Crea una cuenta] o [$2 accede] para recibir notificaciones.",
+ "echo-none": "No tienes notificaciones.",
+ "echo-more-info": "Más información",
+ "echo-feedback": "Comentarios",
+ "notification-link-text-view-message": "Ver mensaje",
+ "notification-link-text-view-mention": "Ver la mención",
+ "notification-link-text-view-changes": "Ver cambios",
+ "notification-link-text-view-page": "Ver página",
+ "notification-link-text-view-edit": "Ver edición",
+ "notification-edit-talk-page2": "[[User:$1|$1]] te ha dejado un mensaje en tu [[User talk:$2#$3|página de discusión]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] te ha dejado un mensaje en tu página de discusión: «[[User talk:$2#$3|$4]]».",
+ "notification-edit-talk-page-flyout2": "$1 te ha dejado un mensaje en tu [[User talk:$2#$3|página de discusión]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 te ha dejado un mensaje en tu página de discusión: «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "[[:$2]] fue {{GENDER:$1|enlazado}} a [[:$3]]. [[Special:WhatLinksHere/$2|Ver todos los enlaces a esta página]].",
+ "notification-page-linked-flyout": "[[:$2]] fue {{GENDER:$1|enlazado}} desde [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|comentó}} en la sección \"[[$3|$2]]\" de la página de discusión de \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] inició un nuevo hilo, \"$2\", en [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|te envió}} un mensaje: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|comentó}} \"[[$3#$2|$2]]\" en tu página de discusión.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|te mencionó}} en la página de discusión de $5 en \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|te mencionó}} en la página de discusión de $5 en \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] te ha mencionado en la [[:$3|página de discusión de $2]].",
+ "notification-mention-nosection-flyout": "$1 te ha {{GENDER:$1|mencionado}} en la [[:$3|$2 página de discusión]].",
+ "notification-user-rights": "Tus permisos de usuario [[Special:Log/rights/$1|han sido {{GENDER:$1|modificados}}]] por [[User:$1|$1]]. $2. [[Special:ListGroupRights|Ver más]]",
+ "notification-user-rights-flyout": "Tus permisos de usuario {{GENDER:$1|han sido modificados}} por $1. $2. [[Special:ListGroupRights|Ver más]]",
+ "notification-user-rights-add": "Ahora eres miembro {{PLURAL:$2|del siguiente grupo|de los siguientes grupos grupos}}: $1",
+ "notification-user-rights-remove": "Has dejado de pertenecer {{PLURAL:$2|al siguiente grupo|a los siguientes grupos}}: $1",
+ "notification-new-user": "¡Bienvenido a {{SITENAME}}, $1! Nos alegra que estés aquí.",
+ "notification-reverted2": "{{PLURAL:$4|Tu|Tus}} {{PLURAL:$4|edición en [[:$2]] ha|ediciones en [[:$2]] han}} sido {{PLURAL:$4|revertida|revertidas}} por {{GENDER:$1|el|la|el}} usuari{{GENDER:$1|o|a|o}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Tu|Tus}} {{PLURAL:$4|edición en $2 ha|ediciones en $2 han}} sido {{PLURAL:$4|revertida|revertidas}} por {{GENDER:$1|el|la|el}} usuari{{GENDER:$1|o|a|o}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 te ha dejado un mensaje en {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 te ha dejado un mensaje en tu página de discusión:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 te ha dejado un mensaje en tu página de discusión: «$2»",
+ "notification-page-linked-email-subject": "Se ha añadido un enlace a una página creada por ti en {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 ha sido {{GENDER:$1|enlazada}} desde $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Tu|Tus}} {{PLURAL:$3|edición fue|ediciones fueron}} {{GENDER:$1|{{PLURAL:$3|revertida|revertidas}}}} en {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Tu|Tus}} {{PLURAL:$3|edición en $2 ha sido|ediciones en $2 han sido}} {{GENDER:$1|{{PLURAL:$3|revertida|revertidas}}}} por $1.",
+ "notification-mention-email-subject": "$1 te ha {{GENDER:$1|mencionado}} en {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 te ha {{GENDER:$1|mencionado}} en la página de discusión de $4, en \"$3\"",
+ "notification-mention-nosection-email-batch-body": "$1 te ha mencionado en la página de discusión de $2.",
+ "notification-user-rights-email-subject": "Tus permisos de usuario en {{SITENAME}} han sido modificados.",
+ "notification-user-rights-email-batch-body": "Tus permisos de usuario fueron {{GENDER:$1|modificados}} por $1. $2.",
+ "echo-email-subject-default": "Nueva notificación en {{SITENAME}}",
+ "echo-email-body-default": "Tienes una nueva notificación en {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Tienes una nueva notificación",
+ "echo-email-footer-default": "$2\n\nPara controlar los emails que te enviamos, visita:\n{{canonicalurl:{{#Especial:Preferencias}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Para controlar los emails que te enviamos, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">verifica tus preferencias</a>.<br />\n\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Alerta ($1)|Alertas ($1)|100=Alertas (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mensaje ($1)|Mensajes ($1)|100=Mensajes (99+)}}",
+ "echo-notification-alert-text-only": "Alertas",
+ "echo-notification-message-text-only": "Mensajes",
+ "echo-overlay-link": "Todas las notificaciones",
+ "echo-overlay-title": "<b>Notificaciones</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notificaciones}}</b> (se muestran $1 de $2 sin leer)",
+ "echo-mark-all-as-read": "Marcar todo como leído",
+ "echo-date-today": "Hoy",
+ "echo-date-yesterday": "Ayer",
+ "echo-load-more-error": "Se ha producido un error al intentar obtener más resultados.",
+ "notification-edit-talk-page-bundle": "$1 y $3 {{PLURAL:$4|usuario|usuarios}} más han escrito en tu [[User talk:$2|página de discusión]].",
+ "notification-page-linked-bundle": "$2 fue {{GENDER:$1|enlazado|enlazada|enlazado}} desde $3 y $4 {{PLURAL:$5|página|páginas}} más. [[Special:WhatLinksHere/$2|Verifica todos los enlaces a ésta página]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 y $2 {{PLURAL:$3|usuario|usuarios}} más han escrito en tu página de discusión.",
+ "notification-page-linked-email-batch-bundle-body": "$2 fue {{GENDER:$1|enlazada}} desde $3 y $4 {{PLURAL:$5|página|páginas}} más.",
+ "echo-email-batch-subject-daily": "Tienes {{PLURAL:$2|una nueva notificación|nuevas notificaciones}} en {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Tienes {{PLURAL:$2|una nueva notificación|nuevas notificaciones}} esta semana",
+ "echo-email-batch-body-intro-daily": "Hola, $1:\nAquí está un resumen de la actividad de hoy en {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Hola, $1:\nAquí está un resumen de la actividad de esta semana en {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Ver todas las notificaciones",
+ "echo-rev-deleted-text-view": "Esta revisión de página ha sido suprimida.",
+ "apihelp-echomarkread-description": "Marcar notificaciones como leídas para el usuario actual.",
+ "apihelp-echomarkread-param-list": "Lista de IDs de notificación para marcar como leído.",
+ "apihelp-echomarkread-param-all": "Si se establece, marca todas las notificaciones de un usuario como leídas.",
+ "apihelp-echomarkread-param-sections": "Lista de secciones a marcar como leídas.",
+ "apihelp-echomarkread-example-1": "Marca la notificación 8 como leída.",
+ "apihelp-echomarkread-example-2": "Marca todas las notificaciones como leídas.",
+ "apihelp-query+notifications-description": "Recibe notificaciones de espera para el usuario actual.",
+ "apihelp-query+notifications-param-prop": "Detalles que solicitar.",
+ "apihelp-query+notifications-param-sections": "Las secciones de notificación a consultar.",
+ "apihelp-query+notifications-param-groupbysection": "Si se agrupan los resultados por sección. Cada sección se obtiene por separado si así se establece.",
+ "apihelp-query+notifications-param-format": "Si se especifica, las notificaciones se recibirán en éste formatdo.",
+ "apihelp-query+notifications-param-limit": "Número máximo de notificaciones a recibir.",
+ "apihelp-query+notifications-param-index": "Si se especifica, se recibirá una lista de IDs de notificación.",
+ "apihelp-query+notifications-param-alertcontinue": "Cuando están disponibles alertas adicionales, utilice esta opción para continuar.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Muestra las notificaciones de mensajes sin leer primero.",
+ "apihelp-query+notifications-param-messagecontinue": "Cuando nuevos mensajes están disponibles, utilice esta opción para continuar.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Muestra las notificaciones de alertas sin leer primero.",
+ "apihelp-query+notifications-example-1": "Lista de notificaciones",
+ "apihelp-query+notifications-example-2": "Lista de notificaciones, agrupadas por sección, incluyendo contadores."
+}
diff --git a/Echo/i18n/et.json b/Echo/i18n/et.json
new file mode 100644
index 00000000..ecf12763
--- /dev/null
+++ b/Echo/i18n/et.json
@@ -0,0 +1,118 @@
+{
+ "@metadata": {
+ "authors": [
+ "Avjoska",
+ "Kyng",
+ "Pikne"
+ ]
+ },
+ "echo-desc": "Teavitussüsteem",
+ "prefs-echo": "Teavitused",
+ "prefs-emailsettings": "E-posti suvandid",
+ "prefs-displaynotifications": "Kuvaseaded",
+ "prefs-echosubscriptions": "Teavita mind neist sündmustest",
+ "prefs-newmessageindicator": "Uue sõnumi indikaator",
+ "echo-pref-send-me": "Saada mulle:",
+ "echo-pref-send-to": "Saada aadressile:",
+ "echo-pref-email-format": "E-posti vorming:",
+ "echo-pref-web": "Veeb",
+ "echo-pref-email": "E-post",
+ "echo-pref-email-frequency-never": "Ära saada mulle ühtegi e-posti teavitust",
+ "echo-pref-email-frequency-immediately": "Üksikud teavitused nende ilmumisel",
+ "echo-pref-email-frequency-daily": "Teavituste päevakokkuvõte",
+ "echo-pref-email-frequency-weekly": "Teavituste nädalakokkuvõte",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Lihttekst",
+ "echo-pref-notify-show-link": "Näita teavitusi minu tööriistaribal",
+ "echo-pref-new-message-indicator": "Näita arutelulehekülje postituste indikaatorit minu tööriistaribal",
+ "echo-learn-more": "Lisateave",
+ "echo-new-messages": "Sulle on uusi sõnumeid",
+ "echo-category-title-edit-user-talk": "Arutelulehekülje {{PLURAL:$1|sõnum|sõnumid}}",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Leheküljelink|Leheküljelingid}}",
+ "echo-category-title-reverted": "Tühistatud {{PLURAL:$1|muudatus|muudatused}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Mainimine|Mainimised}}",
+ "echo-category-title-other": "{{PLURAL:$1|Muu}}",
+ "echo-category-title-system": "{{PLURAL:$1|Süsteem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Kasutajaõiguste muutmine|Kasutajaõiguste muutmised}}",
+ "echo-pref-tooltip-edit-user-talk": "Teavita mind, kui keegi postitab või vastab minu aruteluleheküljel.",
+ "echo-pref-tooltip-article-linked": "Teavita mind, kui keegi lingib mõnest artiklist minu alustatud leheküljele.",
+ "echo-pref-tooltip-reverted": "Teavita mind, kui keegi tühistab minu muudatuse, kasutades eemaldus- või tühistusfunktsiooni.",
+ "echo-pref-tooltip-mention": "Teavita mind, kui keegi lingib minu kasutajaleheküljele.",
+ "echo-pref-tooltip-user-rights": "Teavita mind, kui keegi muudab minu kasutajaõigusi.",
+ "echo-no-agent": "[Eikeegi]",
+ "echo-no-title": "[Lehekülge pole]",
+ "echo-error-no-formatter": "Teavituse vormindusviis on määramata.",
+ "echo-error-preference": "Viga: Ei saanud kasutaja eelistusi salvestada",
+ "echo-error-token": "Tõrge: Ei õnnestunud leida kasutajaluba.",
+ "notifications": "Teavitused",
+ "tooltip-pt-notifications": "Sinu teavitused",
+ "echo-specialpage": "Teavitused",
+ "echo-anon": "Et teavitusi saada, [$1 loo konto] või [$2 logi sisse].",
+ "echo-none": "Sul pole uusi teavitusi.",
+ "echo-more-info": "Lisateave",
+ "echo-feedback": "Tagasiside",
+ "notification-link-text-view-message": "Vaata sõnumit",
+ "notification-link-text-view-mention": "Vaata mainimist",
+ "notification-link-text-view-changes": "Vaata muudatusi",
+ "notification-link-text-view-page": "Vaata lehekülge",
+ "notification-link-text-view-edit": "Vaata muudatust",
+ "notification-edit-talk-page2": "[[User:$1|$1]] jättis sõnumi sinu [[User talk:$2#$3|aruteluleheküljele]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] jättis sõnumi sinu arutelulehekülje alaosasse \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 jättis sõnumi sinu [[User talk:$2#$3|aruteluleheküljele]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 jättis sõnumi sinu arutelulehekülje alaosasse \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Leheküljele [[:$2]] {{GENDER:$1|lingiti}} asukohast [[:$3]]. [[Special:WhatLinksHere/$2|Vaata kõiki linke sellele leheküljele]].",
+ "notification-page-linked-flyout": "Leheküljele [[:$2]] {{GENDER:$1|lingiti}} asukohast [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] lisas kommentaari lehekülje \"$4\" arutelu alaosasse \"[[$3|$2]]\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|postitas}} uue teema \"$2\" arutellu [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|saatis}} sulle sõnumi: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] lisas kommentaari sinu arutelulehekülje alaosasse \"[[$3#$2|$2]]\".",
+ "notification-mention": "[[User:$1|$1]] mainis sind lehekülje \"$5\" arutelu alaosas \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 mainis sind lehekülje \"$5\" arutelu alaosas \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] mainis sind lehekülje \"$2\" [[:$3|arutelus]].",
+ "notification-mention-nosection-flyout": "$1 mainis sind lehekülje \"$2\" [[:$3|arutelus]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|muutis]] sinu kasutajaõigusi. $2. [[Special:ListGroupRights|Lisateave]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|muutis}} sinu kasutajaõigusi. $2. [[Special:ListGroupRights|Lisateave]]",
+ "notification-user-rights-add": "Kuulud nüüd {{PLURAL:$2|sellesse rühma|nendesse rühmadesse}}: $1",
+ "notification-user-rights-remove": "Sa ei kuulu enam {{PLURAL:$2|sellesse rühma|nendesse rühmadesse}}: $1",
+ "notification-new-user": "Tere tulemast saidile {{SITENAME}}, $1! Meil on hea meel, et siin oled.",
+ "notification-reverted2": "[[User:$1|$1]] tühistas sinu {{PLURAL:$4|muudatuse|muudatused}} leheküljel [[:$2]]. $3",
+ "notification-reverted-flyout2": "$1 tühistas sinu {{PLURAL:$4|muudatuse|muudatused}} leheküljel $2. $3",
+ "notification-edit-talk-page-email-subject2": "$1 jättis sulle {{GRAMMAR:inessive|{{SITENAME}}}} sõnumi",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|jättis}} sinu arutelulehele sõnumi:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|jättis}} sinu arutelulehele sõnumi \"$2\":",
+ "notification-page-linked-email-subject": "{{GRAMMAR:inessive|{{SITENAME}}}} lingiti sinu leheküljele",
+ "notification-page-linked-email-batch-body": "Leheküljele $2 {{GENDER:$1|lingiti}} asukohast $3.",
+ "notification-reverted-email-subject2": "Sinu {{PLURAL:$3|muudatus|muudatused}} {{GRAMMAR:inessive|{{SITENAME}}}} {{GENDER:$1|tühistati}}",
+ "notification-reverted-email-batch-body2": "$1 tühistas võrgukohas {{SITENAME}} leheküljel $2 sinu {{PLURAL:$3|muudatuse|muudatused}}",
+ "notification-mention-email-subject": "$1 mainis {{GRAMMAR:inessive|{{SITENAME}}}} sind",
+ "notification-mention-email-batch-body": "$1 mainis sind lehekülje \"$4\" arutelu alaosas \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 mainis sind lehekülje \"$2\" arutelus.",
+ "notification-user-rights-email-subject": "{{GRAMMAR:inessive|{{SITENAME}}}} muudeti sinu kasutajaõigusi",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|muutis}} sinu kasutajaõigusi. $2.",
+ "echo-email-subject-default": "Uus teavitus {{GRAMMAR:inessive|{{SITENAME}}}}",
+ "echo-email-body-default": "Võrgukohas {{SITENAME}} on sulle uus teavitus:\n\n$1",
+ "echo-email-batch-body-default": "Sulle on uus teavitus.",
+ "echo-email-footer-default": "$2\n\nEt valida, milliseid e-kirju sulle saadetakse, sea oma eelistusi:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Et valida, milliseid e-kirju sulle saadetakse, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">sea oma eelistusi</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Üks lugemata teavitus|$1 lugemata teavitust|0=Lugemata teavitusi pole.|100=Üle 99 lugemata teavituse}}",
+ "echo-notification-message": "{{PLURAL:$1|Üks sõnum|$1 sõnumit|0=Sõnumeid pole.|100=Üle 99 sõnumi}}",
+ "echo-notification-alert-text-only": "Teavitused",
+ "echo-notification-message-text-only": "Sõnumid",
+ "echo-overlay-link": "Kõik teavitused",
+ "echo-overlay-title": "<b>Teavitused</b>",
+ "echo-overlay-title-overflow": "<b>Teavitused</b> (näidatakse {{PLURAL:$1|üht|$1}} $2-st lugemata teavitusest)",
+ "echo-mark-all-as-read": "Märgi kõik loetuks",
+ "echo-date-today": "Täna",
+ "echo-date-yesterday": "Eile",
+ "echo-load-more-error": "Rohkemate tulemuste laadimisel ilmnes tõrge.",
+ "notification-edit-talk-page-bundle": "$1 ja veel {{PLURAL:$4|üks kasutaja|$3 kasutajat}} jätsid sõnumi sinu [[User talk:$2|aruteluleheküljele]].",
+ "notification-page-linked-bundle": "Leheküljele $2 {{GENDER:$1|lingiti}} asukohast $3 ja veel {{PLURAL:$5|ühelt|$4}} leheküljelt. [[Special:WhatLinksHere/$2|Vaata kõiki linke sellele leheküljele]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 ja veel {{PLURAL:$3|üks kasutaja|$2 kasutajat}} jätsid sõnumi sinu aruteluleheküljele.",
+ "notification-page-linked-email-batch-bundle-body": "Leheküljele $2 {{GENDER:$1|lingiti}} asukohast $3 ja veel {{PLURAL:$5|ühelt|$4}} leheküljelt.",
+ "echo-email-batch-subject-daily": "Sulle on {{GRAMMAR:inessive|{{SITENAME}}}} {{PLURAL:$2|uus teavitus|uusi teavitusi}}",
+ "echo-email-batch-subject-weekly": "Sulle on sellel nädalal {{GRAMMAR:inessive|{{SITENAME}}}} {{PLURAL:$2|uus teavitus|uusi teavitusi}}",
+ "echo-email-batch-body-intro-daily": "Tere, $1.\nSiin on sulle kokkuvõte võrgukohas {{SITENAME}} täna toimunust.",
+ "echo-email-batch-body-intro-weekly": "Tere, $1.\nSiin on sulle kokkuvõte võrgukohas {{SITENAME}} sellel nädalal toimunust.",
+ "echo-email-batch-link-text-view-all-notifications": "Vaata kõiki teavitusi",
+ "echo-rev-deleted-text-view": "Lehekülje see redaktsioon on varjatud."
+}
diff --git a/Echo/i18n/eu.json b/Echo/i18n/eu.json
new file mode 100644
index 00000000..ebefdec5
--- /dev/null
+++ b/Echo/i18n/eu.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Subi",
+ "Xabier Armendaritz"
+ ]
+ },
+ "prefs-echo": "Jakinarazpenak",
+ "echo-learn-more": "Gehiago ikasi",
+ "echo-new-messages": "Mezu berriak dituzu",
+ "echo-no-agent": "[Inor ez]",
+ "echo-no-title": "[Ez dago orririk]",
+ "notifications": "Jakinarazpenak",
+ "tooltip-pt-notifications": "Zure jakinarazpenak",
+ "echo-specialpage": "Jakinarazpenak",
+ "echo-none": "Ez duzu jakinarazpenik.",
+ "echo-more-info": "Informazio gehiago",
+ "notification-link-text-view-message": "Ikusi mezua",
+ "notification-link-text-view-mention": "Ikusi aipamena",
+ "echo-email-batch-body-default": "Jakinarazpen berri bat daukazu.",
+ "echo-notification-message": "{{PLURAL:$1|Mezua ($1)|Mezuak ($1)|100=Mezuak (+99)}}",
+ "echo-notification-alert-text-only": "Alertak",
+ "echo-notification-message-text-only": "Mezuak",
+ "echo-overlay-link": "Jakinarazpen guztiak",
+ "echo-overlay-title": "<b>Jakinarazpenak</b>",
+ "echo-date-today": "Gaur",
+ "echo-date-yesterday": "Atzo",
+ "echo-email-batch-link-text-view-all-notifications": "Jakinarazpen guztiak ikusi",
+ "apihelp-query+notifications-example-1": "Zerrendatu jakinarazpenak",
+ "apihelp-query+notifications-example-2": "Zerrendatu jakinarazpenak, atalka antolaturik, kontagailuekin"
+}
diff --git a/Echo/i18n/fa.json b/Echo/i18n/fa.json
new file mode 100644
index 00000000..d13beead
--- /dev/null
+++ b/Echo/i18n/fa.json
@@ -0,0 +1,132 @@
+{
+ "@metadata": {
+ "authors": [
+ "A.R.Rostamzade",
+ "Dalba",
+ "Ebraminio",
+ "Ladsgroup",
+ "Mjbmr",
+ "Omidh",
+ "Reza1615",
+ "Rtemis",
+ "درفش کاویانی",
+ "فلورانس",
+ "Alirezaaa",
+ "Bersam",
+ "Saeidpourbabak"
+ ]
+ },
+ "echo-desc": "سامانهٔ آگاه‌سازی‌ها",
+ "prefs-echo": "آگاه‌سازی‌ها",
+ "prefs-emailsettings": "تنظیمات ایمیل",
+ "prefs-displaynotifications": "گزینه‌های نمایش",
+ "prefs-echosubscriptions": "مرا از این رویدادها آگاه کن",
+ "prefs-newmessageindicator": "نشانگر پیام تازه",
+ "echo-pref-send-me": "برایم فرستاده شود:",
+ "echo-pref-send-to": "فرستاده‌شود به:",
+ "echo-pref-email-format": "قالب ایمیل:",
+ "echo-pref-web": "وب‌گاه",
+ "echo-pref-email": "ایمیل",
+ "echo-pref-email-frequency-never": "ایمیل اعلان برایم فرستاده نشود",
+ "echo-pref-email-frequency-immediately": "آگاه‌سازی‌های جداگانه به محض دریافت",
+ "echo-pref-email-frequency-daily": "خلاصهٔ روزانهٔ آگاه‌سازی‌‌ها",
+ "echo-pref-email-frequency-weekly": "خلاصهٔ هفتگی از آگاه‌سازی‌ها",
+ "echo-pref-email-format-html": "اچ‌تی‌ام‌ال",
+ "echo-pref-email-format-plain-text": "متن ساده",
+ "echo-pref-notify-show-link": "نمایش آگاه‌سازی‌ها در نوار ابزار من",
+ "echo-pref-new-message-indicator": "نمایش نشانگر پیام صفحهٔ بحث در نوار ابزار من",
+ "echo-learn-more": "اطلاعات بیشتر",
+ "echo-new-messages": "پیام‌های جدیدی دارید",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|پیام|پیام‌های}} صفحهٔ بحث",
+ "echo-category-title-article-linked": "{{PLURAL:$1|پیوند|پیوندهای}} صفحه",
+ "echo-category-title-reverted": "{{PLURAL:$1|واگردانی|واگردانی‌های}} ویرایش",
+ "echo-category-title-mention": "{{PLURAL:$1|اشاره}}",
+ "echo-category-title-other": "{{PLURAL:$1|دیگر}}",
+ "echo-category-title-system": "{{PLURAL:$1|سامانه}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|تغییر دسترسی کاربر|تغییرات دسترسی کاربر}}",
+ "echo-pref-tooltip-edit-user-talk": "هنگامی که کسی برای من پیام فرستاد یا جواب پیام مرا در صفحهٔ بحثم داد، مرا آگاه کن.",
+ "echo-pref-tooltip-article-linked": "هنگامی که کسی به مقالهٔ ایجادشده توسط من پیوند داد، مرا آگاه کن.",
+ "echo-pref-tooltip-reverted": "هنگامی که کسی ویرایشی را که من انجام داده‌ام را با استفاده از ابزار خثنی‌سازی یا واگردانی، خثنی کرد، مرا آگاه کن.",
+ "echo-pref-tooltip-mention": "هنگامی که شخصی به صفحهٔ کاربری من در هر صفحه‌ای پیوند ایجاد کرد، مرا آگاه کن.",
+ "echo-pref-tooltip-user-rights": "وقتی کسی دسترسی‌های کاربری من را تغییر داد مرا مطلع کن.",
+ "echo-no-agent": "[هیچ کس]",
+ "echo-no-title": "[بدون عنوان]",
+ "echo-error-no-formatter": "هیچ قالب تعریف‌شده‌ای برای آگاه‌سازی وجود ندارد",
+ "echo-error-preference": "خطا: ترجیحات کاربر تنظیم نشده‌است.",
+ "echo-error-token": "خطا: رمز کاربر قابل بازیابی نیست.",
+ "notifications": "آگاه‌سازی‌ها",
+ "tooltip-pt-notifications": "آگاه‌سازی‌های شما",
+ "echo-specialpage": "آگاه‌سازی‌ها",
+ "echo-anon": "برای دریافت آگاه‌سازی‌ها [$1 حسابی بسازید] یا [$2 وارد سامانه شوید] .",
+ "echo-none": "شما هیچگونه آگاه‌سازی‌ای ندارید.",
+ "echo-more-info": "اطلاعات بیشتر",
+ "echo-feedback": "بازخورد",
+ "echo-quotation-marks": "«$1»",
+ "notification-link-text-view-message": "نمایش پیام",
+ "notification-link-text-view-mention": "مشاهدهٔ تذکر",
+ "notification-link-text-view-changes": "نمایش تغییرات",
+ "notification-link-text-view-page": "مشاهدهٔ صفحه",
+ "notification-link-text-view-edit": "نمایش ویرایش",
+ "notification-edit-talk-page2": "[[User:$1|$1]] در صفحه‌‌ٔ بحث شما [[User talk:$2#$3|پیامی]] گذاشته‌است.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] برای شما در صفحهٔ بحث‌تان در «[[User talk:$2#$3|$4]]» پیامی {{GENDER:$1|گذاشت}}.",
+ "notification-edit-talk-page-flyout2": "$1 در صفحه‌‌ٔ‌‌‌ بحث شما [[User talk:$2#$3|مطلبی]] گذاشته‌است.",
+ "notification-edit-talk-page-flyout-with-section": "$1 یک پیام در بحث شما در «[[User talk:$2#$3|$4]]» {{GENDER:$1|گذاشته‌است}}.",
+ "notification-page-linked": "[[:$2]] از [[:$3]] {{GENDER:$1|پیوند گرفته‌است}}. [[Special:WhatLinksHere/$2|همهٔ پیوندها به این صفحه را ببینید]].",
+ "notification-page-linked-flyout": "[[:$2]] از [[:$3]] {{GENDER:$1|پیوند گرفته‌است}}.",
+ "notification-add-comment2": "[[User:$1|$1]] در «[[$3|$2]]» در صفحه بحث «$4» نظری افزود.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] بخش جدیدی «$2» در [[$3]] ایجاد کرد.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] به شما پیامی فرستاد: «[[$3#$2|$2]]»",
+ "notification-add-comment-yours2": "[[User:$1|$1]] در «[[$3#$2|$2]]» در صفحه بحث شما نظری داده‌است",
+ "notification-mention": "[[User:$1|$1]] به شما در بحث $5 در «[[:$3#$2|$4]]» {{GENDER:$1|اشاره‌کرد}}.",
+ "notification-mention-flyout": "$1 در بحث $5 در «[[:$3#$2|$4]]» به شما {{GENDER:$1|اشاره}} کرده‌است.",
+ "notification-mention-nosection": "[[User:$1|$1]] در [[:$3|صفحهٔ بحث $2]] به شما {{GENDER:$1|اشاره}} کرده‌ است.",
+ "notification-mention-nosection-flyout": "$1 در [[:$3|صفحهٔ بحث $2]] به شما {{GENDER:$1|اشاره}} کرده است.",
+ "notification-user-rights": "دسترسی‌های شما توسط [[User:$1|$1]] [[Special:Log/rights/$1|تغییر یافته است]] . $2. [[Special:ListGroupRights|بیشتر بخوانید]]",
+ "notification-user-rights-flyout": "دسترسی‌های شما توسط $1 تغییر یافت. $2. [[Special:ListGroupRights|اطلاعات بیشتر]]",
+ "notification-user-rights-add": "شما در حال حاضر عضو {{PLURAL:$2| این گروه|این گروه‌ها}} هستید:$1",
+ "notification-user-rights-remove": "شما دیگر عضو {{PLURAL:$2|این گروه|این گروه‌ها}} نیستید: $1",
+ "notification-new-user": "به {{SITENAME}} خوش‌آمدید، $1! خوشحالیم که شما اینجا هستید.",
+ "notification-reverted2": "ویرایش(های) شما در [[:$2]] توسط [[User:$1|$1]] {{PLURAL:$4|خنثی‌سازی|واگردانی}} شده است. $3",
+ "notification-reverted-flyout2": "ویرایش(های) شما بر روی $2 توسط $1 {{PLURAL:$4|خنثی‌سازی|واگردانی}} شده است. $3",
+ "notification-edit-talk-page-email-subject2": "شما یک پیام تازه از طرف $1 در صفحهٔ بحث {{SITENAME}} دارید.",
+ "notification-edit-talk-page-email-batch-body2": "$1 پیامی بر روی صفحهٔ بحثتان {{GENDER:$1|گذاشته‌است}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 یک پیام در بحث شما در «$2» {{GENDER:$1|گذاشته‌است}}.",
+ "notification-page-linked-email-subject": "صفحه‌ای که شما آغازگر آن بودید در {{SITENAME}} پیوند شد.",
+ "notification-page-linked-email-batch-body": "$2 از $3 {{GENDER:$1|پیوند داده شده‌است}}.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|ویرایش|ویرایش‌های}} شما در {{SITENAME}} {{GENDER:$1|واگردانی شده‌است}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|ویرایش|ویرایش‌های}} شما در $2 توسط $1 {{GENDER:$1|واگردانی شده‌است}}.",
+ "notification-mention-email-subject": "$1 شما را در {{SITENAME}} {{GENDER:$1|ذکر کرده‌است}}",
+ "notification-mention-email-batch-body": "$1 در $4 صفحهٔ بحث «$3» به شما {{GENDER:$1|اشاره کرد}}",
+ "notification-mention-nosection-email-batch-body": "$1 در صفحهٔ بحث $2 به‌ شما {{GENDER:$1|اشاره}} کرده است.",
+ "notification-user-rights-email-subject": "دسترسی‌های شما در {{SITENAME}} تغییر یافته‌است",
+ "notification-user-rights-email-batch-body": "دسترسی‌های شما توسط $1 تغییر یافته‌است. $2",
+ "echo-email-subject-default": "آگاه‌سازی‌های تازه در {{SITENAME}}",
+ "echo-email-body-default": "شما در {{SITENAME}} آگاه‌سازی تازه‌ای دارید:\n\n$1",
+ "echo-email-batch-body-default": "شما آگاه‌سازی تازه‌ای دارید.",
+ "echo-email-footer-default": "$2\n\nبرای کنترل ایمیل‌های ارسالی به شما، ترجیحات‌تان را بررسی کنید:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "برای کنترل اینکه چه ایمیلی به شما بفرستیم، <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">ترجیحاتتان را بررسی کنید</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|هشدارها ($1)|هشدارها ($1)|100=هشدارها (۹۹+)}}",
+ "echo-notification-message": "{{PLURAL:$1|پیام‌ها ($1)|پیام‌ها ($1)|100=پیام‌ها (۹۹+)}}",
+ "echo-notification-alert-text-only": "هشدار",
+ "echo-notification-message-text-only": "پیام‌ها",
+ "echo-overlay-link": "همهٔ آگاه‌سازی‌ها",
+ "echo-overlay-title": "<b>آگاه‌سازی‌ها</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|آگاه‌سازی‌ها}}</b> (نمایش $1 از $2 خوانده‌نشده)",
+ "echo-mark-all-as-read": "نشان‌گذاری همه به عنوان خوانده‌شده",
+ "echo-date-today": "امروز",
+ "echo-date-yesterday": "دیروز",
+ "echo-load-more-error": "دریافت نتیجه‌های بیشتر با خطا مواجه شده‌است.",
+ "notification-edit-talk-page-bundle": "$1 و $3 {{PLURAL:$4|کاربر دیگر}} در صفحهٔ [[User talk:$2|بحث شما]] پیامی گذاشته‌اند.",
+ "notification-page-linked-bundle": "$2 بدست $1 از $3 و $4 {{PLURAL:$5|صفحهٔ دیگر}} پیوند داده شده‌است. [[Special:WhatLinksHere/$2|دیدن همهٔ پیوندها به این صفحه]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 و $2 {{PLURAL:$3|شخص دیگر}} پیامی در صفحهٔ بحث شما گذاشته‌اند.",
+ "notification-page-linked-email-batch-bundle-body": "$2 از $3 و $4 {{PLURAL:$5|صفحهٔ دیگر}} {{GENDER:$1|پیوند داده شده‌است}}.",
+ "echo-email-batch-subject-daily": "شما دارای {{PLURAL:$2|یک آگاه‌سازی تازه|آگاه‌سازی‌های تازه‌ای}} در {{SITENAME}} هستید",
+ "echo-email-batch-subject-weekly": "شما دارای {{PLURAL:$2|یک آگاه‌سازی تازه|آگاه‌سازی‌های تازه‌ای}} در {{SITENAME}} در این هفته هستید",
+ "echo-email-batch-body-intro-daily": "سلام $1،\nدر اینجا خلاصهٔ فعالیت امروز شما در {{SITENAME}} وجود دارد.",
+ "echo-email-batch-body-intro-weekly": "سلام $1،\nدر اینجا خلاصهٔ فعالیت این هفتهٔ شما در {{SITENAME}} وجود دارد.",
+ "echo-email-batch-link-text-view-all-notifications": "دیدن همهٔ آگاه‌سازی‌ها",
+ "echo-rev-deleted-text-view": "بازنگری این صفحه متوقف شده‌است.",
+ "apihelp-echomarkread-example-2": "علامت‌گذاری تمامی اعلان‌ها به عنوان خوانده شده",
+ "apihelp-query+notifications-example-1": "فهرست اعلان‌ها",
+ "apihelp-query+notifications-example-2": "فهرست اعلان‌ها، بخش بندیش شده، همراه با شمار آن‌ها."
+}
diff --git a/Echo/i18n/fi.json b/Echo/i18n/fi.json
new file mode 100644
index 00000000..856e424d
--- /dev/null
+++ b/Echo/i18n/fi.json
@@ -0,0 +1,124 @@
+{
+ "@metadata": {
+ "authors": [
+ "Crt",
+ "Nedergard",
+ "Nike",
+ "Olli",
+ "Pxos",
+ "Samoasambia",
+ "Silvonen",
+ "Stryn",
+ "VezonThunder"
+ ]
+ },
+ "echo-desc": "Ilmoitusten lähetysjärjestelmä",
+ "prefs-echo": "Ilmoitukset",
+ "prefs-emailsettings": "Sähköpostiasetukset",
+ "prefs-displaynotifications": "Näyttöasetukset",
+ "prefs-echosubscriptions": "Ilmoita minulle näistä tapahtumista",
+ "prefs-newmessageindicator": "Uuden viestin ilmaisin",
+ "echo-pref-send-me": "Lähetä minulle:",
+ "echo-pref-send-to": "Lähetä osoitteeseen:",
+ "echo-pref-email-format": "Sähköpostin muoto:",
+ "echo-pref-web": "Verkko",
+ "echo-pref-email": "Sähköposti",
+ "echo-pref-email-frequency-never": "Älä lähetä minulle sähköposti-ilmoituksia",
+ "echo-pref-email-frequency-immediately": "Yksittäiset ilmoitukset sitä mukaa kun niitä tulee",
+ "echo-pref-email-frequency-daily": "Päivittäinen yhteenveto ilmoituksista",
+ "echo-pref-email-frequency-weekly": "Viikottainen yhteenveto ilmoituksista",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Pelkkä teksti",
+ "echo-pref-notify-show-link": "Näytä ilmoitukset työkalurivissä",
+ "echo-pref-new-message-indicator": "Näytä keskustelusivujen viestistä erillinen ilmoitus työkalurivilläni",
+ "echo-learn-more": "Lue lisää aiheesta",
+ "echo-new-messages": "Sinulle on uusia viestejä",
+ "echo-category-title-edit-user-talk": "Keskustelusivun {{PLURAL:$1|viesti|viestit}}",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Sivun linkki|Sivujen linkit}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Muokkauksen kumoaminen|Muokkausten kumoamiset}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Maininta|Maininnat}}",
+ "echo-category-title-other": "{{PLURAL:$1|Muu|Muut}}",
+ "echo-category-title-system": "{{PLURAL:$1|Järjestelmä}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Käyttöoikeusmuutos|Käyttöoikeusmuutokset}}",
+ "echo-pref-tooltip-edit-user-talk": "Ilmoita minulle, kun joku kirjoittaa viestin tai vastaa viestiini keskustelusivullani.",
+ "echo-pref-tooltip-article-linked": "Ilmoita minulle, kun joku linkittää luomaani sivuun artikkelisivulta.",
+ "echo-pref-tooltip-reverted": "Ilmoita minulle, kun joku kumoaa tekemäni muokkauksen käyttäen kumoa/palauta-työkalua.",
+ "echo-pref-tooltip-mention": "Ilmoita minulle, kun joku tekee linkin käyttäjäsivulleni joltakin keskustelusivulta.",
+ "echo-pref-tooltip-user-rights": "Ilmoita minulle, kun joku muuttaa käyttöoikeuksiani.",
+ "echo-no-agent": "[Ei kukaan]",
+ "echo-no-title": "[Ei sivua]",
+ "echo-error-no-formatter": "Mitään muotoilua ei ole määritelty tälle ilmoitukselle.",
+ "echo-error-preference": "Virhe: Käyttäjäasetuksen määritys epäonnistui.",
+ "echo-error-token": "Virhe: Käyttäjätunnisteen (token) haku epäonnistui.",
+ "notifications": "Ilmoitukset",
+ "tooltip-pt-notifications": "Omat ilmoitukset",
+ "echo-specialpage": "Ilmoitukset",
+ "echo-anon": "Jos haluat saada ilmoituksia, [$1 luo käyttäjätunnus] tai [$2 kirjaudu sisään].",
+ "echo-none": "Sinulla ei ole ilmoituksia.",
+ "echo-more-info": "Lisätietoja",
+ "echo-feedback": "Palaute",
+ "notification-link-text-view-message": "Näytä viesti",
+ "notification-link-text-view-mention": "Näytä maininta",
+ "notification-link-text-view-changes": "Näytä muutokset",
+ "notification-link-text-view-page": "Näytä sivu",
+ "notification-link-text-view-edit": "Näytä muokkaus",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|jätti}} viestin [[User talk:$2#$3|keskustelusivullesi]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|jätti}} viestin keskustelusivullesi osioon \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|jätti}} viestin [[User talk:$2#$3|keskustelusivullesi]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|jätti}} viestin keskustelusivullesi osioon \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Sivulle [[:$2]] {{GENDER:$1|on nyt linkki}} sivulta [[:$3]].[[Special:WhatLinksHere/$2|Katso kaikki kohteeseen viittaavat linkit]].",
+ "notification-page-linked-flyout": "Sivulle [[:$2]] {{GENDER:$1|johtaa nyt linkki}} sivulta [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|kommentoi}} aihetta \"[[$3|$2]]\" keskustelusivulla \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|lisäsi}} uuden aiheen \"$2\" sivulle [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|lähetti}} sinulle viestin: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|kommentoi}} aihetta \"[[$3#$2|$2]]\" keskustelusivullasi.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|mainitsi}} sinut kohteen $5 keskustelussa osiossa \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|mainitsi}} sinut kohteen $5 keskustelussa osiossa \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|mainitsi}} sinut [[:$3|$2 keskustelusivulla]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|mainitsi}} sinut [[:$3|$2 keskustelusivulla]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|muutti}}]] käyttöoikeuksiasi. $2. [[Special:ListGroupRights|Lisätietoja]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|muutti}} käyttöoikeuksiasi. $2. [[Special:ListGroupRights|Lisätietoja]]",
+ "notification-user-rights-add": "Olet nyt {{PLURAL:$2|tämän ryhmän|näiden ryhmien}} jäsen: $1",
+ "notification-user-rights-remove": "Et ole enää {{PLURAL:$2|tämän ryhmän|näiden ryhmien}} jäsen: $1",
+ "notification-new-user": "Tervetuloa sivustolle {{SITENAME}}, $1! Olemme iloisia että olet täällä.",
+ "notification-reverted2": "[[User:$1|$1]] {{GENDER:$1|kumosi}} {{PLURAL:$4|muokkauksesi}} sivulla [[:$2]]. $3",
+ "notification-reverted-flyout2": "Käyttäjä $1 on {{GENDER:$1|kumonnut}} {{PLURAL:$4|muokkauksesi sivulla $2|muokkauksiasi sivulla $2}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|jätti}} sinulle viestin sivustolla {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|jätti}} viestin keskustelusivullesi:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|jätti}} viestin keskustelusivullesi osioon \"$2\".",
+ "notification-page-linked-email-subject": "Sivusi linkitettiin sivustolla {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Sivulle $2 johtava {{GENDER:$1|linkki lisättiin}} sivulta $3.",
+ "notification-reverted-email-subject2": "Tekemäsi {{PLURAL:$3|muokkaus|muokkaukset}} sivustolla {{SITENAME}} on {{GENDER:$1|kumottu}}.",
+ "notification-reverted-email-batch-body2": "Tekemäsi {{PLURAL:$3|muutoksen sivulle $2 on|muutokset sivulle $2 on}} {{GENDER:$1|kumonnut}} $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|mainitsi}} sinut sivustolla {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|mainitsi}} sinut kohteen $4 keskustelussa osiossa \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|mainitsi}} sinut keskustelusivulla $2.",
+ "notification-user-rights-email-subject": "Käyttöoikeutesi ovat muuttuneet sivustolla {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|muutti}} käyttöoikeuksiasi. $2.",
+ "echo-email-subject-default": "Uusi ilmoitus sivustolla {{SITENAME}}",
+ "echo-email-body-default": "Sinulle on uusi ilmoitus sivustolla {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Sinulla on uusi ilmoitus.",
+ "echo-email-footer-default": "$2\n\nMäärittele, mitä sähköposteja lähetämme sinulle, tarkistamalla asetuksesi:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Määrittele, mitä sähköpostiviestejä lähetämme sinulle, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">tarkistamalla asetuksesi</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Hälytysilmoitukset ($1)|100=Hälytysilmoitukset (yli 99)}}",
+ "echo-notification-message": "{{PLURAL:$1|Viesti ($1)|Viestit ($1)|100=Viestit (99+)}}",
+ "echo-notification-alert-text-only": "Hälytysilmoitukset",
+ "echo-notification-message-text-only": "Viestit",
+ "echo-overlay-link": "Kaikki ilmoitukset",
+ "echo-overlay-title": "<b>Ilmoitukset</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Ilmoitukset}}</b> (näytetään $1 ($2) lukematonta)",
+ "echo-mark-all-as-read": "Merkitse kaikki luetuiksi",
+ "echo-date-today": "Tänään",
+ "echo-date-yesterday": "Eilen",
+ "echo-load-more-error": "Virhe ilmeni, kun haettiin lisää tuloksia.",
+ "notification-edit-talk-page-bundle": "$1 ja {{PLURAL:$4|yksi muu|$3 muuta}} {{GENDER:$1|jättivät}} viestin [[User talk:$2|keskustelusivullesi]].",
+ "notification-page-linked-bundle": "Sivulle $2 {{GENDER:$1|on tehty linkki}} sivulta $3 ja {{PLURAL:$5|yhdeltä muulta sivulta|$4 muulta sivulta}}. [[Special:WhatLinksHere/$2|Katso kaikki kohteeseen viittavat linkit]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 ja {{PLURAL:$3|yksi muu jättivät|$2 muuta ovat jättäneet}} viestin keskustelusivullesi.",
+ "notification-page-linked-email-batch-bundle-body": "Sivu $2 {{GENDER:$1|linkitettiin}} sivulta $3 ja {{PLURAL:$5|yhdeltä muulta sivulta|$4 muulta sivulta}}",
+ "echo-email-batch-subject-daily": "Sinulle on {{PLURAL:$2|yksi uusi ilmoitus|$2 uutta ilmoitusta}} sivustolla {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Sinulle on {{PLURAL:$2|yksi uusi ilmoitus|$2 uutta ilmoitusta}} tällä viikolla sivustolla {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Hei $1.\nTässä on sinulle kooste tämän päivän tapahtumista sivustolla {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Hei $1.\nTässä on sinulle kooste tämän viikon tapahtumista sivustolla {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Katso kaikki ilmoitukset",
+ "echo-rev-deleted-text-view": "Tämä versio sivusta on poistettu."
+}
diff --git a/Echo/i18n/fo.json b/Echo/i18n/fo.json
new file mode 100644
index 00000000..8b6dd178
--- /dev/null
+++ b/Echo/i18n/fo.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "EileenSanda"
+ ]
+ },
+ "echo-desc": "Fráboðanarskipan",
+ "prefs-echo": "Fráboðanir",
+ "prefs-emailsettings": "T-post innstillingar",
+ "prefs-displaynotifications": "Innstillingar fyri sýning",
+ "prefs-echosubscriptions": "Gev mær boð um hesar hendingar",
+ "echo-pref-send-me": "Send mær:",
+ "echo-pref-send-to": "Send til:",
+ "echo-pref-email-format": "Teldupost format:",
+ "echo-pref-web": "Net",
+ "echo-pref-email": "T-postur",
+ "echo-pref-email-frequency-never": "Ikki senda mær fráboðanir við telduposti",
+ "echo-no-agent": "[Ongin]",
+ "echo-no-title": "[Ongin síða]",
+ "notification-link-text-view-page": "Vís síðu",
+ "notification-link-text-view-edit": "Vís rætting",
+ "echo-email-batch-body-default": "Tú hevur nýggj boð.",
+ "echo-overlay-link": "Allar fráboðanir",
+ "echo-overlay-title": "<b>Fráboðanir</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Fráboðanir}}</b> (vísir $1 av $2 ólisnum)",
+ "echo-mark-all-as-read": "Merk alt sum lisið",
+ "echo-date-today": "Í dag",
+ "echo-date-yesterday": "Í gjár"
+}
diff --git a/Echo/i18n/fr.json b/Echo/i18n/fr.json
new file mode 100644
index 00000000..f587da82
--- /dev/null
+++ b/Echo/i18n/fr.json
@@ -0,0 +1,154 @@
+{
+ "@metadata": {
+ "authors": [
+ "Automatik",
+ "Crochet.david",
+ "DavidL",
+ "Gomoko",
+ "Hello71",
+ "IAlex",
+ "Jean-Frédéric",
+ "Ltrlg",
+ "Metroitendo",
+ "Peter17",
+ "Sherbrooke",
+ "Tititou36",
+ "Urhixidur",
+ "Verdy p",
+ "Wyz",
+ "Y-M D",
+ "Kvardek du",
+ "NemesisIII",
+ "Od1n"
+ ]
+ },
+ "echo-desc": "Système de notifications",
+ "prefs-echo": "Notifications",
+ "prefs-emailsettings": "Options de courriel",
+ "prefs-displaynotifications": "Options d'affichage",
+ "prefs-echosubscriptions": "Me prévenir de ces événements",
+ "prefs-newmessageindicator": "Indicateur de nouveau message",
+ "echo-pref-send-me": "M'envoyer :",
+ "echo-pref-send-to": "Envoyer à :",
+ "echo-pref-email-format": "Format de courriel :",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Courriel",
+ "echo-pref-email-frequency-never": "Ne pas m'envoyer de notification par courriel",
+ "echo-pref-email-frequency-immediately": "Notifications individuelles au fur et à mesure",
+ "echo-pref-email-frequency-daily": "Un résumé quotidien des notifications",
+ "echo-pref-email-frequency-weekly": "Un résumé hebdomadaire des notifications",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Texte brut",
+ "echo-pref-notify-show-link": "Afficher les notifications dans ma barre d'outils",
+ "echo-pref-new-message-indicator": "Afficher dans ma barre d’outils l’indicateur de nouveau message sur ma page de discussion",
+ "echo-learn-more": "En savoir plus",
+ "echo-new-messages": "Vous avez de nouveaux messages",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Message|Messages}} de la page de discussion",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Article lié|Article liés}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Modification annulée|Modifications annulées}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Mention|Mentions}}",
+ "echo-category-title-other": "{{PLURAL:$1|Autres}}",
+ "echo-category-title-system": "{{PLURAL:$1|Système}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Modification de droits utilisateur|Modifications de droits utilisateur}}",
+ "echo-pref-tooltip-edit-user-talk": "Me prévenir quand quelqu’un publie un message ou répond sur ma page de discussion.",
+ "echo-pref-tooltip-article-linked": "Me prévenir quand quelqu’un fait référence à une page que j’ai créée à partir d’une page d’article.",
+ "echo-pref-tooltip-reverted": "Me prévenir quand quelqu’un annule une modification que j’ai faite, en utilisant l’outil annulation ou révocation",
+ "echo-pref-tooltip-mention": "Me prévenir quand quelqu’un fait référence à ma page utilisateur.",
+ "echo-pref-tooltip-user-rights": "Me notifier quand quelqu’un modifie mes droits utilisateur.",
+ "echo-no-agent": "[Personne]",
+ "echo-no-title": "[Aucune page]",
+ "echo-error-no-formatter": "Aucune mise en forme définie pour la notification",
+ "echo-error-preference": "Erreur : Impossible de définir la préférence utilisateur",
+ "echo-error-token": "Erreur : Impossible de récupérer le jeton de l’utilisateur",
+ "notifications": "Notifications",
+ "tooltip-pt-notifications": "Vos notifications",
+ "echo-specialpage": "Notifications",
+ "echo-anon": "Pour recevoir des notifications, [$1 créez un compte] ou [$2 connectez-vous].",
+ "echo-none": "Vous n'avez reçu aucune notification.",
+ "echo-more-info": "Plus d’informations",
+ "echo-feedback": "Avis",
+ "echo-quotation-marks": "« $1 »",
+ "notification-link-text-view-message": "Afficher le message",
+ "notification-link-text-view-mention": "Afficher la mention",
+ "notification-link-text-view-changes": "Afficher les modifications",
+ "notification-link-text-view-page": "Afficher la page",
+ "notification-link-text-view-edit": "Afficher la modification",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|a laissé}} un message sur votre [[User talk:$2#$3|page de discussion]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] a laissé un message sur votre page de discussion dans la [[User talk:$2#$3|section ''$4'']].",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|a laissé}} un message sur votre [[User talk:$2#$3|page de discussion]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 a laissé un message sur votre page de discussion dans la [[User talk:$2#$3|section ''$4'']].",
+ "notification-page-linked": "[[:$2]] a été {{GENDER:$1|référencé}} depuis [[:$3]]. [[Special:WhatLinksHere/$2|Voir tous les liens vers cette page]].",
+ "notification-page-linked-flyout": "[[:$2]] a été {{GENDER:$1|référencé}} depuis [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|a fait un commentaire}} dans « [[$3|$2]] » sur la page de discussion « $4 »",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|a publié}} un nouveau sujet \"$2\" sur [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vous {{GENDER:$1|a envoyé}} un message: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|a fait un commentaire}} dans ''[[$3#$2|$2]]'' sur votre page de discussion",
+ "notification-mention": "[[User:$1|$1]] vous a mentionné sur la page de discussion de $5 dans la [[:$3#$2|section ''$4'']].",
+ "notification-mention-flyout": "$1 vous a mentionné sur la page de discussion de $5 dans la [[:$3#$2|section ''$4'']].",
+ "notification-mention-nosection": "[[User:$1|$1]] a fait mention de vous sur la [[:$3|page de discussion de $2]].",
+ "notification-mention-nosection-flyout": "$1 a fait mention de vous sur la [[:$3|page de discussion de $2]].",
+ "notification-user-rights": "Vos droits d’utilisateur [[Special:Log/rights/$1|ont été modifiés]] par [[User:$1|$1]]. $2. [[Special:ListGroupRights|En savoir plus]]",
+ "notification-user-rights-flyout": "Vos droits d’utilisateur {{GENDER:$1|ont été modifiés}} par $1. $2. [[Special:ListGroupRights|En savoir plus]]",
+ "notification-user-rights-add": "Vous êtes maintenant membre de {{PLURAL:$2|ce groupe|ces groupes}} : $1",
+ "notification-user-rights-remove": "Vous n’êtes plus membre de {{PLURAL:$2|ce groupe|ces groupes}} : $1",
+ "notification-new-user": "Bienvenue sur {{SITENAME}}, $1 ! Nous sommes heureux de vous voir ici.",
+ "notification-reverted2": "{{PLURAL:$4|Votre modification sur [[:$2]] a|Vos modifications sur [[:$2]] ont}} été annulée{{PLURAL:$4||s}} par [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Votre modification sur $2 a|Vos modifications sur $2 ont}} été annulée{{PLURAL:$4||s}} par $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|a laissé}} un message sur votre page de discussion sur {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|a laissé}} un message sur votre page de discussion :",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 a laissé un message sur votre page de discussion dans ''$2''.",
+ "notification-page-linked-email-subject": "Votre page a été référencée sur {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 a été {{GENDER:$1|référencé}} depuis $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Votre modification a été {{GENDER:$1|annulée}}|Vos modifications ont été {{GENDER:$1|annulées}}}} sur {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Votre modification sur $2 a été annulée|Vos modifications sur $2 ont été annulées}} par $1",
+ "notification-mention-email-subject": "$1 vous a mentionné sur {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 vous a mentionné sur la page de discussion de $4 dans ''$3''.",
+ "notification-mention-nosection-email-batch-body": "$1 a fait mention de vous sur la page de discussion de $2.",
+ "notification-user-rights-email-subject": "Vos droits d’utilisateur ont été modifiés sur {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Vos droits d’utilisateur {{GENDER:$1|ont été modifiés}} par $1. $2",
+ "echo-email-subject-default": "Nouvelle notification sur {{SITENAME}}",
+ "echo-email-body-default": "Vous avez une nouvelle notification sur {{SITENAME}} :\n\n$1",
+ "echo-email-batch-body-default": "Vous avez une nouvelle notification",
+ "echo-email-footer-default": "$2\n\nPour vérifier quels courriels nous vous envoyons, allez dans vos préférences :\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Pour contrôler les courriels que nous vous envoyons, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">vérifiez vos préférences</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Alertes ($1)|100=Alertes (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Messages ($1)|100=Messages (99+)}}",
+ "echo-notification-alert-text-only": "Alertes",
+ "echo-notification-message-text-only": "Messages",
+ "echo-overlay-link": "Toutes les notifications",
+ "echo-overlay-title": "<b>Notifications</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notification|Notifications}}</b> ($1 sur $2 {{PLURAL:$1|non lue affichée|non lues affichées}})",
+ "echo-mark-all-as-read": "Tout marquer comme lu",
+ "echo-date-today": "Aujourd’hui",
+ "echo-date-yesterday": "Hier",
+ "echo-load-more-error": "Un erreur s'est produite en analysant davantage de résultats.",
+ "notification-edit-talk-page-bundle": "$1 et $3 {{PLURAL:$4|autre|autres}} ont laissé un message sur votre [[User talk:$2|page de discussion]].",
+ "notification-page-linked-bundle": "$2 a été {{GENDER:$1|référencé}} depuis $3 et $4 {{PLURAL:$5|autre page|autres pages}}. [[Special:WhatLinksHere/$2|Voir tous les liens vers cette page]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 et $2 {{PLURAL:$3|autre|autres}} ont {{GENDER:$1|laissé}} un message sur votre page de discussion.",
+ "notification-page-linked-email-batch-bundle-body": "$2 a été {{GENDER:$1|lié}} depuis $3 et $4 {{PLURAL:$5|autre page|autres pages}}.",
+ "echo-email-batch-subject-daily": "Vous avez {{PLURAL:$2|une nouvelle notification|de nouvelles notifications}} aujourd'hui sur {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Vous avez {{PLURAL:$2|une nouvelle notification|de nouvelles notifications}} sur {{SITENAME}} cette semaine",
+ "echo-email-batch-body-intro-daily": "Bonjour $1,\nVoici pour vous un résumé de l’activité d’aujourd’hui sur {{SITENAME}}",
+ "echo-email-batch-body-intro-weekly": "Bonjour $1,\nVoici pour vous un résumé de l’activité de la semaine sur {{SITENAME}}",
+ "echo-email-batch-link-text-view-all-notifications": "Voir toutes les notifications",
+ "echo-rev-deleted-text-view": "Cette révision de page a été supprimée",
+ "apihelp-echomarkread-description": "Marquer les notifications comme lues pour l’utilisateur actuel.",
+ "apihelp-echomarkread-param-list": "Une liste des IDs de notification à marquer comme lues.",
+ "apihelp-echomarkread-param-all": "Si défini, marque toutes les notifications de l’utilisateur comme lues.",
+ "apihelp-echomarkread-param-sections": "Une liste des sections à marquer comme lues.",
+ "apihelp-echomarkread-example-1": "Marquer la notification 8 comme lue",
+ "apihelp-echomarkread-example-2": "Marquer toutes les notifications comme lues",
+ "apihelp-query+notifications-description": "Obtenir les notifications en attente pour l’utilisateur courant.",
+ "apihelp-query+notifications-param-prop": "Détails à demander.",
+ "apihelp-query+notifications-param-sections": "Les sections de notification à demander.",
+ "apihelp-query+notifications-param-groupbysection": "S’il faut grouper les résultats par section. Chaque section est analysée séparément, s’il est défini.",
+ "apihelp-query+notifications-param-format": "Si spécifié, les notifications seront renvoyées dans ce format.",
+ "apihelp-query+notifications-param-limit": "Le nombre maximal de notifications à renvoyer.",
+ "apihelp-query+notifications-param-index": "Si spécifié, une liste ordonnée d’IDs de notification sera renvoyée.",
+ "apihelp-query+notifications-param-alertcontinue": "Quand plus d’alertes sont disponibles, utiliser cela pour continuer.",
+ "apihelp-query+notifications-param-alertunreadfirst": "S’il faut afficher d’abord les notifications de message non lu.",
+ "apihelp-query+notifications-param-messagecontinue": "Quand plus de résultats de message sont disponibles, utiliser cela pour continuer.",
+ "apihelp-query+notifications-param-messageunreadfirst": "S’il faut afficher les notifications d’alerte non lues en premier.",
+ "apihelp-query+notifications-example-1": "Lister les notifications",
+ "apihelp-query+notifications-example-2": "Lister les notifications, groupées par section, avec les compteurs"
+}
diff --git a/Echo/i18n/frp.json b/Echo/i18n/frp.json
new file mode 100644
index 00000000..e7ecc098
--- /dev/null
+++ b/Echo/i18n/frp.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "echo-desc": "Sistèmo de notificacions",
+ "prefs-echo": "Notificacions",
+ "prefs-displaynotifications": "Chouèx de visualisacion",
+ "echo-no-agent": "[Nion]",
+ "echo-no-title": "[Niona pâge]",
+ "notifications": "Notificacions",
+ "tooltip-pt-notifications": "Voutres notificacions",
+ "echo-specialpage": "Mes notificacions",
+ "echo-none": "Vos éd reçu gins de notificacion.",
+ "notification-new-user": "Benvegnua sur {{SITENAME}}, $1 !",
+ "echo-email-subject-default": "Novèla notificacion dessus {{SITENAME}}",
+ "echo-email-body-default": "Vos avéd na novèla notificacion dessus {{SITENAME}} :\n\n$1",
+ "echo-email-footer-default": "$2\n\nPor controlar quints mèssâjos nos vos mandens, visitâd :\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-overlay-link": "Totes les notificacions",
+ "echo-overlay-title": "Mes notificacions",
+ "echo-overlay-title-overflow": "Mes notificacions (montrent $1 sur $2 pas liesues)",
+ "echo-date-today": "Houé",
+ "echo-date-yesterday": "Hièr",
+ "echo-load-more-error": "Na fôta est arrevâye pendent la rècupèracion de més de rèsultats.",
+ "echo-email-batch-subject-daily": "Vos avéd $1 notificacion{{PLURAL:$2||s}} houé",
+ "echo-email-batch-subject-weekly": "Vos avéd $1 notificacion{{PLURAL:$2||s}} ceta semana"
+}
diff --git a/Echo/i18n/frr.json b/Echo/i18n/frr.json
new file mode 100644
index 00000000..481d484f
--- /dev/null
+++ b/Echo/i18n/frr.json
@@ -0,0 +1,135 @@
+{
+ "@metadata": {
+ "authors": [
+ "Murma174"
+ ]
+ },
+ "echo-desc": "Bööd-süsteem",
+ "prefs-echo": "Bööd",
+ "prefs-emailsettings": "E-mail iinstelangen",
+ "prefs-displaynotifications": "Mögelkhaiden för't uunwisin",
+ "prefs-echosubscriptions": "Schüür mi diar en bööd am",
+ "prefs-newmessageindicator": "Nei bööd uunwiiser",
+ "echo-pref-send-me": "Schüür mi:",
+ "echo-pref-send-to": "Schüür tu:",
+ "echo-pref-email-format": "E-mail-formoot:",
+ "echo-pref-web": "Wääb",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Schüür mi nian bööd",
+ "echo-pref-email-frequency-immediately": "Enkelt bööd tu arke föörgung",
+ "echo-pref-email-frequency-daily": "Iansis a dai en bööd",
+ "echo-pref-email-frequency-weekly": "Iansis a weg en bööd",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Normool tekst",
+ "echo-pref-notify-show-link": "Bööd uun min werktjüchlist uunwise",
+ "echo-pref-new-message-indicator": "Nei bööd üüb min diskuschuunssidj uun min werktjüchlist uunwise",
+ "echo-learn-more": "Ik wal muar wed",
+ "echo-new-messages": "Dü heest nei bööd",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|bööd|bööden}} üüb min diskuschuunssidj",
+ "echo-category-title-article-linked": "$1 {{PLURAL:$1|ferwisang|ferwisangen}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|turagsaatang|turagsaatangen}} bewerke",
+ "echo-category-title-mention": "{{PLURAL:$1|henwis|henwiser}}",
+ "echo-category-title-other": "{{PLURAL:$1|Öödern}}",
+ "echo-category-title-system": "{{PLURAL:$1|Süsteem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Feranrang|Feranrangen}} faan brükerrochten",
+ "echo-pref-tooltip-edit-user-talk": "Sai mi beskias, wan diar hoker en bööd of en oonswaar üüb min diskuschuunsidj skraft.",
+ "echo-pref-tooltip-article-linked": "Sai mi beskias, wan diar hoker en ferwisang üüb en sidj saat, diar ik skrewen haa.",
+ "echo-pref-tooltip-reverted": "Sai mi beskias, wan diar hoker en feranrang faan mi uun en artiikel turagsaat.",
+ "echo-pref-tooltip-mention": "Sai mi beskias, wan diar hoker en ferwisang faan en diskuschuunsidj üüb min brükersidj saat.",
+ "echo-pref-tooltip-user-rights": "Du mi bööd, wan hoker min brükerrochten feranert.",
+ "echo-no-agent": "[Näämen]",
+ "echo-no-title": "[Nian sidj]",
+ "echo-error-no-formatter": "Tu detdiar bööd as nian formoot fäästlaanj wurden.",
+ "echo-error-preference": "Feeler: Brükeriinstelangen küd ei seekert wurd.",
+ "echo-error-token": "Feeler: Brüker-token küd ei ufrepen wurd.",
+ "notifications": "Bööd",
+ "tooltip-pt-notifications": "Din bööd",
+ "echo-specialpage": "Bööd",
+ "echo-anon": "Am bööd tu fun, skel dü en [$1 brükerkonto] iinracht of di [$2 uunmelde].",
+ "echo-none": "Dü heest nian bööd.",
+ "echo-more-info": "Muar diartu",
+ "echo-feedback": "Ragmeldang",
+ "notification-link-text-view-message": "Bööd/en uunwise",
+ "notification-link-text-view-mention": "Henwis/er uunwise",
+ "notification-link-text-view-changes": "Feranrang/en uunwise",
+ "notification-link-text-view-page": "Sidj uunwise",
+ "notification-link-text-view-edit": "Feranrang uunwise",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|hää}} en bööd üüb din [[User talk:$2#$3|brükersidj]] skrewen.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|hää}} en bööd üüb din diskuschuunsidj skrewen auer \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|hää}} en bööd üüb din [[User talk:$2#$3|diskuschuunsidj]] skrewen.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|hää}} en bööd üüb din diskuschuunsidj skrewen auer \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Üüb [[:$2]] as faan [[:$3]] {{GENDER:$1|ferwiset}} wurden. [[Special:WhatLinksHere/$2|Aal a ferwisangen üüb detdiar sidj uunwise]].",
+ "notification-page-linked-flyout": "Üüb [[:$2]] as faan [[:$3]] {{GENDER:$1|ferwiset}} wurden.",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|skrääw}} auer \"[[$3|$2]]\" üüb det \"$4\" diskuschuunsidj.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|skrääw}} en nei kirew \"$2\" üüb [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|hää}} di en bööd schüürd: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|skrääw}} auer \"[[$3#$2|$2]]\" üüb din diskuschuunsidj.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|näämd}} di üüb det $5 diskuschuunsidj auer \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|näämd}} di üüb det $5 diskuschuunsidj uun \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|näämd}} di üüb det [[:$3|$2 diskuschuunsidj]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|näämd}} di üüb det [[:$3|$2 diskuschuunsidj]].",
+ "notification-user-rights": "Din brükerrochten [[Special:Log/rights/$1|san {{GENDER:$1|feranert}}]] wurden faan [[User:$1|$1]]. $2. [[Special:ListGroupRights|Muar diartu]]",
+ "notification-user-rights-flyout": "Din brükerrochten san {{GENDER:$1|feranert}} wurden faan $1. $2. [[Special:ListGroupRights|Muar diartu]]",
+ "notification-user-rights-add": "Dü beest nü lasmoot faan {{PLURAL:$2|detdiar brükerskööl|jodiar brükersköölen}}: $1",
+ "notification-user-rights-remove": "Dü beest nian lasmoot muar faan {{PLURAL:$2|detdiar brükerskööl|jodiar brükersköölen}}: $1",
+ "notification-new-user": "Welkimen tu {{SITENAME}}, $1! Wi san bliis, dat dü diar beest.",
+ "notification-reverted2": "Din {{PLURAL:$4|feranrang üüb [[:$2]] as|feranrangen üüb [[:$2]] san}} {{GENDER:$1|turagsaat}} wurden faan [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Din {{PLURAL:$4|feranrang üüb $2 as|feranrangen üüb $2 san}} {{GENDER:$1|turagsaat}} wurden faan $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|hää}} di en bööd schüürd üüb {{SITENAME}}.",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|hää}} en bööd üüb din diskuschuunsidj skrewen:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|hää}} en bööd üüb din diskuschuunsidj skrewen auer \"$2\".",
+ "notification-page-linked-email-subject": "Üüb din sidj as faan {{SITENAME}} ferwiset wurden.",
+ "notification-page-linked-email-batch-body": "Üüb $2 as faan $3 {{GENDER:$1|ferwiset}} wurden.",
+ "notification-reverted-email-subject2": "Din {{PLURAL:$3|feranrang as|feranrangen san}} {{GENDER:$1|turagsaat}} wurden üüb {{SITENAME}}.",
+ "notification-reverted-email-batch-body2": "Din {{PLURAL:$3|feranrang üüb $2 as|feranrangen üüb $2 san}} faan $1 {{GENDER:$1|turagsaat}} wurden.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|näämd}} di üüb {{SITENAME}}.",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|näämd}} di üüb det $4 diskuschuunsidj uun \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|näämd}} di üüb det $2 diskuschuunsidj.",
+ "notification-user-rights-email-subject": "Din brükerrochten san feranert wurden üüb {{SITENAME}}.",
+ "notification-user-rights-email-batch-body": "Din brükerrochten san {{GENDER:$1|feranert}} wurden faan $1. $2.",
+ "echo-email-subject-default": "Nei bööd üüb {{SITENAME}}.",
+ "echo-email-body-default": "Dü heest nei bööd üüb {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Dü heest nei bööd.",
+ "echo-email-footer-default": "$2\n\nAm iintustelen, hük e-mails tu di schüürd wurd, brük din iinstelangs-sidj:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Am iintustelen, hük e-mails tu di schüürd wurd, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">brük din iinstelangs-sidj</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Ian bööd|$1 bööden|100=99+ bööden}}",
+ "echo-notification-message": "{{PLURAL:$1|Ian bööd|$1 bööden|100=99+ bööden}}",
+ "echo-notification-alert-text-only": "Bööden",
+ "echo-notification-message-text-only": "Bööden",
+ "echo-overlay-link": "Aal din bööd",
+ "echo-overlay-title": "<b>Bööd</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Bööden}}</b> (Uunwiset wurd $1 faan $2, diar noch ei leesen wurden san)",
+ "echo-mark-all-as-read": "Aaltumaal üs leesen kääntiakne",
+ "echo-date-today": "Daalang",
+ "echo-date-yesterday": "Jister",
+ "echo-load-more-error": "Bi't ufrepen as wat skiaf gingen.",
+ "notification-edit-talk-page-bundle": "$1 an $3 {{PLURAL:$4|brüker muar|muar brükern}} {{GENDER:$1|schüürd}} en bööd tu din [[User talk:$2|diskuschuunsidj]].",
+ "notification-page-linked-bundle": "Üüb $2 as faan $3 an $4 {{PLURAL:$5|sidj muar|muar sidjen}} {{GENDER:$1|ferwiset}} wurden. [[Special:WhatLinksHere/$2|Aal a ferwisangen üüb detdiar sidj uunwise]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 an $2 {{PLURAL:$3|brüker muar|muar brükern}} {{GENDER:$1|haa}} en bööd tu din diskuschuunsidj schüürd.",
+ "notification-page-linked-email-batch-bundle-body": "Üüb $2 as faan $3 an $4 {{PLURAL:$5|sidj muar|muar sidjen}} {{GENDER:$1|ferwiset}} wurden.",
+ "echo-email-batch-subject-daily": "Dü heest {{PLURAL:$2|en nei bööd|nei bööden}} üüb {{SITENAME}}.",
+ "echo-email-batch-subject-weekly": "Dü heest das weg {{PLURAL:$2|ian nei bööd|nei bööden}} üüb {{SITENAME}}.",
+ "echo-email-batch-body-intro-daily": "Hoi $1,\ndiar as en auersicht för di auer feranrangen üüb {{SITENAME}} faan daalang.",
+ "echo-email-batch-body-intro-weekly": "Hoi $1,\nDiar as en auersicht för di auer a feranrangen üüb {{SITENAME}} faan das weg.",
+ "echo-email-batch-link-text-view-all-notifications": "Aal min bööd uunwise",
+ "echo-rev-deleted-text-view": "Detdiar sidjenwerjuun as ferbürgen wurden.",
+ "apihelp-echomarkread-description": "Bööden för di uugenblakelk brüker ruad uunwise",
+ "apihelp-echomarkread-param-list": "En list faan bööd-IDs ruad uuntuwisin",
+ "apihelp-echomarkread-param-all": "Wan det so fäästlaanj as, wurd aal a bööden üs al leesen uunwiset.",
+ "apihelp-echomarkread-param-sections": "En list faan kirwer ruad uuntuwisin.",
+ "apihelp-echomarkread-example-1": "Bööd 8 üs al leesen uunwise",
+ "apihelp-echomarkread-example-2": "Aal a bööden üs al leesen uunwise",
+ "apihelp-query+notifications-description": "Bööden för di uugenblakelk brüker haale.",
+ "apihelp-query+notifications-param-prop": "Enkelthaiden uuntufraagin.",
+ "apihelp-query+notifications-param-sections": "Bööd kirwer uftufraagin",
+ "apihelp-query+notifications-param-groupbysection": "Of det resultaat efter kirwer uunwiset woort. Arke kirew woort enkelt haalet, wan det so fäästlaanj as.",
+ "apihelp-query+notifications-param-format": "Bööden wurd formatiaret uunwiset, wan det so fäästlaanj as.",
+ "apihelp-query+notifications-param-limit": "Det huuchst taal faan uunwiset bööden.",
+ "apihelp-query+notifications-param-index": "En list faan bööd-IDs woort efter a rä uunwiset, wan det so fäästlaanj as.",
+ "apihelp-query+notifications-param-alertcontinue": "Wann diar muar resultaaten san, brük det heer, am widjer tu maagin.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Of diar bööden tuiarst uunwiset wurd skel, diar noch ei leesen wurden san.",
+ "apihelp-query+notifications-param-messagecontinue": "Wann diar muar resultaaten san, brük det heer, am widjer tu maagin.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Of diar bööden tuiarst uunwiset wurd skel, diar noch ei leesen wurden san.",
+ "apihelp-query+notifications-example-1": "List faan din bööden",
+ "apihelp-query+notifications-example-2": "List faan din bööden, efter a rä faan a kirwer, mä taalen"
+}
diff --git a/Echo/i18n/fy.json b/Echo/i18n/fy.json
new file mode 100644
index 00000000..8898084e
--- /dev/null
+++ b/Echo/i18n/fy.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet"
+ ]
+ },
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-format-html": "HTML",
+ "echo-feedback": "Weromkeppeling",
+ "echo-date-today": "Hjoed",
+ "echo-date-yesterday": "Juster"
+}
diff --git a/Echo/i18n/gd.json b/Echo/i18n/gd.json
new file mode 100644
index 00000000..0b8a492f
--- /dev/null
+++ b/Echo/i18n/gd.json
@@ -0,0 +1,114 @@
+{
+ "@metadata": {
+ "authors": [
+ "GunChleoc"
+ ]
+ },
+ "echo-desc": "Siostam nam brathan-naidheachd",
+ "prefs-echo": "Brathan-naidheachd",
+ "prefs-emailsettings": "Roghainnean a' phuist-d",
+ "prefs-displaynotifications": "Roghainnean an t-seallaidh",
+ "prefs-echosubscriptions": "Cuir brath thugam mu na tachartasan seo",
+ "prefs-newmessageindicator": "Taisbeanair nan teachdaireachdan ùra",
+ "echo-pref-send-me": "Cuir thugam:",
+ "echo-pref-send-to": "Cuir gu:",
+ "echo-pref-email-format": "Fòrmat a' phuist-d:",
+ "echo-pref-web": "Lìon",
+ "echo-pref-email": "Post-d",
+ "echo-pref-email-frequency-never": "Na chuir brathan-naidheachd thugam air a' phost-d",
+ "echo-pref-email-frequency-immediately": "Brathan-naidheachd fa leth nuair a thig iad a-steach",
+ "echo-pref-email-frequency-daily": "Gearr chunntas dhe bhrathan-naidheachd an latha",
+ "echo-pref-email-frequency-weekly": "Gearr chunntas dhe bhrathan-naidheachd na seachdaine",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Teacsa lom",
+ "echo-pref-notify-show-link": "Seall brathan-naidheachd air a' bhàr-inneal agam",
+ "echo-pref-new-message-indicator": "Seall taisbeanair airson duilleag na deasbaireachd air a' bhàr-inneal agam",
+ "echo-learn-more": "Barrachd fiosrachaidh",
+ "echo-new-messages": "Tha teachdaireachdan ùra agad",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Teachdaireachd|Teachdaireachdan}} air duilleag na deasbaireachd",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Ceangal|Ceanglaichean}} gu dhuilleag",
+ "echo-category-title-mention": "{{PLURAL:$1|Iomradh|Iomraidhean}}",
+ "echo-category-title-other": "{{PLURAL:$1|Eile}}",
+ "echo-category-title-system": "{{PLURAL:$1|Siostam}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Atharrachadh air ceadan a' chleachdaiche|Atharrachaidhean air ceadan a' chleachdaiche}}",
+ "echo-pref-tooltip-edit-user-talk": "Cuir brath-naidheachd thugam nuair a sgrìobhas cuideigin teachdaireachd no freagairt air duilleag na deasbaireachd agam.",
+ "echo-pref-tooltip-article-linked": "Cuir brath-naidheachd thugam nuair a cheanglas cuideigin ri duilleag a chruthaich mi o dhuilleag artaigil.",
+ "echo-pref-tooltip-reverted": "Cuir brath-naidheachd thugam nuair a thilleas cuideigin deasachadh a rinn mi le inneal an neo-dhèanaimh no an tillidh.",
+ "echo-pref-tooltip-mention": "Cuir brath-naidheachd thugam nuair a cheanglas cuideigin ris duilleag a' chleachdaiche agam o dhuilleag na deasbaireachd sam bith.",
+ "echo-pref-tooltip-user-rights": "Cuir brath-naidheachd thugam nuair a dh'atharraicheas cuideigin ceadan a' chleachdaiche agam.",
+ "echo-no-agent": "[Chan eil duine]",
+ "echo-no-title": "[Gun duilleag]",
+ "echo-error-no-formatter": "Tha deach fòrmatadh a shònrachadh airson a' bhratha-naidheachd.",
+ "echo-error-preference": "Mearachd: cha b' urrainn dhuinn roghainn a' chleachdaiche a shuidheachadh.",
+ "echo-error-token": "Mearachd: Cha b' urrainn dhuinn tòcan a' chleachdaiche fhaighinn.",
+ "notifications": "Brathan-naidheachd",
+ "tooltip-pt-notifications": "Na brathan-naidheachd agad",
+ "echo-specialpage": "Brathan-naidheachd",
+ "echo-anon": "[$1 Cruthaich cunntas] no [$2 log a-steach] gus brathan-naidheachd fhaighinn.",
+ "echo-none": "Chan eil brath-naidheachd agad.",
+ "echo-more-info": "Barrachd fiosrachaidh",
+ "echo-feedback": "Beachd thugainn",
+ "echo-quotation-marks": "\"$1\"",
+ "notification-link-text-view-message": "Seall an teachdaireachd",
+ "notification-link-text-view-mention": "Seall an t-iomradh",
+ "notification-link-text-view-changes": "Seall na h-atharraichean",
+ "notification-link-text-view-page": "Seall an duilleag",
+ "notification-link-text-view-edit": "Seall an deasachadh",
+ "notification-edit-talk-page2": "Dh'fhàg [[User:$1|$1]] {{GENDER:$1|}} teachdaireachd air [[User talk:$2#$3|duilleag na deasbaireachd]] agad.",
+ "notification-edit-talk-page-with-section": "Dh'fhàg [[User:$1|$1]] {{GENDER:$1|}} teachdaireachd duilleag na deasbaireachd agad ann an \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "Dh'fhàg $1 {{GENDER:$1|}} teachdaireachd air [[User talk:$2#$3|duilleag na deasbaireachd]] agad.",
+ "notification-edit-talk-page-flyout-with-section": "Dh'fhàg $1 {{GENDER:$1|}} teachdaireachd duilleag na deasbaireachd agad ann an \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Chaidh [[:$2]] a cheangal {{GENDER:$1|}} o [[:$3]]. [[Special:WhatLinksHere/$2|Seall a h-uile ceangal dhan duilleag seo]].",
+ "notification-page-linked-flyout": "Chaidh [[:$2]] a cheangal {{GENDER:$1|}} o [[:$3]].",
+ "notification-add-comment2": "Bheachdaich [[User:$1|$1]] {{GENDER:$1|}} air \"[[$3|$2]]\" air duilleag na deasbaireachd \"$4\".",
+ "notification-add-talkpage-topic2": "Thòisich [[User:$1|$1]] {{GENDER:$1|}} cuspair ùr \"$2\" air [[$3]].",
+ "notification-add-talkpage-topic-yours2": "Chuir [[User:$1|$1]] {{GENDER:$1|}} teachdaireachd thugad: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "Bheachdaich [[User:$1|$1]] {{GENDER:$1|}} air \"[[$3#$2|$2]]\" air duilleag na deasbaireachd agad.",
+ "notification-mention": "Thug [[User:$1|$1]] {{GENDER:$1|}} iomradh ort air duilleag na deasbaireachd \"$5\" ann an \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "Thug $1 {{GENDER:$1|}} iomradh ort air duilleag na deasbaireachd \"$5\" ann an \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "Thug [[User:$1|$1]] {{GENDER:$1|}} iomradh ort air [[:$3|$2 duilleag na deasbaireachd]].",
+ "notification-mention-nosection-flyout": "Thug $1 {{GENDER:$1|}} iomradh ort air [[:$3|$2 duilleag na deasbaireachd]].",
+ "notification-user-rights": "Chaidh ceadan a' chleachdaiche agad [[Special:Log/rights/$1|{{GENDER:$1|atharrachadh}}]] le [[User:$1|$1]]. $2. [[Special:ListGroupRights|Barrachd fiosrachaidh]]",
+ "notification-user-rights-flyout": "Chaidh ceadan a' chleachdaiche agad {{GENDER:$1|atharrachadh}} le $1. $2. [[Special:ListGroupRights|Barrachd fiosrachaidh]]",
+ "notification-user-rights-add": "Tha thu 'nad bhall {{PLURAL:$2|sa bhuidheann seo|sna buidhnean seo}} a-nis: $1",
+ "notification-user-rights-remove": "Chan eil thu 'nad bhall {{PLURAL:$2|sa bhuidheann seo|sna buidhnean seo}} tuilleadh: $1",
+ "notification-new-user": "Fàilte gu {{SITENAME}}, $1! Tha sinn toilichte gu bheil thu ann.",
+ "notification-reverted2": "Chaidh {{PLURAL:$4|an deasachadh agad air [[:$2]] |na deasachaidhean agad air [[:$2]]}} {{GENDER:$1|a thilleadh}} le [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Chaidh {{PLURAL:$4|an deasachadh agad air $2 |na deasachaidhean agad air $2}} {{GENDER:$1|a thilleadh}} le $1. $3",
+ "notification-edit-talk-page-email-subject2": "Dh'fhag $1 {{GENDER:$1|}} teachdaireachd dhut air {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "Dh'fhàg $1 {{GENDER:$1|}} teachdaireachd air duilleag na deasbaireachd agad:",
+ "notification-edit-talk-page-email-batch-body-with-section": "Dh'fhàg $1 {{GENDER:$1|}} teachdaireachd air duilleag na deasbaireachd agad ann an \"$2\".",
+ "notification-page-linked-email-subject": "Chaidh ceangal ris an duilleag agad air {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Chaidh $2 a cheangal {{GENDER:$1|}} o $3.",
+ "notification-reverted-email-subject2": "Chaidh {{PLURAL:$3|an deasachadh agad|na deasachaidhean agad}} {{GENDER:$1|a thilleadh}} air {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "Chaidh {{PLURAL:$3|an deasachadh agad air $2 |na deasachaidhean agad air $2}} {{GENDER:$1|a thilleadh}} le $1.",
+ "notification-mention-email-subject": "Thug $1 {{GENDER:$1|iomradh}} ort air {{SITENAME}}",
+ "notification-mention-email-batch-body": "Thug $1 {{GENDER:$1|}} iomradh ort air duilleag na deasbaireachd \"$4\" ann an \"$3\".",
+ "notification-mention-nosection-email-batch-body": "Thug $1 {{GENDER:$1|}} iomradh ort air duilleag na deasbaireachd \"$2\".",
+ "notification-user-rights-email-subject": "Chaidh ceadan a' chleachdaiche agad atharrachadh air {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Chaidh ceadan a' chleachdaiche agad {{GENDER:$1|atharrachadh}} le $1. $2.",
+ "echo-notification-count": "$1+",
+ "echo-email-subject-default": "Brath-naidheachd ùr air {{SITENAME}}",
+ "echo-email-body-default": "Tha brath-naidheachd ùr agad air {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Tha brath-naidheachd ùr agad.",
+ "echo-email-footer-default": "$2\n\nThoir sùil air na roghainnean agad gus taghadh dè na puist-d a chuireas sinn thugad:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "<a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">Thoir sùil air na roghainnean agad</a> gus taghadh dè na puist-d a chuireas sinn thugad.<br />\n$1",
+ "echo-overlay-link": "A h-uile brath-naidheachd",
+ "echo-overlay-title": "<b>Brathan-naidheachd</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Brath-naidheachd|Brathan-naidheachd}}</b> (a' sealltainn $1 à $2 gun leughadh)",
+ "echo-mark-all-as-read": "Cuir comharra gun deach iad uile a leughadh",
+ "echo-date-today": "An-diugh",
+ "echo-date-yesterday": "An-dè",
+ "echo-load-more-error": "Thachair mearachd nuair a bha sinn a' faighinn barrachd thoraidhean.",
+ "notification-edit-talk-page-bundle": "Dh'fhàg $1 agus $3 {{PLURAL:$4|eile}} {{GENDER:$1|}} teachdaireachd air [[User talk:$2|duilleag na deasbaireachd agad]].",
+ "notification-page-linked-bundle": "Chaidh $2 a cheangal {{GENDER:$1|}} o $3 agus $4 {{PLURAL:$5|duilleag|duilleagan}} eile. [[Special:WhatLinksHere/$2|Seall a h-uile ceangal dhan duilleag seo]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "Dh'fhàg $1 agus $3 {{PLURAL:$4|eile}} {{GENDER:$1|}} teachdaireachd air duilleag na deasbaireachd agad.",
+ "notification-page-linked-email-batch-bundle-body": "Chaidh $2 a cheangal {{GENDER:$1|}} o $3 agus $4 {{PLURAL:$5|duilleag|duilleagan}} eile.",
+ "echo-email-batch-bullet": "•",
+ "echo-email-batch-subject-daily": "Tha {{PLURAL:$2|bràth-naidheachd ùr|brathan-naidheachd ùra}} agad air {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Tha {{PLURAL:$2|bràth-naidheachd ùr|brathan-naidheachd ùra}} agad air {{SITENAME}} an t-seachdain seo",
+ "echo-email-batch-body-intro-daily": "$1, a charaid,\nSeo gearr-chunntas dhut dhen ghnìomhachd air {{SITENAME}} an-diugh.",
+ "echo-email-batch-body-intro-weekly": "$1, a charaid,\nSeo gearr-chunntas dhut dhen ghnìomhachd air {{SITENAME}} an t-seachdain seo.",
+ "echo-email-batch-link-text-view-all-notifications": "Seall a h-uile brath-naidheachd",
+ "echo-rev-deleted-text-view": "Chaidh am mùthadh duilleige seo a mùchadh."
+}
diff --git a/Echo/i18n/gl.json b/Echo/i18n/gl.json
new file mode 100644
index 00000000..d51ff42d
--- /dev/null
+++ b/Echo/i18n/gl.json
@@ -0,0 +1,126 @@
+{
+ "@metadata": {
+ "authors": [
+ "Elisardojm",
+ "Toliño",
+ "Vivaelcelta",
+ "Banjo"
+ ]
+ },
+ "echo-desc": "Sistema de notificacións",
+ "prefs-echo": "Notificacións",
+ "prefs-emailsettings": "Opcións de correo electrónico",
+ "prefs-displaynotifications": "Opcións de visualización",
+ "prefs-echosubscriptions": "Notificádeme sobre estes eventos",
+ "prefs-newmessageindicator": "Indicador de mensaxe nova",
+ "echo-pref-send-me": "Enviádeme:",
+ "echo-pref-send-to": "Enviar a:",
+ "echo-pref-email-format": "Formato do correo:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Correo electrónico",
+ "echo-pref-email-frequency-never": "Non me enviedes ningunha notificación por correo electrónico",
+ "echo-pref-email-frequency-immediately": "Notificacións individuais en canto cheguen",
+ "echo-pref-email-frequency-daily": "Un resumo diario das notificacións",
+ "echo-pref-email-frequency-weekly": "Un resumo semanal das notificacións",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Texto simple",
+ "echo-pref-notify-show-link": "Mostrar as notificacións na miña barra de ferramentas",
+ "echo-pref-new-message-indicator": "Mostrar o indicador de mensaxe na páxina de conversa na miña barra de ferramentas",
+ "echo-learn-more": "Máis información",
+ "echo-new-messages": "Ten mensaxes novas",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mensaxe|Mensaxes}} na páxina de conversa",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Ligazón|Ligazóns}} a unha páxina",
+ "echo-category-title-reverted": "{{PLURAL:$1|Reversión|Reversións}} dunha edición",
+ "echo-category-title-mention": "{{PLURAL:$1|Mención|Mencións}}",
+ "echo-category-title-other": "{{PLURAL:$1|Outra|Outras}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Cambio|Cambios}} nos dereitos de usuario",
+ "echo-pref-tooltip-edit-user-talk": "Notificádeme cando alguén deixe unha mensaxe na miña páxina de conversa.",
+ "echo-pref-tooltip-article-linked": "Notificádeme cando alguén ligue cunha páxina que creei desde un artigo.",
+ "echo-pref-tooltip-reverted": "Notificádeme cando alguén reverta unha edición feita por min usando a ferramenta de reversión ou desfacer.",
+ "echo-pref-tooltip-mention": "Notificádeme cando alguén ligue cara a miña páxina de usuario.",
+ "echo-pref-tooltip-user-rights": "Notificádeme cando alguén modifique os meus dereitos de usuario.",
+ "echo-no-agent": "[Ninguén]",
+ "echo-no-title": "[Ningunha páxina]",
+ "echo-error-no-formatter": "Non se definiu formato ningún para a notificación",
+ "echo-error-preference": "Erro: Non se puido establecer a preferencia de usuario",
+ "echo-error-token": "Erro: Non se puido recuperar o pase de usuario",
+ "notifications": "Notificacións",
+ "tooltip-pt-notifications": "As súas notificacións",
+ "echo-specialpage": "Notificacións",
+ "echo-anon": "Para recibir notificacións, [$1 cree unha conta] ou [$2 acceda ao sistema].",
+ "echo-none": "Non ten ningunha notificación.",
+ "echo-more-info": "Máis información",
+ "echo-feedback": "Comentarios",
+ "notification-link-text-view-message": "Mostrar a mensaxe",
+ "notification-link-text-view-mention": "Mostrar a mención",
+ "notification-link-text-view-changes": "Mostrar os cambios",
+ "notification-link-text-view-page": "Mostrar a páxina",
+ "notification-link-text-view-edit": "Mostrar a edición",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|deixou}} unha mensaxe na súa [[User talk:$2#$3|páxina de conversa]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|deixou}} unha mensaxe na súa páxina de conversa na sección \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|deixou}} unha mensaxe na súa [[User talk:$2#$3|páxina de conversa]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|deixou}} unha mensaxe na súa páxina de conversa na sección \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "\"[[:$2]]\" foi {{GENDER:$1|ligada}} desde \"[[:$3]]\". [[Special:WhatLinksHere/$2|Ollar todas as ligazóns cara a esta páxina]].",
+ "notification-page-linked-flyout": "\"[[:$2]]\" foi {{GENDER:$1|ligada}} desde \"[[:$3]]\".",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|comentou}} en \"[[$3|$2]]\" na páxina de conversa \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|comezou}} o fío de conversa \"$2\" en \"[[$3]]\"",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|envioulle}} unha mensaxe: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|comentou}} en \"[[$3#$2|$2]]\" na súa páxina de conversa.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|fíxolle}} unha mención na páxina de conversa de \"$5\" na sección \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|fíxolle}} unha mención na páxina de conversa de \"$5\" na sección \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|fíxolle}} unha mención na [[:$3|páxina de conversa de \"$2\"]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|fíxolle}} unha mención na [[:$3|páxina de conversa de \"$2\"]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|mudou}} os seus dereitos de usuario]]. $2. [[Special:ListGroupRights|Máis información]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|mudou}} os seus dereitos de usuario. $2. [[Special:ListGroupRights|Máis información]]",
+ "notification-user-rights-add": "Agora pertence a {{PLURAL:$2|este grupo|estes grupos}}: $1",
+ "notification-user-rights-remove": "Xa non pertence a {{PLURAL:$2|este grupo|estes grupos}}: $1",
+ "notification-new-user": "Dámoslle a benvida a {{SITENAME}}, $1! Alegrámonos de que estea aquí.",
+ "notification-reverted2": "[[User:$1|$1]] {{GENDER:$1|reverteu}} {{PLURAL:$4|a súa edición|as súas edicións}} en \"[[:$2]]\" $3",
+ "notification-reverted-flyout2": "$1 {{GENDER:$1|reverteu}} {{PLURAL:$4|a súa edición|as súas edicións}} en \"$2\" $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|deixoulle}} unha mensaxe en {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|deixou}} unha mensaxe na súa páxina de conversa:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|deixou}} unha mensaxe na súa páxina de conversa na sección \"$2\"",
+ "notification-page-linked-email-subject": "A súa páxina foi ligada en {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "\"$2\" foi {{GENDER:$1|ligada}} desde \"$3\"",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Reverteuse a súa edición|Revertéronse as súas edicións}} {{GENDER:$1|en}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|reverteu}} {{PLURAL:$3|a súa edición|as súas edicións}} en \"$2\"",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|fíxolle}} unha mención en {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|fíxolle}} unha mención na páxina de conversa de \"$4\" na sección \"$3\"",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|fíxolle}} unha mención na páxina de conversa de \"$2\".",
+ "notification-user-rights-email-subject": "Os seus dereitos de usuario cambiaron en {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|mudou}} os seus dereitos de usuario. $2",
+ "echo-email-subject-default": "Nova notificación en {{SITENAME}}",
+ "echo-email-body-default": "Ten unha nova notificación en {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Ten unha nova notificación",
+ "echo-email-footer-default": "$2\n\nPara controlar os correos electrónicos que lle enviamos, comprobe as súas preferencias:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Para controlar os correos electrónicos que lle enviamos, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">comprobe as súas preferencias</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Alertas ($1)|100=Alertas (máis de 99)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mensaxes ($1)|100=Mensaxes (máis de 99)}}",
+ "echo-notification-alert-text-only": "Alertas",
+ "echo-notification-message-text-only": "Mensaxes",
+ "echo-overlay-link": "Todas as notificacións",
+ "echo-overlay-title": "<b>Notificacións</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notificación|Notificacións}}</b> (mostrando $1 de $2 sen ler)",
+ "echo-mark-all-as-read": "Marcar todo como lido",
+ "echo-date-today": "Hoxe",
+ "echo-date-yesterday": "Onte",
+ "echo-load-more-error": "Houbo un erro ao procurar máis resultados.",
+ "notification-edit-talk-page-bundle": "$1 e {{PLURAL:$4|outra persoa|$3 persoas máis}} {{GENDER:$1|deixaron}} mensaxes na súa [[User talk:$2|páxina de conversa]].",
+ "notification-page-linked-bundle": "\"$2\" foi {{GENDER:$1|ligada}} desde \"$3\" e $4 {{PLURAL:$5|páxina|páxinas}} máis. [[Special:WhatLinksHere/$2|Ollar todas as ligazóns cara a esta páxina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e {{PLURAL:$3|outra persoa|$2 persoas máis}} {{GENDER:$1|deixaron}} mensaxes na súa páxina de conversa",
+ "notification-page-linked-email-batch-bundle-body": "\"$2\" foi {{GENDER:$1|ligada}} desde \"$3\" e {{PLURAL:$5|outra páxina|$4 páxinas máis}}",
+ "echo-email-batch-subject-daily": "Ten {{PLURAL:$2|unha nova notificación|novas notificacións}} en {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Esta semana ten {{PLURAL:$2|unha nova notificación|novas notificacións}} en {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Boas, $1:\nVelaquí ten un resumo da actividade de hoxe en {{SITENAME}}",
+ "echo-email-batch-body-intro-weekly": "Boas, $1:\nVelaquí ten un resumo da actividade da semana en {{SITENAME}}",
+ "echo-email-batch-link-text-view-all-notifications": "Ollar todas as notificacións",
+ "echo-rev-deleted-text-view": "Eliminouse a revisión da páxina",
+ "apihelp-echomarkread-description": "Marcar notificacións coma lidas para o usuario actual.",
+ "apihelp-echomarkread-param-list": "Lista de identificadores de notificacións a marcar coma lidas.",
+ "apihelp-echomarkread-param-sections": "Unha lista das seccións a marcar como lidas.",
+ "apihelp-echomarkread-example-1": "Marcar a notificación 8 coma lida",
+ "apihelp-echomarkread-example-2": "Marcar tódalas notificacións como lidas",
+ "apihelp-query+notifications-param-limit": "Número máximo de notifiacións a retornar.",
+ "apihelp-query+notifications-example-1": "Listar notificacións"
+}
diff --git a/Echo/i18n/gn.json b/Echo/i18n/gn.json
new file mode 100644
index 00000000..eb5d352e
--- /dev/null
+++ b/Echo/i18n/gn.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "P. S. F. Freitas"
+ ]
+ },
+ "echo-desc": "Maranduha reko",
+ "prefs-echo": "Maranduha",
+ "prefs-emailsettings": "E-mail jeporavo",
+ "prefs-displaynotifications": "Jehecha jeporavo",
+ "prefs-echosubscriptions": "Tomomarandu chéve kóva rehegua",
+ "prefs-newmessageindicator": "Momba'ukaha pyahu hechaukaha",
+ "echo-pref-send-me": "Chemombe'ukarãː",
+ "echo-pref-send-to": "Mombe'ukaː",
+ "echo-pref-email-format": "E-mail rekoː",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-format-html": "HTML",
+ "echo-no-agent": "[Mavave]",
+ "echo-no-title": "[Ndaipóri Kuatirogue]",
+ "notifications": "Maranduha",
+ "tooltip-pt-notifications": "Nde maranduha",
+ "echo-specialpage": "Maranduha",
+ "echo-none": "Nderereko maranduha pyahu.",
+ "echo-more-info": "Maranduve",
+ "echo-feedback": "Ñeimo'ã",
+ "notification-link-text-view-message": "Mombe'ukaha jehecha",
+ "notification-link-text-view-changes": "Ñemoambue jehecha",
+ "notification-link-text-view-page": "Kuatiarogue jehecha",
+ "notification-link-text-view-edit": "Jehaijey jehecha",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|omoĩ}} mombe'ukaha pyahu nde [[User talk:$2#$3|myangekõi kuatiápe]]."
+}
diff --git a/Echo/i18n/gom-deva.json b/Echo/i18n/gom-deva.json
new file mode 100644
index 00000000..c568131b
--- /dev/null
+++ b/Echo/i18n/gom-deva.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Darshan kandolkar"
+ ]
+ },
+ "tooltip-pt-notifications": "तुमच्यो अधिसुचोवण्यो"
+}
diff --git a/Echo/i18n/gu.json b/Echo/i18n/gu.json
new file mode 100644
index 00000000..16d1b696
--- /dev/null
+++ b/Echo/i18n/gu.json
@@ -0,0 +1,101 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dsvyas",
+ "KartikMistry",
+ "Rangilo Gujarati"
+ ]
+ },
+ "echo-desc": "સૂચના સિસ્ટમ",
+ "prefs-echo": "સૂચનાઓ",
+ "prefs-emailsettings": "ઈમેઇલ વિકલ્પો",
+ "prefs-displaynotifications": "પ્રદર્શન વિકલ્પો",
+ "prefs-echosubscriptions": "મને આ ઘટનાઓ વિશે જાણ કરવી",
+ "prefs-newmessageindicator": "નવો સંદેશ સૂચક",
+ "echo-pref-send-me": "મને મોકલો:",
+ "echo-pref-send-to": "આને મોકલો:",
+ "echo-pref-email-format": "ઈમેઇલ માળખું:",
+ "echo-pref-web": "વેબ",
+ "echo-pref-email": "ઈમેઇલ",
+ "echo-pref-email-frequency-never": "મને કોઈ ઈમેઇલ સૂચનાઓ ન મોકલવી",
+ "echo-pref-email-frequency-immediately": "વ્યક્તિગત સૂચનાઓ મોકલવી",
+ "echo-pref-email-frequency-daily": "સૂચનાઓનો દૈનિક સારાંશ",
+ "echo-pref-email-frequency-weekly": "સૂચનાઓનો સાપ્તાહિક સારાંશ",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "સાદું લખાણ",
+ "echo-pref-notify-show-link": "સૂચનાઓ મારી સાધનપટ્ટીમાં દેખાડવી",
+ "echo-pref-new-message-indicator": "ચર્ચા પાનાઓની સૂચનાઓ મારી સાધનપટ્ટીમાં દેખાડવી",
+ "echo-learn-more": "વધુ જાણો",
+ "echo-new-messages": "તમારા માટે નવા સંદેશાઓ છે",
+ "echo-category-title-edit-user-talk": "ચર્ચા પાનું {{PLURAL:$1|સંદેશ|સંદેશાઓ}}",
+ "echo-category-title-article-linked": "પાનું {{PLURAL:$1|કડી|કડીઓ}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|ઉલટાવેલ|ઉલટાવેલા}} ફેરફાર કરો",
+ "echo-category-title-mention": "{{PLURAL:$1|ઉલ્લેખ|ઉલ્લેખો}}",
+ "echo-category-title-other": "{{PLURAL:$1|અન્ય}}",
+ "echo-category-title-system": "{{PLURAL:$1|સિસ્ટમ}}",
+ "echo-pref-tooltip-edit-user-talk": "નવાં સંદેશા કે ચર્ચા પાનાનાં ફેરફાર પર મને સૂચન કરવું.",
+ "echo-pref-tooltip-article-linked": "જ્યારે કોઇ મારા દ્વારા બનાવવામાં આવેલ લેખને કોઈ જગ્યાએ જોડવામાં આવે ત્યારે મને જાણ કરવી.",
+ "echo-pref-tooltip-reverted": "જ્યારે કોઈ મારું સંપાદન રદ કરે કે કોઈ રોલબેક ઉપકરણ વાપરે ત્યારે મને જાણ કરવી.",
+ "echo-pref-tooltip-mention": "મારા સભ્ય પાનાને જ્યારે કોઈ જોડે ત્યારે મને જાણ કરવી.",
+ "echo-no-agent": "[કોઈ નહી]",
+ "echo-no-title": "[કોઈ પાનું નહી]",
+ "echo-error-no-formatter": "સૂચનાઓ માટે કોઈ માળખું નિયત નથી કર્યું.",
+ "echo-error-preference": "ભૂલ: સભ્ય પસંદગી સાચવી ન શક્યા.",
+ "echo-error-token": "ભૂલ: સભ્ય ટોકન શોધાયુ નહી.",
+ "notifications": "સૂચનાઓ",
+ "tooltip-pt-notifications": "તમારી સૂચનાઓ",
+ "echo-specialpage": "સૂચનાઓ",
+ "echo-anon": "સૂચનાઓ પ્રાપ્ત કરવા, [$1 નવું ખાતું ખોલો] અથવા [$2 પ્રવેશ કરો].",
+ "echo-none": "તમારા માટે કોઈ સૂચનાઓ નથી.",
+ "echo-more-info": "વધારે જાણકારી",
+ "echo-feedback": "અભિપ્રાય",
+ "notification-link-text-view-message": "સંદેશ જુઓ",
+ "notification-link-text-view-mention": "ઉલ્લેખ જુઓ",
+ "notification-link-text-view-changes": "ફેરફારો જુઓ",
+ "notification-link-text-view-page": "પાનું જુઓ",
+ "notification-link-text-view-edit": "ફેરફાર જુઓ",
+ "notification-edit-talk-page2": "[[User:$1|$1]]એ તમારાં [[User talk:$2#$3|ચર્ચા પાનાં]] પર સંદેશો {{GENDER:$1|છોડ્યો}} છે.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]]એ તમારા ચર્ચા પાનાંમાં \"[[User talk:$2#$3|$4]]\" પર સંદેશો {{GENDER:$1|છોડ્યો}} છે.",
+ "notification-edit-talk-page-flyout2": "$1એ તમારા [[User talk:$2#$3|ચર્ચા પાનાં]] પર સંદેશો {{GENDER:$1|છોડયો}} છે.",
+ "notification-edit-talk-page-flyout-with-section": "$1એ તમારા \"[[User talk:$2#$3|$4]]\" ચર્ચા પાનાં પર સંદેશો {{GENDER:$1|છોડયો}} છે.",
+ "notification-page-linked": "{{GENDER:$1|linked}} દ્વારા [[:$2]], [[:$3]] પર જોડવામાં આવેલું. [[Special:WhatLinksHere/$2|આ પાનાંને સમ્બોધતી બધી કડીઓ જુઓ]].",
+ "notification-page-linked-flyout": "[[:$2]]ને [[:$3]] સાથે {{GENDER:$1|જોડ્યું છે}}.",
+ "notification-add-comment2": "[[User:$1|$1]]એ \"$4\"નાં \"[[$3|$2]]\" પર {{GENDER:$1|સંદેશો છોડ્યો}}.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]]એ [[$3]] પર નવો વિશય \"$2\" {{GENDER:$1|ચાલૂ કર્યો}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]]એ તમને નવો સંદેશો {{GENDER:$1|મોકલ્યો}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]]એ \"[[$3#$2|$2]]\" પર {{GENDER:$1|ટીપ્પણી કરી}}.",
+ "notification-mention": "[[User:$1|$1]]એ $5નાં ચર્ચાનાં પાને \"[[:$3#$2|$4]]\"માં તમારો {{GENDER:$1|ઉલ્લેખ કર્યો છે}}.",
+ "notification-mention-flyout": "$1એ $5નાં ચર્ચાનાં પાને \"[[:$3#$2|$4]]\"માં તમારો {{GENDER:$1|ઉલ્લેખ કર્યો છે}}.",
+ "notification-user-rights-flyout": "તમારા સભ્ય હક્કો $1એ {{GENDER:$1|બદલ્યા}} છે. $2.\n[[Special:ListGroupRights|વધુ જાણો]]",
+ "notification-user-rights-add": "તમે હવે {{PLURAL:$2|આ જુથ|આ જુથો}}ના સભ્ય છો: $1",
+ "notification-user-rights-remove": "હવે તમે {{PLURAL:$2|આ જુથ|આ જુથો}}ના સભ્ય રહ્યા નથી: $1",
+ "notification-new-user": "$1 તમારું {{SITENAME}} પર સ્વાગત છે! તમને અહીં જોઇ અમે આનંદિત થયા છીએ.",
+ "notification-reverted2": "{{PLURAL:$4|[[:$2]] પરનો તમારો ફેરફાર|[[:$2]] પરના તમારા ફેરફારો}} [[User:$1|$1]]એ {{GENDER:$1|{{PLURAL|પાછો વાળ્યો|પાછા વાળ્યા}} છે}}. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|$2 પરનો તમારો ફેરફાર|$2 પરના તમારા ફેરફારો}} $1એ {{GENDER:$1|પૂર્વવત્}} કરેલ છે. $3",
+ "notification-edit-talk-page-email-subject2": "{{SITENAME}} પર તમારા માટે $1એ {{GENDER:$1|સંદેશો}} મૂક્યો છે.",
+ "notification-edit-talk-page-email-batch-body2": "$1એ તમારા ચર્ચાનાં પાને {{GENDER:$1|સંદેશો}} મૂક્યો છે:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1એ તમારા ચર્ચાનાં પાને ''$2'' હેઠળ તમારા માટે {{GENDER:$1|સંદેશો}} મૂક્યો છે.",
+ "notification-page-linked-email-subject": "તમારુ પાનાની કડી {{SITENAME}} પર જોડવામાં આવી",
+ "notification-page-linked-email-batch-body": "$2ને $3 સાથે {{GENDER:$1|જોડ્યું}} હતું,",
+ "notification-reverted-email-subject2": "{{SITENAME}} પર {{PLURAL:$3|તમારો ફેરફાર|તમારા ફેરફારો}} {{GENDER:$1|{{PLURAL|પાછો વાળ્યો|પાછા વાળ્યા}} છે}}.",
+ "notification-mention-email-subject": "$1એ {{SITENAME}} પર તમારો {{GENDER:$1|ઉલ્લેખ}} કર્યો છે.",
+ "notification-mention-nosection-email-batch-body": "$2 ચર્ચા પાનાં પર $1 એ તમારો {{GENDER:$1|ઉલ્લેખ}} કર્યો.",
+ "notification-user-rights-email-subject": "તમારાં {{SITENAME}} પરનાં અધિકારો બદલાયા છે.",
+ "notification-user-rights-email-batch-body": "તમારા સભ્ય અધિકારો {{GENDER:$1|દ્વારા}} બદલાવવમાં આવ્યા છે. $2",
+ "echo-email-subject-default": "{{SITENAME}} પર નવી સૂચના",
+ "echo-email-body-default": "તમારા માટે {{SITENAME}} પર નવી સૂચના છે:\n\n$1",
+ "echo-email-batch-body-default": "તમને નવો સંદેશ આવેલો છે",
+ "echo-overlay-link": "બધી સૂચનાઓ",
+ "echo-overlay-title": "<b>સૂચનાઓ</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|સુચનાઓ}}</b> ($2 પૈકીની નહિવાંચેલી $1 દર્શાવી છે)",
+ "echo-mark-all-as-read": "બધીને વાંચેલી તરીકે અંકિત કરો",
+ "echo-date-today": "આજે",
+ "echo-date-yesterday": "ગઈ કાલે",
+ "echo-load-more-error": "વધુ પરિણામો લાવતી વખતે ભૂલ આવી.",
+ "echo-email-batch-subject-daily": "તમારા માટે {{SITENAME}} પર {{PLURAL:$2|નવી સૂચના|નવી સૂચનાઓ}} છે.",
+ "echo-email-batch-subject-weekly": "આ અઠવાડીએ {{SITENAME}} પર તમારા માટે {{PLURAL:$2|નવી સુચના|નવી સુચનાઓ}} છે",
+ "echo-email-batch-body-intro-daily": "નમસ્કાર $1,\n{{SITENAME}} પર તમારી ક્રિયાઓનો આજનો સારાંશ આ પ્રમાણે છે.",
+ "echo-email-batch-body-intro-weekly": "નમસ્કાર $1,\n{{SITENAME}} પર તમારી ક્રિયાઓનો સાપ્તાહિક સારાંશ આ પ્રમાણે છે.",
+ "echo-email-batch-link-text-view-all-notifications": "બધાં સંદેશાઓ જુઓ",
+ "echo-rev-deleted-text-view": "આ પાનાંની આવૃત્તિ દબાવી દેવામાં આવી છે."
+}
diff --git a/Echo/i18n/haw.json b/Echo/i18n/haw.json
new file mode 100644
index 00000000..23174a12
--- /dev/null
+++ b/Echo/i18n/haw.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kolonahe"
+ ]
+ },
+ "echo-desc": "‘Ōnaehana notikala",
+ "prefs-echo": "Notikala",
+ "prefs-emailsettings": "Koho leka uila",
+ "prefs-displaynotifications": "Koho hō‘ike",
+ "prefs-newmessageindicator": "Hō‘ailona no nā memo hou",
+ "echo-pref-send-me": "Ho‘ouna ia‘u:",
+ "echo-pref-send-to": "Ho‘ouna iā:",
+ "echo-pref-email-format": "Hulu leka uila:",
+ "echo-pref-web": "Pūnaewele",
+ "echo-pref-email": "Leka uila",
+ "echo-pref-email-frequency-never": "Mai ho‘ouna ia‘u i nā leka uila notikala",
+ "echo-learn-more": "A‘o hou a‘e",
+ "echo-new-messages": "Loa‘a nā memo hou",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|memo|mau memo}} ‘ao‘ao kūkākūkā",
+ "echo-category-title-article-linked": "{{PLURAL:$1|loulou|mau loulou}} ‘ao‘ao",
+ "notifications": "Notikala",
+ "tooltip-pt-notifications": "Kāu notikala",
+ "echo-specialpage": "Notikala",
+ "echo-none": "‘A‘ohe notikala.",
+ "echo-more-info": "‘Ike ‘ē a‘e",
+ "notification-link-text-view-message": "Nānā memo"
+}
diff --git a/Echo/i18n/he.json b/Echo/i18n/he.json
new file mode 100644
index 00000000..42a560d8
--- /dev/null
+++ b/Echo/i18n/he.json
@@ -0,0 +1,125 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Guycn1",
+ "Guycn2",
+ "Inkbug",
+ "Orsa",
+ "Ypnypn",
+ "דולב",
+ "חיים",
+ "ערן"
+ ]
+ },
+ "echo-desc": "מערכת הודעות",
+ "prefs-echo": "הודעות",
+ "prefs-emailsettings": "אפשרויות דוא\"ל",
+ "prefs-displaynotifications": "אפשרויות תצוגה",
+ "prefs-echosubscriptions": "להודיע לי על האירועים הבאים",
+ "prefs-newmessageindicator": "סמן הודעות חדשות",
+ "echo-pref-send-me": "מה לשלוח לי:",
+ "echo-pref-send-to": "לשלוח אל:",
+ "echo-pref-email-format": "תסדיר דוא\"ל:",
+ "echo-pref-web": "באתר",
+ "echo-pref-email": "בדוא\"ל",
+ "echo-pref-email-frequency-never": "לא לשלוח לי שום הודעות בדואר אלקטרוני",
+ "echo-pref-email-frequency-immediately": "הודעות בודדות כשהן מגיעות",
+ "echo-pref-email-frequency-daily": "סיכום יומי של הודעות",
+ "echo-pref-email-frequency-weekly": "סיכום שבועי של הודעות",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "טקסט רגיל",
+ "echo-pref-notify-show-link": "להציג הודעות בסרגל שלי",
+ "echo-pref-new-message-indicator": "הצגת סמן הודעות דף שיחה בסרגל הכלים שלי",
+ "echo-learn-more": "מידע נוסף",
+ "echo-new-messages": "יש לך הודעות חדשות",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|הודעה|הודעות}} בדף שיחה",
+ "echo-category-title-article-linked": "{{PLURAL:$1|קישור לדף|קישורים לדפים}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|שחזור עריכה|שחזורי עריכות}}",
+ "echo-category-title-mention": "{{PLURAL:$1|אזכור|אזכורים}}",
+ "echo-category-title-other": "{{PLURAL:$1|אחר}}",
+ "echo-category-title-system": "{{PLURAL:$1|מערכת}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|שינוי|שינויים}} בהרשאות משתמש",
+ "echo-pref-tooltip-edit-user-talk": "להודיע לי כשמישהו כותב בדף השיחה שלי.",
+ "echo-pref-tooltip-article-linked": "להודיע לי כשמישהו מקשר לדף שיצרתי מדף אחר.",
+ "echo-pref-tooltip-reverted": "להודיע לי כשמישהו משחזר עריכה שעשיתי, באמצעות כלי הביטול או השחזור.",
+ "echo-pref-tooltip-mention": "להודיע לי כשמישהו מקשר לדף המשתמש שלי.",
+ "echo-pref-tooltip-user-rights": "להודיע לי כשמישהו משנה את הרשאות המשתמש שלי.",
+ "echo-no-agent": "[אף אחד]",
+ "echo-no-title": "[ללא דף]",
+ "echo-error-no-formatter": "לא הוגדר עיצוב להודעות.",
+ "echo-error-preference": "שגיאה: לא ניתן להגדיר העדפת משתמש.",
+ "echo-error-token": "שגיאה: לא ניתן לאחזר אסימון משתמש",
+ "notifications": "הודעות",
+ "tooltip-pt-notifications": "ההודעות שלך",
+ "echo-specialpage": "הודעות",
+ "echo-anon": "כדי לקבל הודעות, [$1 יש ליצור חשבון] או [$2 להיכנס].",
+ "echo-none": "אין לך הודעות.",
+ "echo-more-info": "מידע נוסף",
+ "echo-feedback": "משוב",
+ "notification-link-text-view-message": "הצגת הודעה",
+ "notification-link-text-view-mention": "הצגת אזכור",
+ "notification-link-text-view-changes": "הצגת שינויים",
+ "notification-link-text-view-page": "הצגת דף",
+ "notification-link-text-view-edit": "הצגת עריכה",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|כתב|כתבה}} ב[[User talk:$2#$3|דף השיחה]] שלך.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|כתב|כתבה}} בדף השיחה שלך הודעה תחת הכותרת '[[User talk:$2#$3|$4]]'.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|כתב|כתבה}} ב[[User talk:$2#$3|דף השיחה שלך]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|כתב|כתבה}} בדף השיחה שלך הודעה תחת הכותרת '[[User talk:$2#$3|$4]]'.",
+ "notification-page-linked": "{{GENDER:$1|נוסף קישור}} אל הדף [[:$2]] מהדף [[:$3]]. [[Special:WhatLinksHere/$2|כל הקישורים אל הדף הזה]].",
+ "notification-page-linked-flyout": "{{GENDER:$1|נוסף קישור}} אל הדף [[:$2]] מהדף [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|העיר|העירה}} על הנושא \"[[$3|$2]]\" בדף השיחה של \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|והוסיף|הוסיפה}} את נושא החדש \"$2\" לדף [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|שלח|שלחה}} לך הודעה: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|העיר|העירה}} על הנושא \"[[$3#$2|$2]]\" בדף השיחה שלך",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|הזכיר|הזכירה}} אותך בפסקה \"[[:$3#$2|$4]]\" בדף השיחה של $5.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|הזכיר|הזכירה}} אותך בפסקה \"[[:$3#$2|$4]]\" בדף השיחה של $5.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|הזכיר|הזכירה}} אותך ב[[:$3|דף השיחה $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|הזכיר|הזכירה}} אותך ב[[:$3|דף השיחה $2]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|שינה|שינתה}}]] את ההרשאות שלך. $2. [[Special:ListGroupRights|מידע נוסף]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|שינה|שינתה}} את ההרשאות שלך. $2. [[Special:ListGroupRights|מידע נוסף]]",
+ "notification-user-rights-add": "צורפת {{PLURAL:$2|לקבוצה הבאה|לקבוצות הבאות}}: $1",
+ "notification-user-rights-remove": "נמחקת {{PLURAL:$2|מהקבוצה הבאה|מהקבוצות הבאות}}: $1",
+ "notification-new-user": "ברוך בואך ל{{GRAMMAR:תחילית|{{SITENAME}}}}&rlm;, $1! אנחנו שמחים לראות אותך כאן.",
+ "notification-reverted2": "[[User:$1|$1]] {{GENDER:$1|ביטל|ביטלה}} {{PLURAL:$4|עריכה שלך|עריכות שלך}} בדף [[:$2]] $3",
+ "notification-reverted-flyout2": "$1 {{GENDER:$1|ביטל|ביטלה}} {{PLURAL:$4|עריכה שלך|עריכות שלך}} בדף $2 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|כתב|כתבה}} לך הודעה חדשה באתר {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|כתב|כתבה}} הודעה בדף השיחה שלך:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|כתב|כתבה}} בדף השיחה שלך הודעה תחת הכותרת '$2'.",
+ "notification-page-linked-email-subject": "מישהו קישר אל הדף שלך באתר {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|מישהו קישר|מישהי קישרה}} מהדף $3 אל הדף $2",
+ "notification-reverted-email-subject2": "$1 {{GENDER:$1|שחזר|שחזרה}} {{PLURAL:$3|עריכה שלך|עריכות שלך}} באתר {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|שחזר|שחזרה}} {{PLURAL:$3|עריכה שלך|עריכות שלך}} בדף $2",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|הזכיר|הזכירה}} אותך באתר {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|הזכיר|הזכירה}} אותך בדיון בדף השיחה של $4 בפסקה '$3'.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|הזכיר|הזכירה}} אותך בדף השיחה $2.",
+ "notification-user-rights-email-subject": "ההרשאות שלך באתר {{SITENAME}} שונו",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|שינה|שינתה}} את ההרשאות שלך. $2",
+ "echo-notification-count": "יותר מ־$1",
+ "echo-email-subject-default": "הודעה חדשה באתר {{SITENAME}}",
+ "echo-email-body-default": "יש לך הודעה חדשה באתר {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "יש לך הודעה חדשה.",
+ "echo-email-footer-default": "$2\n\nכדי לבחור אילו מכתבים נשלח לך, אפשר לשנות את ההעדפות שלך:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "כדי לשלוט בסוגי המכתבים שאנחנו שולחים לך <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">נא להתאים את ההעדפות שלך</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|התראות ($1)|100=התראות (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|הודעות ($1)|100=הודעות (99+)}}",
+ "echo-notification-alert-text-only": "התראות",
+ "echo-notification-message-text-only": "הודעות",
+ "echo-overlay-link": "כל ההודעות",
+ "echo-overlay-title": "<b>הודעות</b>",
+ "echo-overlay-title-overflow": "<b>הודעות</b> ({{PLURAL:$1|מוצגת אחת|מוצגות $1}} {{PLURAL:$2|שלא נקראה|מתוך $2 שלא נקראו}})",
+ "echo-mark-all-as-read": "לסמן שהכול נקרא",
+ "echo-date-today": "היום",
+ "echo-date-yesterday": "אתמול",
+ "echo-load-more-error": "אירעה שגיאה בעת אחזור תוצאות נוספות.",
+ "notification-edit-talk-page-bundle": "$1 ועוד {{PLURAL:$4|אדם אחד|$3 אנשים}} כתבו הודעות ב[[User talk:$2|דף השיחה]] שלך.",
+ "notification-page-linked-bundle": "אל הדף $2 {{GENDER:$1|נוסף קישור}} מהדף $3 ומעוד {{PLURAL:$5|דף|$4 דפים אחרים}}. [[Special:WhatLinksHere/$2|כל הקישורים אל הדף הזה]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 ועוד {{PLURAL:$3|אדם אחד|$2 אנשים}} כתבו הודעות בדף השיחה שלך.",
+ "notification-page-linked-email-batch-bundle-body": "אל הדף $2 {{GENDER:$1|נוסף קישור}} מהדף $3 ומעוד {{PLURAL:$5|דף|$4 דפים אחרים}}.",
+ "echo-email-batch-subject-daily": "קיבלת {{PLURAL:$2|הודעה חדשה|הודעות חדשות}} באתר {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "קיבלת {{PLURAL:$2|הודעה חדשה|הודעות חדשות}} השבוע באתר {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "שלום $1,\nלהלן תקציר של פעילויות שקשורות אליך באתר {{SITENAME}} היום.",
+ "echo-email-batch-body-intro-weekly": "שלום $1,\nלהלן תקציר של פעילויות שקשורות אליך באתר {{SITENAME}} השבוע.",
+ "echo-email-batch-link-text-view-all-notifications": "הצגת כל ההודעות",
+ "echo-rev-deleted-text-view": "הגרסה הזאת של הדף הועלמה."
+}
diff --git a/Echo/i18n/hi.json b/Echo/i18n/hi.json
new file mode 100644
index 00000000..4ba6a293
--- /dev/null
+++ b/Echo/i18n/hi.json
@@ -0,0 +1,115 @@
+{
+ "@metadata": {
+ "authors": [
+ "Akash.bhargude",
+ "Ansumang",
+ "Bill william compton",
+ "Hindustanilanguage",
+ "Shubhamkanodia",
+ "Siddhartha Ghai"
+ ]
+ },
+ "echo-desc": "अधिसूचना प्रणाली",
+ "prefs-echo": "अधिसूचनाएँ",
+ "prefs-emailsettings": "ईमेल विकल्प",
+ "prefs-displaynotifications": "प्रदर्शन विकल्प",
+ "prefs-echosubscriptions": "मुझे इन घटनाओं के बारे में सूचित करें",
+ "prefs-newmessageindicator": "नए संदेश का संकेतक",
+ "echo-pref-send-me": "मुझे भेजिए:",
+ "echo-pref-send-to": "यहाँ भेजिए:",
+ "echo-pref-email-format": "ईमेल प्रारूप:",
+ "echo-pref-web": "वेब",
+ "echo-pref-email": "ईमेल",
+ "echo-pref-email-frequency-never": "मुझे कोई भी ईमेल अधिसूचना मत भेजें",
+ "echo-pref-email-frequency-immediately": "अधिसूचनाएँ एक-एक कर के, जैसे-जैसे वे प्राप्त होती हैं",
+ "echo-pref-email-frequency-daily": "अधिसूचनाओं का दैनिक सारांश",
+ "echo-pref-email-frequency-weekly": "अधिसूचनाओं का साप्ताहिक सारांश",
+ "echo-pref-email-format-html": "एच॰टी॰एम॰एल॰",
+ "echo-pref-email-format-plain-text": "सादा पाठ",
+ "echo-pref-notify-show-link": "अधिसूचनाओं को मेरी उपकरण-पट्टी में दिखाएँ",
+ "echo-pref-new-message-indicator": "वार्ता पृष्ठ संदेश संकेतक मेरी उपकरण पट्टी में दिखाएँ",
+ "echo-learn-more": "अधिक जानिए",
+ "echo-new-messages": "आपके लिए नए संदेश हैं",
+ "echo-category-title-edit-user-talk": "वार्ता पृष्ठ {{PLURAL:$1| सन्देश}}",
+ "echo-category-title-article-linked": "पृष्ठ {{PLURAL:$1| कड़ी | कड़ियाँ}}",
+ "echo-category-title-reverted": "सम्पादन {{PLURAL:$1|पूर्ववत किये जाने की}}",
+ "echo-category-title-mention": "{{PLURAL:$1|उल्लेख}}",
+ "echo-category-title-other": "{{PLURAL:$1|अन्य}}",
+ "echo-category-title-system": "{{PLURAL:$1|प्रणाली}}",
+ "echo-pref-tooltip-edit-user-talk": "जब कोई मुझे संदेश भेजे या मेरे वार्ता पृष्ठ पर उत्तर दे तो मुझे सूचित करें।",
+ "echo-pref-tooltip-article-linked": "जब कोई मेरे द्वारा बनाए गए लेख की कड़ी कहीं जोड़े तो मुझे सूचित करें।",
+ "echo-pref-tooltip-reverted": "जब कोई मेरे किसी सम्पादन को पूर्ववत करे या वापस ले तो मुझे सूचित करें।",
+ "echo-pref-tooltip-mention": "जब कोई मेरे सदस्य पृष्ठ की कड़ी का किसी वार्ता पृष्ठ पर प्रयोग करे तो मुझे सूचित करें।",
+ "echo-no-agent": "[कोई नहीं]",
+ "echo-no-title": "[कोई पृष्ठ नहीं]",
+ "echo-error-no-formatter": "अधिसूचना के लिए कोई स्वरूपण परिभाषित नहीं है।",
+ "echo-error-preference": "त्रुटि: सदस्य पसंद निर्धारित नहीं की जा सकी।",
+ "echo-error-token": "त्रुटि: सदस्य टोकन प्राप्त नहीं किया जा सका।",
+ "notifications": "अधिसूचनाएँ",
+ "tooltip-pt-notifications": "आपकी अधिसूचनाएँ",
+ "echo-specialpage": "अधिसूचनाएँ",
+ "echo-anon": "अधिसूचनाएँ पाने के लिये, [$1 खाता बनाएँ] या [$2 लॉग इन करें]।",
+ "echo-none": "आपके लिये कोई अधिसूचना नहीं है।",
+ "echo-more-info": "अधिक जानकारी",
+ "echo-feedback": "आपके सुझाव",
+ "notification-link-text-view-message": "संदेश देखें",
+ "notification-link-text-view-mention": "उल्लेख देखें",
+ "notification-link-text-view-changes": "बदलाव देखें",
+ "notification-link-text-view-page": "पृष्ठ देखें",
+ "notification-link-text-view-edit": "सम्पादन देखें",
+ "notification-edit-talk-page2": "[[User:$1|$1]] ने आपके [[User talk:$2#$3|वार्ता पृष्ठ]] पर एक नया सन्देश {{GENDER:$1|छोड़ा}} है।",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] ने आपके वार्ता पृष्ठ पर \"[[User talk:$2#$3|$4]]\" भाग में एक नया सन्देश {{GENDER:$1|छोड़ा}} है।",
+ "notification-edit-talk-page-flyout2": "$1 ने आपके [[User talk:$2#$3|वार्ता पृष्ठ]] पर एक सन्देश {{GENDER:$1|छोड़ा}} है।",
+ "notification-edit-talk-page-flyout-with-section": "$1 ने आपके वार्ता पृष्ठ पर \"[[User talk:$2#$3|$4]]\" भाग में एक सन्देश {{GENDER:$1|छोड़ा}} है।",
+ "notification-page-linked": "[[:$3]] पर [[:$2]] की कड़ी {{GENDER:$1|जोड़ी}} गयी थी। [[Special:WhatLinksHere/$2|इस पृष्ठ से जुड़ने वाले सभी पृष्ठ देखें]]।",
+ "notification-page-linked-flyout": "[[:$3]] पर [[:$2]] की कड़ी {{GENDER:$1|जोड़ी}} गयी।",
+ "notification-add-comment2": "[[User:$1|$1]] ने \"$4\" वार्ता पृष्ठ पर \"[[$3|$2]]\" भाग में {{GENDER:$1|टिप्पणी की है}}।",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] ने [[$3]] पर \"$2\" विषय पर चर्चा शुरू {{GENDER:$1|की}} है।",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] ने आपको एक नया सन्देश {{GENDER:$1|भेजा}} है: \"[[$3#$2|$2]]\"।",
+ "notification-add-comment-yours2": "[[User:$1|$1]] ने आपके वार्ता पृष्ठ पर \"[[$3#$2|$2]]\" भाग में टिप्पणी की है।",
+ "notification-mention": "[[User:$1|$1]] ने $5 के वार्ता पृष्ठ पर \"[[:$3#$2|$4]]\" भाग में आपका उल्लेख {{GENDER:$1|किया}} है।",
+ "notification-mention-flyout": "$1 ने $5 के वार्ता पृष्ठ पर \"[[:$3#$2|$4]]\" भाग में आपका उल्लेख {{GENDER:$1|किया}} है।",
+ "notification-mention-nosection": "[[User:$1|$1]] ने [[:$3|$2 वार्ता पृष्ठ]] में आपका {{GENDER:$1|उल्लेख}} किया है।",
+ "notification-mention-nosection-flyout": "$1 ने [[:$3|$2 वार्ता पृष्ठ]] में आपका {{GENDER:$1|उल्लेख}} किया है।",
+ "notification-user-rights": "आपके सदस्य अधिकार [[User:$1|$1]] द्वारा [[Special:Log/rights/$1|{{GENDER:$1|बदले गये}}]]। $2। [[Special:ListGroupRights|अधिक जानिये]]",
+ "notification-user-rights-flyout": "आपके सदस्य अधिकार $1 द्वारा {{GENDER:$1|बदले गये}}। $2। [[Special:ListGroupRights|अधिक जानिये]]",
+ "notification-user-rights-add": "आप अब {{PLURAL:$2|इस समूह|इन समूहों}} के सदस्य हैं: $1",
+ "notification-user-rights-remove": "आप अब {{PLURAL:$2|इस समूह|इन समूहों}} के सदस्य नहीं रहे: $1",
+ "notification-new-user": "आपका {{SITENAME}} पर स्वागत है, $1! हमे ख़ुशी है आप यहाँ आये।",
+ "notification-reverted2": "[[:$2]] पर आपके {{PLURAL:$4|सम्पादन|सम्पादनों}} को [[User:$1|$1]] द्वारा {{GENDER:$1|पूर्ववत}} कर दिया गया है। $3",
+ "notification-reverted-flyout2": "$2 पर आपके {{PLURAL:$4|सम्पादन|सम्पादनों}} को $1 द्वारा {{GENDER:$1|पूर्ववत}} कर दिया गया है। $3",
+ "notification-edit-talk-page-email-subject2": "$1 ने आपके लिए {{SITENAME}} पर संदेश {{GENDER:$1|छोड़ा है}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 ने आपके वार्ता पृष्ठ पर संदेश {{GENDER:$1|छोड़ा है}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 ने आपके वार्ता पृष्ठ पर \"$2\" भाग में संदेश {{GENDER:$1|छोड़ा है}}।",
+ "notification-page-linked-email-subject": "आपका पृष्ठ {{SITENAME}} पर लिंक किया गया",
+ "notification-page-linked-email-batch-body": "$2 {{GENDER:$1|लिंक किया गया}} $3 से।",
+ "notification-reverted-email-subject2": "{{SITENAME}} पर आपके {{PLURAL:$3|सम्पादन|सम्पादनों}} को {{GENDER:$1|पूर्ववत}} किया गया।",
+ "notification-reverted-email-batch-body2": "$2 पर आपके {{PLURAL:$3|सम्पादन|सम्पादनों}} को $1 द्वारा {{GENDER:$1|पूर्ववत}} किया गया।",
+ "notification-mention-email-subject": "$1 ने {{SITENAME}} पर आपका {{GENDER:$1|उल्लेख}} किया",
+ "notification-mention-email-batch-body": "$1 ने $4 के वार्ता पृष्ठ पर \"$3\" भाग में आपका {{GENDER:$1|उल्लेख}} किया।",
+ "notification-mention-nosection-email-batch-body": "$1 ने $2 वार्ता पृष्ठ में आपका {{GENDER:$1|उल्लेख}} किया।",
+ "notification-user-rights-email-subject": "{{SITENAME}} पर आपके सदस्य अधिकार बदले गए हैं",
+ "notification-user-rights-email-batch-body": "आपके सदस्य अधिकार $1 द्वारा {{GENDER:$1|बदले गए}} हैं। $2।",
+ "echo-email-subject-default": "{{SITENAME}} पर नई अधिसूचना",
+ "echo-email-body-default": "आपके लिए {{SITENAME}} पर नई अधिसूचना है:\n\n$1",
+ "echo-email-batch-body-default": "आपके लिए नई अधिसूचना है।",
+ "echo-email-footer-default": "$2\n\nहमारी ओर से भेजे जाने वाले ईमेलों पर नियंत्रण करने के लिये कृपया अपनी पसन्द देखिए:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "हमारी ओर से भेजे जाने वाले ईमेलों पर नियंत्रण करने के लिये <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">अपनी पसन्द देखिए</a>।<br />\n\n$1",
+ "echo-overlay-link": "सभी अधिसूचनाएँ",
+ "echo-overlay-title": "<b>अधिसूचनाएँ</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|अधिसूचनाएँ}}</b>($2 अपठित में से $1 दिखाई जा रही हैं)",
+ "echo-mark-all-as-read": "सभी पढ़ी गयी चिन्हित करें",
+ "echo-date-today": "आज",
+ "echo-date-yesterday": "कल",
+ "echo-load-more-error": "अधिक परिणाम प्राप्त करते समय एक त्रुटि हुई।",
+ "notification-edit-talk-page-bundle": "$1 और $3 {{PLURAL:$4|अन्य}} ने आपके [[User talk:$2|वार्ता पृष्ठ]] पर सन्देश छोड़े हैं।",
+ "notification-page-linked-bundle": "$2 की कड़ी $3 और $4 अन्य {{PLURAL:$5|पृष्ठ|पृष्ठों}} पर {{GENDER:$1|जोड़ी}} गयी। [[Special:WhatLinksHere/$2|इस पृष्ठ से जुड़ने वाले सभी पृष्ठ देखें]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 और $2 {{PLURAL:$3|अन्य}} ने आपके वार्ता पृष्ठ पर सन्देश छोड़े हैं।",
+ "notification-page-linked-email-batch-bundle-body": "$2 की कड़ी $3 और $4 अन्य {{PLURAL:$5|पृष्ठ|पृष्ठों}} में {{GENDER:$1|जोड़ी}} गयी।",
+ "echo-email-batch-subject-daily": "आपके लिये {{SITENAME}} पर नई {{PLURAL:$2|अधिसूचना है|अधिसूचनाएँ हैं}}।",
+ "echo-email-batch-subject-weekly": "आपके लिये {{SITENAME}} पर इस सप्ताह नई {{PLURAL:$2|अधिसूचना है|अधिसूचनाएँ हैं}}।",
+ "echo-email-batch-body-intro-daily": "नमस्कार $1,\n{{SITENAME}} पर आज की गतिविधि का सारांश निम्न है।",
+ "echo-email-batch-body-intro-weekly": "नमस्कार $1,\n{{SITENAME}} पर इस सप्ताह की गतिविधि का सारांश निम्न है।",
+ "echo-email-batch-link-text-view-all-notifications": "सभी अधिसूचनाएँ देखें",
+ "echo-rev-deleted-text-view": "यह पृष्ठ अवतरण छिपा दिया गया है।"
+}
diff --git a/Echo/i18n/hr.json b/Echo/i18n/hr.json
new file mode 100644
index 00000000..d9f613f7
--- /dev/null
+++ b/Echo/i18n/hr.json
@@ -0,0 +1,93 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "MaGa",
+ "Roberta F."
+ ]
+ },
+ "echo-desc": "Sustav obavješćivanja",
+ "prefs-echo": "Obavijesti",
+ "prefs-emailsettings": "Mogućnosti elektroničke pošte",
+ "prefs-displaynotifications": "Opcije prikaza",
+ "prefs-echosubscriptions": "Obavijesti me o događajima",
+ "prefs-newmessageindicator": "Pokazivač novih poruka",
+ "echo-pref-send-me": "Pošalji mi:",
+ "echo-pref-send-to": "Pošalji:",
+ "echo-pref-email-format": "Oblik e-poruke:",
+ "echo-pref-web": "Mreža",
+ "echo-pref-email": "Elektronička pošta",
+ "echo-pref-email-frequency-never": "ne šalji mi nikakve obavijesti e-mailom",
+ "echo-pref-email-frequency-immediately": "pojedinačne obavijesti po redoslijedu",
+ "echo-pref-email-frequency-daily": "dnevni sažetak obavijesti",
+ "echo-pref-email-frequency-weekly": "tjedni sažetak obavijesti",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "obični tekst",
+ "echo-pref-notify-show-link": "Prikaži obavijesti na mojoj alatnoj vrpci",
+ "echo-pref-new-message-indicator": "Prikaži pokazivač poruka na stranici za razgovor na mojoj alatnoj traci",
+ "echo-learn-more": "Saznajte više",
+ "echo-new-messages": "Imate nove poruke",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Poruka}} na stranici za razgovor",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Poveznica|Poveznice|Poveznica}} na stranicu",
+ "echo-category-title-reverted": "Uklanjanje {{PLURAL:$1|uređivanja}}",
+ "echo-category-title-mention": "Spominjanja",
+ "echo-category-title-system": "{{PLURAL:$1|Sustav}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Promjena suradničkih prava}}",
+ "echo-pref-tooltip-edit-user-talk": "Obavijesti me kad netko snimi poruku ili odgovori na mojoj stranici za razgovor.",
+ "echo-pref-tooltip-article-linked": "Obavijesti me kad netko doda poveznicu na stranicu koju sam započeo.",
+ "echo-pref-tooltip-reverted": "Obavijesti me kad netko ukloni moje uređivanje.",
+ "echo-pref-tooltip-mention": "Obavijesti me kad netko doda poveznicu prema mojoj suradničkoj stranici s bilo koje razgovorne stranice.",
+ "echo-pref-tooltip-user-rights": "Obavijesti me kad netko promijeni moja suradnička prava.",
+ "echo-no-agent": "[Nitko]",
+ "echo-no-title": "[Nema stranice]",
+ "echo-error-preference": "Pogrješka: Nije moguće postaviti suradničke postavke.",
+ "notifications": "Obavijesti",
+ "tooltip-pt-notifications": "Vaše obavijesti",
+ "echo-specialpage": "Obavijesti",
+ "echo-anon": "Da biste primali obavijesti, [$1 otvorite račun] ili se [$2 prijavite].",
+ "echo-none": "Nemate obavijesti.",
+ "echo-more-info": "Više informacija",
+ "echo-feedback": "Povratna informacija",
+ "notification-link-text-view-message": "Pogledajte poruku",
+ "notification-link-text-view-mention": "Pogledaj spominjanja",
+ "notification-link-text-view-changes": "Prikaži promjene",
+ "notification-link-text-view-page": "Vidi stranicu",
+ "notification-link-text-view-edit": "Prikaži promjene",
+ "notification-edit-talk-page2": "[[User:$1|$1]] je {{GENDER:$1|ostavio|ostavila}} poruku na Vašoj [[User talk:$2#$3|razgovornoj stranici]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] je {{GENDER:$1|ostavio|ostavila}} poruku na Vašoj razgovornoj stranici \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 je {{GENDER:$1|ostavio|ostavila}} poruku na Vašoj [[User talk:$2#$3|razgovornoj stranici]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 je {{GENDER:$1|ostavio|ostavila}} poruku na Vašoj razgovornoj stranici u \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Članak [[:$2]] je {{GENDER:$1|povezan}} s člankom [[:$3]]. [[Special:WhatLinksHere/$2|Pogledajte što vodi prema ovom članku]].",
+ "notification-page-linked-flyout": "Članak [[:$2]] je {{GENDER:$1|povezan}} s člankom [[:$3]].",
+ "notification-mention": "[[User:$1|$1]] Vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $5, u odlomku [[:$3#$2|$4]].",
+ "notification-mention-flyout": "$1 Vas je {{GENDER:$1|spomenuo|spomenula}} na stranici za razgovor $5, u odlomku [[:$3#$2|$4]].",
+ "notification-user-rights": "Vaša suradnička prava [[Special:Log/rights/$1|{{GENDER:$1|promijenio|promijenila}}]] je {{GENDER:$1|suradnik|suradnica}} [[User:$1|$1]]. $2. [[Special:ListGroupRights|Saznajte više]]",
+ "notification-user-rights-add": "Sada ste član {{PLURAL:$2|sljedeće grupe|sljedećih grupa}}: $1",
+ "notification-reverted2": "{{PLURAL:$4|Vaše uređivanje na stranici [[:$2]]|Vaša uređivanja na stranici [[:$2]]}} {{GENDER:$1|uklonio je suradnik|uklonila je suradnica}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Vaše uređivanje na stranici $2|Vaša uređivanja na stranici $2}} {{GENDER:$1|uklonio je suradnik|uklonila je suradnica}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 Vam je {{GENDER:$1|ostavio|ostavila}} poruku na projektu {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 Vam je {{GENDER:$1|ostavio|ostavila}} poruku na Vašoj stranici za razgovor:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 je {{GENDER:$1|ostavio|ostavila}} poruku na Vašoj stranici za razgovor u odlomku \"$2\".",
+ "notification-page-linked-email-subject": "Na projektu {{SITENAME}} dodana je poveznica na Vaš članak",
+ "notification-page-linked-email-batch-body": "Članak $2 je {{GENDER:$1|povezan}} s člankom $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Vaša izmjena je {{GENDER:$1|uklonjena}}|Vaše izmjene su {{GENDER:$1|uklonjene}}}} na projektu {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Vaše uređivanje|Vaša uređivanja}} na stranici $2 {{GENDER:$1|uklonio je|uklonila je}} $1.",
+ "notification-mention-email-subject": "$1 Vas je {{GENDER:$1|spomenuo|spomenula}} na projektu {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 Vas je {{GENDER:$1|spomenuo|spomenula}} na stranici za razgovor $4, u odlomku $3.",
+ "notification-user-rights-email-subject": "Vaša suradnička prava su promijenjena na projektu {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Vaša suradnička prava {{GENDER:$1|promijenio|promijenila}} je $1. $2.",
+ "echo-email-batch-body-default": "Imate novu poruku.",
+ "echo-email-footer-default": "$2\n\nUkoliko želite prilagoditi primanje e-pošte, prilagodite svoje postavke:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Ukoliko želite prilagoditi primanje e-pošte, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">prilagodite svoje postavke</a>.<br />\n$1",
+ "echo-overlay-link": "Sve obavijesti",
+ "echo-overlay-title": "<b>Obavijesti</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Obavijesti}}</b> (prikazano $1 od $2 {{PLURAL:$1|nepročitana|nepročitane|nepročitanih}})",
+ "echo-mark-all-as-read": "Označi sve pročitanim",
+ "echo-date-today": "Danas",
+ "echo-date-yesterday": "Jučer",
+ "notification-edit-talk-page-bundle": "$1 i još $3 {{PLURAL:$4|suradnik|suradnika}} {{GENDER:$1|ostavili}} su poruku na Vašoj [[User talk:$2|stranici za razgovor]].",
+ "notification-page-linked-bundle": "Članak $2 je {{GENDER:$1|povezan}} s člankom $3 i još $4 {{PLURAL:$5|člankom|članka|članaka}}. [[Special:WhatLinksHere/$2|Pogledajte što vodi prema ovom članku]].",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 i još $2 {{PLURAL:$3|suradnik|suradnika}} {{GENDER:$1|ostavili}} su poruku na Vašoj stranici za razgovor.",
+ "notification-page-linked-email-batch-bundle-body": "Članak $2 je {{GENDER:$1|povezan}} s člankom $3 i još $4 {{PLURAL:$5|člankom|članka|članaka}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Prikaži sve obavijesti"
+}
diff --git a/Echo/i18n/hsb.json b/Echo/i18n/hsb.json
new file mode 100644
index 00000000..a5d7b4ea
--- /dev/null
+++ b/Echo/i18n/hsb.json
@@ -0,0 +1,113 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "echo-desc": "Zdźělenski system",
+ "prefs-echo": "Zdźělenki",
+ "prefs-emailsettings": "E-mejlowe nastajenja",
+ "prefs-displaynotifications": "Zwobraznjenske opcije",
+ "prefs-echosubscriptions": "Mje wo tutych podawkach informować",
+ "prefs-newmessageindicator": "Nowy powěsćowy indikator",
+ "echo-pref-send-me": "Pósćel mi:",
+ "echo-pref-send-to": "Pósłać na:",
+ "echo-pref-email-format": "E-mejlowy format:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mejl",
+ "echo-pref-email-frequency-never": "Njepósćel mi e-mejlowe zdźělenki",
+ "echo-pref-email-frequency-immediately": "Indiwiduelne zdźělenki kaž dochadźeja",
+ "echo-pref-email-frequency-daily": "Wšědny přehlad zdźělenkow",
+ "echo-pref-email-frequency-weekly": "Tydźenski přehlad zdźělenkow",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Luty tekst",
+ "echo-pref-notify-show-link": "Zdźělenki w symbolowej lajsće pokazać",
+ "echo-pref-new-message-indicator": "Powěsćowy indikator diskusijneje strony w symbolowej lajsće pokazać",
+ "echo-learn-more": "Dalše informacije",
+ "echo-new-messages": "Maš nowe powěsće",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Powěsć|Powěsći|Powěsće|Powěsćow}} na diskusijnej stronje",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Wotkaz|Wotkazaj|Wotkazy}} strony",
+ "echo-category-title-reverted": "{{PLURAL:$1|Cofnjenje|Cofnjeni|Cofnjenja}} změnow",
+ "echo-category-title-mention": "{{PLURAL:$1|Naspomnjenje|Naspomnjeni|Naspomnjenja}}",
+ "echo-category-title-other": "{{PLURAL:$1|Druha|Druhej|Druhe}}",
+ "echo-category-title-system": "{{PLURAL:$1|System|Systemaj|Systemy}}",
+ "echo-pref-tooltip-edit-user-talk": "Informuj mje, hdyž něchtó powěsć abo wotmołwu na mojej diskusijnej stronje zawostaja.",
+ "echo-pref-tooltip-article-linked": "Informuj mje, hdyž něchtó na stronu wotkazuje, kotruž sym z nastawka wutworił.",
+ "echo-pref-tooltip-reverted": "Informuj mje, hdyž něchtó z pomocu cofnjenja abo nastroja změnu anuluje, kotruž sym činił.",
+ "echo-pref-tooltip-mention": "Informuj mje, hdyž něchtó z někajkeje diskusijneje strony k mojej wužiwarskej stronje wotkazuje.",
+ "echo-no-agent": "[Nichtó]",
+ "echo-no-title": "[Žana strona]",
+ "echo-error-no-formatter": "Za zdźělenje njeje so formatowanje definowało.",
+ "echo-error-preference": "Zmylk: Wužiwarske nastajenje njeda so stajić.",
+ "echo-error-token": "Zmylk: Wužiwarski token njeda so wotwołać.",
+ "notifications": "Zdźělenki",
+ "tooltip-pt-notifications": "Twoje zdźělenki",
+ "echo-specialpage": "Zdźělenki",
+ "echo-anon": "Zo by zdźělenki dóstał, dyrbiš [$1 konto załožić] abo [$2 so přizjewić].",
+ "echo-none": "Nimaš zdźělenki.",
+ "echo-more-info": "Dalše informacije",
+ "echo-feedback": "Komentary",
+ "echo-quotation-marks": "\"$1\"",
+ "notification-link-text-view-message": "Powěsć pokazać",
+ "notification-link-text-view-mention": "Naspomnjenje pokazać",
+ "notification-link-text-view-changes": "Změny pokazać",
+ "notification-link-text-view-page": "Stronu pokazać",
+ "notification-link-text-view-edit": "Změnu pokazać",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|zawostaji}} powěsć na twojej [[User talk:$2#$3|diskusijnej stronje]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|zawostaji}} powěsć na twojej diskusijnej stronje w \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|zawostaji}} powěsć na twojej [[User talk:$2#$3|diskusijnej stronje]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|zawostaji}} powěsć na twojej diskusijnej stronje w \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] je so wot [[:$3]] {{GENDER:$1|wotkazał|wotkazała}}. [[Special:WhatLinksHere/$2|Wšě wotkazy k tutej stronje pokazać]].",
+ "notification-page-linked-flyout": "[[:$2]] je so wot [[:$3]] {{GENDER:$1|wotkazał}}.",
+ "notification-add-comment2": "[[User:$1|$1]] je na \"[[$3|$2]]\" na diskusijnej stronje \"$4\" {{GENDER:$1|komentował|komentowała}}.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] je nowu temu \"$2\" na [[$3]] {{GENDER:$1|startował|startowała}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] je ći powěsć {{GENDER:$1|pósłał|pósłała}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] je na \"[[$3#$2|$2]]\" na twojej diskusijnej stronje {{GENDER:$1|komentował|komentowała}}.",
+ "notification-mention": "[[User:$1|$1]] je će na diskusijnej stronje $5 w \"[[:$3#$2|$4]]\" {{GENDER:$1|naspomnił|naspomniła}}.",
+ "notification-mention-flyout": "$1 je će na diskusijnej stronje $5 w \"[[:$3#$2|$4]]\" {{GENDER:$1|naspomnił|naspomniła}}.",
+ "notification-mention-nosection": "[[User:$1|$1]] je će na [[:$3|diskusijnej stronje $2]] {{GENDER:$1|naspomnił|naspomniła}}.",
+ "notification-mention-nosection-flyout": "$1 je će na [[:$3|diskusijnej stronje $2]] {{GENDER:$1|naspomnił|naspomniła}}.",
+ "notification-user-rights": "Twoje wužiwarske prawa [[Special:Log/rights/$1|su so wot [[User:$1|$1]] {{GENDER:$1|změnili}}]] . $2. [[Special:ListGroupRights|Dalše informacije]]",
+ "notification-user-rights-flyout": "Twoje wužiwarske prawa su so wot $1 {{GENDER:$1|změnili}}. $2. [[Special:ListGroupRights|Dalše informacije]]",
+ "notification-user-rights-add": "Sy nětko čłon {{PLURAL:$2|tuteje skupiny|tuteju skupinow|tutych skupinow}}: $1",
+ "notification-user-rights-remove": "Njejsy hižo čłon {{PLURAL:$2|tuteje skupiny|tuteju skupinow|tutych skupinow}}: $1",
+ "notification-new-user": "Witaj do {{GRAMMAR:genitiw|{{SITENAME}}}}, $1! Wjeselimy so, zo sy tu.",
+ "notification-reverted2": "[[User:$1|$1]] je {{PLURAL:$4|změnu na [[:$2]]|změnje na [[:$2]]|změny na [[:$2]]}} {{GENDER:$1|anulował|anulowała}}. $3",
+ "notification-reverted-flyout2": "$1 je {{PLURAL:$4|změnu na $2|změnje na $2|změny na $2}} {{GENDER:$1|anulował|anulowała}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 je ći powěsć na {{GRAMMAR:lokatiw|{{SITENAME}}}} {{GENDER:$1|zawostajił|zawostajiła}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 je powěsć na twojej diskusijnej stronje {{GENDER:$1|zawostajił|zawostajiła}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 je powěsć wo \"$2\" na twojej diskusijnej stronje {{GENDER:$1|zawostajił|zawostajiła}}.",
+ "notification-page-linked-email-subject": "Twoja strona je so na {{GRAMMAR:lokatiw|{{SITENAME}}}} wotkazała.",
+ "notification-page-linked-email-batch-body": "$2 je so z $3 {{GENDER:$1|wotkazał}}.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Twoja změna je|Twojej změnje stej|Twoje změny su}} so na {{GRAMMAR:lokatiw|{{SITENAME}}}}{{GENDER:$1|{{PLURAL:$3|anulowała|anulowałoj|anulowali}}}}",
+ "notification-reverted-email-batch-body2": "$1 je {{PLURAL:$3|twoju změnu na $2|twojej změnje na $2|twoje změny na $2}} {{GENDER:$1|anulował|anulowała}}.",
+ "notification-mention-email-subject": "$1 je će na {{GRAMMAR:lokatiw|{{SITENAME}}}} {{GENDER:$1|naspomnił|naspomniła}}",
+ "notification-mention-email-batch-body": "$1 je će na diskusijnej stronje $4 w \"$3\" {{GENDER:$1|naspomnił|naspomniła}}.",
+ "notification-mention-nosection-email-batch-body": "$1 je će na diskusijnej stronje $2 {{GENDER:$1|naspomnił|naspomniła}}.",
+ "notification-user-rights-email-subject": "Twoje wužiwarske prawa su so na {{GRAMMAR:lokatiw|{{SITENAME}}}} změnili",
+ "notification-user-rights-email-batch-body": "Twoje wužiwarske prawa su so wot $1 {{GENDER:$1|změnili}}. $2",
+ "echo-notification-count": "$1+",
+ "echo-email-subject-default": "Nowa zdźělenka na {{GRAMMAR:lokatiw|{{SITENAME}}}}",
+ "echo-email-body-default": "Maš nowu zdźělenku na {{GRAMMAR:lokatiw|{{SITENAME}}}}:\n\n$1",
+ "echo-email-batch-body-default": "Maš nowu powěsć.",
+ "echo-email-footer-default": "$2\n\nZo by kontrolował, kotre e-mejle ći sćelemy, přepruwuj swoje nastajenja:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Zo by kontrolował, kotre e-mejle ći sćelemy, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">přepruwuj swoje nastajenja</a>.<br />\n$1",
+ "echo-overlay-link": "Wšě zdźělenki",
+ "echo-overlay-title": "<b>Zdźělenki</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Zdźělenka|Zdźělence|Zdźělenki}}</b> ($1 z $2 {{PLURAL:$2|njepřitaneje|njepřečitaneju|njepřečitanych}} so {{PLURAL:$1|pokazuje|pokazujetej|pokazuja|pokazuje}})",
+ "echo-mark-all-as-read": "Wšě jako přečitane markěrować",
+ "echo-date-today": "Dźensa",
+ "echo-date-yesterday": "Wčera",
+ "echo-load-more-error": "Při wobstarowanju dalšich wuslědkow je zmylk wustupił.",
+ "notification-edit-talk-page-bundle": "$1 a {{PLURAL:$4|dalši wužiwar je|$3 dalšej wužiwarjej stej|$3 dalši wužiwarjo su|$3 dalšich wužiwarjow je}} powěsć na twojej [[User talk:$2|diskusijnej stronje]] {{PLURAL:$4|zawostajił|zawostajiłoj|zawostajili|zawostajiło}}.",
+ "notification-page-linked-bundle": "$2 je so z $3 a {{PLURAL:$5|jedneje dalšeje strony|$4 dalšeju stronow|$4 dalšich stronow}} {{GENDER:$1|wotkazał}}. [[Special:WhatLinksHere/$2|Wšě wotkazy k tutej stronje pokazać]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 a {{PLURAL:$3|dalši wužiwar staj|$2 dalšej wužiwarjej su|$2 dalši wužiwarjo su|dalšich wužiwarjow su}} powěsć na twojej diskusijnej stronje {{GENDER:$1|zawostajiłoj|zawostajili}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2 je so wot $3 a {{PLURAL:$5|jedneje dalšeje strony|$4 dalšeju stronow|$4 dalšich stronow}} {{GENDER:$1|wotkazał}}.",
+ "echo-email-batch-bullet": "•",
+ "echo-email-batch-subject-daily": "Maš {{PLURAL:$2|nowu zdźělenku|nowej zdźělence|nowe zdźělenki}} na {{GRAMMAR:lokatiw|{{SITENAME}}}}",
+ "echo-email-batch-subject-weekly": "Maš {{PLURAL:$2|nowu zdźělenku|nowej zdźělence|nowe zdźělenki}} na {{GRAMMAR:lokatiw|{{SITENAME}}}} tutón tydźeń",
+ "echo-email-batch-body-intro-daily": "Witaj $1,\n\ntu je zjeće dźensnišich aktiwitow na {{GRAMMAR:lokatiw|{{SITENAME}}}} za tebje.",
+ "echo-email-batch-body-intro-weekly": "Witja $1,\n\ntu je zjeće aktiwitow z tutoho tydźenja na {{GRAMMAR:lokatiw|{{SITENAME}}}} za tebje.",
+ "echo-email-batch-link-text-view-all-notifications": "Wšě zdźělenki pokazać",
+ "echo-rev-deleted-text-view": "Tuta wersija strony je so potłóčiła."
+}
diff --git a/Echo/i18n/hu.json b/Echo/i18n/hu.json
new file mode 100644
index 00000000..78adcd50
--- /dev/null
+++ b/Echo/i18n/hu.json
@@ -0,0 +1,122 @@
+{
+ "@metadata": {
+ "authors": [
+ "BáthoryPéter",
+ "Dj",
+ "Misibacsi",
+ "TK-999",
+ "Tgr",
+ "Tacsipacsi",
+ "Samat"
+ ]
+ },
+ "echo-desc": "Értesítési rendszer",
+ "prefs-echo": "Értesítések",
+ "prefs-emailsettings": "E-mail beállítások",
+ "prefs-displaynotifications": "Megjelenítési beállítások",
+ "prefs-echosubscriptions": "Értesítést kérek ezekről az eseményekről",
+ "prefs-newmessageindicator": "Új üzenet jelzése",
+ "echo-pref-send-me": "Gyakoriság:",
+ "echo-pref-send-to": "Erre a címre:",
+ "echo-pref-email-format": "A levél formátuma:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Egyáltalán ne küldjön e-mail értesítést",
+ "echo-pref-email-frequency-immediately": "Küldjön külön értesítést minden eseményről",
+ "echo-pref-email-frequency-daily": "Küldjön napi összefoglalót az értesítésekről",
+ "echo-pref-email-frequency-weekly": "Küldjön heti összefoglalót az értesítésekről",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Sima szöveg",
+ "echo-pref-notify-show-link": "Mutassa az értesítéseket a lap tetején lévő menüben",
+ "echo-pref-new-message-indicator": "Jelezze a vitalapi üzeneteket a lap tetején lévő menüben",
+ "echo-learn-more": "Tudj meg többet",
+ "echo-new-messages": "Új üzeneted van",
+ "echo-category-title-edit-user-talk": "vitalapi {{PLURAL:$1|üzenet|üzenetek}}",
+ "echo-category-title-article-linked": "hivatkozott {{PLURAL:$1|lap|lapok}}",
+ "echo-category-title-reverted": "visszaállított {{PLURAL:$1|szerkesztés|szerkesztések}}",
+ "echo-category-title-mention": "{{PLURAL:$1|említés|említések}}",
+ "echo-category-title-other": "{{PLURAL:$1|Más}}",
+ "echo-category-title-system": "{{PLURAL:$1|rendszerüzenet|rendszerüzenetek}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Felhasználói jogok változása|Felhasználói jogok változásai}}",
+ "echo-pref-tooltip-edit-user-talk": "Értesítést kérek, ha valaki üzen vagy válaszol a vitalapomon.",
+ "echo-pref-tooltip-article-linked": "Értesítést kérek, ha valaki hivatkozik egy általam írt szócikkre egy másik cikkben.",
+ "echo-pref-tooltip-reverted": "Értesítést kérek, ha valaki visszaállítja egy szerkesztésemet.",
+ "echo-pref-tooltip-mention": "Értesítést kérek, ha valaki hivatkozik a felhasználói lapomra.",
+ "echo-pref-tooltip-user-rights": "Értesítést kérek, ha valaki megváltoztatja a felhasználói jogaimat.",
+ "echo-no-agent": "[Senki]",
+ "echo-no-title": "[Nincs lap]",
+ "echo-error-no-formatter": "Nincs értesítési formátum definiálva",
+ "echo-error-preference": "Hiba: Nem sikerült elmenteni a felhasználói beállítást",
+ "echo-error-token": "Hiba: nem sikerült lekérni a felhasználói tokent",
+ "notifications": "Értesítések",
+ "tooltip-pt-notifications": "Értesítéseid",
+ "echo-specialpage": "Értesítések",
+ "echo-anon": "Értesítések fogadásához [$1 hozz létre egy fiókot] vagy [$2 jelentkezz be].",
+ "echo-none": "Nincsenek értesítéseid.",
+ "echo-more-info": "További információ",
+ "echo-feedback": "Visszajelzés",
+ "notification-link-text-view-message": "Üzenet mutatása",
+ "notification-link-text-view-mention": "Említés mutatása",
+ "notification-link-text-view-changes": "Változások mutatása",
+ "notification-link-text-view-page": "Lap mutatása",
+ "notification-link-text-view-edit": "Szerkesztés mutatása",
+ "notification-edit-talk-page2": "[[User:$1|$1]] üzenetet hagyott [[User talk:$2#$3|a vitalapodon]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] üzenetet hagyott a vitalapodon „[[User talk:$2#$3|$4]]” címmel.",
+ "notification-edit-talk-page-flyout2": "$1 üzenetet hagyott [[User talk:$2#$3|a vitalapodon]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 üzenetet hagyott a vitalapodon „[[User talk:$2#$3|$4]]” címmel.",
+ "notification-page-linked": "A(z) [[:$2]] szócikkedre {{GENDER:$1|hivatkoztak}} a(z) [[:$3]] cikkben. [[Special:WhatLinksHere/$2|Kilistázhatod az összes hivatkozást a szócikkre]].",
+ "notification-page-linked-flyout": "A(z) [[:$2]] szócikkedre {{GENDER:$1|hivatkoztak}} a(z) [[:$3]] cikkben.",
+ "notification-add-comment2": "[[User:$1|$1]] hozzászólt a(z) „[[$3|$2]]” témához a(z) „$4” vitalapon",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] új témát kezdett „$2” néven a(z) [[$3]] lapon.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] üzenetet küldött neked: „[[$3#$2|$2]]”",
+ "notification-add-comment-yours2": "[[User:$1|$1]] hozzászólt a „[[$3#$2|$2]]” témához a vitalapodon",
+ "notification-mention": "[[User:$1|$1]] megemlített téged $5 vitalapján a(z) „[[:$3#$2|$4]]” szakaszban.",
+ "notification-mention-flyout": "$1 megemlített téged $5 vitalapján a(z) „[[:$3#$2|$4]]” szakaszban.",
+ "notification-mention-nosection": "[[User:$1|$1]] megemlített téged [[:$3|$2 vitalapján]].",
+ "notification-mention-nosection-flyout": "$1 megemlített téged [[:$3|$2 vitalapján]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|megváltoztatta a jogosultságaidat]]. $2. [[Special:ListGroupRights|Információ a jogosultságokról]]",
+ "notification-user-rights-flyout": "$1 megváltoztatta a jogosultságaidat. $2. [[Special:ListGroupRights|Információ a jogosultságokról]]",
+ "notification-user-rights-add": "Tagja lettél {{PLURAL:$2|ennek a csoportnak|ezeknek a csoportoknak}}: $1",
+ "notification-user-rights-remove": "Kikerültél {{PLURAL:$2|ebből a csoportból|ezekből a csoportokból}}: $1",
+ "notification-new-user": "Kedves $1! Üdvözlünk a {{SITENAME}} oldalon. Örülünk, hogy csatlakoztál hozzánk.",
+ "notification-reverted2": "[[User:$1|$1]] visszavonta a {{PLURAL:$4|szerkesztésedet|szerkesztéseidet}} a(z) [[:$2]] cikkben. $3",
+ "notification-reverted-flyout2": "$1 visszavonta a {{PLURAL:$4|szerkesztésedet|szerkesztéseidet}} a(z) $2 cikkben. $3",
+ "notification-edit-talk-page-email-subject2": "$1 üzenetet hagyott neked a(z) {{SITENAME}} wikin",
+ "notification-edit-talk-page-email-batch-body2": "$1 üzenetet hagyott a vitalapodon:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 üzenetet hagyott a vitalapodon a(z) „$2” szakaszban.",
+ "notification-page-linked-email-subject": "Hivatkoztak egy általad létrehozott oldalra a(z) {{SITENAME}} wikin",
+ "notification-page-linked-email-batch-body": "A(z) $2 lapra {{GENDER:$1|hivatkoztak}} a(z) $3 lapról.",
+ "notification-reverted-email-subject2": "Visszavonták a {{PLURAL:$3|szerkesztésedet|szerkesztéseidet}} a(z) {{SITENAME}} wikin",
+ "notification-reverted-email-batch-body2": "$1 visszavonta a {{PLURAL:$3|szerkesztésedet|szerkesztéseidet}} a(z) $2 oldalon.",
+ "notification-mention-email-subject": "$1 említett téged a(z) {{SITENAME}} wikin",
+ "notification-mention-email-batch-body": "$1 említett téged $4 vitalapján a(z) „$3” szakaszban.",
+ "notification-mention-nosection-email-batch-body": "$1 megemlített téged $2 vitalapján.",
+ "notification-user-rights-email-subject": "Megváltoztak a jogosultságaid a(z) {{SITENAME}} wikin",
+ "notification-user-rights-email-batch-body": "$1 megváltoztatta a jogosultságaidat. $2",
+ "echo-email-subject-default": "Új értesítés a(z) {{SITENAME}} wikin",
+ "echo-email-body-default": "Új értesítést kaptál a(z) {{SITENAME}} wikin:\n\n$1",
+ "echo-email-batch-body-default": "Új értesítést kaptál.",
+ "echo-email-footer-default": "$2\n\nA beállításaidnál módosíthatod, mikor küldjünk e-mailt:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "<a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">A beállításaidnál</a> módosíthatod, mikor küldjünk e-mailt.<br />\n$1",
+ "echo-notification-alert": "Értesítések ({{PLURAL:$1|1|$1|100=99+}})",
+ "echo-notification-message": "Üzenetek ({{PLURAL:$1|1|$1|100=99+}})",
+ "echo-notification-alert-text-only": "Értesítések",
+ "echo-notification-message-text-only": "Üzenetek",
+ "echo-overlay-link": "Összes értesítés",
+ "echo-overlay-title": "<b>Értesítéseim</b>",
+ "echo-overlay-title-overflow": "<b>Értesítéseim</b> ($2 olvasatlanból $1 mutatva)",
+ "echo-mark-all-as-read": "Összes olvasottnak jelölése",
+ "echo-date-today": "Ma",
+ "echo-date-yesterday": "Tegnap",
+ "echo-load-more-error": "Hiba történt a további eredmények lekérdezése során.",
+ "notification-edit-talk-page-bundle": "$1 és még {{PLURAL:$4|egy|$3}} szerkesztő üzenetet hagyott [[User talk:$2|a vitalapodon]].",
+ "notification-page-linked-bundle": "A(z) $2 lapra {{GENDER:$1|hivatkoztak}} a(z) $3 lapról és {{PLURAL:$5|egy|még $4}} másikról. [[Special:WhatLinksHere/$2|Kilistázhatod az összes hivatkozást a szócikkre]].",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 és {{PLURAL:$3|egy másik|még $2}} szerkesztő üzenetet hagyott a vitalapodon.",
+ "notification-page-linked-email-batch-bundle-body": "A(z) $2 lapra {{GENDER:$1|hivatkoztak}} a(z) $3 lapról és {{PLURAL:$5|egy|még $4}} másikról",
+ "echo-email-batch-subject-daily": "Új {{PLURAL:$2|értesítést|értesítéseket}} kaptál a(z) {{SITENAME}} wikin",
+ "echo-email-batch-subject-weekly": "A héten új {{PLURAL:$2|értesítést|értesítéseket}} kaptál a(z) {{SITENAME}} wikin",
+ "echo-email-batch-body-intro-daily": "Kedves $1,\nösszefoglaltuk, mi történt ma a(z) {{SITENAME}} wikin.",
+ "echo-email-batch-body-intro-weekly": "Kedves $1,\nösszefoglaltuk, mi történt a héten a(z) {{SITENAME}} wikin.",
+ "echo-email-batch-link-text-view-all-notifications": "Nézd meg az összes értesítést",
+ "echo-rev-deleted-text-view": "Ezt a lapváltozatot elrejtették."
+}
diff --git a/Echo/i18n/hy.json b/Echo/i18n/hy.json
new file mode 100644
index 00000000..6751e226
--- /dev/null
+++ b/Echo/i18n/hy.json
@@ -0,0 +1,78 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xelgen",
+ "Lilitik22",
+ "Դավիթ Սարոյան"
+ ]
+ },
+ "echo-desc": "Ծանուցումների համակարգ",
+ "prefs-echo": "Ծանուցումներ",
+ "prefs-emailsettings": "Էլ․ փոստի կարգավորումներ",
+ "prefs-displaynotifications": "Ցուցադրման կարգավորումներ",
+ "prefs-echosubscriptions": "Ծանուցել հետևյալ դեպքերում",
+ "prefs-newmessageindicator": "Նոր ուղերձների ցուցիչ։",
+ "echo-pref-send-me": "Ուղարկել ինձ․",
+ "echo-pref-send-to": "Ուղարկել․",
+ "echo-pref-email-format": "Նամակի ձևաչափ․",
+ "echo-pref-web": "Ոստայն",
+ "echo-pref-email": "Էլ. փոստ",
+ "echo-pref-email-frequency-never": "Չուղարկել ինձ ծանուցումներ էլ․ փոստով",
+ "echo-pref-email-frequency-immediately": "Առանձին ծանուցումներ հայտնվելուն պես",
+ "echo-pref-email-frequency-daily": "Ծանուցումների օրական ամփոփում",
+ "echo-pref-email-frequency-weekly": "Ծանուցումների շաբաթական ամփոփում",
+ "echo-pref-email-format-html": "ԷյչԹիԷմԷլ",
+ "echo-pref-email-format-plain-text": "Պարզ տեքստ",
+ "echo-pref-notify-show-link": "Ցուցադրել ծանուցումները իմ վահանակում",
+ "echo-pref-new-message-indicator": "Ցուցադրել քննարկման էջի հաղորդագրությունների ցուցիչը իմ վահանակում",
+ "echo-learn-more": "Իմանալ ավելին",
+ "echo-new-messages": "Դուք նոր ուղերձներ ունեք",
+ "echo-category-title-edit-user-talk": "Քննարկման էջում {{PLURAL:$1|ուղերձ|ուղերձներ}}",
+ "echo-category-title-article-linked": "Էջի {{PLURAL:$1|հղում|հղումներ}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|1=Խմբագրման|Խմբագրումների}} հետ շրջում",
+ "echo-category-title-mention": "{{PLURAL:$1|Նշում|Նշումներ}}",
+ "echo-category-title-other": "{{PLURAL:$1|Այլ}}",
+ "echo-category-title-system": "{{PLURAL:$1|Համակարգ}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Մասնակցի իրավունքի փոփոխություն|Մասնակցի իրավունքի փոփոխություններ}}",
+ "echo-pref-tooltip-edit-user-talk": "Տեղեկացնել ինձ, երբ ինչ-որ մեկը իմ քննարկման էջում պատասխանում կամ թողնում է հաղորդագրություն:",
+ "echo-no-agent": "[Ոչ ոք]",
+ "echo-no-title": "[Էջը չկա]",
+ "notifications": "Ծանուցումներ",
+ "tooltip-pt-notifications": "Ձեր ծանուցումները",
+ "echo-specialpage": "Ծանուցումներ",
+ "echo-anon": "Ծանուցումներ ստանալու համար [$1 ստեղծեք հաշիվ] կամ [$2 մուտք գործեք]։",
+ "echo-none": "Դուք ծանուցումներ չունեք։",
+ "echo-more-info": "Մանրամասն",
+ "echo-feedback": "Հետադարձ կապ",
+ "notification-link-text-view-message": "Դիտել ուղերձը",
+ "notification-link-text-view-mention": "Դիտել հիշատակումը",
+ "notification-link-text-view-changes": "Դիտել փոփոխությունները",
+ "notification-link-text-view-page": "Դիտել էջը",
+ "notification-link-text-view-edit": "Դիտել խմբագրումը",
+ "notification-edit-talk-page2": "[[User:$1|$1]] մասնակիցը հաղորդագրություն է {{GENDER:$1|թողել}} [[User talk:$2#$3|Ձեր քննարկման էջում]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] մասնակիցը հաղորդագրություն է թողել Ձեր քննարկման էջի «[[User talk:$2#$3|$4]]» բաժնում:",
+ "notification-edit-talk-page-flyout2": "$1 մասնակիցը հաղորդագրություն է թողել Ձեր [[User talk:$2#$3|քննարկման էջում]]:",
+ "notification-edit-talk-page-flyout-with-section": "$1 մասնակիցը հաղորդագրություն է թողել Ձեր քննարկման էջի \"[[User talk:$2#$3|$4]]\" բաժնում:",
+ "notification-page-linked": "[[:$2]] {{GENDER:$1|հղվել է}} [[:$3]] հոդվածից: [[Special:WhatLinksHere/$2|Տեսնել այս էջին հղվող բոլոր հոդվածները]].",
+ "notification-page-linked-flyout": "[[:$2]] {{GENDER:$1|հղվել է}} [[:$3]] հոդվածից:",
+ "notification-add-comment2": "[[User:$1|$1]] մասնակիցը {{GENDER:$1|մեկնաբանել է}} \"$4\" քննարկման էջի \"[[$3|$2]]\" բաժնում:",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] մասնակիցը [[$3]] էջում {{GENDER:$1|ավելացրել է}} \"$2\" անվամբ բաժին:",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] մասնակիցը \"[[$3#$2|$2]]\" բաժնում Ձեզ {{GENDER:$1|ուղարկել է}} նոր հաղորդագրություն:",
+ "notification-add-comment-yours2": "[[User:$1|$1]] մասնակիցը {{GENDER:$1|մեկնաբանել}} է ձեր քննարկման էջի «[[$3#$2|$2]]» բաժնում։",
+ "notification-mention": "[[User:$1|$1]] մասնակիցը {{GENDER:$1|հիշատակել}} է Ձեզ, $5 էջի «[[:$3#$2|$4]]» բաժնում։",
+ "notification-mention-flyout": "$1 մասնակիցը {{GENDER:$1|հիշատակել}} է Ձեզ $5 քննարկման էջի «[[:$3#$2|$4]]» բաժնում։",
+ "notification-new-user": "Բարի՛ գալուստ {{SITENAME}}, $1։ Ուրախ ենք տեսնել Ձեզ այստեղ։",
+ "echo-email-subject-default": "Նոր ծանուցումներ {{SITENAME}} կայքից։",
+ "echo-email-body-default": "Դուք ունեք նոր ծանուցումներ «{{SITENAME}}» կայքից:\n\n$1",
+ "echo-email-batch-body-default": "Դուք ունեք նոր ծանուցում։",
+ "echo-notification-alert-text-only": "Ծանուցումներ",
+ "echo-notification-message-text-only": "Հողորդագրություններ",
+ "echo-overlay-link": "Բոլոր ծանուցումները",
+ "echo-overlay-title": "<b>Ծանուցումներ</b>",
+ "echo-mark-all-as-read": "Ամենը ընթերցված նշել",
+ "echo-date-today": "Այսօր",
+ "echo-date-yesterday": "Երեկ",
+ "notification-edit-talk-page-bundle": "$1 և $3 {{PLURAL:$4|այլ}} մասնկից հաղորդագրություն են {{GENDER:$1|թողել}} Ձեր [[User talk:$2|քննարկման էջում]]։",
+ "echo-email-batch-link-text-view-all-notifications": "Դիտել բոլոր ծանուցումները",
+ "echo-rev-deleted-text-view": "Էջի այս խմբագրումը թաքցված է։"
+}
diff --git a/Echo/i18n/ia.json b/Echo/i18n/ia.json
new file mode 100644
index 00000000..deda545a
--- /dev/null
+++ b/Echo/i18n/ia.json
@@ -0,0 +1,110 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "echo-desc": "Systema de notificationes",
+ "prefs-echo": "Notificationes",
+ "prefs-emailsettings": "Optiones de e-mail",
+ "prefs-displaynotifications": "Optiones de presentation",
+ "prefs-echosubscriptions": "Notificar me de iste eventos",
+ "prefs-newmessageindicator": "Indicator de nove messages",
+ "echo-pref-send-me": "Inviar me:",
+ "echo-pref-send-to": "Inviar a:",
+ "echo-pref-email-format": "Formato de e-mail:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Non inviar me notificationes in e-mail",
+ "echo-pref-email-frequency-immediately": "Notificationes individual al momento de cata occurrentia",
+ "echo-pref-email-frequency-daily": "Un summario quotidian de notificationes",
+ "echo-pref-email-frequency-weekly": "Un summario septimanal de notificationes",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Texto simple",
+ "echo-pref-notify-show-link": "Monstrar notificationes in mi instrumentario",
+ "echo-pref-new-message-indicator": "Monstrar indicator de message in pagina de discussion in mi instrumentario",
+ "echo-learn-more": "Leger plus",
+ "echo-new-messages": "Tu ha nove messages",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Message|Messages}} del pagina de discussion",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Ligamine|Ligamines}} a un pagina",
+ "echo-category-title-reverted": "{{PLURAL:$1|Modification|Modificationes}} revertite",
+ "echo-category-title-mention": "{{PLURAL:$1|Mention|Mentiones}}",
+ "echo-category-title-other": "{{PLURAL:$1|Altere|Alteres}}",
+ "echo-category-title-system": "{{PLURAL:$1|Systema|Systemas}}",
+ "echo-pref-tooltip-edit-user-talk": "Notificar me quando alcuno scribe o responde in mi pagina de discussion",
+ "echo-pref-tooltip-article-linked": "Notificar me quando alcuno insere in un pagina de articulo un ligamine a un pagina que io ha create.",
+ "echo-pref-tooltip-reverted": "Notificar me quando alcuno reverte un modification que io ha facite per medio de \"disfacer\" o \"revocar\".",
+ "echo-pref-tooltip-mention": "Notificar me quando alcuno insere un ligamine a mi pagina de usator in alcun pagina de discussion.",
+ "echo-no-agent": "[Nemo]",
+ "echo-no-title": "[Nulle pagina]",
+ "echo-error-no-formatter": "Nulle formato definite pro notification",
+ "echo-error-preference": "Error: Impossibile definir le preferentia de usator",
+ "echo-error-token": "Error: Impossibile recuperar le indicio de usator",
+ "notifications": "Notificationes",
+ "tooltip-pt-notifications": "Tu notificationes",
+ "echo-specialpage": "Notificationes",
+ "echo-anon": "Pro reciper notificationes, [$1 crea un conto] o [$2 aperi session].",
+ "echo-none": "Tu non ha notificationes.",
+ "echo-more-info": "Plus info",
+ "echo-feedback": "Commentario",
+ "notification-link-text-view-message": "Vider message",
+ "notification-link-text-view-mention": "Vider mention",
+ "notification-link-text-view-changes": "Vider modificationes",
+ "notification-link-text-view-page": "Vider pagina",
+ "notification-link-text-view-edit": "Vider modification",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|lassava}} un message in tu [[User talk:$2#$3|pagina de discussion]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] te lassava un message in tu pagina de discussion sub \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 te lassava un message in tu [[User talk:$2#$3|pagina de discussion]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 te lassava un message in tu pagina de discussion sub \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Un ligamine a [[:$2]] ha essite {{GENDER:$1|inserite}} in [[:$3]]. [[Special:WhatLinksHere/$2|Vider tote le ligamines a iste pagina]].",
+ "notification-page-linked-flyout": "Un ligamine a [[:$2]] ha essite {{GENDER:$1|inserite}} in [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] commentava \"[[$3|$2]]\" in le pagina de discussion \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|ha comenciate}} un nove discussion \"$2\" in [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] te {{GENDER:$1|ha inviate}} un message: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|ha commentate}} \"[[$3#$2|$2]]\" in tu pagina de discussion.",
+ "notification-mention": "[[User:$1|$1]] te {{GENDER:$1|ha mentionate}} in le pagina de discussion de $5 in \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 te {{GENDER:$1|ha mentionate}} in le pagina de discussion de $5 in \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] te {{GENDER:$1|mentionava}} in le [[:$3|$2 pagina de discussion]].",
+ "notification-mention-nosection-flyout": "$1 te {{GENDER:$1|mentionava}} in le [[:$3|$2 pagina de discussion]].",
+ "notification-user-rights": "Tu derectos de usator [[Special:Log/rights/$1|ha essite {{GENDER:$1|cambiate}}]] per [[User:$1|$1]]. $2. [[Special:ListGroupRights|Leger plus]]",
+ "notification-user-rights-flyout": "Tu derectos de usator ha essite {{GENDER:$1|cambiate}} per $1. $2. [[Special:ListGroupRights|Leger plus]]",
+ "notification-user-rights-add": "Tu es ora membro de iste {{PLURAL:$2|gruppo|gruppos}}: $1",
+ "notification-user-rights-remove": "Tu non plus es membro de iste {{PLURAL:$2|gruppo|gruppos}}: $1",
+ "notification-new-user": "Benvenite a {{SITENAME}}, $1! Nos es felice de vider te hic.",
+ "notification-reverted2": "Tu {{PLURAL:$4|modification|modificationes}} de [[:$2]] ha essite {{GENDER:$1|revertite}} per [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Tu {{PLURAL:$4|modification|modificationes}} de $2 ha essite {{GENDER:$1|revertite}} per $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 te {{GENDER:$1|ha lassate}} un message in {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|ha lassate}} un message in tu pagina de discussion:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|ha lassate}} un message in tu pagina de discussion in \"$2\".",
+ "notification-page-linked-email-subject": "Un ligamine a tu pagina ha essite inserite in {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Un ligamine a $2 ha essite {{GENDER:$1|inserite}} in $3.",
+ "notification-reverted-email-subject2": "Tu {{PLURAL:$3|modification|modificationes}} ha essite {{GENDER:$1|revertite}} in {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "Tu {{PLURAL:$3|modification|modificationes}} de $2 ha essite {{GENDER:$1|revertite}} per $1.",
+ "notification-mention-email-subject": "$1 te {{GENDER:$1|ha mentionate}} in {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 te {{GENDER:$1|ha mentionate}} in le pagina de discussion de $4 in \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 te {{GENDER:$1|mentionava}} in le pagina de discussion de $2.",
+ "notification-user-rights-email-subject": "Tu derectos de usator ha cambiate in {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Tu derectos de usator ha essite {{GENDER:$1|cambiate}} per $1. $2",
+ "echo-email-subject-default": "Nove notification in {{SITENAME}}",
+ "echo-email-body-default": "Tu ha un nove notification in {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Tu ha un nove notification.",
+ "echo-email-footer-default": "$2\n\nPro seliger le e-mails que nos te invia, controla tu preferentias:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Pro seliger le e-mails que nos te invia, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">controla tu preferentias</a>.<br />\n$1",
+ "echo-overlay-link": "Tote le notificationes",
+ "echo-overlay-title": "<b>Notificationes</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notificationes}}</b> ($1 monstrate de $2 non legite)",
+ "echo-mark-all-as-read": "Marcar toto como legite",
+ "echo-date-today": "Hodie",
+ "echo-date-yesterday": "Heri",
+ "echo-load-more-error": "Un error ha occurrite durante le obtention de altere resultatos.",
+ "notification-edit-talk-page-bundle": "$1 e $3 {{PLURAL:$4|altere|alteres}} {{GENDER:$1|ha lassate}} un message in tu [[User talk:$2|pagina de discussion]].",
+ "notification-page-linked-bundle": "Ligamines a $2 ha essite {{GENDER:$1|inserite}} in $3 e $4 altere {{PLURAL:$5|pagina|paginas}}. [[Special:WhatLinksHere/$2|Vider tote le ligamines a iste pagina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e $2 {{PLURAL:$3|altere|alteres}} {{GENDER:$1|ha lassate}} un message in tu pagina de discussion.",
+ "notification-page-linked-email-batch-bundle-body": "Un ligamine a $2 ha essite {{GENDER:$1|inserite}} in $3 e $4 altere {{PLURAL:$5|pagina|paginas}}.",
+ "echo-email-batch-subject-daily": "Tu ha {{PLURAL:$2|un nove notification|nove notificationes}} in {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Tu ha {{PLURAL:$2|un nove notification|nove notificationes}} in {{SITENAME}} iste septimana",
+ "echo-email-batch-body-intro-daily": "Salute $1,\nEcce un summario del activitate de hodie in {{SITENAME}} pro te.",
+ "echo-email-batch-body-intro-weekly": "Salute $1,\nEcce un summario del activitate de iste septimana in {{SITENAME}} pro te.",
+ "echo-email-batch-link-text-view-all-notifications": "Vider tote le notificationes",
+ "echo-rev-deleted-text-view": "Iste version del pagina ha essite supprimite."
+}
diff --git a/Echo/i18n/id.json b/Echo/i18n/id.json
new file mode 100644
index 00000000..d87c1da5
--- /dev/null
+++ b/Echo/i18n/id.json
@@ -0,0 +1,139 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Farras",
+ "William Surya Permana",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "echo-desc": "Sistem pemberitahuan",
+ "prefs-echo": "Pemberitahuan",
+ "prefs-emailsettings": "Opsi surel",
+ "prefs-displaynotifications": "Opsi tampilan",
+ "prefs-echosubscriptions": "Beritahu saya mengenai peristiwa berikut",
+ "prefs-newmessageindicator": "Penanda pesan baru",
+ "echo-pref-send-me": "Kirimi saya:",
+ "echo-pref-send-to": "Kirimkan ke:",
+ "echo-pref-email-format": "Format surel:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Surel",
+ "echo-pref-email-frequency-never": "Jangan kirimi saya pemberitahuan surel apapun",
+ "echo-pref-email-frequency-immediately": "Pemberitahuan tunggal setiap suatu peristiwa terjadi",
+ "echo-pref-email-frequency-daily": "Ringkasan harian dari beberapa pemberitahuan",
+ "echo-pref-email-frequency-weekly": "Ringkasan mingguan dari beberapa pemberitahuan",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Teks polos",
+ "echo-pref-notify-show-link": "Tampilkan pemberitahuan di bilah alat saya",
+ "echo-pref-new-message-indicator": "Tampilkan penanda pesan halaman pembicaraan pada bilah alat saya",
+ "echo-learn-more": "Pelajari selengkapnya",
+ "echo-new-messages": "Anda memiliki pesan baru",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Pesan}} halaman pembicaraan",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Pranala}} halaman",
+ "echo-category-title-reverted": "{{PLURAL:$1|Pembalikan}} suntingan",
+ "echo-category-title-mention": "{{PLURAL:$1|Sebutan}}",
+ "echo-category-title-other": "{{PLURAL:$1|Lainnya}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Perubahan hak pengguna}}",
+ "echo-pref-tooltip-edit-user-talk": "Beritahu saya saat seseorang mengirimkan pesan atau balasan pada halaman pembicaraan saya.",
+ "echo-pref-tooltip-article-linked": "Beritahu saya saat seseorang membuat pranala di halaman artikel ke sebuah halaman yang pernah saya rintis.",
+ "echo-pref-tooltip-reverted": "Beritahu saya saat seseorang membalikkan suntingan yang pernah saya buat, dengan menggunakan alat batalkan atau balikkan.",
+ "echo-pref-tooltip-mention": "Beritahu saya saat seseorang membuat pranala menuju halaman pengguna saya.",
+ "echo-pref-tooltip-user-rights": "Beritahu saya saat seseorang mengubah hak pengguna saya.",
+ "echo-no-agent": "[Tidak seorang pun]",
+ "echo-no-title": "[Tidak ada halaman]",
+ "echo-error-no-formatter": "Tidak ada pemformatan yang ditetapkan untuk pemberitahuan.",
+ "echo-error-preference": "Galat: Tidak dapat menetapkan preferensi pengguna.",
+ "echo-error-token": "Galat: Tidak dapat mengambil token pengguna.",
+ "notifications": "Pemberitahuan",
+ "tooltip-pt-notifications": "Pemberitahuan Anda",
+ "echo-specialpage": "Pemberitahuan",
+ "echo-anon": "Untuk menerima pemberitahuan, [$1 buat sebuah akun] atau [$2 masuk log].",
+ "echo-none": "Anda tidak memiliki pemberitahuan.",
+ "echo-more-info": "Informasi selengkapnya",
+ "echo-feedback": "Umpan balik",
+ "echo-quotation-marks": "\"$1\"",
+ "notification-link-text-view-message": "Lihat pesan",
+ "notification-link-text-view-mention": "Lihat sebutan",
+ "notification-link-text-view-changes": "Lihat perubahan",
+ "notification-link-text-view-page": "Lihat halaman",
+ "notification-link-text-view-edit": "Lihat suntingan",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|meninggalkan}} sebuah pesan pada [[User talk:$2#$3|halaman pembicaraan]] Anda.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda di [[User talk:$2#$3|$4]].",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan pada [[User talk:$2#$3|halaman pembicaraan]] Anda.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda di [[User talk:$2#$3|$4]].",
+ "notification-page-linked": "Pranala ke [[:$2]] {{GENDER:$1|ditambahkan}} di [[:$3]]. [[Special:WhatLinksHere/$2|Lihat semua pranala balik ke halaman ini]].",
+ "notification-page-linked-flyout": "Pranala ke [[:$2]] {{GENDER:$1|ditambahkan}} di [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|mengomentari}} \"[[$3|$2]]\" pada halaman pembicaraan \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|mengirimkan}} sebuah topik baru \"$2\" di [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|mengirimi}} Anda sebuah pesan: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|mengomentari}} \"[[$3#$2|$2]]\" pada halaman pembicaraan Anda.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|menyebut}} Anda di \"[[:$3#$2|$4]]\" pada halaman pembicaraan $5.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|menyebut}} Anda di \"[[:$3#$2|$4]]\" pada halaman pembicaraan $5.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|menyebut}} Anda pada [[:$3|halaman pembicaraan $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|menyebut}} Anda pada [[:$3|halaman pembicaraan $2]].",
+ "notification-user-rights": "Hak pengguna Anda [[Special:Log/rights/$1|telah {{GENDER:$1|diubah}}]] oleh [[User:$1|$1]]. $2. [[Special:ListGroupRights|Pelajari selengkapnya]]",
+ "notification-user-rights-flyout": "Hak pengguna Anda telah {{GENDER:$1|diubah}} oleh $1. $2. [[Special:ListGroupRights|Pelajari selengkapnya]]",
+ "notification-user-rights-add": "Anda sekarang adalah anggota dari {{PLURAL:$2|kelompok berikut}}: $1",
+ "notification-user-rights-remove": "Anda tidak lagi menjadi anggota dari {{PLURAL:$2|kelompok berikut}}: $1",
+ "notification-new-user": "Selamat datang di {{SITENAME}}, $1! Kami senang Anda hadir di sini.",
+ "notification-reverted2": "{{PLURAL:$4|Suntingan Anda pada [[:$2]] telah}} {{GENDER:$1|dibalikkan}} oleh [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Suntingan Anda pada $2 telah}} {{GENDER:$1|dibalikkan}} oleh $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|meninggalkan}} Anda sebuah pesan di {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan di \"$2\" pada halaman pembicaraan Anda.",
+ "notification-page-linked-email-subject": "Pranala ke halaman Anda ditambahkan di {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Pranala ke $2 {{GENDER:$1|ditambahkan}} di $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Suntingan}} Anda telah {{GENDER:$1|dibalikkan}} di {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|suntingan Anda pada $2 telah}} {{GENDER:$1|dibalikkan}} oleh $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|menyebut}} Anda di {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|menyebut}} Anda di \"$3\" pada halaman pembicaraan $4.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|menyebut}} Anda pada halaman pembicaraan $2.",
+ "notification-user-rights-email-subject": "Hak pengguna Anda telah diubah di {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Hak pengguna Anda telah {{GENDER:$1|diubah}} oleh $1. $2.",
+ "echo-email-subject-default": "Pemberitahuan baru di {{SITENAME}}",
+ "echo-email-body-default": "Anda memiliki pemberitahuan baru di {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Anda memiliki pemberitahuan baru.",
+ "echo-email-footer-default": "$2\n\nUntuk mengendalikan surel mana saja yang akan kami kirimkan kepada Anda, periksa preferensi Anda:\n{{canonicalurl: {{#special:Preferences}} #mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Untuk mengendalikan surel mana saja yang akan kami kirimkan kepada Anda, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">periksa preferensi Anda</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Penanda ($1)|100=Penanda (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Pesan ($1)|100=Pesan (99+)}}",
+ "echo-notification-alert-text-only": "Penanda",
+ "echo-notification-message-text-only": "Pesan",
+ "echo-overlay-link": "Semua pemberitahuan",
+ "echo-overlay-title": "<b>Pemberitahuan</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Pemberitahuan}}</b> (menampilkan $1 dari $2 yang belum dibaca)",
+ "echo-mark-all-as-read": "Tandai semua sebagai telah dibaca",
+ "echo-date-today": "Hari ini",
+ "echo-date-yesterday": "Kemarin",
+ "echo-load-more-error": "Terjadi galat saat mengambil hasil selengkapnya.",
+ "notification-edit-talk-page-bundle": "$1 dan $3 pengguna {{PLURAL:$4|lainnya}} {{GENDER:$1|meninggalkan}} sebuah pesan pada [[User talk:$2|halaman pembicaraan]] Anda.",
+ "notification-page-linked-bundle": "Pranala ke $2 {{GENDER:$1|ditambahkan}} di $3 dan $4 {{PLURAL:$5|halaman}} lainnya. [[Special:WhatLinksHere/$2|Lihat semua pranala balik ke halaman ini]].",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 dan $2 pengguna {{PLURAL:$3|lainnya}} {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda.",
+ "notification-page-linked-email-batch-bundle-body": "Pranala ke $2 {{GENDER:$1|ditambahkan}} di $3 dan $4 {{PLURAL:$5|halaman}} lainnya.",
+ "echo-email-batch-subject-daily": "Anda memiliki {{PLURAL:$2|sebuah|beberapa}} pemberitahuan baru di {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Anda memiliki {{PLURAL:$2|sebuah|beberapa}} pemberitahuan baru di {{SITENAME}} pekan ini",
+ "echo-email-batch-body-intro-daily": "Hai $1,\nIni adalah ringkasan aktivitas kegiatan hari ini di {{SITENAME}} untuk Anda.",
+ "echo-email-batch-body-intro-weekly": "Hai $1,\nIni adalah ringkasan aktivitas kegiatan pekan ini di {{SITENAME}} untuk Anda.",
+ "echo-email-batch-link-text-view-all-notifications": "Tampilkan semua pemberitahuan",
+ "echo-rev-deleted-text-view": "Revisi halaman ini telah ditekan.",
+ "apihelp-echomarkread-description": "Tandai pemberitahuan dari pengguna ini sebagai telah dibaca.",
+ "apihelp-echomarkread-param-list": "Daftar ID pemberitahuan yang ingin ditandai sebagai telah dibaca.",
+ "apihelp-echomarkread-param-all": "Jika ditetapkan, menandai semua pemberitahuan pengguna sebagai telah dibaca.",
+ "apihelp-echomarkread-param-sections": "Daftar bagian yang ingin ditandai sebagai telah dibaca.",
+ "apihelp-echomarkread-example-1": "Tandai pemberitahuan 8 sebagai telah dibaca",
+ "apihelp-echomarkread-example-2": "Tandai semua pemberitahuan sebagai telah dibaca",
+ "apihelp-query+notifications-description": "Dapatkan penungguan pemberitahuan untuk pengguna ini.",
+ "apihelp-query+notifications-param-prop": "Rincian yang diminta.",
+ "apihelp-query+notifications-param-sections": "Bagian pemberitahuan yang ingin didapatkan.",
+ "apihelp-query+notifications-param-groupbysection": "Menentukan apakah perlu mengelompokkan hasil berdasarkan bagian. Jika ditetapkan, setiap bagian diambil secara terpisah.",
+ "apihelp-query+notifications-param-format": "Jika ditetapkan, pemberitahuan akan menghasilkan format seperti ini.",
+ "apihelp-query+notifications-param-limit": "Jumlah maksimum pemberitahuan yang dihasilkan.",
+ "apihelp-query+notifications-param-index": "Jika ditetapkan, daftar ID pemberitahuan akan dihasilkan, secara berurutan.",
+ "apihelp-query+notifications-param-alertcontinue": "Saat ada lebih banyak hasil penanda yang tersedia, gunakan ini untuk melanjutkan.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Menentukan apakah harus menampilkan pemberitahuan pesan yang belum dibaca terlebih dahulu.",
+ "apihelp-query+notifications-param-messagecontinue": "Saat ada lebih banyak hasil pesan yang tersedia, gunakan ini untuk melanjutkan.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Menentukan apakah harus menampilkan pemberitahuan penanda terlebih dahulu.",
+ "apihelp-query+notifications-example-1": "Daftar pemberitahuan",
+ "apihelp-query+notifications-example-2": "Daftar pemberitahuan, dikelompokkan berdasarkan bagian, dengan jumlah"
+}
diff --git a/Echo/i18n/ig.json b/Echo/i18n/ig.json
new file mode 100644
index 00000000..348138a2
--- /dev/null
+++ b/Echo/i18n/ig.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ukabia"
+ ]
+ },
+ "echo-date-today": "Ta",
+ "echo-date-yesterday": "Nnyáfụ̀"
+}
diff --git a/Echo/i18n/ilo.json b/Echo/i18n/ilo.json
new file mode 100644
index 00000000..a001166c
--- /dev/null
+++ b/Echo/i18n/ilo.json
@@ -0,0 +1,112 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lam-ang"
+ ]
+ },
+ "echo-desc": "Sistema dagiti pakaammo",
+ "prefs-echo": "Dagiti pakaammo",
+ "prefs-emailsettings": "Pagpilian ti esurat",
+ "prefs-displaynotifications": "Ipakita dagiti pagpilian",
+ "prefs-echosubscriptions": "Pakammuannak ti maipanggep kadagitoy a pasamak",
+ "prefs-newmessageindicator": "Baro a panangipakita ti mensahe",
+ "echo-pref-send-me": "Patulodannak:",
+ "echo-pref-send-to": "Ipatulod kenni:",
+ "echo-pref-email-format": "Pormat ti esurat:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Esurat",
+ "echo-pref-email-frequency-never": "Saannak a patulodan kadagiti aniaman a pakaammo ti esurat",
+ "echo-pref-email-frequency-immediately": "Dagiti agmaymaysa a pakaaamo a kas um-umayda",
+ "echo-pref-email-frequency-daily": "Ti inaldaw a pakapukpukan dagiti pakaammo",
+ "echo-pref-email-frequency-weekly": "Ti linawas a pakapukpukan dagiti pakaammo",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Naranas a testo",
+ "echo-pref-notify-show-link": "Ipakita dagiti pakaammo iti baras ti ramitko",
+ "echo-pref-new-message-indicator": "Iparang ti panangipakita ti mensahe ti tungtungan a panid iti baras ti ramitko",
+ "echo-learn-more": "Agadal pay ti adu",
+ "echo-new-messages": "Adda dagiti baro a mensahem",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Ti mensahe|Dagiti mensahe}} ti tungtungan a panid",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Ti silpo|Dagiti silpo}} ti panid",
+ "echo-category-title-reverted": "{{PLURAL:$1|Ti naisubli|Dagiti naisubli}} nga inurnos",
+ "echo-category-title-mention": "{{PLURAL:$1|Naibaga|Naibagbaga}}",
+ "echo-category-title-other": "{{PLURAL:$1|Sabali}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Panagbaliw ti karkarbengan ti agar-aramat|Panagbalbaliw ti karkarbengan ti agar-aramat}}",
+ "echo-pref-tooltip-edit-user-talk": "Pakaammuannak no adda agipablaak ti mensahe wenno sumungbat iti tungtungan a panidko.",
+ "echo-pref-tooltip-article-linked": "Pakaammuannak no adda mangisilpo iti panid a pinartuatko manipud ti maysa a panid ti artikulo.",
+ "echo-pref-tooltip-reverted": "Pakaammuannak no adda mangisubli ti inurnosko, babaen ti panag-usar ti ramit ti panagukas wenno panangisubli.",
+ "echo-pref-tooltip-mention": "Pakaammuannak no adda mangisilpo iti panidko.",
+ "echo-pref-tooltip-user-rights": "Pakaammuannak no adda mangbaliw ti karkarbengak.",
+ "echo-no-agent": "[Awan ti sinoman]",
+ "echo-no-title": "[Awan ti panid]",
+ "echo-error-no-formatter": "Awan ti naipalawag a panagporma para iti pakaammo.",
+ "echo-error-preference": "Biddut: Saan a maiyasentar ti kakaykayatan ti agar-aramat.",
+ "echo-error-token": "Biddut: Saan a maala ti tandaan ti agar-aramat.",
+ "notifications": "Dagiti pakaammo",
+ "tooltip-pt-notifications": "Dagiti pakaammom",
+ "echo-specialpage": "Dagiti pakaammo",
+ "echo-anon": "Tapno makaawat kadagiti pakaammo, [$1 agpartuat ti pakabilangan] wenno [$2 sumrek].",
+ "echo-none": "Awan dagiti pakaammom.",
+ "echo-more-info": "Adu pay a pakaammo",
+ "echo-feedback": "Feedback",
+ "notification-link-text-view-message": "Kitaen ti mensahe",
+ "notification-link-text-view-mention": "Kitaen ti naibaga",
+ "notification-link-text-view-changes": "Kitaen dagiti sinukatan",
+ "notification-link-text-view-page": "Kitaen ti panid",
+ "notification-link-text-view-edit": "Kitaen ti inurnos",
+ "notification-edit-talk-page2": "Ni [[User:$1|$1]] ket {{GENDER:$1|nangibati}} ti mensahe idiay [[User talk:$2#$3|tungtungam a panid]].",
+ "notification-edit-talk-page-with-section": "Ni [[User:$1|$1]] ket {{GENDER:$1|nangibati}} ti mensahe idiay tungtungam a panid idiay \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "Ni $1 ket {{GENDER:$1|nangibati}} ti mensahe a idiay [[User talk:$2#$3|tungtungam a panid]].",
+ "notification-edit-talk-page-flyout-with-section": "Ni $1 ket {{GENDER:$1|nangibati}} ti mensahe idiay tungtungam a panid idiay \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Ti [[:$2]] ket {{GENDER:$1|naisilpo}} manipud ti [[:$3]]. [[Special:WhatLinksHere/$2|Kitaen amin dagiti silpo iti daytoy a panid]].",
+ "notification-page-linked-flyout": "Ti [[:$2]] ket {{GENDER:$1|naisilpo}} manipud ti [[:$3]].",
+ "notification-add-comment2": "Ni [[User:$1|$1]] ket {{GENDER:$1|nagkomentario}} iti \"[[$3|$2]]\" iti tungtungan a panid ti \"$4\".",
+ "notification-add-talkpage-topic2": "Ni [[User:$1|$1]] ket {{GENDER:$1|nangipablaak}} ti baro a topiko ti \"$2\" iti [[$3]].",
+ "notification-add-talkpage-topic-yours2": "Ni [[User:$1|$1]] ket {{GENDER:$1|pinatulodannaka}} ti mensahe: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "Ni [[User:$1|$1]] ken {{GENDER:$1|nagkomentario}} iti \"[[$3#$2|$2]]\" idiay tungtungam a panid.",
+ "notification-mention": "Ni [[User:$1|$1]] ket {{GENDER:$1|inbaganaka}} iti tungtungan a panid ti $5 iti \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "Ni $1 ket {{GENDER:$1|inbaganaka}} iti tungtungan a panid ti $5 iti \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "Ni [[User:$1|$1]] ket {{GENDER:$1|inbaganaka}} idiay [[:$3|$2 a tungtungan a panid]].",
+ "notification-mention-nosection-flyout": "Ni $1 ket {{GENDER:$1|inbaganaka}} idiay [[:$3|$2 a tungtungan a panid]].",
+ "notification-user-rights": "Dagiti karbengam nga agar-aramat [[Special:Log/rights/$1|ket {{GENDER:$1|binaliwan}}]] babaen ni [[User:$1|$1]]. $2. [[Special:ListGroupRights|Agadal pay ti adu]]",
+ "notification-user-rights-flyout": "Dagiti karbengam nga agar-aramat ket {{GENDER:$1|binaliwan}} babaen ni $1. $2. [[Special:ListGroupRights|Agadal pay ti adu]]",
+ "notification-user-rights-add": "Kamengka itan {{PLURAL:$2|iti daytoy a grupo|kadagitoy a grupo}}: $1",
+ "notification-user-rights-remove": "Saankan a kameng {{PLURAL:$2|iti daytoy a grupo|kadagitoy a grupo}}: $1",
+ "notification-new-user": "Naragsak nga isasangbay iti {{SITENAME}}, $1! Maragsakankami nga addaka ditoy.",
+ "notification-reverted2": "Ti {{PLURAL:$4|inurnosmo iti [[:$2]] ket|inur-urnosmo iti [[:$2]] ket}} {{GENDER:$1|naisubli}} babaen ni [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Ti {{PLURAL:$4|inurnosmo iti $2 ket|inur-urnosmo iti $2 ket}} {{GENDER:$1|naisubli}} babaen ni $1. $3",
+ "notification-edit-talk-page-email-subject2": "Ni $1 ket {{GENDER:$1|nangibati}} kenka ti mensahe idiay {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "Ni $1 ket {{GENDER:$1|nangibati}} ti mensahe idiay tungtungam a panid:",
+ "notification-edit-talk-page-email-batch-body-with-section": "Ni $1 ket {{GENDER:$1|nangibati}} ti mensahe idiay tungtungam a panid iti \"$2\".",
+ "notification-page-linked-email-subject": "Ti panidmo ket naisilpo idiay {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Ti $2 ket {{GENDER:$1|naisilpo}} manipud iti $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Ti inurnosmo ket|Dagiti inurnosmo ket}} {{GENDER:$1|naisubli}} idiay {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Ti inurnosmo iti $2 ket|Dagiti inurnosmo iti $2 ket}} {{GENDER:$1|insubli}} babaen ni $1.",
+ "notification-mention-email-subject": "Ni $1 {{GENDER:$1|inbaganaka}} idiay {{SITENAME}}",
+ "notification-mention-email-batch-body": "Ni $1 {{GENDER:$1|inbaganaka}} idiay tungtungan a panid ti $4 iti \"$3\".",
+ "notification-mention-nosection-email-batch-body": "Ni $1 ket {{GENDER:$1|inbaganaka}} idiay $2 a tungtungan a panid.",
+ "notification-user-rights-email-subject": "Dagiti karbengam nga agar-aramat ket nabaliwan idiay {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Dagiti karbengam nga agar-aramat ket {{GENDER:$1|binaliwan}} babaen ni $1. $2.",
+ "echo-email-subject-default": "Baro a pakaammo idiay {{SITENAME}}",
+ "echo-email-body-default": "Adda baro a pakaammom idiay {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Adda baro a pakaammom.",
+ "echo-email-footer-default": "$2\n\nTi mangtengngel no ania dagiti esurat nga ipatulodmi kenka, kitaem dagiti kakaykayatam:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Ti mangtengngel no ania dagiti esurat nga ipatulodmi kenka, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">kitaem dagiti kakaykayatam</a>.<br />\n$1",
+ "echo-overlay-link": "Dagiti amin a pakaaammo",
+ "echo-overlay-title": "<b>Dagiti pakaammo</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Dagiti pakaammo}}</b> (agipakpakita ti $1 iti $2 a saan pay a nabasa)",
+ "echo-mark-all-as-read": "Markaan amin a kas nabasa",
+ "echo-date-today": "Ita nga aldaw",
+ "echo-date-yesterday": "Idi kalman",
+ "echo-load-more-error": "Adda biddut a rimsua bayat nga agal-ala kadagiti ad-adu a resulta.",
+ "notification-edit-talk-page-bundle": "Ni $1 ken $3 a {{PLURAL:$4|sabali|sabsabali}} ket {{GENDER:$1|nangibati}} ti mensahe idiay [[User talk:$2|tungtungam a panid]].",
+ "notification-page-linked-bundle": "Ti $2 ket {{GENDER:$1|naisilpo}} manipud ti $3 ken ti $4 a sabali a {{PLURAL:$5|panid|pampanid}}. [[Special:WhatLinksHere/$2|Kitaen amin dagiti silpo iti daytoy a panid]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "Ni $1 ken $2 a {{PLURAL:$3|sabali|sabsabali}} ket {{GENDER:$1|nangibati}} ti mensahe idiay tungtungam a panid.",
+ "notification-page-linked-email-batch-bundle-body": "Ti $2 ket {{GENDER:$1|naisilpo}} manipud ti $3 ken $4 a sabali a {{PLURAL:$5|panid|pampanid}}.",
+ "echo-email-batch-subject-daily": "Addaanka {{PLURAL:$2|ti baro a pakaammo|kadagiti baro a pakaammo}} idiay {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Addaanka {{PLURAL:$2|ti baro a pakaammo|kadagiti baro a pakaammo}} idiay {{SITENAME}} ita a lawas",
+ "echo-email-batch-body-intro-daily": "Kumusta $1,\nAdda ditoy ti pakapukpukan ti aktibidad ita nga aldaw idiay {{SITENAME}} para kenka.",
+ "echo-email-batch-body-intro-weekly": "Kumusta $1,\nAdda ditoy ti pakapukpukan ti aktibidad ita a lawas idiay {{SITENAME}} para kenka.",
+ "echo-email-batch-link-text-view-all-notifications": "Kitaen amin dagiti pakaammo",
+ "echo-rev-deleted-text-view": "Daytoy a panagbaliw ti panid ket napasardengen."
+}
diff --git a/Echo/i18n/is.json b/Echo/i18n/is.json
new file mode 100644
index 00000000..87ff0e59
--- /dev/null
+++ b/Echo/i18n/is.json
@@ -0,0 +1,106 @@
+{
+ "@metadata": {
+ "authors": [
+ "Snævar",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "echo-desc": "Tilkynninga kerfi",
+ "prefs-echo": "Tilkynningar",
+ "prefs-emailsettings": "Tölvupósts stillingar",
+ "prefs-displaynotifications": "Útlits möguleikar",
+ "prefs-echosubscriptions": "Gefðu mér tilkynningar fyrir eftirfarandi viðburði",
+ "echo-pref-send-me": "Sentu mér:",
+ "echo-pref-send-to": "Senda til:",
+ "echo-pref-email-format": "Stílviðmið tölvupósts:",
+ "echo-pref-web": "Á netinu",
+ "echo-pref-email": "Með tölvupósti",
+ "echo-pref-email-frequency-never": "Ekki senda mér tilkynningar í tölvupósti",
+ "echo-pref-email-frequency-immediately": "Einstakar tilkynningar um leið og þær koma",
+ "echo-pref-email-frequency-daily": "Daglegt yfirlit yfir tilkynningar",
+ "echo-pref-email-frequency-weekly": "Vikulegt yfirlit yfir tilkynningar",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "óstílfærður texti",
+ "echo-pref-notify-show-link": "Sýna tilkynningar í verkfærastiku",
+ "echo-new-messages": "Þú hefur ný skilaboð",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Skilaboð}} á spjallsíðu",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Tengil|Tengla}} á síðum",
+ "echo-category-title-reverted": "{{PLURAL:$1|Breyting tekin|Breytingar teknar}} aftur",
+ "echo-category-title-mention": "{{PLURAL:$1|Minnst á þig}}",
+ "echo-category-title-other": "{{PLURAL:$1|Annað}}",
+ "echo-category-title-system": "{{PLURAL:$1|Kerfi}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Réttinda breyting|Réttinda breytingar}}",
+ "echo-pref-tooltip-edit-user-talk": "Tilkynntu mig um þegar einhver skilur eftir skilaboð eða svarar skilaboðum á spjallsíðunni minni.",
+ "echo-pref-tooltip-article-linked": "Gefðu mér tilkynningu þegar einhver tengir í síðu, sem ég bjó til, frá annari síðu.",
+ "echo-pref-tooltip-reverted": "Gefðu mér tilkynningu þegar einhver tekur aftur breytingu sem ég gerði.",
+ "echo-pref-tooltip-mention": "Gefðu mér tilkynningu þegar einhver tengir í notendasíðu mína.",
+ "echo-pref-tooltip-user-rights": "Tilkynntu mér þegar einhver breytir notendaréttendum mínum.",
+ "echo-no-agent": "[Enginn]",
+ "echo-no-title": "[Engin síða]",
+ "echo-error-no-formatter": "Engin stílviðmið tilgreind fyrir tilkynningum.",
+ "echo-error-preference": "Villa: Mistókst að setja notenda stillingu.",
+ "echo-error-token": "Villa: Mistókst að sækja tóka notanda.",
+ "notifications": "Tilkynningar",
+ "tooltip-pt-notifications": "Þínar tilkynningar",
+ "echo-specialpage": "Tilkynningar",
+ "echo-anon": "Til þess að fá tilkynningar þarft þú annaðhvort að [$1 búa til aðgang] eða [$2 skrá þig inn].",
+ "echo-none": "Þú hefur engar tilkynningar.",
+ "echo-more-info": "Frekari upplýsingar",
+ "echo-feedback": "Svörun",
+ "notification-link-text-view-message": "Sjá skilaboð",
+ "notification-link-text-view-changes": "Sjá breytingar",
+ "notification-link-text-view-page": "Skoða síðu",
+ "notification-link-text-view-edit": "Skoða breytingu",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|skildi}} eftir skilaboð á [[User talk:$2#$3|spjallsíðu þinni]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|skildi}} eftir skilaboð í \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|skildi}} eftir skilaboð á [[User talk:$2#$3|spjallsíðu þinni]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|skildi}} eftir skilaboð á spjallsíðu þinni í \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] var {{GENDER:$1|tengd}} við [[:$3]]. [[Special:WhatLinksHere/$2|Sjá alla tengla sem tengjast hingað]].",
+ "notification-page-linked-flyout": "[[:$2]] var {{GENDER:$1|tengd}} við [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|tjáði sig}} um „[[$3|$2]]” á spjallsíðu „$4”.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|skrifaði}} nýtt innlegg um \"$2\" á [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|senti}} þér skilaboð: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|tjáði sig}} í \"[[$3#$2|$2]]\" á spjallsíðu þinni.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|minntist á}} þig á spjallsíðu $5 í „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|minntist á}} þig á spjallsíðu $5 í „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|minntist á}} þig á [[:$3|spjallsíðu $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|minntist á}} þig á [[:$3|spjallsíðu $2]].",
+ "notification-user-rights": "Notendaréttindum þínum [[Special:Log/rights/$1|var {{GENDER:$1|breytt}}]] af [[User:$1|$1]]. $2. [[Special:ListGroupRights|Læra meira]]",
+ "notification-user-rights-flyout": "Notendaréttindum þínum var {{GENDER:$1|breytt}} af $1. $2. [[Special:ListGroupRights|Læra meira]]",
+ "notification-user-rights-add": "Þú ert nú meðlimur {{PLURAL:$2|þessa hóps|þessara hópa}}: $1",
+ "notification-user-rights-remove": "Þú ert ekki lengur meðlimur {{PLURAL:$2|þessa hóps|þessara hópa}}: $1",
+ "notification-new-user": "Velkomin til {{SITENAME}}, $1! Við erum ánægð með að sjá þig hér.",
+ "notification-reverted2": "{{PLURAL:$4|Breyting þín|Breytingar þínar}} á [[:$2]] {{PLURAL:$4|hefur verið {{GENDER:$1|tekin aftur}}|hafa verið {{GENDER:$1|teknar aftur}}}} af [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Breyting þín|Breytingar þínar}} á $2 {{PLURAL:$4|hefur verið {{GENDER:$1|tekin aftur}}|hafa verið {{GENDER:$1|teknar aftur}}}} af $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|skildi}} eftir skilaboð handa þér á {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|skildi}} eftir skilaboð á spjallsíðu þinni:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|skildi}} eftir skilaboð á spjallsíðu þinni undir \"$2\".",
+ "notification-page-linked-email-subject": "Tengt var við síðuna þína á {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 var {{GENDER:$1|tengd}} frá $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Breytingin þín var tekin aftur|Breytingarnar þínar voru teknar}} {{GENDER:$1|aftur}} á {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Breytingin þín á $2 hefur verið tekin|Breytingarnar þínar á $2 hafa verið teknar}} {{GENDER:$1|aftur}} af $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|minntist}} á þig á {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|minntist}} á þig í „$3” á spjallsíðu $4.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|minntist}} á þig á spjallsíðu $2.",
+ "notification-user-rights-email-subject": "Notendaréttindi þín hafa breyst á {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Notendaréttindunum þínum var {{GENDER:$1|breytt}} af $1. $2.",
+ "echo-email-subject-default": "Ný tilkynning á {{SITENAME}}",
+ "echo-notification-alert": "{{PLURAL:$1|$1 áminning|$1 Áminningar|100=Áminningar (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|$1 skilaboð|100=Skilaboð (99+)}}",
+ "echo-notification-alert-text-only": "Áminningar",
+ "echo-notification-message-text-only": "Skilaboð",
+ "echo-overlay-link": "Allar tilkynningar",
+ "echo-overlay-title": "<b>Tilkynningar</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Tilkynning|Tilkynningar}}</b> (sýni $1 af $2 ólesnum)",
+ "echo-mark-all-as-read": "Merkja allt sem lesið",
+ "echo-date-today": "Í dag",
+ "echo-date-yesterday": "Í gær",
+ "echo-load-more-error": "Villa átti sér stað þegar fleiri niðurstöður voru sóttar.",
+ "notification-edit-talk-page-bundle": "$1 og $3 {{PLURAL:$4|annar|aðrir}} {{GENDER:$1|skildi eftir}} skilaboð á [[User talk:$2|spjallsíðu]] þinni.",
+ "notification-page-linked-bundle": "$2 var {{GENDER:$1|tengd}} frá $3 og $4 {{PLURAL:$5|annarri síðu|öðrum síðum}}. [[Special:WhatLinksHere/$2|Sjá alla tengla á þessa síðu]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 og $2 {{PLURAL:$3|annar skildi|aðrir skildu}} {{GENDER:$1|eftir}} skilaboð á spjallsíðu þinni.",
+ "notification-page-linked-email-batch-bundle-body": "$2 var {{GENDER:$1|tengd}} frá $3 og $4 {{PLURAL:$5|annarri síðu|öðrum síðum}}.",
+ "echo-email-batch-subject-daily": "Þú hefur {{PLURAL:$2|nýja tilkynningu|nýjar tilkynningar}} á {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Þú hefur {{PLURAL:$2|nýja tilkynningu|nýjar tilkynningar}} á {{SITENAME}} í þessari viku",
+ "echo-rev-deleted-text-view": "Þessi útgáfa síðunnar hefur verið falin."
+}
diff --git a/Echo/i18n/it.json b/Echo/i18n/it.json
new file mode 100644
index 00000000..8f43f67b
--- /dev/null
+++ b/Echo/i18n/it.json
@@ -0,0 +1,131 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Darth Kule",
+ "Eleonora negri",
+ "Elitre",
+ "Nemo bis",
+ "Pietrodn",
+ "Raoli",
+ "Vituzzu"
+ ]
+ },
+ "echo-desc": "Sistema di notifica",
+ "prefs-echo": "Notifiche",
+ "prefs-emailsettings": "Opzioni email",
+ "prefs-displaynotifications": "Opzioni di visualizzazione",
+ "prefs-echosubscriptions": "Inviami una notifica su questi eventi",
+ "prefs-newmessageindicator": "Barra dei nuovi messaggi",
+ "echo-pref-send-me": "Inviami:",
+ "echo-pref-send-to": "Invia a:",
+ "echo-pref-email-format": "Formato email:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Email",
+ "echo-pref-email-frequency-never": "Non inviarmi alcuna notifica via e-mail",
+ "echo-pref-email-frequency-immediately": "Notifiche singole per ogni evento",
+ "echo-pref-email-frequency-daily": "Un riepilogo giornaliero delle notifiche",
+ "echo-pref-email-frequency-weekly": "Un riepilogo settimanale delle notifiche",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Testo normale",
+ "echo-pref-notify-show-link": "Visualizza le notifiche nella mia barra degli strumenti",
+ "echo-pref-new-message-indicator": "Notificami i nuovi messaggi nella mia pagina di discussione con un avviso nella barra degli strumenti",
+ "echo-learn-more": "Ulteriori informazioni",
+ "echo-new-messages": "Hai nuovi messaggi",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Messaggio|Messaggi}} sulla pagina di discussione",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Collegamento|Collegamenti}} a una pagina",
+ "echo-category-title-reverted": "{{PLURAL:$1|Modifica annullata|Modifiche annullate}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Menzione|Menzioni}}",
+ "echo-category-title-other": "{{PLURAL:$1|Altro}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Modifica diritto|Modifiche diritti}} utente",
+ "echo-pref-tooltip-edit-user-talk": "Avvisami quando qualcuno mi scrive un messaggio o risponde nella mia pagina di discussione.",
+ "echo-pref-tooltip-article-linked": "Avvisami quando qualcuno collega, da una voce, una pagina che ho creato.",
+ "echo-pref-tooltip-reverted": "Avvisami quando qualcuno annulla una modifica che ho fatto, usando le funzioni annulla o rollback.",
+ "echo-pref-tooltip-mention": "Avvisami quando qualcuno collega la mia pagina utente.",
+ "echo-pref-tooltip-user-rights": "Avvisami quando qualcuno modifica i miei diritti di utente.",
+ "echo-no-agent": "[Nessuno]",
+ "echo-no-title": "[Nessuna pagina]",
+ "echo-error-no-formatter": "Nessuna formattazione definita per le notifiche",
+ "echo-error-preference": "Errore: impossibile impostare le preferenze dell'utente",
+ "echo-error-token": "Errore: impossibile recuperare token utente",
+ "notifications": "Notifiche",
+ "tooltip-pt-notifications": "Tutte le notifiche",
+ "echo-specialpage": "Notifiche",
+ "echo-anon": "Per ricevere le notifiche, [$1 registrati] o [$2 accedi].",
+ "echo-none": "Non hai notifiche.",
+ "echo-more-info": "Altre informazioni",
+ "echo-feedback": "Commenti",
+ "notification-link-text-view-message": "Vedi messaggio",
+ "notification-link-text-view-mention": "Vedi menzione",
+ "notification-link-text-view-changes": "Vedi modifiche",
+ "notification-link-text-view-page": "Vedi pagina",
+ "notification-link-text-view-edit": "Vedi modifica",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|ha lasciato}} un messaggio sulla tua [[User talk:$2#$3|pagina di discussione]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|ha lasciato}} un messaggio nella tua pagina di discussione in '[[User talk:$2#$3|$4]]'.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|ha lasciato}} un messaggio sulla tua [[User talk:$2#$3|pagina di discussione]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|ha lasciato}} un messaggio nella tua pagina di discussione in '[[User talk:$2#$3|$4]]'.",
+ "notification-page-linked": "[[:$2]] è stata {{GENDER:$1|collegata}} da [[:$3]]. [[Special:WhatLinksHere/$2|Vedi tutti i collegamenti a questa pagina]].",
+ "notification-page-linked-flyout": "[[:$2]] è stata {{GENDER:$1|collegata}} da [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|ha lasciato un commento}} riguardo a \"[[$3|$2]]\" nella pagina di discussione di \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|ha aggiunto}} un nuovo argomento \"$2\" su [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] ti {{GENDER:$1|ha inviato}} un messaggio: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|ha lasciato un commento}} riguardo a \"[[$3#$2|$2]]\" nella tua pagina di discussione",
+ "notification-mention": "[[User:$1|$1]] ti ha {{GENDER:$1|menzionato|menzionata|menzionato/a}} sulla pagina di discussione di $5 in '[[:$3#$2|$4]]'.",
+ "notification-mention-flyout": "$1 ti ha {{GENDER:$1|menzionato|menzionata|menzionato/a}} sulla pagina di discussione di $5 in '[[:$3#$2|$4]]'.",
+ "notification-mention-nosection": "[[User:$1|$1]] ti {{GENDER:$1|ha menzionato}} nella [[:$3|pagina di discussione $2]].",
+ "notification-mention-nosection-flyout": "$1 ti {{GENDER:$1|ha menzionato}} nella [[:$3|pagina di discussione $2]].",
+ "notification-user-rights": "I tuoi diritti utente [[Special:Log/rights/$1|sono stati {{GENDER:$1|modificati}}]] da [[User:$1|$1]]. $2. [[Special:ListGroupRights|Ulteriori informazioni]]",
+ "notification-user-rights-flyout": "I tuoi diritti utente sono stati {{GENDER:$1|modificati}} da $1. $2. [[Special:ListGroupRights|Ulteriori informazioni]]",
+ "notification-user-rights-add": "Ora sei membro di {{PLURAL:$2|questo gruppo|questi gruppi}}: $1",
+ "notification-user-rights-remove": "Non sei più membro di {{PLURAL:$2|questo gruppo|questi gruppi}}: $1",
+ "notification-new-user": "Benvenuto su {{SITENAME}}, $1! Siamo felici che tu sia qui.",
+ "notification-reverted2": "{{PLURAL:$4|La tua modifica|Le tue modifiche}} su [[:$2]] {{PLURAL:$4|è stata annullata|sono state annullate}} {{GENDER:$1|da}} [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|La tua modifica|Le tue modifiche}} su $2 {{PLURAL:$4|è stata annullata|sono state annullate}} {{GENDER:$1|da}} $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 ti {{GENDER:$1|ha lasciato}} un messaggio in {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|ha lasciato}} un messaggio sulla tua pagina di discussione:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|ha lasciato}} un messaggio sulla tua pagina di discussione in '$2'.",
+ "notification-page-linked-email-subject": "Una pagina che hai creato è stata collegata su {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 è stata {{GENDER:$1|collegata}} da $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|La tua modifica è stata annullata|Le tue modifiche sono state annullate}} {{GENDER:$1|su}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|La tua modifica|Le tue modifiche}} su $2 {{PLURAL:$3|è stata annullata|sono state annullate}} {{GENDER:$1|da}} $1",
+ "notification-mention-email-subject": "$1 ti ha {{GENDER:$1|menzionato|menzionata|menzionato/a}} su {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 ti ha {{GENDER:$1|menzionato|menzionata|menzionato/a}} sulla pagina di discussione di $4 in '$3'.",
+ "notification-mention-nosection-email-batch-body": "$1 ti {{GENDER:$1|ha menzionato}} nella pagina di discussione $2.",
+ "notification-user-rights-email-subject": "I tuoi diritti utente sono stati modificati su {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "I tuoi diritti utente sono stati {{GENDER:$1|modificati}} da $1. $2",
+ "echo-email-subject-default": "Nuova notifica su {{SITENAME}}",
+ "echo-email-body-default": "Hai una nuova notifica su {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Hai una nuova notifica",
+ "echo-email-footer-default": "$2\n\nPer controllare quali email ti verranno inviate, controlla le tue preferenze:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Per verificare quali email ti vengono inviate, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">controlla le tue preferenze</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Avviso ($1)|Avvisi ($1)|100=Avvisi (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Messaggio ($1)|Messaggi ($1)|100=Messaggi (99+)}}",
+ "echo-notification-alert-text-only": "Avvisi",
+ "echo-notification-message-text-only": "Messaggi",
+ "echo-overlay-link": "Tutte le notifiche",
+ "echo-overlay-title": "<b>Notifiche</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notifica|Notifiche}}</b> (mostrate $1 di $2 non lette)",
+ "echo-mark-all-as-read": "Segna tutte come lette",
+ "echo-date-today": "Oggi",
+ "echo-date-yesterday": "Ieri",
+ "echo-load-more-error": "Si è verificato un errore nel recupero di ulteriori risultati.",
+ "notification-edit-talk-page-bundle": "$1 e {{PLURAL:$4|un altro utente|altri $3 utenti}} {{GENDER:$1|hanno lasciato}} un messaggio nella tua [[User talk:$2|pagina di discussione]].",
+ "notification-page-linked-bundle": "$2 è stata {{GENDER:$1|collegata}} da $3 ed {{PLURAL:$5|un altra pagina|altre $4 pagine}}. [[Special:WhatLinksHere/$2|Vedi tutti i collegamenti a questa pagina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e {{PLURAL:$3|un altro|altri $2}} {{GENDER:$1|hanno lasciato}} un messaggio sulla tua pagina di discussione",
+ "notification-page-linked-email-batch-bundle-body": "$2 è stata {{GENDER:$1|collegata}} da $3 ed {{PLURAL:$5|un altra pagina|altre $4 pagine}}",
+ "echo-email-batch-subject-daily": "Hai {{PLURAL:$2|una nuova notifica|nuove notifiche}} su {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Hai {{PLURAL:$2|una nuova notifica|nuove notifiche}} su {{SITENAME}} questa settimana",
+ "echo-email-batch-body-intro-daily": "Ciao $1,\neccoti una sintesi delle attività di oggi su {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Ciao $1,\neccoti una sintesi delle attività di questa settimana su {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Vedi tutte le notifiche",
+ "echo-rev-deleted-text-view": "Questa versione della pagina è stata soppressa",
+ "apihelp-echomarkread-description": "Contrassegna tutte le notifiche come lette per l'utente attuale.",
+ "apihelp-echomarkread-param-list": "Un elenco di ID notifiche da contrassegnare come lette.",
+ "apihelp-echomarkread-param-all": "Se impostato, contrassegna tutte le notifiche dell'utente come lette.",
+ "apihelp-echomarkread-param-sections": "Un elenco di sezioni da contrassegnare come lette.",
+ "apihelp-echomarkread-example-1": "Contrassegna la notifica 8 come letta",
+ "apihelp-echomarkread-example-2": "Contrassegna tutte le notifiche come lette",
+ "apihelp-query+notifications-example-1": "Elenco notifiche",
+ "apihelp-query+notifications-example-2": "Elenco notifiche, raggruppate per sezione, con i conteggi"
+}
diff --git a/Echo/i18n/ja.json b/Echo/i18n/ja.json
new file mode 100644
index 00000000..bbfd33f8
--- /dev/null
+++ b/Echo/i18n/ja.json
@@ -0,0 +1,120 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fryed-peach",
+ "Shirayuki",
+ "Whym",
+ "Penn Station"
+ ]
+ },
+ "echo-desc": "通知システム",
+ "prefs-echo": "通知",
+ "prefs-emailsettings": "メールの設定",
+ "prefs-displaynotifications": "表示の設定",
+ "prefs-echosubscriptions": "以下の場合に通知を受け取る",
+ "prefs-newmessageindicator": "新着メッセージの表示",
+ "echo-pref-send-me": "受け取る頻度:",
+ "echo-pref-send-to": "送信先:",
+ "echo-pref-email-format": "メールの形式:",
+ "echo-pref-web": "ウェブ",
+ "echo-pref-email": "メール",
+ "echo-pref-email-frequency-never": "通知メールを何も受け取らない",
+ "echo-pref-email-frequency-immediately": "個別の通知が来るたび",
+ "echo-pref-email-frequency-daily": "通知を1日ごとに要約",
+ "echo-pref-email-frequency-weekly": "通知を1週間ごとに要約",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "プレーンテキスト",
+ "echo-pref-notify-show-link": "通知をツールバーに表示",
+ "echo-pref-new-message-indicator": "トークページのメッセージの未読数をツールバーに表示",
+ "echo-learn-more": "詳細",
+ "echo-new-messages": "新着メッセージがあります",
+ "echo-category-title-edit-user-talk": "トークページヘの{{PLURAL:$1|メッセージ}}",
+ "echo-category-title-article-linked": "ページへの{{PLURAL:$1|リンク}}",
+ "echo-category-title-reverted": "編集の{{PLURAL:$1|差し戻し}}",
+ "echo-category-title-mention": "{{PLURAL:$1|言及}}",
+ "echo-category-title-other": "{{PLURAL:$1|その他}}",
+ "echo-category-title-system": "{{PLURAL:$1|システム}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|利用者権限の変更}}",
+ "echo-pref-tooltip-edit-user-talk": "誰かが私のトークページでメッセージの投稿または返信をしたときに通知する。",
+ "echo-pref-tooltip-article-linked": "誰かが私が作成したページに記事からリンクしたときに通知する。",
+ "echo-pref-tooltip-reverted": "誰かが取り消しや巻き戻しの機能で私の編集を差し戻したときに通知する。",
+ "echo-pref-tooltip-mention": "誰かが私の利用者ページにリンクしたときに通知する。",
+ "echo-pref-tooltip-user-rights": "誰かが私の利用者権限を変更したときに通知する。",
+ "echo-no-agent": "[送信者なし]",
+ "echo-no-title": "[ページなし]",
+ "echo-error-no-formatter": "通知の書式が定義されていません。",
+ "echo-error-preference": "エラー: 個人設定を変更できませんでした。",
+ "echo-error-token": "エラー: 利用者トークンを取得できませんでした。",
+ "notifications": "通知",
+ "tooltip-pt-notifications": "あなたへの通知",
+ "echo-specialpage": "通知",
+ "echo-anon": "通知を受け取るには、[$1 アカウント作成]または[$2 ログイン]をしてください。",
+ "echo-none": "通知はありません。",
+ "echo-more-info": "詳細情報",
+ "echo-feedback": "フィードバック",
+ "echo-quotation-marks": "「$1」",
+ "notification-link-text-view-message": "メッセージを閲覧",
+ "notification-link-text-view-mention": "言及を閲覧",
+ "notification-link-text-view-changes": "差分を閲覧",
+ "notification-link-text-view-page": "ページを閲覧",
+ "notification-link-text-view-edit": "編集内容を閲覧",
+ "notification-edit-talk-page2": "[[User:$1|$1]] があなたの[[User talk:$2#$3|トークページ]]にメッセージを{{GENDER:$1|投稿しました}}。",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] があなたのトークページの「[[User talk:$2#$3|$4]]」にメッセージを{{GENDER:$1|投稿しました}}。",
+ "notification-edit-talk-page-flyout2": "$1 があなたの[[User talk:$2#$3|トークページ]]にメッセージを{{GENDER:$1|投稿しました}}。",
+ "notification-edit-talk-page-flyout-with-section": "$1 があなたのトークページの「[[User talk:$2#$3|$4]]」にメッセージを{{GENDER:$1|投稿しました}}。",
+ "notification-page-linked": "[[:$2]] が [[:$3]] から{{GENDER:$1|リンクされました}}。[[Special:WhatLinksHere/$2|このページのリンク元]]",
+ "notification-page-linked-flyout": "[[:$2]] が [[:$3]] から{{GENDER:$1|リンクされました}}。",
+ "notification-add-comment2": "[[User:$1|$1]] が「$4」のトークページの「[[$3|$2]]」に{{GENDER:$1|コメントしました}}。",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] が [[$3]] に新しい話題「$2」を{{GENDER:$1|投稿しました}}。",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] があなたにメッセージを{{GENDER:$1|送信しました}}:「[[$3#$2|$2]]」",
+ "notification-add-comment-yours2": "[[User:$1|$1]] があなたのトークページの「[[$3#$2|$2]]」に{{GENDER:$1|コメントしました}}。",
+ "notification-mention": "[[User:$1|$1]] が $5 のトークページの「[[:$3#$2|$4]]」であなたに{{GENDER:$1|言及しました}}。",
+ "notification-mention-flyout": "$1 が $5 のトークページの「[[:$3#$2|$4]]」であなたに{{GENDER:$1|言及しました}}。",
+ "notification-mention-nosection": "[[User:$1|$1]] が [[:$3|$2 のトークページ]]であなたに{{GENDER:$1|言及しました}}。",
+ "notification-mention-nosection-flyout": "$1 が [[:$3|$2 のトークページ]]であなたに{{GENDER:$1|言及しました}}。",
+ "notification-user-rights": "あなたの権限を[[User:$1|$1]]が[[Special:Log/rights/$1|{{GENDER:$1|変更しました}}]]。$2。[[Special:ListGroupRights|詳細はこちら]]",
+ "notification-user-rights-flyout": "あなたの権限を $1 が{{GENDER:$1|変更しました}}。$2。[[Special:ListGroupRights|詳細はこちら]]",
+ "notification-user-rights-add": "あなたは{{PLURAL:$2|以下のグループ}}に所属になりました: $1",
+ "notification-user-rights-remove": "あなたは{{PLURAL:$2|以下のグループ}}の所属から外れました: $1",
+ "notification-new-user": "$1さん、{{SITENAME}}へようこそおいでくださいました。",
+ "notification-reverted2": "{{PLURAL:$4|[[:$2]] でのあなたの編集}}を [[User:$1|$1]] が{{GENDER:$1|差し戻しました}}。$3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|$2 でのあなたの編集}}を $1 が{{GENDER:$1|差し戻しました}}。$3",
+ "notification-edit-talk-page-email-subject2": "{{SITENAME}}で $1 があなたのトークページにメッセージを{{GENDER:$1|投稿しました}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 があなたのトークページにメッセージを{{GENDER:$1|投稿しました}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 があなたのトークページの「$2」にメッセージを{{GENDER:$1|投稿しました}}。",
+ "notification-page-linked-email-subject": "あなたのページが{{SITENAME}}でリンクされました",
+ "notification-page-linked-email-batch-body": "$2 が $3 から{{GENDER:$1|リンクされました}}。",
+ "notification-reverted-email-subject2": "{{SITENAME}}でのあなたの{{PLURAL:$3|編集}}が{{GENDER:$1|差し戻されました}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|$2 でのあなたの編集}}を $1 が{{GENDER:$1|差し戻しました}}。",
+ "notification-mention-email-subject": "$1 が{{SITENAME}}であなたに{{GENDER:$1|言及しました}}",
+ "notification-mention-email-batch-body": "$1 が $4 のトークページの「$3」であなたに{{GENDER:$1|言及しました}}。",
+ "notification-mention-nosection-email-batch-body": "$1 が $2 のトークページであなたに{{GENDER:$1|言及しました}}。",
+ "notification-user-rights-email-subject": "{{SITENAME}}での利用者権限が変更されました",
+ "notification-user-rights-email-batch-body": "あなたの権限が $1 により{{GENDER:$1|変更されました}}。$2",
+ "echo-email-subject-default": "{{SITENAME}}での新しい通知",
+ "echo-email-body-default": "{{SITENAME}}で新しい通知があります:\n\n$1",
+ "echo-email-batch-body-default": "新しい通知があります。",
+ "echo-email-footer-default": "$2\n\n受け取るメールの設定を変更するには、個人設定をご確認ください:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "お送りするメールの設定を変更するには、<a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">個人設定を参照してください</a>。<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|アラート ($1)|100=アラート (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|メッセージ ($1)|100=メッセージ (99+)}}",
+ "echo-notification-alert-text-only": "アラート",
+ "echo-notification-message-text-only": "メッセージ",
+ "echo-overlay-link": "すべての通知",
+ "echo-overlay-title": "<b>通知</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|通知}}</b> (未読 $2 件中 $1 件を表示中)",
+ "echo-mark-all-as-read": "すべて既読にする",
+ "echo-date-today": "今日",
+ "echo-date-yesterday": "昨日",
+ "echo-load-more-error": "結果の続きを取得する際にエラーが発生しました。",
+ "notification-edit-talk-page-bundle": "$1 と他 $3 {{PLURAL:$4|人}}があなたの[[User talk:$2|トークページ]]にメッセージを{{GENDER:$1|投稿しました}}。",
+ "notification-page-linked-bundle": "$2 が $3 と他 $4 {{PLURAL:$5|件のページ}}から{{GENDER:$1|リンクされました}}。[[Special:WhatLinksHere/$2|このページのリンク元]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 と他 $2 {{PLURAL:$3|人}}があなたのトークページにメッセージを{{GENDER:$1|投稿しました}}。",
+ "notification-page-linked-email-batch-bundle-body": "$2 が $3 と他 $4 {{PLURAL:$5|件のページ}}から{{GENDER:$1|リンクされました}}。",
+ "echo-email-batch-subject-daily": "{{SITENAME}}で{{PLURAL:$2|新たな通知}}が届いています",
+ "echo-email-batch-subject-weekly": "{{SITENAME}}でこの1週間に{{PLURAL:$2|新たな通知}}が届いています",
+ "echo-email-batch-body-intro-daily": "こんにちは、$1 さん。\nこれが {{SITENAME}} での今日の出来事をあなたのために要約したものです。",
+ "echo-email-batch-body-intro-weekly": "こんにちは、$1 さん。\nこれが {{SITENAME}} での今週の出来事をあなたのために要約したものです。",
+ "echo-email-batch-link-text-view-all-notifications": "すべての通知を閲覧",
+ "echo-rev-deleted-text-view": "ページのこの版は秘匿されています。"
+}
diff --git a/Echo/i18n/jv.json b/Echo/i18n/jv.json
new file mode 100644
index 00000000..4a335e77
--- /dev/null
+++ b/Echo/i18n/jv.json
@@ -0,0 +1,109 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anggoro",
+ "Bennylin",
+ "NoiX180"
+ ]
+ },
+ "echo-desc": "Sistem pemberitahuan",
+ "prefs-echo": "Wara-wara",
+ "prefs-emailsettings": "Opsi layang elektronik",
+ "prefs-displaynotifications": "Duduhna pilihan",
+ "prefs-echosubscriptions": "Beritahu saya mengenai peristiwa berikut",
+ "prefs-newmessageindicator": "Penanda layang anyar",
+ "echo-pref-send-me": "Kirim nang aku:",
+ "echo-pref-send-to": "Kirim nang:",
+ "echo-pref-email-format": "Format layang elektronik:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Layang èlèktronik",
+ "echo-pref-email-frequency-never": "Ora usah ngirimi aku notifikasi",
+ "echo-pref-email-frequency-immediately": "Pemberitahuan tunggal setiap suatu peristiwa terjadi",
+ "echo-pref-email-frequency-daily": "Ringkasan harian dari beberapa pemberitahuan",
+ "echo-pref-email-frequency-weekly": "Ringkasan mingguan dari beberapa pemberitahuan",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "aksara nglegena",
+ "echo-pref-notify-show-link": "Tampilkan pemberitahuan di bilah alat saya",
+ "echo-pref-new-message-indicator": "Tampilkan penanda pesan halaman pembicaraan pada bilah alat saya",
+ "echo-learn-more": "Sinau luwih",
+ "echo-new-messages": "Panjenengan olèh pesen-pesen anyar",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Pesan}} halaman pembicaraan",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Pranala|Pranala}} kaca",
+ "echo-category-title-reverted": "{{PLURAL:$1|Balikna|Baliknya}} pangowahan",
+ "echo-category-title-mention": "{{PLURAL:$1|Panyebutan|Panyebutan}}",
+ "echo-category-title-other": "{{PLURAL:$1|Liyane}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-pref-tooltip-edit-user-talk": "Beritahu saya saat seseorang mengirim pesan atau balasan pada halaman pembicaraan saya.",
+ "echo-pref-tooltip-article-linked": "Beritahu saya saat seseorang membuat pranala di halaman artikel ke sebuah halaman yang pernah saya rintis.",
+ "echo-pref-tooltip-reverted": "Beritahu saya saat seseorang membalikkan suntingan yang pernah saya buat, dengan menggunakan alat batalkan atau balikkan.",
+ "echo-pref-tooltip-mention": "Beritahu saya saat seseorang membuat pranala di halaman pembicaraan apapun ke halaman pengguna saya.",
+ "echo-no-agent": "[Dudu sapa-sapa]",
+ "echo-no-title": "[Ora ana kaca]",
+ "echo-error-no-formatter": "Tidak ada pemformatan yang ditetapkan untuk pemberitahuan.",
+ "echo-error-preference": "Galat: Tidak dapat menetapkan preferensi pengguna.",
+ "echo-error-token": "Galat: Tidak dapat mengambil token pengguna.",
+ "notifications": "Wara-wara",
+ "tooltip-pt-notifications": "Pemberitahuan Anda",
+ "echo-specialpage": "Wara-wara",
+ "echo-anon": "Kanggo nampa wara-wara [$1 gawé akun] utawa [$2 mlebu log].",
+ "echo-none": "Sampéyan durung nampa wara-wara apa-apa.",
+ "echo-more-info": "Info jangkep",
+ "echo-feedback": "Lebon saran",
+ "notification-link-text-view-message": "Lihat pesan",
+ "notification-link-text-view-mention": "Lihat sebutan",
+ "notification-link-text-view-changes": "Tuduhna pangowahan",
+ "notification-link-text-view-page": "Tuduhna kaca",
+ "notification-link-text-view-edit": "Tuduhna pangowahan",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|meninggalkan}} sebuah pesan pada [[User talk:$2#$3|halaman pembicaraan]] Anda.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda di [[User talk:$2#$3|$4]].",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan pada [[User talk:$2#$3|halaman pembicaraan]] Anda.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda di [[User talk:$2#$3|$4]].",
+ "notification-page-linked": "Pranala ke [[:$2]] {{GENDER:$1|ditambahkan}} di [[:$3]]. [[Special:WhatLinksHere/$2|Lihat semua pranala balik ke halaman ini]].",
+ "notification-page-linked-flyout": "Pranala ke [[:$2]] {{GENDER:$1|ditambahkan}} di [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|mengomentari}} \"[[$3|$2]]\" pada halaman pembicaraan \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|mengirimkan}} sebuah topik baru \"$2\" di [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|mengirimi}} Anda sebuah pesan: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|mengomentari}} \"[[$3|$2]]\" pada halaman pembicaraan \"$4\".",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|menyebut}} Anda di \"[[:$3#$2|$4]]\" pada halaman pembicaraan $5.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|menyebut}} Anda di \"[[:$3#$2|$4]]\" pada halaman pembicaraan $5.",
+ "notification-user-rights": "Hak pengguna Anda [[Special:Log/rights/$1|telah {{GENDER:$1|diubah}}]] oleh [[User:$1|$1]]. $2. [[Special:ListGroupRights|Pelajari selengkapnya]]",
+ "notification-user-rights-flyout": "Hak pengguna Anda telah {{GENDER:$1|diubah}} oleh $1. $2. [[Special:ListGroupRights|Pelajari selengkapnya]]",
+ "notification-user-rights-add": "Anda sekarang adalah anggota dari {{PLURAL:$2|kelompok berikut}}: $1",
+ "notification-user-rights-remove": "Anda tidak lagi menjadi anggota dari {{PLURAL:$2|kelompok berikut}}: $1",
+ "notification-new-user": "Selamat datang di {{SITENAME}}, $1! Kami senang Anda hadir di sini.",
+ "notification-reverted2": "{{PLURAL:$4|Suntingan Anda pada [[:$2]] telah}} {{GENDER:$1|dibalikkan}} oleh [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Suntingan Anda pada $2 telah}} {{GENDER:$1|dibalikkan}} oleh $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|meninggalkan}} Anda sebuah pesan di {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|meninggalkan}} sebuah pesan di \"$2\" pada halaman pembicaraan Anda.",
+ "notification-page-linked-email-subject": "Pranala ke halaman Anda ditambahkan di {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Pranala ke $2 {{GENDER:$1|ditambahkan}} di [[:$3]].",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Suntingan}} Anda telah {{GENDER:$1|dibalikkan}} di {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$4|Suntingan Anda pada $2 telah}} {{GENDER:$1|dibalikkan}} oleh $1. $3",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|menyebut}} Anda di {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|menyebut}} Anda di \"[[$3#$2|$4]]\" pada halaman pembicaraan $5.",
+ "notification-user-rights-email-subject": "Hak pengguna Anda telah diubah di {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Hak pengguna Anda telah {{GENDER:$1|diubah}} oleh $1. $2.",
+ "echo-email-subject-default": "Wara-wara anyar nèng {{SITENAME}}",
+ "echo-email-body-default": "Sampéyan nduwé wara-wara anyar nèng {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Sampéyan nampa wara-wara anyar.",
+ "echo-email-footer-default": "$2\n\nUntuk mengendalikan surel mana saja yang akan kami kirimkan kepada Anda, periksa preferensi Anda:\n{{canonicalurl: {{#special:Preferences}} #mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Untuk mengendalikan surel mana saja yang akan kami kirimkan kepada Anda, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">periksa preferensi Anda</a>.<br />\n$1",
+ "echo-overlay-link": "Kabèh wara-wara",
+ "echo-overlay-title": "<b>Wara-wara</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Pemberitahuan}}</b> (menampilkan $1 dari $2 yang belum dibaca)",
+ "echo-mark-all-as-read": "Tandhai kabèh minangka kawaca",
+ "echo-date-today": "Dina iki",
+ "echo-date-yesterday": "Dina wingi",
+ "echo-load-more-error": "Ana kasalahan nalika njupuk luwih akèh asil.",
+ "notification-edit-talk-page-bundle": "$1 dan $3 pengguna {{PLURAL:$4|lainnya}} {{GENDER:$1|meninggalkan}} sebuah pesan pada [[User talk:$2|halaman pembicaraan]] Anda.",
+ "notification-page-linked-bundle": "Pranala ke $2 {{GENDER:$1|ditambahkan}} di $3 dan $4 {{PLURAL:$5|halaman}} lainnya. [[Special:WhatLinksHere/$2|Lihat semua pranala balik ke halaman ini]].",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 dan $2 pengguna {{PLURAL:$3|lainnya}} {{GENDER:$1|meninggalkan}} sebuah pesan pada halaman pembicaraan Anda.",
+ "notification-page-linked-email-batch-bundle-body": "Pranala ke $2 {{GENDER:$1|ditambahkan}} di $3 dan $4 {{PLURAL:$5|halaman}} lainnya.",
+ "echo-email-batch-subject-daily": "Anda memiliki {{PLURAL:$2|sebuah|beberapa}} pemberitahuan baru di {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Anda memiliki {{PLURAL:$2|sebuah|beberapa}} pemberitahuan baru di {{SITENAME}} pekan ini",
+ "echo-email-batch-body-intro-daily": "Hai $1,\nIni adalah ringkasan aktivitas kegiatan hari ini di {{SITENAME}} untuk Anda.",
+ "echo-email-batch-body-intro-weekly": "Hai $1,\nIni adalah ringkasan aktivitas kegiatan pekan ini di {{SITENAME}} untuk Anda.",
+ "echo-email-batch-link-text-view-all-notifications": "Tampilkan semua pemberitahuan",
+ "echo-rev-deleted-text-view": "Revisi halaman ini telah ditekan."
+}
diff --git a/Echo/i18n/ka.json b/Echo/i18n/ka.json
new file mode 100644
index 00000000..f6e341a6
--- /dev/null
+++ b/Echo/i18n/ka.json
@@ -0,0 +1,72 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010",
+ "MIKHEIL",
+ "Nodar Kherkheulidze",
+ "Tokoko"
+ ]
+ },
+ "echo-desc": "შეტყობინებების სისტემა",
+ "prefs-echo": "შეტყობინებები",
+ "prefs-emailsettings": "ელ-ფოსტის პარამეტრები",
+ "prefs-displaynotifications": "გამოსახვის პარამეტრები",
+ "prefs-echosubscriptions": "შემატყობინეთ ამ ღონისძიებების შესახებ",
+ "prefs-newmessageindicator": "ახალი შეტყობინების ინდიკატორი",
+ "echo-pref-send-me": "გამომიგზავნეთ:",
+ "echo-pref-send-to": "გასაგზავნი მისამართი:",
+ "echo-pref-email-format": "ელ.ფოსტის ფორმატი:",
+ "echo-pref-web": "ქსელი",
+ "echo-pref-email": "ელ. ფოსტა",
+ "echo-pref-email-frequency-never": "არ გამომიგზავნოთ არავითარი შეტყობინება ელ.ფოსტაზე",
+ "echo-pref-email-frequency-immediately": "ინდივიდუალური შეტყობინებები როგორც ისინი მოდის",
+ "echo-pref-email-frequency-daily": "დღის შემაჯამებელი შეტყობინებები",
+ "echo-pref-email-frequency-weekly": "კვირის შემაჯამებელი შეტყობინებები",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "ჩვეულებრივი ტექსტი",
+ "echo-pref-new-message-indicator": "განხილვის გვერდის შეტყობინების ინდიკატორის ჩვენება ხელსაწყოების პანელზე",
+ "echo-learn-more": "გაიგეთ მეტი",
+ "echo-new-messages": "თქვენ გაქვთ ახალი შეტყობინება",
+ "echo-category-title-edit-user-talk": "განხილვის გვერდის {{PLURAL:$1|შეტყობინება}}",
+ "echo-pref-tooltip-edit-user-talk": "შემატყობინე, როდესაც ვინმე დაარედაქტირებს ჩემს განხილვის გვერდს.",
+ "echo-pref-tooltip-reverted": "შემატყობინე, როდესაც ვინმე ჩემს რედაქტირებას გააუქმებს.",
+ "echo-pref-tooltip-mention": "შემატყობინე, როდესაც ვინმე მომნიშნავს განხილვაში.",
+ "echo-no-agent": "[არავინ]",
+ "echo-no-title": "[არ არის გვერდი]",
+ "notifications": "შეტყობინებები",
+ "tooltip-pt-notifications": "თქვენი შეტყობინებები",
+ "echo-specialpage": "შეტყობინებები",
+ "echo-anon": "რომ მიიღოთ შეტყობინებები, [$1 შექმენით ანგარიში] ან [$2 შედით სისტემაში].",
+ "echo-none": "თქვენ არ გაქვთ შეტყობინება.",
+ "echo-more-info": "დეტალურად",
+ "echo-feedback": "შეფასება",
+ "notification-link-text-view-message": "შეტყობინების ნახვა",
+ "notification-link-text-view-mention": "მონიშვნის ნახვა",
+ "notification-link-text-view-changes": "ცვლილებების ნახვა",
+ "notification-link-text-view-page": "გვერდის ნახვა",
+ "notification-link-text-view-edit": "რედაქტირების ნახვა",
+ "notification-edit-talk-page2": "მომხმარებელმა [[User:$1|$1]] {{GENDER:$1|დატოვა}} შეტყობინება თქვენი [[User talk:$2#$3|განხილვის გვერდზე]].",
+ "notification-edit-talk-page-with-section": "მომხმარებელმა [[User:$1|$1]] {{GENDER:$1|დატოვა}} შეტყობინება თქვენი განხილვის გვერდზე განყოფილებაში „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "მომხმარებელმა $1 {{GENDER:$1|დატოვა}} შეტყობინება თქვენი [[User talk:$2#$3|განხილვის გვერდზე]].",
+ "notification-edit-talk-page-flyout-with-section": "მომხმარებელმა $1 {{GENDER:$1|დატოვა}} შეტყობინება თქვენი განხილვის გვერდზე განყოფილებაში „[[User talk:$2#$3|$4]]“.",
+ "notification-page-linked": "[[:$2]] {{GENDER:$1|ბმული}} გაკეთდა სტატიაში [[:$3]]. [[Special:WhatLinksHere/$2|იხილეთ ამ გვერდის ყველა ბმული]].",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|მოგნიშნათ}} განხილვის გვერდზე „$5“ სექციაში „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|მოგნიშნათ}} განხილვის გვერდზე „$5“ სექციაში „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|მოგნიშნათ}} [[:$3|$2 განხილვის გვერდზე]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|მოგნიშნათ}} [[:$3|$2 განხილვის გვერდზე]].",
+ "notification-user-rights-add": "თქვენ გაწევრიანებული ხართ {{PLURAL:$2|ამ ჯგუფში|ამ ჯგუფებში}}: $1",
+ "notification-user-rights-remove": "თქვენ აღარ ხართ გაწევრიანებული {{PLURAL:$2|ამ ჯგუფში|ამ ჯგუფებში}}: $1",
+ "notification-new-user": "კეთილი იყოს თქვენი მობრძანება საიტზე {{SITENAME}}, $1! ჩვენ მოხარული ვართ თქვენი აქ ყოფნით.",
+ "notification-edit-talk-page-email-batch-body2": "მომხმარებელმა $1 {{GENDER:$1|დატოვა}} შეტყობინება თქვენი განხილვის გვერდზე:",
+ "notification-edit-talk-page-email-batch-body-with-section": "მომხმარებელმა $1 {{GENDER:$1|დატოვა}} შეტყობინება თქვენი განხილვის გვერდზე განყოფილებაში „$2“.",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|მოგნიშნათ}} განხილვის გვერდზე „$4“ სექციაში „$3“.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|მოგნიშნათ}} $2 განხილვის გვერდზე.",
+ "echo-notification-count": "$1+",
+ "echo-email-batch-body-default": "თქვენ გაქვთ ახალი შეტყობინება.",
+ "echo-overlay-link": "შეტყობინება",
+ "echo-overlay-title": "<b>შეტყობინებები</b>",
+ "echo-mark-all-as-read": "მონიშნეთ ყველა, როგორც წაკითხული",
+ "echo-date-today": "დღეს",
+ "echo-date-yesterday": "გუშინ",
+ "echo-email-batch-bullet": "•"
+}
diff --git a/Echo/i18n/kk-cyrl.json b/Echo/i18n/kk-cyrl.json
new file mode 100644
index 00000000..63ea4831
--- /dev/null
+++ b/Echo/i18n/kk-cyrl.json
@@ -0,0 +1,115 @@
+{
+ "@metadata": {
+ "authors": [
+ "Arystanbek"
+ ]
+ },
+ "echo-desc": "Хабарландыру жүйесі",
+ "prefs-echo": "Хабарландырулар",
+ "prefs-emailsettings": "Е-пошта баптаулары",
+ "prefs-displaynotifications": "Көрсету бапталымдары",
+ "prefs-echosubscriptions": "Бұл оқиғалар туралы маған хабарландыр",
+ "prefs-newmessageindicator": "Жаңа хабарлама көрсеткіші",
+ "echo-pref-send-me": "Маған жіберу:",
+ "echo-pref-send-to": "Жіберу:",
+ "echo-pref-email-format": "Е-пошта пішіні:",
+ "echo-pref-web": "Веб",
+ "echo-pref-email": "Е-поштаңыз",
+ "echo-pref-email-frequency-never": "Ешбір е-пошта хабарландыруларын маған жіберме",
+ "echo-pref-email-frequency-daily": "Хабарландырулардың күнделікті түйіндемесі",
+ "echo-pref-email-frequency-weekly": "Хабарландырулардың апталық түйіндемесі",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Қалыпты мәтін",
+ "echo-pref-notify-show-link": "Құралдар үстелімде ескертпелерді көрсету",
+ "echo-pref-new-message-indicator": "Құралдар үстелімде талқылау беттегі хабарламалар көрсеткішін көрсету",
+ "echo-learn-more": "Көбірек білу",
+ "echo-new-messages": "Сізге жаңа хабарламалар келді",
+ "echo-category-title-edit-user-talk": "Талқылау бетіңіздегі {{PLURAL:$1|хабарлама|хабарламалар}}",
+ "echo-category-title-article-linked": "Бет {{PLURAL:$1|сілтемесі|сілтемелері}}",
+ "echo-category-title-reverted": "Өңдеме {{PLURAL:$1|қайтаруы|қайтарулары}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Еске салу|Еске салу}}",
+ "echo-category-title-other": "{{PLURAL:$1|Басқа}}",
+ "echo-category-title-system": "{{PLURAL:$1|Жүйе}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Қатысушы құқықтары өзгертуі|Қатысушы құқықтары өзгертулері}}",
+ "echo-pref-tooltip-edit-user-talk": "Әлдекім талқылау бетіме хабарлама немесе жауап жазса маған ескерт.",
+ "echo-pref-tooltip-article-linked": "Әлдекім мен бастаған бетті мақала бетінде сілтеген кезде маған ескерт.",
+ "echo-pref-tooltip-reverted": "Әлдекім жоққа шығару несесе шегіндіру құралын қолданып мен жасаған өңдемелерді қайтарған кезде маған ескерт.",
+ "echo-pref-tooltip-mention": "Әлдекім менің қатысушы бетімді сілтеген кезде маған ескерт.",
+ "echo-pref-tooltip-user-rights": "Әлдекім менің қатысушы құқықтарымды өзгерткен кезде маған ескерт",
+ "echo-no-agent": "[Ешкім]",
+ "echo-no-title": "[Бет жоқ]",
+ "echo-error-no-formatter": "Ескертпелер үшін форматтау анықталмайды.",
+ "echo-error-preference": "Қате: Қатысушы бапталымдары орнатылмайды.",
+ "echo-error-token": "Қате: Қатысушы токені қалпына келтірілмейді.",
+ "notifications": "Хабарландырулар",
+ "tooltip-pt-notifications": "Сіздегі хабарландырулар",
+ "echo-specialpage": "Хабарландырулар",
+ "echo-anon": "Ескертпелерді қабылдау үшін [$1 тіркеліңіз] немесе [$2 кіріңіз].",
+ "echo-none": "Сізде ескертпелер жоқ.",
+ "echo-more-info": "Көбірек ақпарат",
+ "echo-feedback": "Кері байланыс",
+ "notification-link-text-view-message": "Хабарламаны көру",
+ "notification-link-text-view-mention": "Еске салуды көру",
+ "notification-link-text-view-changes": "Өзгерістерді көру",
+ "notification-link-text-view-page": "Бетті көру",
+ "notification-link-text-view-edit": "Өңдемені көру",
+ "notification-edit-talk-page2": "[[User:$1|$1]] [[User talk:$2#$3|талқылау бетіңізге]] хабарлама {{GENDER:$1|қалдырды}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] талқылау бетіңіздегі «[[User talk:$2#$3|$4]]» бөліміне хабарлама {{GENDER:$1|қалдырды}}.",
+ "notification-edit-talk-page-flyout2": "$1 [[User talk:$2#$3|талқылау бетіңізге]] хабарлама {{GENDER:$1|қалдырды}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1 талқылау бетіңіздегі «[[User talk:$2#$3|$4]]» бөліміне хабарлама {{GENDER:$1|қалдырды}}.",
+ "notification-page-linked": "[[:$2]] [[:$3]] бетінен {{GENDER:$1|сілтенді}}. [[Special:WhatLinksHere/$2|Бұл бетке барлық сілтенгендерді көріңіз]].",
+ "notification-page-linked-flyout": "[[:$2]] [[:$3]] дегеннен {{GENDER:$1|сілтенді}}.",
+ "notification-add-comment2": "[[User:$1|$1]] \"$4\" талқылау бетіндегі \"[[$3|$2]]\" бөліміне {{GENDER:$1|пікір жазды}}.",
+ "notification-add-talkpage-topic2": "[[$3]] бетінде [[User:$1|$1]] \"$2\" деген жаңа тақырып {{GENDER:$1|қосты}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] сізге хабарлама {{GENDER:$1|жіберді}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] талқылау бетіндегі \"[[$3#$2|$2]]\" бөліміне {{GENDER:$1|пікірін білдірді}}.",
+ "notification-mention": "[[User:$1|$1]] $5 талқылау бетінің «[[:$3#$2|$4]]» бөлімінде сізді {{GENDER:$1|атап өтті}}.",
+ "notification-mention-flyout": "$1 $5 талқылау бетінің «[[:$3#$2|$4]]» бөлімінде сізді {{GENDER:$1|атап өтті}}.",
+ "notification-mention-nosection": "[[User:$1|$1]] [[:$3|$2 талқылау бетінде]] сізді {{GENDER:$1|атап өтті}}.",
+ "notification-mention-nosection-flyout": "$1 [[:$3|$2 талқылау бетінде]] сізді {{GENDER:$1|атап өтті}}.",
+ "notification-user-rights": "Сіздің қатысушы құқықтарыңызды [[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|өзгерті}}]]. $2. [[Special:ListGroupRights|Толығырақ біліңіз]]",
+ "notification-user-rights-flyout": "Сіздің қатысушы құқықтарыңызды $1 {{GENDER:$1|өзгерті}}. $2. [[Special:ListGroupRights|Қатысушы құқықтары туралы көбірек біліңіз]]",
+ "notification-user-rights-add": "Қазір {{PLURAL:$2|бұл топтың|бұл топтардың}} мүшесісіз: $1",
+ "notification-user-rights-remove": "Сіз {{PLURAL:$2|бұл топтың|бұл топтың}} көптен бергі мүшесі емессіз: $1",
+ "notification-new-user": "$1 {{SITENAME}} сайтына қош келдіңіз! Сіз осында болғаныңызға біз қуаныштымыз.",
+ "notification-reverted2": "Сіздің {{PLURAL:$4|[[:$2]] бетіндегі өңдемеңізді|[[:$2]] бетіндегі өңдемелеріңізді}} [[User:$1|$1]] {{GENDER:$1|жоққа шығарды}}. $3",
+ "notification-reverted-flyout2": "Сіздің {{PLURAL:$4|$2 бетіндегі өңдемеңізді|$2 бетіндегі өңдемелеріңізді}} $1 есімді қатысушы {{GENDER:$1|жоққа шығарыды}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{SITENAME}} сайтында сізге хабарлама {{GENDER:$1|қалдырды}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 талқылау бетіңізге хабарлама {{GENDER:$1|қалдырды}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 талқылау бетіңіздегі «$2» бөліміне хабарлама {{GENDER:$1|қалдырды}}.",
+ "notification-page-linked-email-subject": "{{SITENAME}} сайтында сіздің бетіңіз сілтенді",
+ "notification-page-linked-email-batch-body": "$2 $3 дегеннен {{GENDER:$1|сілтенді}}.",
+ "notification-reverted-email-subject2": "{{SITENAME}} сайтында сіздің {{PLURAL:$3|өңдемеңіз|өңдемелеріңіз}}{{GENDER:$1|қайтарылды}}",
+ "notification-reverted-email-batch-body2": "Сіздің {{PLURAL:$3|$2 бетіндегі өңдемеңізді|$2 бетіндегі өңдемелеріңізді}} $1 есімді қатысушы {{GENDER:$1|жоққа шығарыды}}.",
+ "notification-mention-email-subject": "{{SITENAME}} сайтында $1 сізді {{GENDER:$1|атап өтті}}",
+ "notification-mention-email-batch-body": "$1 $4 талқылау бетінің «$3» бөлімінде сізді {{GENDER:$1|атап өтті}}.",
+ "notification-mention-nosection-email-batch-body": "$1 $2 талқылау бетінде сізді {{GENDER:$1|атап өтті}}.",
+ "notification-user-rights-email-subject": "{{SITENAME}} сайтында сіздің қатысушы құқықтарыңыз өзгерілді.",
+ "notification-user-rights-email-batch-body": "Сіздің қатысушы құқықтарыңызды $1 {{GENDER:$1|өзгерті}}. $2.",
+ "echo-email-subject-default": "{{SITENAME}} сайтында жаңа ескертпелер",
+ "echo-email-body-default": "{{SITENAME}} сайтында сіз жаңа ескертпелер алдыңыз:\n\n$1",
+ "echo-email-batch-body-default": "Сізге жаңа ескертпелер келді.",
+ "echo-email-footer-default": "$2\n\nБақылау э-пошта арқылы жіберілсе, бапталымдарыңызды тексеріп шығыңыз:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Бақылау э-почта арқылы жіберілсе, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">бапталымдарыңызды тексеріңіз</a>.<br />\n\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Ескертпе ($1)|Ескертпе ($1)|100=Ескертпе (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Хабарламалар ($1)|Хабарламалар ($1)|100=Хабарламалар (99+)}}",
+ "echo-notification-alert-text-only": "Дабылдар",
+ "echo-notification-message-text-only": "Хабарламалар",
+ "echo-overlay-link": "Барлық ескертпелер",
+ "echo-overlay-title": "<b>Ескертпелер</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Ескертпелер}}</b> (оқылмаған $2 ескертпенің $1 ескертпесі көрселуде)",
+ "echo-mark-all-as-read": "Барлығын оқылды деп белгіле",
+ "echo-date-today": "Бүгін",
+ "echo-date-yesterday": "Кеше",
+ "echo-load-more-error": "Қосымша нәтижелерді алуда қателік кездесті.",
+ "notification-edit-talk-page-bundle": "$1 және {{PLURAL:$4|басқа|басқа}} $3 қатысушы [[User talk:$2|талқылау бетіңізге]] хабарлама {{GENDER:$1|қалдырды}}.",
+ "notification-page-linked-bundle": "$2 $3 және басқа $4 {{PLURAL:$5|беттен|беттен}} {{GENDER:$1|сілтенді}}. [[Special:WhatLinksHere/$2|Бұл бетке барлық сілтенгендерді көріңіз]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 және {{PLURAL:$3|басқа|басқа}} $2 қатысушы талқылау бетіңізге хабарлама {{GENDER:$1|қалдырды}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2 $3 және басқа $4 {{PLURAL:$5|беттен|беттен}} {{GENDER:$1|сілтенді}}.",
+ "echo-email-batch-subject-daily": "Сізге {{SITENAME}} сайтында {{PLURAL:$2|жаңа ескертпе|жаңа ескертпелер}} келді",
+ "echo-email-batch-subject-weekly": "Сізге осы аптада {{SITENAME}} сайтында {{PLURAL:$2|жаңа ескертпе|жаңа ескертпелер}} келді",
+ "echo-email-batch-body-intro-daily": "Сәлем $1, \nБұл {{SITENAME}} жобасындағы бүгінгі сіз үшін іс-әрекеттер түйіндемесі.",
+ "echo-email-batch-body-intro-weekly": "Сәлем $1, \nБұл {{SITENAME}} жобасындағы осы аптадағы сіз үшін іс-әрекеттер түйіндемесі.",
+ "echo-email-batch-link-text-view-all-notifications": "Барлық ескертпелерді көру",
+ "echo-rev-deleted-text-view": "Бұл бет нұсқасы жасырылған"
+}
diff --git a/Echo/i18n/kn.json b/Echo/i18n/kn.json
new file mode 100644
index 00000000..f18c8903
--- /dev/null
+++ b/Echo/i18n/kn.json
@@ -0,0 +1,75 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pavanaja",
+ "Shubha",
+ "Vikashegde"
+ ]
+ },
+ "echo-desc": "ಸೂಚನಾ ವ್ಯವಸ್ಥೆ",
+ "prefs-echo": "ಸೂಚನೆಗಳು",
+ "prefs-emailsettings": "ಇಮೈಲ್ ಆಯ್ಕೆಗಳು",
+ "prefs-displaynotifications": "ಪ್ರದರ್ಶನ ಆಯ್ಕೆಗಳು",
+ "prefs-echosubscriptions": "ಈ ಘಟನೆಗಳ ಬಗ್ಗೆ ನನಗೆ ತಿಳಿಸಿ",
+ "prefs-newmessageindicator": "ಹೊಸ ಸಂದೇಶ ಸೂಚಕ",
+ "echo-pref-send-me": "ನನಗೆ ಕಳುಹಿಸಿ:",
+ "echo-pref-send-to": "ಇವರಿಗೆ ಕಳುಹಿಸಿ:",
+ "echo-pref-email-format": "ಇಮೈಲ್ ನಮೂನೆ:",
+ "echo-pref-web": "ವಿಶ್ವವ್ಯಾಪಿಜಾಲ",
+ "echo-pref-email": "ಇಮೈಲ್",
+ "echo-pref-email-frequency-never": "ನನಗೆ ಯಾವುದೇ ಇಮೈಲ್ ಸಂದೇಶ ಕಳುಹಿಸಬೇಡಿ",
+ "echo-pref-email-frequency-immediately": "ಒಂದೊಂದೆ ಸಂದೇಶ ಅವು ಬರುತ್ತಿದ್ದಂತೆ",
+ "echo-pref-email-frequency-daily": "ಪ್ರತಿದಿನದ ಸೂಚನೆಗಳ ಸಾರಾಂಶ",
+ "echo-pref-email-frequency-weekly": "ಪ್ರತಿ ವಾರದ ಸೂಚನೆಗಳ ಸಾರಾಂಶ",
+ "echo-pref-email-format-html": "ಎಚ್‌ಟಿಎಂಎಲ್",
+ "echo-pref-email-format-plain-text": "ಸಾದಾ ಪಠ್ಯ",
+ "echo-pref-notify-show-link": "ನನ್ನ ಸಾಧನಪಟ್ಟಿಯಲ್ಲಿ ಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ",
+ "echo-pref-new-message-indicator": "ನನ್ನ ಸಾಧನಪಟ್ಟಿಯಲ್ಲಿ ಚರ್ಚಾಪುಟದ ಸಂದೇಶಸೂಚನೆ ತೋರಿಸಿ",
+ "echo-learn-more": "ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ",
+ "echo-new-messages": "ನಿಮಗೆ ಹೊಸ ಸಂದೇಶಗಳಿವೆ",
+ "echo-category-title-edit-user-talk": "ಚರ್ಚಾಪುಟ {{PLURAL:$1|message|messages}}",
+ "echo-category-title-article-linked": "ಪುಟ {{PLURAL:$1|link|links}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|revert|reverts}} ಸಂಪಾದಿಸಿ",
+ "echo-category-title-mention": "{{PLURAL:$1|Mention|Mentions}}",
+ "echo-category-title-other": "{{PLURAL:$1|Other}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-pref-tooltip-edit-user-talk": "ಯಾರಾದರೂ ನನಗೆ ಸಂದೇಶ ಪೋಸ್ಟ್ ಮಾಡಿದರೆ ಅಥವಾ ನನ್ನ ಚರ್ಚಾಪುಟದಲ್ಲಿ ಉತ್ತರಿಸಿದರೆ ತಿಳಿಸಿ",
+ "echo-pref-tooltip-article-linked": "ನಾನು ತಯಾರಿಸಿದ ಲೇಖನಪುಟಕ್ಕೆ ಯಾರಾದರೂ ಕೊಂಡಿ ನೀಡಿದರೆ ನನಗೆ ತಿಳಿಸಿ",
+ "echo-pref-tooltip-reverted": "ನಾನು ಮಾಡಿದ ಸಂಪಾದನೆಯನ್ನು ಯಾರಾದರು ಹಿಂದಿನಂತೆ ಮಾಡಿದರೆ ನನಗೆ ತಿಳಿಸಿ",
+ "echo-pref-tooltip-mention": "ನನ್ನ ಸದಸ್ಯ ಪುಟಕ್ಕೆ ಯಾರಾದರು ಯಾವುದಾದರು ಚರ್ಚಾಪುಟದಿಂದ ಕೊಂಡಿ ನೀಡಿದರೆ ನನಗೆ ತಿಳಿಸಿ",
+ "echo-no-agent": "[ಯಾರೂ ಇಲ್ಲ]",
+ "echo-no-title": "[ಯಾವುದೇ ಪುಟ ಇಲ್ಲ]",
+ "echo-error-no-formatter": "ಸೂಚನೆಗಳಿಗೆ ಯಾವುದೇ ನಮೂನೆ ನಿರ್ಧರಿಸಿಲ್ಲ",
+ "echo-error-preference": "ದೋಷ: ಬಳಕೆದಾರ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ನಿಗದಿ ಮಾಡಲು ಆಗಲಿಲ್ಲ",
+ "echo-error-token": "ದೋಷ: ಬಳಕೆದಾರ ಟೋಕನ್ ಮರಳಿ ಪಡೆಯಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ",
+ "notifications": "ಸೂಚನೆಗಳು",
+ "tooltip-pt-notifications": "ನಿಮ್ಮ ಸೂಚನೆಗಳು",
+ "echo-specialpage": "ಸೂಚನೆಗಳು",
+ "echo-anon": "ಸೂಚನೆಗಳನ್ನು ಸ್ವೀಕರಿಸಲು [ಖಾತೆ ಸೃಷ್ಟಿಸಿ $1] ಅಥವಾ [ಲಾಗಿನ್ $2]",
+ "echo-none": "ನಿಮಗೆ ಯಾವುದೇ ಸೂಚನೆಗಳಿಲ್ಲ",
+ "echo-more-info": "ಹೆಚ್ಚಿನ ಮಾಹಿತಿ",
+ "echo-feedback": "ಹಿಂಮಾಹಿತಿ",
+ "notification-link-text-view-message": "ಸಂದೇಶ ನೋಡಿ",
+ "notification-link-text-view-mention": "ಸಂಬೋಧನೆ ನೋಡಿ",
+ "notification-link-text-view-changes": "ಬದಲಾವಣೆ ನೋಡಿ",
+ "notification-link-text-view-page": "ಪುಟ ನೋಡಿ",
+ "notification-link-text-view-edit": "ಸಂಪಾದನೆ ನೋಡಿ",
+ "notification-new-user": "{{SITENAME}} ಕ್ಕೆ ಸುಸ್ವಾಗತ, $1! ನೀವು ಇಲ್ಲಿ ಬಂದಿದ್ದು ಸಂತಸ ತಂದಿತು",
+ "notification-page-linked-email-subject": "ನಿಮ್ಮ ಪುಟವು {{SITENAME}} ಜಾಲತಾಣಕ್ಕೆ ಸಂಪರ್ಕಿಸಲ್ಪಟ್ಟಿದೆ",
+ "notification-user-rights-email-subject": "{{SITENAME}} ಜಾಲತಾಣದಲ್ಲಿ ನಿಮ್ಮ ಬಳಕೆದಾರ ಹಕ್ಕುಗಳನ್ನು ಬದಲಿಸಲಾಗಿದೆ",
+ "echo-email-subject-default": "{{SITENAME}} ಜಾಲತಾಣದಲ್ಲಿ ಹೊಸ ಸೂಚನೆ ಇದೆ",
+ "echo-email-body-default": "{{SITENAME}} ಜಾಲತಾಣದಲ್ಲಿ ನಿಮಗೆ ಈ ಸೂಚನೆ ಇದೆ: $1",
+ "echo-email-batch-body-default": "ನಿಮಗೆ ಹೊಸ ಸೂಚನೆ ಇದೆ.",
+ "echo-email-footer-default-html": "ನಿಮಗೆ ನಾವು ಯಾವ ಇಮೈಲ್‌ಗಳನ್ನು ಕಳುಹಿಸಬಹುದೆಂಬುದನ್ನು ನಿಯಂತ್ರಿಸಲು, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">ನಿಮ್ಮ ಪ್ರಾಶಸ್ತ್ಯಗಳನ್ನು ಪರಿಶೀಲಿಸಿ</a>.<br /> $1",
+ "echo-overlay-link": "ಎಲ್ಲ ಸೂಚನೆಗಳು",
+ "echo-overlay-title": "<b>ಸೂಚನೆಗಳು</b>",
+ "echo-overlay-title-overflow": "<b>ಸೂಚನೆಗಳು</b> ($2 ರಲ್ಲಿ $1 ಓದದವುಗಳನ್ನು ತೋರಿಸಲಾಗುತ್ತಿದೆ)",
+ "echo-mark-all-as-read": "ಎಲ್ಲವನ್ನೂ ಓದಿದೆ ಎಂದು ಆಯ್ಕೆ ಮಾಡಿ",
+ "echo-date-today": "ಇಂದು",
+ "echo-date-yesterday": "ನಿನ್ನೆ",
+ "echo-load-more-error": "ಹೆಚ್ಚು ಫಲಿತಾಂಶಗಳನ್ನು ಪಡೆಯುವಾಗ ದೋಷವೊಂದು ಆಯಿತು",
+ "echo-email-batch-body-intro-daily": "ನಮಸ್ಕಾರ $1,\n{{SITENAME}} ಜಾಲತಾಣದಲ್ಲಿ ಇಂದು ನಡೆದ ಎಲ್ಲ ಪ್ರಕ್ರಿಯೆಗಳ ಸಾರಾಂಶ ನಿಮಗಾಗಿ ಇಲ್ಲಿದೆ.",
+ "echo-email-batch-body-intro-weekly": "ನಮಸ್ಕಾರ $1,\n{{SITENAME}} ಜಾಲತಾಣದಲ್ಲಿ ಈ ವಾರ ನಡೆದ ಎಲ್ಲ ಪ್ರಕ್ರಿಯೆಗಳ ಸಾರಾಂಶ ನಿಮಗಾಗಿ ಇಲ್ಲಿದೆ.",
+ "echo-email-batch-link-text-view-all-notifications": "ಎಲ್ಲ ಸೂಚನೆಗಳನ್ನು ನೋಡಿ",
+ "echo-rev-deleted-text-view": "ಈ ಪುಟದ ಪರಿಷ್ಕರಣೆಯನ್ನು ಹತ್ತಿಕ್ಕಲಾಗಿದೆ"
+}
diff --git a/Echo/i18n/ko.json b/Echo/i18n/ko.json
new file mode 100644
index 00000000..399f7da5
--- /dev/null
+++ b/Echo/i18n/ko.json
@@ -0,0 +1,125 @@
+{
+ "@metadata": {
+ "authors": [
+ "Daisy2002",
+ "Freebiekr",
+ "Hym411",
+ "Kwj2772",
+ "Priviet",
+ "관인생략",
+ "아라",
+ "Revi",
+ "IRTC1015"
+ ]
+ },
+ "echo-desc": "알림 시스템",
+ "prefs-echo": "알림",
+ "prefs-emailsettings": "이메일 설정",
+ "prefs-displaynotifications": "표시 설정",
+ "prefs-echosubscriptions": "다음 경우에 알림",
+ "prefs-newmessageindicator": "새 메시지 표시기",
+ "echo-pref-send-me": "다음 방식으로 보내기:",
+ "echo-pref-send-to": "다음 주소로 보내기:",
+ "echo-pref-email-format": "이메일 형식:",
+ "echo-pref-web": "웹",
+ "echo-pref-email": "이메일",
+ "echo-pref-email-frequency-never": "내게 어떠한 이메일 알림도 보내지 않기",
+ "echo-pref-email-frequency-immediately": "알릴 내용이 있는 대로 개별적으로 알림",
+ "echo-pref-email-frequency-daily": "매일 알림 요약",
+ "echo-pref-email-frequency-weekly": "매주 알림 요약",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "일반 텍스트",
+ "echo-pref-notify-show-link": "내 도구 모음에 알림 보이기",
+ "echo-pref-new-message-indicator": "내 도구 모음에 토론 문서 메시지 표시기 보이기",
+ "echo-learn-more": "더 알아보기",
+ "echo-new-messages": "새 메시지가 있습니다",
+ "echo-category-title-edit-user-talk": "토론 문서 {{PLURAL:$1|메시지}}",
+ "echo-category-title-article-linked": "문서 {{PLURAL:$1|링크}}",
+ "echo-category-title-reverted": "편집이 {{PLURAL:$1|되돌려짐}}",
+ "echo-category-title-mention": "본인 {{PLURAL:$1|언급}}",
+ "echo-category-title-other": "{{PLURAL:$1|기타}}",
+ "echo-category-title-system": "{{PLURAL:$1|시스템}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|사용자 권한 변경}}",
+ "echo-pref-tooltip-edit-user-talk": "내 토론 문서에 누군가가 글이나 답글을 남길 때 내게 알립니다.",
+ "echo-pref-tooltip-article-linked": "누군가가 어느 문서에서 내가 만든 문서를 링크할 때 내게 알립니다.",
+ "echo-pref-tooltip-reverted": "누군가가 편집 취소나 되돌리기 도구를 사용하여 내 편집을 되돌릴 때 내게 알립니다.",
+ "echo-pref-tooltip-mention": "누군가가 내 사용자 문서를 링크할 때 내게 알립니다.",
+ "echo-pref-tooltip-user-rights": "다른 사용자가 내 사용자 권한을 변경하는 경우 알립니다.",
+ "echo-no-agent": "[알 수 없는 사용자]",
+ "echo-no-title": "[문서 없음]",
+ "echo-error-no-formatter": "알림에 대해 정의된 형식이 없습니다.",
+ "echo-error-preference": "오류: 사용자 환경 설정을 저장할 수 없습니다.",
+ "echo-error-token": "오류: 사용자 토큰을 얻을 수 없습니다.",
+ "notifications": "알림",
+ "tooltip-pt-notifications": "내 알림",
+ "echo-specialpage": "알림",
+ "echo-anon": "알림을 받으려면 [$1 계정을 만들거나] [$2 로그인]하세요.",
+ "echo-none": "알림이 없습니다.",
+ "echo-more-info": "자세한 정보",
+ "echo-feedback": "피드백 남기기",
+ "notification-link-text-view-message": "메시지 보기",
+ "notification-link-text-view-mention": "언급된 내용 보기",
+ "notification-link-text-view-changes": "차이 보기",
+ "notification-link-text-view-page": "문서 보기",
+ "notification-link-text-view-edit": "편집 보기",
+ "notification-edit-talk-page2": "[[User:$1|$1]]님이 당신의 [[User talk:$2#$3|토론 문서]]에 글을 {{GENDER:$1|남겼습니다}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]]님이 당신의 토론 문서의 \"[[User talk:$2#$3|$4]]\" 문단에 글을 {{GENDER:$1|남겼습니다}}.",
+ "notification-edit-talk-page-flyout2": "$1님이 당신의 [[User talk:$2#$3|토론 문서]]에 글을 {{GENDER:$1|남겼습니다}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1님이 당신의 토론 문서의 \"[[User talk:$2#$3|$4]]\" 문단에 글을 {{GENDER:$1|남겼습니다}}.",
+ "notification-page-linked": "[[:$2]] 문서가 [[:$3]]에 {{GENDER:$1|링크되었습니다}}. [[Special:WhatLinksHere/$2|이 문서를 가리키는 모든 링크를 봅니다]].",
+ "notification-page-linked-flyout": "[[:$2]] 문서가 [[:$3]]에 {{GENDER:$1|링크되었습니다}}.",
+ "notification-add-comment2": "[[User:$1|$1]]님이 \"$4\" 토론 문서의 \"[[$3|$2]]\" 문단에 {{GENDER:$1|덧글을 남겼습니다}}.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]]님이 [[$3]]에 새 주제 \"$2\"을(를) {{GENDER:$1|게시했습니다}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]]님이 당신에게 메시지를 {{GENDER:$1|보냈습니다}}: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]]님이 당신의 토론 문서의 \"[[$3#$2|$2]]\" 문단에 {{GENDER:$1|덧글을 남겼습니다}}.",
+ "notification-mention": "[[User:$1|$1]]님이 $5 토론 문서의 \"[[:$3#$2|$4]]\" 문단에서 당신을 {{GENDER:$1|언급했습니다}}.",
+ "notification-mention-flyout": "$1님이 $5 토론 문서의 \"[[:$3#$2|$4]]\"에서 당신을 {{GENDER:$1|언급했습니다}}.",
+ "notification-mention-nosection": "[[User:$1|$1]]님이 [[:$3|$2 토론 문서]]에서 당신을 언급했습니다.",
+ "notification-mention-nosection-flyout": "$1님이 [[:$3|$2 토론 문서]]에서 당신을 언급했습니다.",
+ "notification-user-rights": "[[User:$1|$1]]님이 당신의 [[Special:Log/rights/$1|사용자 권한을 {{GENDER:$1|바꾸었습니다}}]]. $2. [[Special:ListGroupRights|더 알아보기]]",
+ "notification-user-rights-flyout": "$1님이 당신의 사용자 권한을 {{GENDER:$1|바꾸었습니다}}. $2. [[Special:ListGroupRights|더 알아보기]]",
+ "notification-user-rights-add": "당신은 이제 {{PLURAL:$2|다음 권한}}을 갖습니다: $1",
+ "notification-user-rights-remove": "당신은 더 이상 {{PLURAL:$2|다음 권한}}을 갖지 않습니다: $1",
+ "notification-new-user": "$1님, {{SITENAME}}에 온 것을 환영합니다! 당신이 여기에 오신 걸 매우 기쁘게 생각합니다.",
+ "notification-reverted2": "{{PLURAL:$4|[[:$2]]에 대한 내 편집}}을 [[User:$1|$1]]님이 {{GENDER:$1|되돌렸습니다}}. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|$2에 대한 내 편집}}을 $1님이 {{GENDER:$1|되돌렸습니다}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1님이 {{SITENAME}}에서 당신에게 글을 {{GENDER:$1|남겼습니다}}",
+ "notification-edit-talk-page-email-batch-body2": "$1님이 당신의 토론 문서에 글을 {{GENDER:$1|남겼습니다}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1님이 당신의 토론 문서의 \"$2\" 문단에 글을 {{GENDER:$1|남겼습니다}}.",
+ "notification-page-linked-email-subject": "{{SITENAME}}에서 당신의 문서가 링크되었습니다",
+ "notification-page-linked-email-batch-body": "$2 문서가 $3에 {{GENDER:$1|링크되었습니다}}",
+ "notification-reverted-email-subject2": "{{SITENAME}}의 당신의 {{PLURAL:$3|편집}}이 {{GENDER:$1|되돌려졌습니다}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|$2에 대한 내 편집}}을 $1님이 {{GENDER:$1|되돌렸습니다}}.",
+ "notification-mention-email-subject": "$1님이 {{SITENAME}}에서 당신을 {{GENDER:$1|언급했습니다}}",
+ "notification-mention-email-batch-body": "$1님이 $4 토론 문서의 \"$3\" 문단에서 당신을 {{GENDER:$1|언급했습니다}}.",
+ "notification-mention-nosection-email-batch-body": "$1님이 $2 토론 문서에서 당신을 언급했습니다.",
+ "notification-user-rights-email-subject": "{{SITENAME}}에서 당신의 사용자 권한이 바뀌었습니다",
+ "notification-user-rights-email-batch-body": "$1님이 당신의 사용자 권한을 {{GENDER:$1|바꾸었습니다}}. $2",
+ "echo-email-subject-default": "{{SITENAME}}의 새 알림",
+ "echo-email-body-default": "{{SITENAME}}에 새 알림이 있습니다:\n\n$1",
+ "echo-email-batch-body-default": "새 알림이 있습니다",
+ "echo-email-footer-default": "$2\n\n발송되는 이메일을 관리하려면, 환경 설정을 확인하세요:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "발송되는 이메일을 제어하려면, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">사용자 환경 설정을 확인하세요</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|알림 ($1)|알림 ($1)|100=알림 (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|메시지 ($1)|메시지 ($1)|100=메시지 (99+)}}",
+ "echo-notification-alert-text-only": "알림",
+ "echo-notification-message-text-only": "메시지",
+ "echo-overlay-link": "모든 알림",
+ "echo-overlay-title": "<b>알림</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|알림}}</b> (안 읽은 알림 $2개 중 $1개)",
+ "echo-mark-all-as-read": "모두 읽은 것으로 표시",
+ "echo-date-today": "오늘",
+ "echo-date-yesterday": "어제",
+ "echo-load-more-error": "더 많은 결과를 가져오는 동안 오류가 발생했습니다.",
+ "notification-edit-talk-page-bundle": "$1님 {{PLURAL:$4|외}} $3명이 당신의 [[User talk:$2|토론 문서]]에 글을 {{GENDER:$1|남겼습니다}}.",
+ "notification-page-linked-bundle": "$2 문서가 $3 문서와 다른 $4개 {{PLURAL:$5|문서}}에 {{GENDER:$1|링크되었습니다}}. [[Special:WhatLinksHere/$2|이 문서를 가리키는 모든 링크 보기]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1님과 {{PLURAL:$3|다른}} $2명의 사용자가 당신의 토론 문서에 글을 {{GENDER:$1|남겼습니다}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2 문서가 $3 문서와 다른 $4개 {{PLURAL:$5|문서}}에 {{GENDER:$1|링크되었습니다}}",
+ "echo-email-batch-subject-daily": "{{SITENAME}}에서 {{PLURAL:$2|새 알림}}이 있습니다",
+ "echo-email-batch-subject-weekly": "이번 주에 {{SITENAME}}에서 {{PLURAL:$2|새 알림}}이 있습니다",
+ "echo-email-batch-body-intro-daily": "$1님 안녕하세요,\n여기에 {{SITENAME}}에 오늘의 활동 요약이 있습니다.",
+ "echo-email-batch-body-intro-weekly": "$1님 안녕하세요,\n여기에 {{SITENAME}}에 이번 주의 활동 요약이 있습니다.",
+ "echo-email-batch-link-text-view-all-notifications": "모든 알림 보기",
+ "echo-rev-deleted-text-view": "이 문서의 판은 숨겨져 있습니다.",
+ "apihelp-echomarkread-description": "현재 사용자의 알림을 읽은 것으로 표시"
+}
diff --git a/Echo/i18n/krc.json b/Echo/i18n/krc.json
new file mode 100644
index 00000000..baab9610
--- /dev/null
+++ b/Echo/i18n/krc.json
@@ -0,0 +1,108 @@
+{
+ "@metadata": {
+ "authors": [
+ "Iltever"
+ ]
+ },
+ "echo-desc": "Билдириуле система",
+ "prefs-echo": "Билдириуле",
+ "prefs-emailsettings": "Эл. почтаны джарашдырыулары",
+ "prefs-displaynotifications": "Кёрюнюуню джарашдырыулары",
+ "prefs-echosubscriptions": "Бу болууланы юсюнден билдире тур",
+ "prefs-newmessageindicator": "Джангы билдириуню индикатору",
+ "echo-pref-send-me": "Меннге джибер:",
+ "echo-pref-send-to": "Былайгъа джибер:",
+ "echo-pref-email-format": "E-mail'ни форматы:",
+ "echo-pref-web": "Веб",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Эл. почта бла билдириуле джиберме",
+ "echo-pref-email-frequency-immediately": "Келгенлерине кёре энчи билдириуле",
+ "echo-pref-email-frequency-daily": "Билдириулени кюн сайын сводкасы",
+ "echo-pref-email-frequency-weekly": "Билдириулени ыйыкъ сайын сводкасы",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Тюз текст",
+ "echo-pref-notify-show-link": "Адырла панелимде билдириулени кёргюз",
+ "echo-pref-new-message-indicator": "Адырла панелимде сюзюу бетимдеги билдириулени индикаторун кёргюз",
+ "echo-learn-more": "Кёбюрек бил",
+ "echo-new-messages": "Джангы билдириулеринг барды",
+ "echo-category-title-edit-user-talk": "Сюзюу бетде {{PLURAL:$1|1=билдириу|билдириуле}}",
+ "echo-category-title-article-linked": "Бетлеге {{PLURAL:$1|1=джибериу|джибериуле}}",
+ "echo-category-title-reverted": "Тюрлендириулени {{PLURAL:$1|1=ызына алыу|ызына алыула}}",
+ "echo-category-title-mention": "{{PLURAL:$1|1=Сагъыныу|Сагъыныула}}",
+ "echo-category-title-other": "{{PLURAL:$1|башха}}",
+ "echo-category-title-system": "{{PLURAL:$1|Система}}",
+ "echo-pref-tooltip-edit-user-talk": "Ким болса да билдириу ийсе неда сюзюу бетимде джууаб берсе, меннге билдир.",
+ "echo-pref-tooltip-article-linked": "Ким болса да статьялада мен къурагъан бетге джибериу салса, меннге билдир.",
+ "echo-pref-tooltip-reverted": "Ким болса да, ызына алыу неда дженгил къайтарыу функция бла мени тюрлендириуюмю ызына алса, меннге билдир.",
+ "echo-pref-tooltip-mention": "Ким болса да, къайсы болса да сюзюу бетде мени къошулуучу бетиме джибериу салса, меннге билдир.",
+ "echo-no-agent": "[Киши да]",
+ "echo-no-title": "[Бет джокъду]",
+ "echo-error-no-formatter": "Билдириу ючюн форматланыу белгиленмегенди.",
+ "echo-error-preference": "Халат: Къошулуучуну джарашдырыулары этилмедиле.",
+ "echo-error-token": "Халат: къошулуучу маркер (user token) алыналмады.",
+ "notifications": "Билдириуле",
+ "tooltip-pt-notifications": "Билдириулеригиз",
+ "echo-specialpage": "Билдириуле",
+ "echo-anon": "Билдириуле алыр ючюн, [$1 тергеу джазыу къурагъыз] неда [$2 системагъа киригиз].",
+ "echo-none": "Билдириуюгюз болмагъанды.",
+ "echo-more-info": "Толу билги",
+ "echo-feedback": "Ызына билдириу",
+ "notification-link-text-view-message": "Билдириуню кёр",
+ "notification-link-text-view-mention": "Сагъыныуну кёр",
+ "notification-link-text-view-changes": "Тюрлениулени кёр",
+ "notification-link-text-view-page": "Бетни кёр",
+ "notification-link-text-view-edit": "Тюрлендириуню кёр",
+ "notification-edit-talk-page2": "[[User:$1|$1]], [[User talk:$2#$3|сюзюу бетигизде]] билдириу {{GENDER:$1|къойду}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]], сюзюу бетигизде (\"[[User talk:$2#$3|$4]]\") билдириу {{GENDER:$1|къойду}}.",
+ "notification-edit-talk-page-flyout2": "$1, [[User talk:$2#$3|сюзюу бетигизде]] билдириу {{GENDER:$1|къойду}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1, сюзюу бетигизде (\"[[User talk:$2#$3|$4]]\") билдириу {{GENDER:$1|къойду}}.",
+ "notification-page-linked": "[[:$2]], [[:$3]] бла {{GENDER:$1|байламлы}} эди. [[Special:WhatLinksHere/$2|Бу бетге бары джибериулеге къарагъыз]].",
+ "notification-page-linked-flyout": "[[:$2]], [[:$3]] бла {{GENDER:$1|байламлы}} эди.",
+ "notification-add-comment2": "[[User:$1|$1]], \"$4\" сюзюу бетдеги \"[[$3|$2]]\" темада комментарий {{GENDER:$1|къойду}}.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]], [[$3]] бетде \"$2\" деген джангы теманы {{GENDER:$1|ачды}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]], сизге билдириу {{GENDER:$1|джиберди}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]], сизни сюзюу бетигиздеги \"[[$3#$2|$2]]\" темада комментарий {{GENDER:$1|къойду}}.",
+ "notification-mention": "[[User:$1|$1]], $5 сюзюу бетинде (\"[[:$3#$2|$4]]\") сизни {{GENDER:$1|сагъынды}}.",
+ "notification-mention-flyout": "$1, $5 сюзюу бетинде (\"[[:$3#$2|$4]]\") сизни {{GENDER:$1|сагъынды}}.",
+ "notification-user-rights": "Къошулуучу хакъларыгъыз [[User:$1|$1]] джанындан [[Special:Log/rights/$1|{{GENDER:$1|тюрлендирилди}}]]. $2. [[Special:ListGroupRights|Толуракъ билги]]",
+ "notification-user-rights-flyout": "Къошулуучу хакъларыгъызны $1 {{GENDER:$1|тюрлендирди}}. $2. [[Special:ListGroupRights|Толуракъ билги]]",
+ "notification-user-rights-add": "Энди сиз {{PLURAL:$2|1=бу къауумгъа|бу къауумлагъа}} киресиз: $1",
+ "notification-user-rights-remove": "Энди сиз {{PLURAL:$2|1=бу къауумгъа|бу къауумлагъа}} кирмейсиз: $1",
+ "notification-new-user": "{{SITENAME}} сайтха хош келигиз, $1! Сизни былайгъа келгенигизге къууандыкъ.",
+ "notification-reverted2": "[[User:$1|$1]], {{PLURAL:$4|1=[[:$2]] бетде сизни тюрлендириуюгюзню|[[:$2]] бетде сизни тюрлендириулеригизни}} {{GENDER:$1|ызына алды}}. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|1=$2 бетде сизни тюрлендириуюгюзню|$2 бетде сизни тюрлендириулеригизни}} $1 {{GENDER:$1|ызына алды}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|къошулуучу}} сизге «{{SITENAME}}» сайтда билдириу {{GENDER:$1|къойду}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|къошулуучу}}, сюзюу бетигизде билдириу {{GENDER:$1|къойду}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|къошулуучу}}, сюзюу бетигизни «$2» бёлюмюнде (темасында) билдириу {{GENDER:$1|къойду}}.",
+ "notification-page-linked-email-subject": "«{{SITENAME}}» сайтда сизни къошулуучу бетигизге джибериу салынды",
+ "notification-page-linked-email-batch-body": "$1 къошулуучу, $3 бетде $2 бетге джибериу {{GENDER:$1|салды}}.",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Ким эсе да}}, сизни «{{SITENAME}}» сайтда {{PLURAL:$3|1=тюрлендириуюгюзню|тюрлендириулеригизни}} ызына алды",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|1=«$2» бетде сизни тюрлендириуюгюзню|«$2» бетде сизни тюрлендириулеригизни}} $1 {{GENDER:$1|ызына алды}}.",
+ "notification-mention-email-subject": "$1, {{SITENAME}} сайтда сизни {{GENDER:$1|сагъынды}}",
+ "notification-mention-email-batch-body": "$1, $4 сюзюу бетинде (\"$3\") сизни {{GENDER:$1|сагъынды}}.",
+ "notification-user-rights-email-subject": "Сизни «{{SITENAME}}» сайтда хакъларыгъыз тюрлендирилдиле",
+ "notification-user-rights-email-batch-body": "Къошулуучу хакъларыгъызны $1 {{GENDER:$1|тюрлендирди}}. $2.",
+ "echo-email-subject-default": "«{{SITENAME}}» сайтда джангы билдириу",
+ "echo-email-body-default": "«{{SITENAME}}» сайтда джангы билдириуюгюз барды:\n\n$1",
+ "echo-email-batch-body-default": "Сизни джангы билдириуюгюз барды.",
+ "echo-email-footer-default": "$2\n\nЭл. почта бла ийилген билдириулени контролда тутар ючюн энчи джарашдырыуларыгъызны тинтигиз:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Эл. почта бла ийилген билдириулени контролда тутар ючюн <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">энчи джарашдырыуларыгъызны тинтигиз</a><br />\n$1",
+ "echo-notification-alert-text-only": "Билдириуле",
+ "echo-overlay-link": "Бютеу билдириуле",
+ "echo-overlay-title": "<b>Билдириуле</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Билдириуле}}</b> ($2 {{PLURAL|$2|окъулмагъандан}} $1 саны {{PLURAL|$1|кёргюзюлгенди}})",
+ "echo-mark-all-as-read": "Барысын да окъулгъанлача белгиле",
+ "echo-date-today": "Бюгюн",
+ "echo-date-yesterday": "Тюнене",
+ "echo-load-more-error": "Къошакъ эсеблени алгъан сагъатда халат чыкъды.",
+ "notification-edit-talk-page-bundle": "$1 бла $3 {{PLURAL:$4|1=башха къошулуучу|башха къошулуучула}}, [[User talk:$2|сюзюу бетигизде]] билдириу {{GENDER:$1|къойду}}.",
+ "notification-page-linked-bundle": "«$2» бетге «$3» бетден эмда башха $4 {{PLURAL:$5|бетден}} {{GENDER:$1|джибериу}} барды. [[Special:WhatLinksHere/$2|Бу бетге бютеу джибериулеге къарагъыз]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 бла $2 {{PLURAL:$3|1=башха къошулуучу|башха къошулуучула}}, сюзюу бетигизде билдириу {{GENDER:$1|къойду}}.",
+ "notification-page-linked-email-batch-bundle-body": "«$2» бетге «$3» бетден эмда башха $4 {{PLURAL:$5|бетден}} {{GENDER:$1|джибериу}} барды.",
+ "echo-email-batch-subject-daily": "«{{SITENAME}}» проектде сизни $2 {{PLURAL:$2|джангы билдириуюгюз}} барды",
+ "echo-email-batch-subject-weekly": "«{{SITENAME}}» проектде бу ыйыкъда сизге $2 {{PLURAL:$2|джангы билдириу}} келди.",
+ "echo-email-batch-body-intro-daily": "Салам, $1!\nСизге {{SITENAME}} сайтда бюгюннгю турумну юсюнден къысха хапар.",
+ "echo-email-batch-body-intro-weekly": "Салам, $1!\nСизге {{SITENAME}} сайтда турумну юсюнден ыйыкъ сайын къысха хапар.",
+ "echo-email-batch-link-text-view-all-notifications": "Бютеу билдириулени кёрюу",
+ "echo-rev-deleted-text-view": "Бу бет версия джашырылыбды"
+}
diff --git a/Echo/i18n/ksh.json b/Echo/i18n/ksh.json
new file mode 100644
index 00000000..4e384855
--- /dev/null
+++ b/Echo/i18n/ksh.json
@@ -0,0 +1,136 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "echo-desc": "Süßtehm för Meddeilonge",
+ "prefs-echo": "Meddeilonge",
+ "prefs-emailsettings": "Enschtällonge för de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">e-mail</i>",
+ "prefs-displaynotifications": "Enschtällonge för_t Aanzeije",
+ "prefs-echosubscriptions": "Donn mesch enfommehre övver:",
+ "prefs-newmessageindicator": "„Neu Meddeilonge“ Aanzeije",
+ "echo-pref-send-me": "Scheck mer:",
+ "echo-pref-send-to": "Scheck aan:",
+ "echo-pref-email-format": "Dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">e-mail</i> iehr Fommahd:",
+ "echo-pref-web": "Wäb",
+ "echo-pref-email": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">e-mail</i>",
+ "echo-pref-email-frequency-never": "Dom_mer kein ennfommazjuhne pä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">e-mail</i> schecke.",
+ "echo-pref-email-frequency-immediately": "Scheck alles esu, wi et kütt",
+ "echo-pref-email-frequency-daily": "Scheck mer einmohl aam Daach alles zersamme",
+ "echo-pref-email-frequency-weekly": "Scheck mer einmohl pä Woch alles zersamme",
+ "echo-pref-email-format-html": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor</i>",
+ "echo-pref-email-format-plain-text": "Eijfache Täx",
+ "echo-pref-notify-show-link": "Donn „Neu Meddeilonge“ en mingem Menüh anzeije",
+ "echo-pref-new-message-indicator": "Donn „Neu Meddeilonge op Dinger Klaafsigg“ en mingem Menüh anzeije",
+ "echo-learn-more": "Mieh lässe",
+ "echo-new-messages": "Do häs neu Meddeilonge",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Nohreesch|Nohreeschte|Nohreesch}} op der Klaafsigg",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Lengk|Lengks|Lenk}} en Sigge",
+ "echo-category-title-reverted": "Retuur jenumme {{PLURAL:$1|Änderong|Änderonge|Änderong}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Äwähnong|Äwähnonge|Äwähnong}}",
+ "echo-category-title-other": "{{PLURAL:$1|Söns}}",
+ "echo-category-title-system": "{{PLURAL:$1|Fum Wikki}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Änderong aan dä Rääschde vun enem Metmaacher|Änderonge aan Rääschde vun Metmaacher|Nix}}",
+ "echo-pref-tooltip-edit-user-talk": "Scheck mer em Meddeilong, wann eine op ming Klaafsigg schriiv udder antwoot.",
+ "echo-pref-tooltip-article-linked": "Scheck mer em Meddeilong, wann eine ene Lengk op en Sigg uß minge Fädder en ene Atikel deiht.",
+ "echo-pref-tooltip-reverted": "Scheck mer em Meddeilong, wann eine mem !FUZZY!!undo or rollback udder Wärkzüsch en Änderong retuur nemmp, di esch jemaat han.",
+ "echo-pref-tooltip-mention": "Scheck mer em Meddeilong, wann eine ene Lengk noh minge Klaafsigg säz.",
+ "echo-pref-tooltip-user-rights": "Scheck mer em Meddeilong, wann eine ming Rääschde ändert.",
+ "echo-no-agent": "[Keine]",
+ "echo-no-title": "[Kein Sigg]",
+ "echo-error-no-formatter": "Mer künne di Meddeilong nit aanzeije.\nMer weße de Manier nit, wih.",
+ "echo-error-preference": "Fähler: Mer kunnte de Metmaacher_Enschtällonge nit faßhallde.",
+ "notifications": "Meddeilonge",
+ "tooltip-pt-notifications": "Nohreeschte aan Desch",
+ "echo-specialpage": "Meddeilonge",
+ "echo-anon": "Do moß Desch [$1 aanmälde] udder [$2 enlogge], öm Meddeilonge krijje ze künne.",
+ "echo-none": "De häß kein Meddeilonge.",
+ "echo-more-info": "Mih Enfommazjuhne",
+ "echo-feedback": "Rökmäldong",
+ "echo-quotation-marks": "„$1“",
+ "notification-link-text-view-message": "De Nohreesch belohre",
+ "notification-link-text-view-mention": "De Äwähnong belohre",
+ "notification-link-text-view-changes": "De Veränderonge belohre",
+ "notification-link-text-view-page": "De Sigg belohre",
+ "notification-link-text-view-edit": "De Veränderong belohre",
+ "notification-edit-talk-page2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hädd en Nohreech op Ding [[User talk:$2#$3|Klaafsigg]] jedonn.",
+ "notification-edit-talk-page-with-section": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hädd en Nohreech op Ding Klaafsigg en dä Affschnedd „[[User talk:$2#$3|$4]]“ jedonn.",
+ "notification-edit-talk-page-flyout2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hädd en Nohreech op Ding [[User talk:$2#$3|Klaafsigg]] jedonn.",
+ "notification-edit-talk-page-flyout-with-section": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hädd en Nohreech op Ding Klaafsigg en dä Affschnedd „[[User talk:$2#$3|$4]]“ jedonn.",
+ "notification-page-linked": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ häd op dä Sigg „[[:$3]]“ ene Lengk noh „[[:$2]]“ enjebout. De kanns Der [[Special:WhatLinksHere/$2|alle Lengks noh doh]] belohre.",
+ "notification-page-linked-flyout": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ häd op dä Sigg „[[:$3]]“ ene Lengk noh „[[:$2]]“ enjebout.",
+ "notification-add-comment2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät jäd en dä Affschnedd „[[$3|$2]]“ op da Klaafsigg vun dä Sigg „$4“ jedonn.",
+ "notification-add-talkpage-topic2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät ene neu Affschnedd met dä Övverschreff „$2“ op di Sigg „[[$3]]“ jedonn.",
+ "notification-add-talkpage-topic-yours2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät Der en Metdeilong jescheck: „[[$3#$2|$2]]“ .",
+ "notification-add-comment-yours2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät op Dinge Klaafsigg jät zoh „[[$3#$2|$2]]“ jeschrevve.",
+ "notification-mention": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät Desch op dä Klaafsigg vun dä Sigg „$5“ em Affschnet „[[:$3#$2|$4]]“ jenannt.",
+ "notification-mention-flyout": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Desch op dä Klaafsigg vun dä Sigg „$5“ em Affschnet „[[:$3#$2|$4]]“ jenannt.",
+ "notification-mention-nosection": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät Desch op dä Klaafsigg övver di Sigg „[[:$3|$2]]“ jenannt.",
+ "notification-mention-nosection-flyout": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Desch op dä Klaafsigg övver di Sigg „[[:$3|$2]]“ jenannt.",
+ "notification-user-rights": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät [[Special:Log/rights/$1|Ding Rääschde als ene Metmaacher verändert]]. $2. Do kanns [[Special:ListGroupRights|mih övver de einzel Rääschde]] nohlässe.",
+ "notification-user-rights-flyout": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Ding Rääschde als ene Metmaacher verändert. $2. Do kanns [[Special:ListGroupRights|mih övver de einzel Rääschde]] nohlässe.",
+ "notification-user-rights-add": "Do bes jäz en heh dä {{PLURAL:$2|Jropp|Jroppe|Jropp}}: $1",
+ "notification-user-rights-remove": "Do bes jäz nit mih en heh dä {{PLURAL:$2|Jropp|Jroppe|Jropp}}: $1",
+ "notification-new-user": "$1, welkumme op {{GENDER:Dative|{{SITENAME}}}}.\nMer freue ons, dat De doh bes!",
+ "notification-reverted2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „[[User:$1|$1]]“ hät {{PLURAL:$4|Dinge Beijdraach|Ding Beijdrähsch|keine Beijdraach vun Der}} op dä Sigg „[[:$2]]“ retuhr jemaht. $3",
+ "notification-reverted-flyout2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät {{PLURAL:$4|Dinge Beijdraach|Ding Beijdrähsch|keine Beijdraach vun Der}} op dä Sigg „$2“ retuhr jemaht. $3",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Der op {{GENDER:Dative|{{SITENAME}}}} en Metdeilong jeschek.",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Der op en Metdeilong op Ding Klaafsigg jedonn.",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Der op en Metdeilong op Ding Klaafsigg en dä Affschnett „$2“ jedonn.",
+ "notification-page-linked-email-subject": "Op {{GENDER:Dative|{{SITENAME}}}} wohd ene Lengk op Ding Sigg aanjelaht.",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ häd op dä Sigg „$3“ ene Lengk noh „$2“ enjebout.",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ häd op {{GENDER:Dative|{{SITENAME}}}} {{PLURAL:$3|en Änderong|$3 Änderonge|kein Änderonge}} vun Der retuhr jemaht.",
+ "notification-reverted-email-batch-body2": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ häd op {{GENDER:Dative|{{SITENAME}}}} {{PLURAL:$3|en Änderong vun Der|$3 vun Dinge Änderonge|kein vun Dinge Änderonge}} aan dä Sigg „$2“ retuhr jemaht.",
+ "notification-mention-email-subject": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Desch {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}} jenannt.",
+ "notification-mention-email-batch-body": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} hät Desch op dä Sigg „$4“ em Affschnet „$3“ jenannt.",
+ "notification-mention-nosection-email-batch-body": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} hät Desch op dä Sigg „$2“ jenannt.",
+ "notification-user-rights-email-subject": "Ding Rääschde als Metmaacher {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}} sin verändert woode.",
+ "notification-user-rights-email-batch-body": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät Ding Rääschde als Metmaacher verändert. $2.",
+ "echo-notification-count": "övver $1",
+ "echo-email-subject-default": "En neue Meddeilong op {{GRAMMAR:dative|{{ucfirst:{{SITENAME}}}}}}",
+ "echo-email-body-default": "Do häss_en neue Meddeilong op {{GRAMMAR:dative|{{ucfirst:{{SITENAME}}}}}}:\n\n$1",
+ "echo-email-batch-body-default": "Do häss_en neuje Meddeilong.",
+ "echo-email-footer-default": "$2\n\nDonn op:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\nenschtälle, wat mer Der schecke sulle.\n\n$1",
+ "echo-email-footer-default-html": "En Dinge <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">Enschtällonge</a> kanns De faßlähje, wat mer Der jenou scheke sulle.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Eine Henwihß|$1 Henwihse|Keine Henwihß|100=Övver 99 Henwihse}}",
+ "echo-notification-message": "{{PLURAL:$1|Eine Nohreesch ob ene Klaafsigg|$1 Nohreeschte op Klaafsigge|Keine Nohreesch ob ene Klaafsigg|100=Övver 99 Nohreeschte op Klaafsigge}}",
+ "echo-notification-alert-text-only": "Henwihß",
+ "echo-notification-message-text-only": "Nohreschte",
+ "echo-overlay-link": "Alle Meddeilonge",
+ "echo-overlay-title": "<b>Meddeilonge</b>",
+ "echo-overlay-title-overflow": "<b>Meddeilonge</b> ($1 vun $2 wähde aanjezeijsch){{PLURAL:$1|}}",
+ "echo-mark-all-as-read": "Alle als jelässe makehre",
+ "echo-date-today": "Hück",
+ "echo-date-yesterday": "Jäßtere",
+ "echo-load-more-error": "Ene Fähler es opjetrodde beim Versohch, mieh ze holle vun dämm wadd_erus kohm.",
+ "notification-edit-talk-page-bundle": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ un {{PLURAL:$4|eine anndere hät|$3 anndere han|keine söns hät}} en Nohreesch udder Nohreeschte op Ding [[User talk:$2|Klaafsigg]] jeschrevve.",
+ "notification-page-linked-bundle": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ häd op dä Sigg „$3“ un {{PLURAL:$5|eine anndere|$4 anndere|söns keine}} ene Lengk noh „$2“ enjebout. De kanns Der [[Special:WhatLinksHere/$2|alle Lengks noh doh]] belohre.",
+ "notification-edit-user-talk-email-batch-bundle-body": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ un {{PLURAL:$3|eine anndere hät|$2 anndere han|keine söns hät}} en Nohreesch udder Nohreeschte op Ding Klaafsigg jeschrevve.",
+ "notification-page-linked-email-batch-bundle-body": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ häd op dä Sigg „$3“ un {{PLURAL:$5|eine anndere|$4 anndere|söns keine}} ene Lengk noh „$2“ enjebout.",
+ "echo-email-batch-subject-daily": "Do häs {{PLURAL:$2|en neuje Meddeilong|$2 neuje Meddeilong|kein neuje Meddeilonge}} {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}}.",
+ "echo-email-batch-subject-weekly": "Do häs en dä Woch {{PLURAL:$2|en neuje Meddeilong|$2 neuje Meddeilong|kein neuje Meddeilonge}} {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}}.",
+ "echo-email-batch-body-intro-daily": "Daach $1,\nheh küdd en Sammlong vun däm, wadd {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}} hück paßehrd es.",
+ "echo-email-batch-body-intro-weekly": "Daach $1,\nheh küdd en Sammlong vun däm, wadd {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}} di Woch paßehrd es.",
+ "echo-email-batch-link-text-view-all-notifications": "Alle Meddeilonge belohre",
+ "echo-rev-deleted-text-view": "Heh di Väsjohn vun dä Sigg es ongerdrök woode.",
+ "apihelp-echomarkread-description": "Makkehr, dat dä aktoälle Metmaacher di Meddeilonge jelässe hät.",
+ "apihelp-echomarkread-param-list": "En leß met dä Kännonge för di Meddeilonge, di op „jelässe“ jesaz wähde sulle.",
+ "apihelp-echomarkread-param-all": "Wann aanjekleck, dunn all däm Metmaacher singe Meddeilonge op „jelässe“ säze.",
+ "apihelp-echomarkread-param-sections": "En Leß met Affschnedde, di op „jelässe“ jesaz wähde sulle.",
+ "apihelp-echomarkread-example-1": "Säz de Meddeilong aach op „jelässe“.",
+ "apihelp-echomarkread-example-2": "Säz alle Meddeilonge op „jelässe“.",
+ "apihelp-query+notifications-description": "Holl däm aktoälle Metmaacher sing Waadeschlang met Meddeilonge.",
+ "apihelp-query+notifications-param-prop": "De Einzelheijte för dernoh ze frohre.",
+ "apihelp-query+notifications-param-sections": "De Afschnedde vun de Nohreeschte holle.",
+ "apihelp-query+notifications-param-groupbysection": "Of de Leß en Jroppe vun Afschnedde sin sull.\nJehde Affschnedd es för sesch, wann dat aanjeklegg es.",
+ "apihelp-query+notifications-param-format": "Wann aanjejovve, wähde de Nohreeschte en dä Manier daajeschtällt.",
+ "apihelp-query+notifications-param-limit": "Nit mih, wi esu vill Meddeilonge ußjävve.",
+ "apihelp-query+notifications-param-index": "Wann ußjewählt, küdd_en zottehrte Leß met Kännonge för Meddeilonge.",
+ "apihelp-query+notifications-param-alertcontinue": "Wann mih Meddeilonge ze holle sin, nemm dat för wigger ze maache.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Ov de unjelässe Meddeilonge am Aanfang schtonn sulle.",
+ "apihelp-query+notifications-param-messagecontinue": "Wann mih Nohreeschte ze holle sin, nemm dat för wigger ze maache.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Ov de unjelässe Nohreeschte övver Meddeilonge am Aanfang schtonn sulle.",
+ "apihelp-query+notifications-example-1": "Meddeilonge opleßte",
+ "apihelp-query+notifications-example-2": "Meddeilonge opleßte, noh Affschnedde, met der Aanzahl"
+}
diff --git a/Echo/i18n/ku-latn.json b/Echo/i18n/ku-latn.json
new file mode 100644
index 00000000..f0f15c8e
--- /dev/null
+++ b/Echo/i18n/ku-latn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "George Animal"
+ ]
+ },
+ "echo-new-messages": "Peyamên nû ji te re hene"
+}
diff --git a/Echo/i18n/la.json b/Echo/i18n/la.json
new file mode 100644
index 00000000..f02643f1
--- /dev/null
+++ b/Echo/i18n/la.json
@@ -0,0 +1,77 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Autokrator",
+ "UV"
+ ]
+ },
+ "echo-desc": "Modus nuntiorum mittendarum",
+ "prefs-echo": "Nuntia",
+ "prefs-emailsettings": "Praeferentiae litterarum electronicarum",
+ "prefs-displaynotifications": "Praeferentiae nuntiorum",
+ "prefs-echosubscriptions": "De his actionibus nuntiare",
+ "prefs-newmessageindicator": "Nova nuntia",
+ "echo-pref-send-me": "Mitte mihi:",
+ "echo-pref-send-to": "Mittere ad:",
+ "echo-pref-email-format": "Modus litterarum electronicarum:",
+ "echo-pref-web": "Interrete",
+ "echo-pref-email": "Litterae electronicae",
+ "echo-pref-email-frequency-never": "Nullas litteras electronicas mittere",
+ "echo-pref-email-frequency-daily": "Summarium cottidianum nuntiorum",
+ "echo-pref-email-frequency-weekly": "Summarium hebdomadale nuntiorum",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Textus",
+ "echo-pref-notify-show-link": "Nuntia in arca ferramentorum monstrare",
+ "echo-pref-new-message-indicator": "Monstrare indicatorem paginarum disputationis nuntiorum in arca ferramentorum",
+ "echo-learn-more": "Plura legere",
+ "echo-new-messages": "Habes nuntia nova",
+ "echo-category-title-edit-user-talk": "Paginae disputationis {{PLURAL:$1|nuntium|nuntia}}",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Nexus}} ad paginam",
+ "echo-category-title-mention": "{{PLURAL:$1|Mentio|Mentiones}}",
+ "echo-category-title-other": "{{PLURAL:$1|Alia}}",
+ "echo-pref-tooltip-edit-user-talk": "Me certiorem facere si quis nuntium mittat vel in pagina disputationis mea respondat.",
+ "echo-pref-tooltip-article-linked": "Me certiorem facere si quis paginam quam creavi nectit e quadam pagina commentationis.",
+ "echo-pref-tooltip-mention": "Me certiorem facere si quis e quacumque pagina disputationis ad paginam usoris meam nectit.",
+ "echo-no-agent": "[Nemo]",
+ "echo-no-title": "[Nulla pagina]",
+ "echo-error-preference": "Error: Praeferentias usoris adaptare non contigit.",
+ "notifications": "Nuntia",
+ "tooltip-pt-notifications": "Nuntia tua",
+ "echo-specialpage": "Nuntia",
+ "echo-anon": "Ut nuntia accipias, [$1 rationem crees] aut [$2 conventum aperias] rogamus.",
+ "echo-none": "Nulla nuntia.",
+ "echo-more-info": "Plura legere",
+ "echo-feedback": "Responsa",
+ "notification-link-text-view-message": "Nuntium spectare",
+ "notification-link-text-view-mention": "Mentionem spectare",
+ "notification-link-text-view-changes": "Mutata ostendere",
+ "notification-link-text-view-page": "Vide paginam",
+ "notification-link-text-view-edit": "Vide recensionem",
+ "notification-page-linked-flyout": "[[:$2]] nectum est a pagina [[:$3]].",
+ "notification-user-rights-add": "Nunc es sodalis {{PLURAL:$2|eius gregis|eorum gregium}}: $1",
+ "notification-user-rights-remove": "Non iam es sodalis {{PLURAL:$2|eius gregis|eorum gregium}}: $1",
+ "notification-new-user": "Salve ad {{grammar:accusative|{{SITENAME}}}}, $1!",
+ "notification-page-linked-email-subject": "Pagina tua annexa est apud {{grammar:accusative|{{SITENAME}}}}",
+ "notification-mention-email-subject": "$1 tui {{GENDER:$1|mentionem fecit}} apud {{grammar:accusative|{{SITENAME}}}}",
+ "notification-mention-email-batch-body": "$1 tui {{GENDER:$1|mentionem fecit}} in $4 in \"$3\"",
+ "echo-email-subject-default": "Nova nuntia apud {{grammar:accusative|{{SITENAME}}}}",
+ "echo-email-body-default": "Habes nova nuntia apud {{grammar:accusative|{{SITENAME}}}}:\n\n$1",
+ "echo-email-batch-body-default": "Habes novum nuntium.",
+ "echo-email-footer-default": "$2\n\nAd aptandum quales litteras electronicas tibi mittantur praeferentias tuas vide:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Ad aptandum quales litteras electronicas tibi mittantur <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">praeferentias tuas vide</a>.<br />\n$1",
+ "echo-overlay-link": "Omnia nuntia",
+ "echo-overlay-title": "<b>Nuntia</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Nuntium|Nuntia}}</b> (monstrans $1 de $2 inlectis)",
+ "echo-mark-all-as-read": "Omnia perlecta indicare",
+ "echo-date-today": "Hodie",
+ "echo-date-yesterday": "Heri",
+ "echo-load-more-error": "Error in plura eventa quaerendo.",
+ "notification-page-linked-bundle": "$2 nectum est a $3 et $4 {{PLURAL:$5|alia pagina|aliis paginis}}. [[Special:WhatLinksHere/$2|Omnes nexus ad hanc paginam spectare]]",
+ "echo-email-batch-subject-daily": "Habes {{PLURAL:$2|novum nuntium|nova nuntia}} apud {{grammar:accusative|{{SITENAME}}}}",
+ "echo-email-batch-subject-weekly": "Habes {{PLURAL:$2|novum nuntium|nova nuntia}} apud {{grammar:accusative|{{SITENAME}}}} hac hebdomada",
+ "echo-email-batch-body-intro-daily": "Salve $1,\nHoc est summarium actionum hodiernarum apud {{grammar:accusative|{{SITENAME}}}}.",
+ "echo-email-batch-body-intro-weekly": "Salve $1,\nHoc est summarium actionum hebdomadum apud {{grammar:accusative|{{SITENAME}}}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Omnia nuntia spectare",
+ "echo-rev-deleted-text-view": "Haec emendatio paginae oppressa est."
+}
diff --git a/Echo/i18n/lad.json b/Echo/i18n/lad.json
new file mode 100644
index 00000000..a7226e0f
--- /dev/null
+++ b/Echo/i18n/lad.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Menachem.Moreira",
+ "Universal Life"
+ ]
+ },
+ "prefs-emailsettings": "Opsyones del korreo elektroniko",
+ "echo-pref-email": "Korreo elektroniko",
+ "echo-pref-email-format-html": "HTML",
+ "echo-category-title-article-linked": "Pajina{{PLURAL:$1|enlase|enlases}}",
+ "notification-link-text-view-changes": "Amostrar los trocamientos",
+ "notification-link-text-view-page": "Ver la hoja",
+ "notification-link-text-view-edit": "Ver edisyon"
+}
diff --git a/Echo/i18n/lb.json b/Echo/i18n/lb.json
new file mode 100644
index 00000000..21fe4351
--- /dev/null
+++ b/Echo/i18n/lb.json
@@ -0,0 +1,116 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby",
+ "Soued031"
+ ]
+ },
+ "echo-desc": "Notifikatiounssystem",
+ "prefs-echo": "Notifikatiounen",
+ "prefs-emailsettings": "E-Mail-Astellungen",
+ "prefs-displaynotifications": "Optioune vum Affichage",
+ "prefs-echosubscriptions": "Mech iwwer dës Evenementer informéieren",
+ "prefs-newmessageindicator": "Indicateur vun neie Messagen",
+ "echo-pref-send-me": "Mir schécken:",
+ "echo-pref-send-to": "Schécken un:",
+ "echo-pref-email-format": "E-Mail-Format:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-Mail",
+ "echo-pref-email-frequency-never": "Schéckt mir keng E-Mail-Notifikatiounen",
+ "echo-pref-email-frequency-immediately": "Individuell Notifikatiounen sou wéi s'erakommen",
+ "echo-pref-email-frequency-daily": "All Dag e Resumé vun den Notifikatiounen",
+ "echo-pref-email-frequency-weekly": "All Woch e Resumé vun den Notifikatiounen",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Kloertext",
+ "echo-pref-notify-show-link": "Notifikatiounen a menger Geschirläischt weisen",
+ "echo-pref-new-message-indicator": "Indicateur fir Messagen op menger Diskussiounssäit a menger Geschirläischt weisen",
+ "echo-learn-more": "Fir méi ze wëssen",
+ "echo-new-messages": "Dir hutt nei Messagen",
+ "echo-category-title-edit-user-talk": "Diskussiounssäit {{PLURAL:$1|Message|Messagen}}",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Säitelink|Säitelinken}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Zréckgesetzung|Zrécksetzungen}} änneren",
+ "echo-category-title-mention": "{{PLURAL:$1|Mentioun|Mentiounen}}",
+ "echo-category-title-other": "{{PLURAL:$1|Aneren|Anerer}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-pref-tooltip-edit-user-talk": "Mech informéiere wann een eppes op meng Diskussiounssäit schreift oder do äntwert.",
+ "echo-pref-tooltip-article-linked": "Mech informéiere wann een an engem Artikel op eng Säit verlinkt, déi ech kreéiert hunn.",
+ "echo-pref-tooltip-reverted": "Mech informéiere wann ee meng Ännerung zrécksetzt oder andeems hien de 'Rollback'-Tool benotzt.",
+ "echo-pref-tooltip-mention": "Mech informéiere wann een e Link op meng Benotzersäit setzt.",
+ "echo-no-agent": "[Keen]",
+ "echo-no-title": "[Keng Säit]",
+ "echo-error-no-formatter": "Keng Formatéierung fir Notifikatiounen definéiert.",
+ "echo-error-preference": "Feeler: Benotzerastellung konnt net gemaach ginn.",
+ "echo-error-token": "Feelerː Benotzertoken konnt net ofgeruff ginn.",
+ "notifications": "Notifikatiounen",
+ "tooltip-pt-notifications": "Är Notifikatiounen",
+ "echo-specialpage": "Notifikatiounen",
+ "echo-anon": "Fir Notifikatiounen ze kréien, [$1 maacht e Benotzerkont op] oder [$2 loggt Iech an]",
+ "echo-none": "Dir hutt keng Notifikatiounen.",
+ "echo-more-info": "Méi Informatiounen",
+ "echo-feedback": "Feedback",
+ "notification-link-text-view-message": "Message weisen",
+ "notification-link-text-view-mention": "Mentioun weisen",
+ "notification-link-text-view-changes": "Ännerunge weisen",
+ "notification-link-text-view-page": "Säit weisen",
+ "notification-link-text-view-edit": "Ännerung weisen",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|huet}} op Är [[User talk:$2#$3|Diskussiounssäit]] geschriwwen.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|huet}} e Message op Ärer Diskussiounssäit ënner \"[[User talk:$2#$3|$4]]\" hannerlooss.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|huet}} op Är [[User talk:$2#$3|Diskussiounssäit]] geschriwwen.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|huet}} e Message op Ärer Diskussiounssäit ënner \"[[User talk:$2#$3|$4]]\" hannerlooss.",
+ "notification-page-linked": "[[:$2]] gouf vun [[:$3]] {{GENDER:$1|verlinkt}}. [[Special:WhatLinksHere/$2|Kuckt all Linken op dës Säit]].",
+ "notification-page-linked-flyout": "[[:$2]] gouf vun der Säit [[:$3]] {{GENDER:$1|verlinkt}}.",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|huet}} eng Bemierkung iwwer \"[[$3|$2]]\" op der \"$4\" Diskussiounssäit geschriwwen.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|huet}} en neit Thema \"$2\" op [[$3]] ugefaang.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|huet}} Iech ee Message geschéckt: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|huet}} op \"[[$3#$2|$2]]\" op Ärer Diskussiounssäit eng Bemierkung gemaach",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|huet}} Iech op der $5 Diskussiounssäit bei \"[[:$3#$2|$4]]\" ernimmt.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|huet}} Iech op der $5 Diskussiounssäit bei \"[[:$3#$2|$4]]\" ernimmt.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|huet}} Iech op der [[:$3|$2 Diskussiounssäit]] ernimmt.",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|huet}} Iech op der [[:$3|$2 Diskussiounssäit]] ernimmt.",
+ "notification-user-rights": "Är Benotzerrechter [[Special:Log/rights/$1|goufe vum [[User:$1|$1]] {{GENDER:$1|geännert}}]]. $2. [[Special:ListGroupRights|Fir méi ze wëssen]]",
+ "notification-user-rights-flyout": "Är Benotzerrechter goufe vum $1 {{GENDER:$1|geännert}}. $2. [[Special:ListGroupRights|Fir méi ze wëssen]]",
+ "notification-user-rights-add": "Dir sidd elo Member vun {{PLURAL:$2|dësem Grupp|dëse Gruppen}}: $1",
+ "notification-user-rights-remove": "Dir sidd net méi Member vun {{PLURAL:$2|dësem Grupp|dëse Gruppen}}: $1",
+ "notification-new-user": "Wëllkomm op {{SITENAME}}, $1! Mir si frou Iech begréissen ze kënnen.",
+ "notification-reverted2": "Är {{PLURAL:$4|Ännerung vu(n) [[:$2]] gouf|Ännerunge vu(n) [[:$2]] goufe}} vum [[User:$1|$1]] {{GENDER:$1|zréckgesat}}. $3",
+ "notification-reverted-flyout2": "Är {{PLURAL:$4|Ännerung op $2 gouf|Ännerungen op $2 goufe}} vum $1 {{GENDER:$1|zréckgesat}} $3.",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|huet}} Iech en neie Message op Ärer Diskussiounssäit op {{SITENAME}} hannerlooss",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|huet}} ee Message op Är Diskussiounssäit geschriwwen:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|huet}} ee Message op Är Diskussiounssäit op \"$2\" geschriwwen.",
+ "notification-page-linked-email-subject": "Är Säit gouf op {{SITENAME}} verlinkt",
+ "notification-page-linked-email-batch-body": "$2 gouf vu(n) $3 {{GENDER:$1|verlinkt}}.",
+ "notification-reverted-email-subject2": "Är {{PLURAL:$3|Ännerung|Ännerungen}} op {{SITENAME}} {{PLURAL:$3|gouf|goufen}} {{GENDER:$1|zréckgesat}}",
+ "notification-reverted-email-batch-body2": "Är {{PLURAL:$3|Ännerung vu(n) $2 gouf|Ännerunge vu(n) $2 goufe}} vum $1 {{GENDER:$1|zréckgesat}}.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|huet}} Iech op {{SITENAME}} ernimmt",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|huet}} Iech op der $4 Diskussiounssäit ernimmt bei \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|huet}} Iech op der $2 Diskussiounssäit ernimmt.",
+ "notification-user-rights-email-subject": "Är Benotzerrechter op {{SITENAME}} hu geännert",
+ "notification-user-rights-email-batch-body": "Är Benotzerrechter goufe vum $1 {{GENDER:$1|geännert}}. $2",
+ "echo-email-subject-default": "Nei Notifikatioun op {{SITENAME}}",
+ "echo-email-body-default": "Dir hutt eng nei Notifikatioun op {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Dir hutt eng Notifikatioun",
+ "echo-email-footer-default": "$2\n\nFir ze kontrolléiere wat fir eng E-Maile mir Iech schécken, kuckt Är Preferenzen no:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Fir ze kontrolléieren, watfir E-Maile mir Iech schécken, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">kuckt Är Astellungen no</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Warnung ($1)|Warnungen ($1)|100=Warnungen (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Message ($1)|Messagen ($1)|100=Messagen (99+)}}",
+ "echo-notification-message-text-only": "Messagen",
+ "echo-overlay-link": "All Notifikatiounen",
+ "echo-overlay-title": "<b>Notifikatiounen</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notifikatioun|Notifikatiounen}}</b> (weist $1 vun $2 net geliesten)",
+ "echo-mark-all-as-read": "All als geliest markéieren",
+ "echo-date-today": "Haut",
+ "echo-date-yesterday": "Gëschter",
+ "echo-load-more-error": "Am Sichen no méi Resultater ass e Feeler geschitt.",
+ "notification-edit-talk-page-bundle": "$1 a(n) $3 {{PLURAL:$4|een anere|$3 anerer}} {{GENDER:$1|hunn}} ee Message op Är [[User talk:$2|Diskussiounssäit]] geschriwwen.",
+ "notification-page-linked-bundle": "$2 gouf vu(n) $3 an nach {{PLURAL:$5|enger anerer Säit|$4 anere Säite}} {{GENDER:$1|verlinkt}}. [[Special:WhatLinksHere/$2|All Linken op dës Säit weisen]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 a(n) {{PLURAL:$3|een anere|$2 aner}} Benotzer {{GENDER:$1|hunn}} ee Message op Är Diskussiounssäit geschriwwen.",
+ "notification-page-linked-email-batch-bundle-body": "$2 gouf vu(n) $3 a(n) {{PLURAL:$5|enger anerer Säit|$4 anere Säite}} {{GENDER:$1|verlinkt}}.",
+ "echo-email-batch-subject-daily": "Dir hutt haut {{PLURAL:$2|eng nei Notifikatioun|nei Notifikatiounen}} op {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Dir hutt dës Woch {{PLURAL:$2|eng nei Notifikatioun|nei Notifikatiounen}} op {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Salut $1,\n\nHei ass e Resumé vun den Aktivitéite vun haut op {{SITENAME}} fir Iech.",
+ "echo-email-batch-body-intro-weekly": "Salut $1,\n\nHei ass e Resumé vun den Aktivitéite vun dëser Woch op {{SITENAME}} fir Iech.",
+ "echo-email-batch-link-text-view-all-notifications": "All Notifikatioune weisen",
+ "echo-rev-deleted-text-view": "Dës Versioun vun der Säit gouf geläscht.",
+ "apihelp-echomarkread-param-sections": "Eng Lëscht vun den Abschnitter déi als geliest markéiert solle ginn.",
+ "apihelp-query+notifications-param-prop": "Detailer fir unzefroen."
+}
diff --git a/Echo/i18n/lrc.json b/Echo/i18n/lrc.json
new file mode 100644
index 00000000..3bc17de4
--- /dev/null
+++ b/Echo/i18n/lrc.json
@@ -0,0 +1,97 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bonevarluri",
+ "Mogoeilor"
+ ]
+ },
+ "echo-desc": "وارسیاریا سامونه",
+ "prefs-echo": "وارسیاریا",
+ "prefs-emailsettings": "چیا هنی انجومانامه",
+ "prefs-displaynotifications": "گزینه یا نه نشو بیه",
+ "prefs-echosubscriptions": "مه نه سی ای رخ ونیا خوردار کو",
+ "prefs-newmessageindicator": "نشو دیارکن پیغام تازه",
+ "echo-pref-send-me": "کل کو سیم:",
+ "echo-pref-send-to": "کل کو سی:",
+ "echo-pref-email-format": "قالو ایمیل:",
+ "echo-pref-web": "مالگه",
+ "echo-pref-email": "پیومک برقی",
+ "echo-pref-email-frequency-never": "سی مه ایمیل بشگار کو کل نکو",
+ "echo-pref-email-frequency-immediately": "وارسیاری شخصی ایسه دارن میان",
+ "echo-pref-email-frequency-daily": "یه گل چکسه روزانه د وارسیاریا",
+ "echo-pref-email-frequency-weekly": "یه گل چکسه هفته ای د وارسیاریا",
+ "echo-pref-email-format-html": "اچ تی ام ال",
+ "echo-pref-email-format-plain-text": "متن ساده",
+ "echo-pref-notify-show-link": "وارسیاریا نه د نوار اوزار مه نشو بیه",
+ "echo-pref-new-message-indicator": "نشودیارکن پیغوم نه د اوزارجا بلگه چک چنه نشو بیئه",
+ "echo-learn-more": "بيشتر يا بيئريت",
+ "echo-new-messages": "شما پیغومیا تازه داریتو",
+ "echo-category-title-edit-user-talk": "بلگه چک چنه {{جمی:$1|پیغوم|پیغومیا}}",
+ "echo-category-title-article-linked": "بلگه {{جمی:$1|هوم پیوند|هوم پیوندیا}}",
+ "echo-category-title-reverted": "ویایشت بکید {{جمی:$1|ورگشتی|ورگشتیا}}",
+ "echo-category-title-mention": "{{جمی:$1|گوتن|گوتنیا}}",
+ "echo-category-title-other": "{{جمی:$1|هنی}}",
+ "echo-category-title-system": "{{جمی:$1|سامونه}}{{PLURAL:$1|}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|حقوق کاریار سی آلشت دئن|حقو کاریار سی آلشت دئن}}",
+ "echo-pref-tooltip-edit-user-talk": "مه نه وختی که یه نفر د بلگه چک چنم پیغوم می نه یا جواو می ئه خوردار کو.",
+ "echo-pref-tooltip-mention": "هرگاتی که کسی وه بلگه کاریاری مه هوم پیوند بی مه نه وارسیاری بک",
+ "echo-pref-tooltip-user-rights": "هرگاتی که کسی حقوق کاریاری مه نا آلشت ده مه نه وارسیاری بک.",
+ "echo-no-agent": "[هیشکی]",
+ "echo-no-title": "[بی بلگه]",
+ "notifications": "وارسیاریا",
+ "tooltip-pt-notifications": "وارسیاریا شما",
+ "echo-specialpage": "وارسیاریا",
+ "echo-none": "شما هیژ وارسیاری ناریت.",
+ "echo-more-info": "دونسمنیا هنی",
+ "echo-feedback": "بازحرد",
+ "notification-link-text-view-message": "دیئن پیغوما",
+ "notification-link-text-view-mention": "گوته نه بیئنیت.",
+ "notification-link-text-view-changes": "دیئن آلشتیا",
+ "notification-link-text-view-page": "بلگه بوینیت",
+ "notification-link-text-view-edit": "ویرایشت نه بوینیت",
+ "notification-edit-talk-page2": "[[کاریار:$1|$1]] {{GENDER:$1|یه گل پیغوم تازه }} د [[چک چنه کاریاری:$2#$3|بلگه چک چنه]] شما نیا.",
+ "notification-edit-talk-page-with-section": "[[کاریار:$1|$1]] {{جنس:$1|}} یه گل پیغوم د بلگه چک چنه شما نیا د \"[[بلگه چک چنه:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{جنس:$1|}}یه گل پیغوم د [[چک چنه کاریار:$2#$3|بلگه چک چنه]]تو نیائه.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{جنس:$1|}}یه گل پیغوم د بلگه چک چنه شما نیائه\" د[[چک چنه کاریار:$2#$3|$4]]\".",
+ "notification-page-linked-flyout": "[[:$2]] {{جنس:$1|هوم پیوند دئه }}سی [[:$3]].",
+ "notification-add-comment2": "[[کاریار:$1|$1]] {{جنس:$1|د}}د \"[[$3|$2]]\" د بلگه چک چنه \"$4\" نیا.",
+ "notification-add-talkpage-topic-yours2": "[[کاریار:$1|$1]] {{GENDER:$1|}} یه گل پیغوم سی شما کل کرد: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[کاریار:$1|$1]] {{جنس:$1|د}}د \"[[$3|$2]]\" د بلگه چک چنه \"$4\" نیا.",
+ "notification-mention-nosection": "[[کاریار:$1|$1]] {{GENDER:$1|گوته }} د [[:$3|$2 بلگه چک چنه]] شما.$2",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|گوته بیه}} د [[:$3|$2 بلگه چک چنه شما]].",
+ "notification-user-rights": "حقوق کاریاری تو [[ویجه:پهرستنومه/حقوق/$1|بیه {{جنس:$1|آلشت بیه }}]] وا [[کارور:$1|$1]]. $2. [[ویجه:نوم گه حقوق گرو|بیشتر بفئمید]]",
+ "notification-user-rights-add": "شما ایسه اندوم{{PLURAL:$2|ای دسه|ای دسه یا}} هیئت: $1",
+ "notification-new-user": "خوش اومایت د {{نوم سیل جا}}, $1! ایما خوشالیم که ایسه هایتیت ایچه.",
+ "notification-edit-talk-page-email-subject2": "$1 {{جنس:$1|یه گل پیغوم}} د {{نوم دیارگه}} نیائه.",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{جنس:$1|یه گل پیغوم د بلگه چک چنه شما}} نیائه:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{جنس:$1|یه گل پیغوم د بلگه چک چنه شما د \"$2\"}} نیائه.",
+ "notification-page-linked-email-subject": "بلگه شما د {{نوم مالگه}} هوم پیوند بیه",
+ "notification-page-linked-email-batch-body": "$2 {{GENDER:$1|هوم پیوند کرده}} سی$3.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|گوته}} د {{SITENAME}} شما",
+ "notification-user-rights-email-subject": "حقوق کاریاری شما د {{نوم دیارگه}} آلشت دئیه بیه",
+ "notification-user-rights-email-batch-body": "حقوق کاریاری شما {{GENDER:$1|آلشت بیه}} وه دس $1. $2.",
+ "echo-email-subject-default": "یه گل وارسیاری تازه د {{SITENAME}}",
+ "echo-email-body-default": "شما یه گل وارسیاری تاز د {{SITENAME}} داریتو\n\n$1",
+ "echo-email-batch-body-default": "شما یه گل وارسیاری تازه داریت.",
+ "echo-notification-message": "{{PLURAL:$1|پیغوم($1)|پیغومیا($1)|100=پیغومیا(99+)}}",
+ "echo-notification-alert-text-only": "زئناریا",
+ "echo-notification-message-text-only": "پيغومیا",
+ "echo-overlay-link": "همه وارسیاریا",
+ "echo-overlay-title": "<b>وارسیاریا</b>",
+ "echo-overlay-title-overflow": "<b>{{جمی:$1|وارسیاری یا}}</b> (نشو دئه $1 د $2 حنه نبیه)",
+ "echo-mark-all-as-read": "همه نه د عنوان حنه بیه نشو بیه",
+ "echo-date-today": "امرو",
+ "echo-date-yesterday": "دوش،دیرو",
+ "echo-email-batch-link-text-view-all-notifications": "همه وارسیاریانه بوینیت",
+ "echo-rev-deleted-text-view": "وانئری ای بلگه پاکساگری بیه.",
+ "apihelp-echomarkread-description": "نشودار کردن وارسیاریا چی حنه بیه یا سی کاریاری ایسنی.",
+ "apihelp-echomarkread-param-sections": "نومجایی د بهرجایایی که چی حنه بیه نشودار بیه.",
+ "apihelp-echomarkread-example-1": "هشت گله وارسیاری نه چی حنه بیه یا نشودار بک",
+ "apihelp-echomarkread-example-2": "همه وارسیاری یا نه چی حنه بیه یا نشودار بک",
+ "apihelp-query+notifications-description": "وارسیاری آهره داری کردن سی کاریار ایسنی نه وه دس بئیرت.",
+ "apihelp-query+notifications-param-prop": "جزئیات حاسته بیه.",
+ "apihelp-query+notifications-param-sections": "بهرجایا وارسیاری سی پورس کردن.",
+ "apihelp-query+notifications-param-limit": "بیشترونه شماره وارسیاریا سی ؤرئشتن",
+ "apihelp-query+notifications-param-alertunreadfirst": "آیا اول وارسیاریا پیغومیا نحنه نه نشو بیه.",
+ "apihelp-query+notifications-example-1": "نومجا وارسیاریا"
+}
diff --git a/Echo/i18n/lt.json b/Echo/i18n/lt.json
new file mode 100644
index 00000000..90e8aabe
--- /dev/null
+++ b/Echo/i18n/lt.json
@@ -0,0 +1,59 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eitvys200",
+ "Hugo.arg",
+ "Mantak111"
+ ]
+ },
+ "echo-desc": "Pranešimų sistema",
+ "prefs-echo": "Pranešimai",
+ "prefs-emailsettings": "El. pašto nustatymai",
+ "prefs-displaynotifications": "Rodymo nuostatos",
+ "prefs-echosubscriptions": "Praneškite man apie šiuos įvykius",
+ "prefs-newmessageindicator": "Naujų žinučių indikatorius",
+ "echo-pref-send-me": "Siųskite man:",
+ "echo-pref-send-to": "Siųsti:",
+ "echo-pref-email-format": "Elektroninių laškų pavidalas:",
+ "echo-pref-web": "Internetas",
+ "echo-pref-email": "El. paštas",
+ "echo-pref-email-frequency-never": "Nesiųskite man jokiu el. pašto pranešimų",
+ "echo-pref-email-frequency-immediately": "Atskiri pranešimai, vos juos gavus",
+ "echo-pref-email-frequency-daily": "Per dieną gautų pranešimų sąvadas",
+ "echo-pref-email-frequency-weekly": "Per savaitę gautų pranešimų sąvadas",
+ "echo-pref-new-message-indicator": "Rodyti ženklą mano įrankių juostoje apie aptarimų puslapyje gautą pranešimą",
+ "echo-learn-more": "Sužinokite daugiau",
+ "echo-new-messages": "Jūs turite naujų žinučių",
+ "echo-pref-tooltip-edit-user-talk": "Tebūnie pranešta, kai kas nors palieka naują žinutę ar atsakymą mano aptarimų puslapyje.",
+ "echo-pref-tooltip-article-linked": "Tebūnie pranešta, kai kas nors straipsnyje sukuria nuorodą į mano rašytą straipsnį.",
+ "echo-pref-tooltip-reverted": "Tebūnie pranešta, kai kas nors atmeta mano pakeitimus naudodamasis atmetimo ir atšaukimo įrankiais.",
+ "echo-pref-tooltip-mention": "Tebūnie pranešta, kai kas nors sukuria nuorodą į mano naudotojo puslapį.",
+ "echo-pref-tooltip-user-rights": "Tebūnie pranešta, kai kas nors pakeičia mano naudotojo teises.",
+ "echo-no-agent": "[Niekas]",
+ "notifications": "Pranešimai",
+ "tooltip-pt-notifications": "Jūsų pranešimai",
+ "echo-specialpage": "Pranešimai",
+ "echo-none": "Jūs turite jokių pranešimų.",
+ "echo-more-info": "Daugiau informacijos",
+ "echo-feedback": "Atsiliepimas",
+ "notification-link-text-view-message": "Peržiūrėti žinutę",
+ "notification-link-text-view-mention": "Peržiūrėti paminėjimą",
+ "notification-link-text-view-changes": "Peržiūrėti pakeitimus",
+ "notification-link-text-view-page": "Peržiūrėti puslapį",
+ "notification-link-text-view-edit": "Peržiūrėti redagavimą",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|paliko}} žinutę jūsų [[User talk:$2#$3|aptarimų puslapyje]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|paliko}} žinutę jūsų aptarimų puslapyje \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|paliko}} žinutę jūsų [[User talk:$2#$3|aptarimų puslapyje]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|paliko}} žinutę jūsų aptarimų puslapyje \"[[User talk:$2#$3|$4]]\".",
+ "notification-reverted2": "Jūsų {{PLURAL:$4|keitimas puslapyje [[:$2]]|keitimai [[:$2]] puslapyje}} buvo {{PLURAL:$4|atmestas|atmesti}} naudotojo [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Jūsų {{PLURAL:$4|keitimas puslapyje $2|keitimai $2 puslapyje}} buvo {{PLURAL:$4|atmestas|atmesti}} naudotojo $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|paliko}} žinutę jums svetainėje {{SITENAME}}",
+ "echo-email-batch-body-default": "Jūs turite naują pranešimą",
+ "echo-overlay-link": "Visi pranešimai",
+ "echo-overlay-title": "<b>Pranešimai</b>",
+ "echo-mark-all-as-read": "Pažymėti visus kaip skaitytus",
+ "echo-date-today": "Šiandien",
+ "echo-date-yesterday": "Vakar",
+ "echo-load-more-error": "Įvyko klaida gaunant daugiau rezultatų.",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 ir $2 {{PLURAL:$3|kitas|kiti|kitų}} {{GENDER:$1|paliko}} žinutę jūsų aptarimų puslapyje."
+}
diff --git a/Echo/i18n/lv.json b/Echo/i18n/lv.json
new file mode 100644
index 00000000..1b8bc47f
--- /dev/null
+++ b/Echo/i18n/lv.json
@@ -0,0 +1,114 @@
+{
+ "@metadata": {
+ "authors": [
+ "Admresdeserv.",
+ "Edgars2007",
+ "Papuass"
+ ]
+ },
+ "echo-desc": "Paziņojumu sistēma",
+ "prefs-echo": "Paziņojumi",
+ "prefs-emailsettings": "E-pasta uzstādījumi",
+ "prefs-displaynotifications": "Attēlošanas uzstādījumi",
+ "prefs-echosubscriptions": "Paziņot man par šiem notikumiem",
+ "prefs-newmessageindicator": "Jauna ziņojuma indikators",
+ "echo-pref-send-me": "Nosūtīt man:",
+ "echo-pref-send-to": "Nosūtīt uz:",
+ "echo-pref-email-format": "E-pasta formāts:",
+ "echo-pref-web": "Tīmeklis",
+ "echo-pref-email": "E-pasts",
+ "echo-pref-email-frequency-never": "Nesūtīt man e-pasta paziņojumus",
+ "echo-pref-email-frequency-immediately": "Individuāli paziņojumi, tiklīdz tie ienāk",
+ "echo-pref-email-frequency-daily": "Ikdienas paziņojumu kopsavilkums",
+ "echo-pref-email-frequency-weekly": "Iknedēļas paziņojumu kopsavilkums",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Vienkāršs teksts",
+ "echo-pref-notify-show-link": "Rādīt paziņojumus manā rīkjoslā",
+ "echo-pref-new-message-indicator": "Rādīt diskusiju lapas ziņojumu indikatoru manā rīkjoslā",
+ "echo-learn-more": "Uzzināt vairāk",
+ "echo-new-messages": "tev ir jauni paziņojumi",
+ "echo-category-title-edit-user-talk": "Diskusiju lapas {{PLURAL:$1|paziņojumi|paziņojums|paziņojumi}}",
+ "echo-category-title-article-linked": "Lapas {{PLURAL:$1|saites|saite|saites}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Atcelti labojumi|Atcelts labojums|Atcelti labojumi}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Pieminēšanas|Pieminēšana|Pieminēšanas}}",
+ "echo-category-title-other": "{{PLURAL:$1|Citi|Cits|Citi}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistēmas paziņojumi|Sistēmas paziņojums|Sistēmas paziņojumi}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Lietotāja tiesību izmaiņas|Lietotāja tiesības izmaiņas|Lietotāja tiesību izmaiņas}}",
+ "echo-pref-tooltip-edit-user-talk": "Paziņot man, kad kāds pievieno ziņojumu vai atbild manā diskusiju lapā.",
+ "echo-pref-tooltip-article-linked": "Paziņot man, kad kāds izveido saiti uz manis izveidotu lapu.",
+ "echo-pref-tooltip-reverted": "Paziņot man, kad kāds atceļ manis veiktu labojumu, izmanojot atcelšanas rīku.",
+ "echo-pref-tooltip-mention": "Paziņot man, kad kāds izveido saiti uz manu lietotāja lapu.",
+ "echo-pref-tooltip-user-rights": "Paziņot man, kad kāds izmaina manas lietotāja tiesības.",
+ "echo-no-agent": "[Neviens]",
+ "echo-no-title": "[Nav lapas]",
+ "echo-error-no-formatter": "Paziņojumam nav norādīts formatējums",
+ "echo-error-preference": "Kļūda: Neizdevās uzstādīt lietotāja izvēli",
+ "echo-error-token": "Kļūda: Neizdevās iegūt lietotāja identifikatoru",
+ "notifications": "Paziņojumi",
+ "tooltip-pt-notifications": "Jūsu paziņojumi",
+ "echo-specialpage": "Paziņojumi",
+ "echo-anon": "Lai saņemtu paziņojumus, [$1 izveidojiet lietotāja kontu] vai [$2 pieslēdzietes].",
+ "echo-none": "Jums nav paziņojumu.",
+ "echo-more-info": "Vairāk informācijas",
+ "echo-feedback": "Atsauksmes",
+ "notification-link-text-view-message": "Apskatīt ziņojumu",
+ "notification-link-text-view-mention": "Apskatīt pieminēšanu",
+ "notification-link-text-view-changes": "Apskatīt izmaiņas",
+ "notification-link-text-view-page": "Apskatīt lapu",
+ "notification-link-text-view-edit": "Apskatīt labojumu",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|atstāja}} paziņojumu jūsu [[User talk:$2#$3|diskusiju lapā]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|atstāja}} paziņojumu jūsu diskusiju lapā \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|atstāja}} paziņojumu jūsu [[User talk:$2#$3|diskusiju lapā]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|atstāja}} paziņojumu tavā diskusiju lapā \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Uz [[:$2]] {{GENDER:$1|tika izveidota saite}} no [[:$3]]. [[Special:WhatLinksHere/$2|Apskatīt visas saites uz šo lapu]].",
+ "notification-page-linked-flyout": "Uz [[:$2]] tika {{GENDER:$1|izveidota saite}} no [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|komentēja}} par \"[[$3|$2]]\" \"$4\" diskusiju lapā",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|izveidoja}} jaunu tēmu \"$2\" [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|nosūtīja}} jums paziņojumu: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|komentēja}} par \"[[$3#$2|$2]]\" jūsu diskusiju lapā",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|pieminēja}} tevi $5 diskusiju lapā \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|pieminēja}} jūs $5 diskusiju lapā par \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|pieminēja}} tevi [[:$3|$2 diskusiju lapā]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|pieminēja}} tevi [[:$3|$2 diskusiju lapā]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|nomainīja}}]] tavas lietotāja tiesības. $2. [[Special:ListGroupRights|Skatīt informāciju]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|nomainīja}} tavas lietotāja tiesības. $2. [[Special:ListGroupRights|Skatīt informāciju]]",
+ "notification-user-rights-add": "Jūs tagad esat {{PLURAL:$2|šo grupu|šīs grupas|šo grupu}} dalībnieks: $1",
+ "notification-user-rights-remove": "Jūs vairs neesat {{PLURAL:$2|šo grupu|šīs grupas|šo grupu}} dalībnieks: $1",
+ "notification-new-user": "Laipni lūdzam {{SITENAME}}, $1! Mēs priecājamies jūs te redzēt.",
+ "notification-reverted2": "Jūsu {{PLURAL:$4|labojumus lapā [[:$2]]|labojumu lapā [[:$2]]|labojumus lapā [[:$2]]}} {{GENDER:$1|atcēla}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Jūsu {{PLURAL:$4|labojumus lapā $2|labojumu lapā $2|labojumus lapā $2}} {{GENDER:$1|atcēla}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|atstāja}} tev ziņojumu {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|atstāja}} paziņojumu jūsu diskusiju lapā:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|atstāja}} paziņojumu jūsu diskusiju lapā \"$2\".",
+ "notification-page-linked-email-subject": "Uz jūsu lapu {{SITENAME}} tika izveidota saite",
+ "notification-page-linked-email-batch-body": "$3 lapā tika izveidota saite no $2",
+ "notification-reverted-email-subject2": "Jūsu {{PLURAL:$3|atcelts|labojums tika {{GENDER:$1|atcelts}}|labojumi tika {{GENDER:$1|atcelti}}}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "Jūsu {{PLURAL:$3|labojumus $2|labojumu $2|labojumus $2}} {{GENDER:$1|atcēla}} $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|pieminēja}} tevi {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|pieminēja}} tevi $4 diskusiju lapā \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|pieminēja}} tevi $2 diskusijas lapā.",
+ "notification-user-rights-email-subject": "Jūsu lietotāja tiesības tika izmainītas {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Jūsu lietotāja tiesības {{GENDER:$1|izmainīja}} $1. $2.",
+ "echo-email-subject-default": "Jauns paziņojums par {{SITENAME}}",
+ "echo-email-body-default": "Jums ir jauns paziņojums par {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Jums ir jauns paziņojums.",
+ "echo-email-footer-default": "$2\n\nLai kontrolētu, kurus e-pastus mēs Jums sūtām, pārbaudiet savus uzstādījumus:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Lai kontrolētu, kurus e-pastus mēs Jums sūtām, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">pārbaudiet savus iestatījumus</a>.<br />\n$1",
+ "echo-notification-alert-text-only": "Brīdinājumi",
+ "echo-notification-message-text-only": "Ziņojumi",
+ "echo-overlay-link": "Visi paziņojumi",
+ "echo-overlay-title": "<b>Paziņojumi</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Paziņojumi|Paziņojums|Paziņojumi}}</b> (rāda $1 no $2 nelasītiem)",
+ "echo-mark-all-as-read": "Atzīmēt visus kā izlasītus",
+ "echo-date-today": "Šodien",
+ "echo-date-yesterday": "Vakar",
+ "echo-load-more-error": "Ielasot vairāk rezultātus notika kļūda.",
+ "notification-edit-talk-page-bundle": "$1 un $3 {{PLURAL:$4|citi|cits|citi}} {{GENDER:$1|atstāja}} paziņojumu tavā [[User talk:$2|diskusiju lapā]].",
+ "notification-page-linked-email-batch-bundle-body": "{{GENDER:$1|linked}} from $3 un $4 citās {{PLURAL:$5|lapās|lapā|lapās}} tika izveidota saite uz $2.",
+ "echo-email-batch-subject-daily": "Jums ir {{PLURAL:$2|jauni paziņojumi|jauns paziņojums|jauni paziņojumi}} par {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Jums šonedēļ ir {{PLURAL:$2|jauni paziņojumi|jauns paziņojums|jauni paziņojumi}} par {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Sveiks $1,\nŠis ir šīsdienas {{SITENAME}} aktivitāšu saraksts.",
+ "echo-email-batch-body-intro-weekly": "Sveiks $1,\nŠis ir šīs nedēļas {{SITENAME}} aktivitāšu saraksts.",
+ "echo-email-batch-link-text-view-all-notifications": "Apskatīt visus paziņojumus",
+ "apihelp-echomarkread-example-2": "Atzīmēt visus paziņojumus, kā izlasītus"
+}
diff --git a/Echo/i18n/lzh.json b/Echo/i18n/lzh.json
new file mode 100644
index 00000000..0d87ac68
--- /dev/null
+++ b/Echo/i18n/lzh.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yanteng3",
+ "Jason924tw"
+ ]
+ },
+ "prefs-emailsettings": "傳書",
+ "prefs-echosubscriptions": "訊事",
+ "echo-new-messages": "子有新訊息",
+ "notifications": "訊",
+ "echo-notification-alert": "{{PLURAL:$1|訊 ($1)|訊 ($1)|100=訊 (九九+)}}"
+}
diff --git a/Echo/i18n/mai.json b/Echo/i18n/mai.json
new file mode 100644
index 00000000..272a1fc4
--- /dev/null
+++ b/Echo/i18n/mai.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tulsi Bhagat"
+ ]
+ },
+ "tooltip-pt-notifications": "आपने के अधिसूचना"
+}
diff --git a/Echo/i18n/mg.json b/Echo/i18n/mg.json
new file mode 100644
index 00000000..4d56314f
--- /dev/null
+++ b/Echo/i18n/mg.json
@@ -0,0 +1,60 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Jagwar"
+ ]
+ },
+ "echo-desc": "Rafitra fampilazana",
+ "prefs-echo": "Filazana",
+ "prefs-emailsettings": "Safidin'ny mailaka",
+ "prefs-displaynotifications": "Safidin-tseho",
+ "prefs-echosubscriptions": "Ampandreneso momba ireo zava-mitranga ireo aho",
+ "prefs-newmessageindicator": "Tondron-kafatra vaovao",
+ "echo-pref-send-me": "Andefaso ahy:",
+ "echo-pref-send-to": "Alefaso any amy:",
+ "echo-pref-web": "Tranonkala",
+ "echo-pref-email": "Mailaka",
+ "echo-pref-email-frequency-never": "Aza andefasana fampilazana amin'ny mailaka aho",
+ "echo-pref-email-frequency-immediately": "Fampilazana tsirairay araky ny iaviany",
+ "echo-pref-email-frequency-daily": "Famintinana isan'andron'ny fampilazana",
+ "echo-pref-email-frequency-weekly": "Famintinana isan-kerinandron'ny fampilazana",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Soratra tsotra",
+ "echo-pref-notify-show-link": "Asehoy ao amin'ny toolbar-ko ny fampilazana",
+ "echo-pref-new-message-indicator": "Haneho ny mpanondro hafatra ao amin'ny pejin-dresaka ao amin'ny toolbar-ko",
+ "echo-learn-more": "Fampahalalana fanampiny",
+ "echo-new-messages": "Misy hafatra vaovao",
+ "echo-category-title-edit-user-talk": "Hafatry ny {{PLURAL:$1|pejin-dresaka}}",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Rohim-pejy}}",
+ "echo-pref-tooltip-edit-user-talk": "Ilazao aho raha misy mamela hafatra na mamaly hafatra eo amin'ny pejin-dresaka.",
+ "echo-pref-tooltip-article-linked": "Ilazao aho raha misy manisy rohy mankany amina pejy noforiko avy amin'ny pejin-dahatsoratra",
+ "echo-no-agent": "[Tsy misy]",
+ "echo-no-title": "[Tsy misy pejy]",
+ "notifications": "Fampilazana",
+ "tooltip-pt-notifications": "Ny fampilazanao",
+ "echo-specialpage": "Fampilazana",
+ "echo-more-info": "Fampahalalana fanampiny",
+ "echo-feedback": "Famoahan-kevitra",
+ "notification-link-text-view-message": "Hijery hafatra",
+ "notification-link-text-view-mention": "Hijery ny zava-boamarika",
+ "notification-link-text-view-changes": "Hijery ny fiovana",
+ "notification-link-text-view-page": "Hijery ny pejy",
+ "notification-link-text-view-edit": "Hijery ny fanovàna",
+ "notification-edit-talk-page2": "Nametraka hafatra teo amin'ny [[User talk:$2#$3|pejin-dresakao]] i [[User:$1|$1]].",
+ "notification-edit-talk-page-email-subject2": "Nametraka hafatra teo amin'ny pejin-dresakao teo amin'i {{SITENAME}} i $1",
+ "notification-edit-talk-page-email-batch-body-with-section": "Namela hafatra teo amin'ny pejin-dresakao tanatin'i \"$2\" i $1",
+ "notification-user-rights-email-subject": "Voaova teo amin'i {{SITENAME}} ny zom-pikambanao",
+ "notification-user-rights-email-batch-body": "Voaovan'i $1 ny zom-pikambanao. $2",
+ "echo-email-subject-default": "Fampilazana vaovao any amin'i {{SITENAME}}",
+ "echo-email-body-default": "Manana fampilazana vaovao ianao any amin'i {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Manana fampilazana vaovao ianao.",
+ "echo-overlay-link": "Fampilazana rehetra",
+ "echo-overlay-title": "<b>Fampilazana</b>",
+ "echo-mark-all-as-read": "Marihana ho voavaky",
+ "echo-date-today": "Androany",
+ "echo-date-yesterday": "Omaly",
+ "echo-load-more-error": "Nisy hadisoana nitranga tam-panaovana fetch ny valiny.",
+ "echo-email-batch-link-text-view-all-notifications": "Hijery ny fampilazana rehetra",
+ "echo-rev-deleted-text-view": "Voafafa ity filazam-pajy ity."
+}
diff --git a/Echo/i18n/min.json b/Echo/i18n/min.json
new file mode 100644
index 00000000..6a415c86
--- /dev/null
+++ b/Echo/i18n/min.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Iwan Novirion"
+ ]
+ },
+ "echo-new-messages": "Sanak ado pasan baru"
+}
diff --git a/Echo/i18n/mk.json b/Echo/i18n/mk.json
new file mode 100644
index 00000000..1579e6fa
--- /dev/null
+++ b/Echo/i18n/mk.json
@@ -0,0 +1,136 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06"
+ ]
+ },
+ "echo-desc": "Известителен систем",
+ "prefs-echo": "Известувања",
+ "prefs-emailsettings": "Можности за е-пошта",
+ "prefs-displaynotifications": "Нагодувања на приказот",
+ "prefs-echosubscriptions": "Известувај ме за следниве настани",
+ "prefs-newmessageindicator": "Показател за нови пораки",
+ "echo-pref-send-me": "Испрати ми:",
+ "echo-pref-send-to": "Испрати на:",
+ "echo-pref-email-format": "Формат на е-пошта:",
+ "echo-pref-web": "На вики",
+ "echo-pref-email": "Е-пошта",
+ "echo-pref-email-frequency-never": "Не ми праќај известувања на е-пошта",
+ "echo-pref-email-frequency-immediately": "Поединечни известувања, едно по едно",
+ "echo-pref-email-frequency-daily": "Дневен преглед на известувањата",
+ "echo-pref-email-frequency-weekly": "Неделен преглед на известувањата",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Прост текст",
+ "echo-pref-notify-show-link": "Прикажувај известувања во мојот алатник",
+ "echo-pref-new-message-indicator": "Прикажувај показател за нови пораки (на стр. за разговор) во алатникот",
+ "echo-learn-more": "Дознајте повеќе",
+ "echo-new-messages": "Имате нови пораки",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Порака|Пораки}} на стран. за разговор",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Врска|Врски}} до стран.",
+ "echo-category-title-reverted": "{{PLURAL:$1|Вратено уредување|Вратени уредувања}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Споменување|Споменувања}}",
+ "echo-category-title-other": "{{PLURAL:$1|Друго}}",
+ "echo-category-title-system": "{{PLURAL:$1|Систем}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Промена во корисничките права|Промени во корисничките права}}",
+ "echo-pref-tooltip-edit-user-talk": "Извести ме кога некој ќе остави порака или ќе одговори на мојата страница за разговор.",
+ "echo-pref-tooltip-article-linked": "Извести ме кога некој ќе се повика на статија што ја имам создадено.",
+ "echo-pref-tooltip-reverted": "Извести ме кога некој ќе откаже уредување што го имам направено користејќи ја алатката за отповикување или враќање.",
+ "echo-pref-tooltip-mention": "Извести ме кога некој ќе стави врска до мојата корисничка страница.",
+ "echo-pref-tooltip-user-rights": "Извести ме кога некој ќе ми ги смени корисничките права.",
+ "echo-no-agent": "[Никој]",
+ "echo-no-title": "[Нема страница]",
+ "echo-error-no-formatter": "Нема зададено форматирање за ова известување",
+ "echo-error-preference": "Грешка: Не можам да го зададам нагодувањето",
+ "echo-error-token": "Грешка: Не можев да ја добијам корисничката шифра",
+ "notifications": "Известувања",
+ "tooltip-pt-notifications": "Вашите известувања",
+ "echo-specialpage": "Известувања",
+ "echo-anon": "За да добивате известувања, [$1 направете сметка] или [$2 најавете се].",
+ "echo-none": "Немате известувања.",
+ "echo-more-info": "Повеќе информации",
+ "echo-feedback": "Мислења",
+ "echo-quotation-marks": "„$1“",
+ "notification-link-text-view-message": "Погл. порака",
+ "notification-link-text-view-mention": "Погл. споменувањето",
+ "notification-link-text-view-changes": "Погл. промени",
+ "notification-link-text-view-page": "Погл. страница",
+ "notification-link-text-view-edit": "Погл. уредување",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|остави}} порака на вашата [[User talk:$2#$3|страница за разговор]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|остави}} порака на вашата страница за разговор во „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|остави}} порака на вашата [[User talk:$2#$3|страница за разговор]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|остави}} порака на вашата страница за разговор во „[[User talk:$2#$3|$4]]“.",
+ "notification-page-linked": "[[:$2]] е {{GENDER:$1|наведена}} од [[:$3]]. [[Special:WhatLinksHere/$2|Погл. сите врски до страницава]].",
+ "notification-page-linked-flyout": "[[:$2]] е {{GENDER:$1|наведена}} на [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|коментираше}} на „[[$3|$2]]“ на страницата за разговор „$4“",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|ја објави}} новата тема „$2“ на [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|ви испрати}} порака: „[[$3#$2|$2]]“",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|коментираше}} на „[[$3#$2|$2]]“ на вашата страница за разговор",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|ве спомна}} во страницата $5 на „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|ве спомна}} во страницата $5 на „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|ве спомна}} на [[:$3|страницата за разговор на $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|ве спомна}} во [[:$3|страницата за разговор на $2]].",
+ "notification-user-rights": "Вашите кориснички права се [[Special:Log/rights/$1|{{GENDER:$1|изменети}}]] од [[User:$1|$1]]. $2. [[Special:ListGroupRights|Дознајте повеќе]]",
+ "notification-user-rights-flyout": "Вашите кориснички права се {{GENDER:$1|изменети}} од $1. $2. [[Special:ListGroupRights|Дознајте повеќе]]",
+ "notification-user-rights-add": "Сега членувате во {{PLURAL:$2|оваа група|овие групи}}: $1",
+ "notification-user-rights-remove": "Повеќе не членувате во {{PLURAL:$2|оваа група|овие групи}}: $1",
+ "notification-new-user": "Добре дојдовте на {{SITENAME}}, $1! Драго ни е што сте тука.",
+ "notification-reverted2": "[[User:$1|$1]] {{PLURAL:$4|го|ги}} {{GENDER:$1|врати}} {{PLURAL:$4|вашето уредување на [[:$2]]|вашите уредувања на [[:$2]]}} $3",
+ "notification-reverted-flyout2": "$1 {{PLURAL:$4|го|ги}} {{GENDER:$1|врати}} {{PLURAL:$4|вашето уредување на $2|вашите уредувања на $2}} $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|ви остави}} порака на {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|остави}} порака на вашата страница за разговор:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|остави}} порака на вашата страница за разговор на „$2“.",
+ "notification-page-linked-email-subject": "Ваша страница беше наведена на {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 е {{GENDER:$1|наведена}} на $3",
+ "notification-reverted-email-subject2": "{{GENDER:$1|На}} {{SITENAME}} {{PLURAL:$3|е вратено ваше уредување|се вратени ваши уредувања}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|врати}} {{PLURAL:$3|ваше уредување на $2|ваши уредувања на $2}}",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|ве спомна}} на {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|ве спомна}} во страницата $4 на „$3“.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|ве спомна}} во страницата за разговор на $2.",
+ "notification-user-rights-email-subject": "Вашите кориснички права на {{SITENAME}} се изменети",
+ "notification-user-rights-email-batch-body": "Вашите кориснички права се {{GENDER:$1|изменети}} од $1. $2",
+ "echo-email-subject-default": "Ново известување на {{SITENAME}}",
+ "echo-email-body-default": "Имате ново известување на {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Имате ново известување",
+ "echo-email-footer-default": "$2\n\nАко сакате да изберете какви пораки да добивате, појдете на страницата:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}} $1\n\n$1",
+ "echo-email-footer-default-html": "За да изберете какви писма да примате од нас, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">појдете во вашите нагодувања</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Едно известување|$1 известувања|100=99+ известувања}}",
+ "echo-notification-message": "{{PLURAL:$1|Една порака|$1 пораки|100=99+ пораки}}",
+ "echo-notification-alert-text-only": "Известувања",
+ "echo-notification-message-text-only": "Пораки",
+ "echo-overlay-link": "Сите известувања",
+ "echo-overlay-title": "<b>Известувања</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Известувања}}</b> ({{PLURAL:$1|прикажано|прикажани}} $1 од $2 непрочитани)",
+ "echo-mark-all-as-read": "Означи ги сите како прочитани",
+ "echo-date-today": "Денес",
+ "echo-date-yesterday": "Вчера",
+ "echo-load-more-error": "Се појави грешка при обидот да добијам повеќе резултати.",
+ "notification-edit-talk-page-bundle": "$1 и {{PLURAL:$4|уште еден друг|уште $3 други}} {{GENDER:$1|оставија}} порака на вашата [[User talk:$2|страница за разговор]].",
+ "notification-page-linked-bundle": "$2 е {{GENDER:$1|наведена}} на $3 и уште $4 {{PLURAL:$5|страница|страници}}. [[Special:WhatLinksHere/$2|Погл. сите врски до страницава]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 и уште {{PLURAL:$3|еден|$2 корисници}} {{GENDER:$1|оставија}} порака на вашата страница за разговор",
+ "notification-page-linked-email-batch-bundle-body": "$2 беше {{GENDER:$1|наведена}} од $3 и уште {{PLURAL:$5|една страница|$4 страници}}",
+ "echo-email-batch-subject-daily": "Имате {{PLURAL:$2|ново известување|нови известувања}} на {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Неделава имате {{PLURAL:$2|ново известување|нови известувања}} на {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Здраво $1,\nВи даваме преглед на денешните збиднувања на {{SITENAME}}",
+ "echo-email-batch-body-intro-weekly": "Здраво $1,\nВи даваме преглед на збиднувањата на {{SITENAME}} за оваа седмица",
+ "echo-email-batch-link-text-view-all-notifications": "Погл. сите известувања",
+ "echo-rev-deleted-text-view": "Оваа преработка е скриена",
+ "apihelp-echomarkread-description": "Означи ги сите известувања како прочитани за тековниот корисник.",
+ "apihelp-echomarkread-param-list": "Список на назнаки на известувањата што треба да се означат како прочитани.",
+ "apihelp-echomarkread-param-all": "Ако е зададено, ги означува сите известувања на еден корисник како прочитани.",
+ "apihelp-echomarkread-param-sections": "Список на поднаслови што треба да се означат како прочитани.",
+ "apihelp-echomarkread-example-1": "Означи го известувањето 8 како прочитано",
+ "apihelp-echomarkread-example-2": "Означиу ги сите известувања како прочитани",
+ "apihelp-query+notifications-description": "Дај ги известувањата што го исчекуваат тековниот корисник.",
+ "apihelp-query+notifications-param-prop": "Подробности што треба да се побараат.",
+ "apihelp-query+notifications-param-sections": "Известителните поднаслови што треба да се побараат.",
+ "apihelp-query+notifications-param-groupbysection": "Дали да се групираат резултатите по поднаслови. Ако е зададено, секој поднаслов се дава посебно.",
+ "apihelp-query+notifications-param-format": "Ако е укажано, известувањата ќе се дадат форматирани на овој начин.",
+ "apihelp-query+notifications-param-limit": "Максималниот број на известувања што ќе се дадат.",
+ "apihelp-query+notifications-param-index": "Ако е укажано, ќе се даде список на назнаки на известувања по редослед.",
+ "apihelp-query+notifications-param-alertcontinue": "Употребете го ова за да продолжите кога има повеќе напомени за известувања.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Дали прво да се прикажуваат непрочитаните известувања за порака.",
+ "apihelp-query+notifications-param-messagecontinue": "Употребете го ова за да продолжите кога има повеќе резултати за пораки.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Дали прво да се прикажуваат непрочитаните напомени за известувања.",
+ "apihelp-query+notifications-example-1": "Испиши известувања",
+ "apihelp-query+notifications-example-2": "Испиши известувања, групирани по поднаслови, со бројност"
+}
diff --git a/Echo/i18n/ml.json b/Echo/i18n/ml.json
new file mode 100644
index 00000000..42d18f70
--- /dev/null
+++ b/Echo/i18n/ml.json
@@ -0,0 +1,138 @@
+{
+ "@metadata": {
+ "authors": [
+ "Praveenp",
+ "Santhosh.thottingal",
+ "Sidharthan",
+ "Vssun"
+ ]
+ },
+ "echo-desc": "അറിയിപ്പ് സംവിധാനം",
+ "prefs-echo": "അറിയിപ്പുകൾ",
+ "prefs-emailsettings": "ഇമെയിൽ ഐച്ഛികങ്ങൾ",
+ "prefs-displaynotifications": "പ്രദർശന ഐച്ഛികങ്ങൾ",
+ "prefs-echosubscriptions": "ഈ സംഭവങ്ങളെക്കുറിച്ച് എന്നെ അറിയിക്കുക",
+ "prefs-newmessageindicator": "പുതിയ സന്ദേശത്തിന്റെ അടയാളം",
+ "echo-pref-send-me": "അയക്കേണ്ട രീതി:",
+ "echo-pref-send-to": "അയക്കേണ്ട വിലാസം:",
+ "echo-pref-email-format": "ഇമെയിൽ എഴുത്തുരീതി:",
+ "echo-pref-web": "വെബ്",
+ "echo-pref-email": "ഇമെയിൽ",
+ "echo-pref-email-frequency-never": "എനിക്ക് ഇമെയിൽ അറിയിപ്പുകൾ വേണ്ട",
+ "echo-pref-email-frequency-immediately": "വരുന്ന മുറയ്ക്ക് വെവ്വേറെ അറിയിപ്പുകൾ",
+ "echo-pref-email-frequency-daily": "ഒരു ദിവസത്തെ അറിയിപ്പുകളുടെ അവലോകനം",
+ "echo-pref-email-frequency-weekly": "ഒരു ആഴ്ചയിലെ അറിയിപ്പുകളുടെ അവലോകനം",
+ "echo-pref-email-format-html": "എച്ച്.റ്റി.എം.എൽ.",
+ "echo-pref-email-format-plain-text": "വെറും എഴുത്ത്",
+ "echo-pref-notify-show-link": "അറിയിപ്പുകൾ ടൂൾബാറിൽ പ്രദർശിപ്പിക്കുക",
+ "echo-pref-new-message-indicator": "എന്റെ സംവാദത്താളിലെ സന്ദേശങ്ങളുടെ സൂചന ടൂൾബാറിൽ പ്രദർശിപ്പിക്കുക",
+ "echo-learn-more": "കൂടുതൽ അറിയുക",
+ "echo-new-messages": "താങ്കൾക്ക് പുതിയ സന്ദേശങ്ങൾ ഉണ്ട്",
+ "echo-category-title-edit-user-talk": "സംവാദത്താളിലെ {{PLURAL:$1|സന്ദേശം|സന്ദേശങ്ങൾ}}",
+ "echo-category-title-article-linked": "താളിലേയ്ക്കുള്ള {{PLURAL:$1|കണ്ണി|കണ്ണികൾ}}",
+ "echo-category-title-reverted": "തിരുത്തൽ {{PLURAL:$1|മുൻപ്രാപനം|മുൻപ്രാപനങ്ങൾ}}",
+ "echo-category-title-mention": "{{PLURAL:$1|പരാമർശം|പരാമർശങ്ങൾ}}",
+ "echo-category-title-other": "{{PLURAL:$1|മറ്റുള്ളവ}}",
+ "echo-category-title-system": "{{PLURAL:$1|വ്യവസ്ഥ}}",
+ "echo-category-title-user-rights": "ഉപയോക്തൃ അവകാശ {{PLURAL:$1|മാറ്റം|മാറ്റങ്ങൾ}}",
+ "echo-pref-tooltip-edit-user-talk": "ആരെങ്കിലും എന്റെ സംവാദത്താളിൽ ഒരു സന്ദേശമോ മറുപടിയോ ഇട്ടാൽ എന്നെ അറിയിക്കുക.",
+ "echo-pref-tooltip-article-linked": "ഞാൻ സൃഷ്ടിച്ച ഒരു ലേഖനതാളിൽ ആരെങ്കിലും കണ്ണി ചേർത്താൽ എന്നെ അറിയിക്കുക.",
+ "echo-pref-tooltip-reverted": "തിരസ്കരണ അല്ലെങ്കിൽ മുൻപ്രാപന ഉപകരണമുപയോഗിച്ച് ആരെങ്കിലും ഞാൻ വരുത്തിയ തിരുത്തൽ ഒഴിവാക്കിയാൽ എന്നെ അറിയിക്കുക.",
+ "echo-pref-tooltip-mention": "ആരെങ്കിലും എന്റെ ഉപയോക്തൃതാളിലേക്ക് കണ്ണി ചേർത്താൽ എന്നെ അറിയിക്കുക.",
+ "echo-pref-tooltip-user-rights": "എന്റെ ഉപയോക്തൃ അവകാശങ്ങളിൽ ആരെങ്കിലും മാറ്റം വരുത്തിയാൽ എന്നെ അറിയിക്കുക.",
+ "echo-no-agent": "[ആരുമില്ല]",
+ "echo-no-title": "[താൾ ഇല്ല]",
+ "echo-error-no-formatter": "അറിയിപ്പിനായി യാതൊരു രൂപവും നിർവ്വചിച്ചിട്ടില്ല",
+ "echo-error-preference": "പിഴവ്: ഉപയോക്താവിന്റെ ക്രമീകരണങ്ങൾ സജ്ജീകരിക്കാൻ കഴിഞ്ഞില്ല",
+ "echo-error-token": "പിഴവ്: ഉപയോക്താവിന്റെ ചീട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല",
+ "notifications": "അറിയിപ്പുകൾ",
+ "tooltip-pt-notifications": "താങ്കൾക്കുള്ള അറിയിപ്പുകൾ",
+ "echo-specialpage": "അറിയിപ്പുകൾ",
+ "echo-anon": "അറിയിപ്പുകൾ ലഭിക്കാനായി, [$1 അംഗത്വമെടുക്കയോ] [$2 പ്രവേശിക്കുകയോ] ചെയ്യേണ്ടതാണ്.",
+ "echo-none": "താങ്കൾക്ക് അറിയിപ്പുകളൊന്നുമില്ല.",
+ "echo-more-info": "കൂടുതൽ വിവരങ്ങൾ",
+ "echo-feedback": "പ്രതികരണം",
+ "notification-link-text-view-message": "സന്ദേശം കാണുക",
+ "notification-link-text-view-mention": "പരാമർശിച്ചിരിക്കുന്നത് കാണുക",
+ "notification-link-text-view-changes": "മാറ്റങ്ങൾ കാണുക",
+ "notification-link-text-view-page": "താൾ കാണുക",
+ "notification-link-text-view-edit": "തിരുത്ത് കാണുക",
+ "notification-edit-talk-page2": "താങ്കളുടെ [[User talk:$2#$3|സംവാദത്താളിൽ]] [[User:$1|$1]] ഒരു സന്ദേശം {{GENDER:$1|ചേർത്തിരിക്കുന്നു}} .",
+ "notification-edit-talk-page-with-section": "താങ്കളുടെ സംവാദത്താളിൽ ''[[User talk:$2#$3|$4]]'' എന്ന് [[User:$1|$1]] ഒരു സന്ദേശം {{GENDER:$1|ചേർത്തിരിക്കുന്നു}}.",
+ "notification-edit-talk-page-flyout2": "താങ്കളുടെ [[User talk:$2#$3|സംവാദത്താളിൽ]] $1 ഒരു സന്ദേശം {{GENDER:$1|ചേർത്തിരിക്കുന്നു}}.",
+ "notification-edit-talk-page-flyout-with-section": "താങ്കളുടെ സംവാദത്താളിൽ ''[[User talk:$2#$3|$4]]'' എന്ന് ഒരു സന്ദേശം $1 {{GENDER:$1|ചേർത്തിരിക്കുന്നു}}.",
+ "notification-page-linked": "[[:$2]] എന്ന താളിലേയ്ക്ക് [[:$3]] എന്ന താളിൽ നിന്ന് കണ്ണി {{GENDER:$1|ചേർക്കപ്പെട്ടിരിക്കുന്നു}}: [[Special:WhatLinksHere/$2|ഈ താളിലേയ്ക്കുള്ള എല്ലാ കണ്ണികളും കാണുക]]",
+ "notification-page-linked-flyout": "[[:$2]] എന്ന താളിലേയ്ക്ക് [[:$3]] എന്ന താളിൽ നിന്ന് കണ്ണി {{GENDER:$1|ചേർക്കപ്പെട്ടിരിക്കുന്നു}}.",
+ "notification-add-comment2": "[[User:$1|$1]] \"$4\" സംവാദത്താളിലെ \"[[$3|$2]]\" എന്നതിൽ {{GENDER:$1|കുറിപ്പിട്ടിരിക്കുന്നു}}",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] [[$3]] എന്ന താളിലെ \"$2\" എന്നതിൽ ഒരു പുതിയ വിഷയം {{GENDER:$1|ചേർത്തു}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] താങ്കൾക്ക് ഒരു സന്ദേശം {{GENDER:$1|അയച്ചിട്ടുണ്ട്}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] താങ്കളുടെ സംവാദത്താളിലെ \"[[$3#$2|$2]]\" എന്നതിൽ {{GENDER:$1|കുറിപ്പിട്ടു}}",
+ "notification-mention": "[[User:$1|$1]] താങ്കളെ $5 എന്ന സംവാദത്താളിൽ \"[[:$3#$2|$4]]\" എന്ന് {{GENDER:$1|പരാമർശിച്ചിരിക്കുന്നു}}.",
+ "notification-mention-flyout": "$1 എന്ന ഉപയോക്താവ് താങ്കളെ $5 എന്ന സംവാദത്താളിലെ \"[[:$3#$2|$4]]\" എന്ന ഭാഗത്ത് {{GENDER:$1|പരാമർശിച്ചിരിക്കുന്നു}}.",
+ "notification-mention-nosection": "[[:$3|$2 സംവാദത്താളിൽ]] താങ്കളെ [[User:$1|$1]] {{GENDER:$1|പരാമർശിച്ചിരിക്കുന്നു}}.",
+ "notification-mention-nosection-flyout": "[[:$3|$2 സംവാദത്താളിൽ]] താങ്കളെ $1 {{GENDER:$1|പരാമർശിച്ചിരിക്കുന്നു}}.",
+ "notification-user-rights": "താങ്കളുടെ ഉപയോക്തൃ അവകാശങ്ങൾ [[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|മാറ്റിയിരിക്കുന്നു}}]]. $2 . [[Special:ListGroupRights|കൂടുതലറിയുക]]",
+ "notification-user-rights-flyout": "താങ്കളുടെ ഉപയോക്തൃ അവകാശങ്ങൾ $1 {{GENDER:$1|മാറ്റിയിരിക്കുന്നു}}. $2 . [[Special:ListGroupRights|കൂടുതലറിയുക]]",
+ "notification-user-rights-add": "താങ്കളിപ്പോൾ {{PLURAL:$2|ഈ സംഘത്തിൽ|ഈ സംഘങ്ങളിൽ}} അംഗമാണ്: $1",
+ "notification-user-rights-remove": "താങ്കളിപ്പോൾ {{PLURAL:$2|ഈ സംഘത്തിൽ|ഈ സംഘങ്ങളിൽ}} അംഗമല്ല: $1",
+ "notification-new-user": "{{SITENAME}} സംരംഭത്തിലേയ്ക്ക് സ്വാഗതം, $1! താങ്കളിവിടെ എത്തിയതിൽ സന്തോഷമുണ്ട്.",
+ "notification-reverted2": "[[:$2]] എന്ന താളിൽ, താങ്കൾ ചെയ്ത {{PLURAL:$4|തിരുത്ത്|തിരുത്തുകൾ}} [[User:$1|$1]] {{GENDER:$1|മുൻപ്രാപനം ചെയ്തിരിക്കുന്നു}}. $3",
+ "notification-reverted-flyout2": "$2 എന്ന താളിൽ, താങ്കൾ ചെയ്ത {{PLURAL:$4|തിരുത്ത്|തിരുത്തുകൾ}} $1 {{GENDER:$1|മുൻപ്രാപനം ചെയ്തിരിക്കുന്നു}}. $3",
+ "notification-edit-talk-page-email-subject2": "{{SITENAME}} സംരംഭത്തിൽ, താങ്കൾക്കൊരു സന്ദേശം $1 {{GENDER:$1|ചേർത്തിട്ടുണ്ട്}}",
+ "notification-edit-talk-page-email-batch-body2": "താങ്കളുടെ സംവാദത്താളിൽ, ഒരു സന്ദേശം $1 {{GENDER:$1|ചേർത്തിട്ടുണ്ട്}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "താങ്കളുടെ സംവാദത്താളിൽ, \"$2\" എന്നതിൽ ഒരു സന്ദേശം $1 {{GENDER:$1|ചേർത്തിട്ടുണ്ട്}}.",
+ "notification-page-linked-email-subject": "താങ്കളുടെ താൾ {{SITENAME}} സംരംഭത്തിൽ കണ്ണിചേർക്കപ്പെട്ടിരിക്കുന്നു",
+ "notification-page-linked-email-batch-body": "$2 എന്ന താളിലേയ്ക്ക് $3 എന്ന താളിൽ നിന്ന് കണ്ണി {{GENDER:$1|ചേർക്കപ്പെട്ടിരിക്കുന്നു}}",
+ "notification-reverted-email-subject2": "{{SITENAME}} സംരംഭത്തിൽ താങ്കൾ വരുത്തിയ {{PLURAL:$3|തിരുത്ത്|തിരുത്തുകൾ}} {{GENDER:$1|മുൻപ്രാപനം ചെയ്തിരിക്കുന്നു}}",
+ "notification-reverted-email-batch-body2": "താങ്കൾ വരുത്തിയ {{PLURAL:$3|$2 താളിലെ തിരുത്ത്|$2 താളിലെ തിരുത്തുകൾ}} $1 {{GENDER:$1|മുൻപ്രാപനം ചെയ്തിരിക്കുന്നു}}",
+ "notification-mention-email-subject": "$1 താങ്കളെ {{SITENAME}} സംരംഭത്തിൽ {{GENDER:$1|പരാമർശിച്ചിരിക്കുന്നു}}",
+ "notification-mention-email-batch-body": "$1 താങ്കളെ $4 സംവാദത്താളിൽ \"$3\" എന്നതിൽ {{GENDER:$1|പരാമർശിച്ചിരിക്കുന്നു}}.",
+ "notification-mention-nosection-email-batch-body": "$2 സംവാദത്താളിൽ താങ്കളെ $1 {{GENDER:$1|പരാമർശിച്ചിരിക്കുന്നു}}.",
+ "notification-user-rights-email-subject": "{{SITENAME}} സംരംഭത്തിൽ താങ്കളുടെ അവകാശങ്ങളിൽ മാറ്റമുണ്ടായിരിക്കുന്നു",
+ "notification-user-rights-email-batch-body": "താങ്കളുടെ ഉപയോക്തൃ അവകാശങ്ങൾ $1 {{GENDER:$1|മാറ്റിയിരിക്കുന്നു}}. $2",
+ "echo-email-subject-default": "{{SITENAME}} സംരംഭത്തിൽ അറിയിപ്പുണ്ട്",
+ "echo-email-body-default": "{{SITENAME}} സംരംഭത്തിൽ താങ്കൾക്ക് ഒരു അറിയിപ്പുണ്ട്:\n\n$1",
+ "echo-email-batch-body-default": "താങ്കൾക്ക് ഒരറിയിപ്പുണ്ട്",
+ "echo-email-footer-default": "$2\n\nഞങ്ങൾ താങ്കൾക്കയയ്ക്കുന്ന ഇമെയിലുകൾ നിയന്ത്രിക്കാൻ, താങ്കളുടെ ക്രമീകരണങ്ങൾ ഉപയോഗിക്കുക: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "ഞങ്ങൾ താങ്കൾക്കയയ്ക്കുന്ന ഇമെയിലുകൾ നിയന്ത്രിക്കാൻ, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">താങ്കളുടെ ക്രമീകരണങ്ങൾ പരിശോധിക്കുക</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|അറിയിപ്പ് ($1)|അറിയിപ്പുകൾ ($1)|100=അറിയിപ്പുകൾ (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|സന്ദേശം ($1)|സന്ദേശങ്ങൾ ($1)|100=സന്ദേശങ്ങൾ (99+)}}",
+ "echo-notification-alert-text-only": "അറിയിപ്പുകൾ",
+ "echo-notification-message-text-only": "സന്ദേശങ്ങൾ",
+ "echo-overlay-link": "എല്ലാ അറിയിപ്പുകളും",
+ "echo-overlay-title": "<b>അറിയിപ്പുകൾ</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|അറിയിപ്പുകൾ}}</b> (വായിക്കാത്ത $2 എണ്ണത്തിലെ $1 എണ്ണം കാണിക്കുന്നു)",
+ "echo-mark-all-as-read": "എല്ലാം വായിച്ചതായി അടയാളപ്പെടുത്തുക",
+ "echo-date-today": "ഇന്ന്",
+ "echo-date-yesterday": "ഇന്നലെ",
+ "echo-load-more-error": "കൂടുതൽ ഫലങ്ങൾ എടുക്കുന്നതിനിടെ ഒരു പിഴവുണ്ടായി.",
+ "notification-edit-talk-page-bundle": "$1 എന്നയാൾക്കുപുറമേ {{PLURAL:$4|മറ്റൊരാളും|മറ്റ് $3 പേരും}} താങ്കളുടെ [[User talk:$2|സംവാദത്താളിൽ]] സന്ദേശം {{GENDER:$1|ചേർത്തിരിക്കുന്നു}}.",
+ "notification-page-linked-bundle": "$2 എന്ന താളിലേയ്ക്ക് $3 എന്ന താളിൽ നിന്നും മറ്റ് $4 {{PLURAL:$5|താളിൽ|താളുകളിൽ}} നിന്നും കണ്ണി {{GENDER:$1|ചേർക്കപ്പെട്ടിരിക്കുന്നു}}. [[Special:WhatLinksHere/$2|ഈ താളിലേയ്ക്കുള്ള എല്ലാ കണ്ണികളും കാണുക]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 എന്ന ഉപയോക്താവും ഒപ്പം {{PLURAL:$3|മറ്റൊരു ഉപയോക്താവും|$2 മറ്റുപയോക്താക്കളും}} താങ്കളുടെ സം‌വാദത്താളിൽ സന്ദേശം {{GENDER:$1|ചേർത്തിരിക്കുന്നു}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2 എന്ന താളിലേയ്ക്ക് $3 എന്ന താളിൽ നിന്നും മറ്റ് $4 {{PLURAL:$5|താളിൽ|താളുകളിൽ}} നിന്നും {{GENDER:$1|കണ്ണി ചേർക്കപ്പെട്ടിരിക്കുന്നു}}.",
+ "echo-email-batch-subject-daily": "താങ്കൾക്ക് {{SITENAME}} സംരംഭത്തിൽ {{PLURAL:$2|ഒരു പുതിയ അറിയിപ്പ്|പുതിയ അറിയിപ്പുകൾ}} ഉണ്ട്",
+ "echo-email-batch-subject-weekly": "താങ്കൾക്ക് ഈ ആഴ്ച, {{SITENAME}} സംരംഭത്തിൽ {{PLURAL:$2|പുതിയ ഒരറിയിപ്പ്|പുതിയ അറിയിപ്പുകൾ}} ഉണ്ട്",
+ "echo-email-batch-body-intro-daily": "പ്രിയ $1,\n{{SITENAME}} സംരംഭത്തിൽ, താങ്കളെ ബാധിക്കുന്ന ഇന്നത്തെ പ്രവർത്തനങ്ങളുടെ സംഗ്രഹം ഇതാ.",
+ "echo-email-batch-body-intro-weekly": "പ്രിയ $1,\n{{SITENAME}} സംരംഭത്തിൽ, താങ്കളെ ബാധിക്കുന്ന ഈ ആഴ്ചയിലെ പ്രവർത്തനങ്ങളുടെ സംഗ്രഹം ഇതാ.",
+ "echo-email-batch-link-text-view-all-notifications": "എല്ലാ അറിയിപ്പുകളും കാണുക",
+ "echo-rev-deleted-text-view": "താളിന്റെ ഈ നാൾപ്പതിപ്പ് ഒതുക്കിയിരിക്കുന്നു.",
+ "apihelp-echomarkread-description": "ഇപ്പോഴത്തെ ഉപയോക്താവിന്റെ അറിയിപ്പുകൾ വായിച്ചതായി അടയാളപ്പെടുത്തുക.",
+ "apihelp-echomarkread-param-list": "വായിച്ചതായി അടയാളപ്പെടുത്തേണ്ട അറിയിപ്പ് ഐ.ഡി.കളുടെ പട്ടിക.",
+ "apihelp-echomarkread-param-all": "സജ്ജമെങ്കിൽ ഉപയോക്താവിനുള്ള അറിയിപ്പുകളെല്ലാം വായിച്ചതായി അടയാളപ്പെടുത്തുക.",
+ "apihelp-echomarkread-param-sections": "വായിച്ചതായി അടയാളപ്പെടുത്തേണ്ട ഭാഗങ്ങളുടെ പട്ടിക.",
+ "apihelp-echomarkread-example-1": "അറിയിപ്പ് 8 വായിച്ചതായി അടയാളപ്പെടുത്തുക",
+ "apihelp-echomarkread-example-2": "എല്ലാ അറിയിപ്പുകളും വായിച്ചതായി അടയാളപ്പെടുത്തുക",
+ "apihelp-query+notifications-description": "ഇപ്പോഴത്തെ ഉപയോക്താവിനായി കാത്തുനിൽക്കുന്ന അറിയിപ്പുകൾ ലഭ്യമാക്കുക.",
+ "apihelp-query+notifications-param-prop": "അഭ്യർത്ഥനയുടെ വിശദാംശങ്ങൾ.",
+ "apihelp-query+notifications-param-sections": "ചോദിക്കേണ്ട അറിയിപ്പ് ഭാഗങ്ങൾ.",
+ "apihelp-query+notifications-param-groupbysection": "ഫലങ്ങൾ വിഭാഗമനുസരിച്ച് വർഗ്ഗീകരിക്കണോ. സജ്ജമെങ്കിൽ ഓരോ ഭാഗവും വ്യത്യസ്തമായിട്ടാവും എടുക്കുക.",
+ "apihelp-query+notifications-param-format": "വ്യക്തമാക്കിയിട്ടുണ്ടെങ്കിൽ, അറിയിപ്പുകൾ ഇതുവഴിയായിരിക്കും വിന്യസികുക.",
+ "apihelp-query+notifications-param-limit": "എടുക്കേണ്ട അറിയിപ്പുകളുടെ പരമാവധി എണ്ണം.",
+ "apihelp-query+notifications-param-index": "വ്യക്തമാക്കിയിട്ടുണ്ടെങ്കിൽ, അറിയിപ്പ് ഐ.ഡി.കളുടെ ഒരു പട്ടിക, ക്രമാനുസരണം, നൽകപ്പെടും.",
+ "apihelp-query+notifications-param-alertcontinue": "അധികം അറിയിപ്പ് ഫലങ്ങൾ ലഭ്യമായിരിക്കുമ്പോൾ, തുടരാൻ ഇതുപയോഗിക്കുക.",
+ "apihelp-query+notifications-param-alertunreadfirst": "വായിക്കാത്ത സന്ദേശ അറിയിപ്പുകൾ ആദ്യം പ്രദർശിപ്പിക്കണോ.",
+ "apihelp-query+notifications-param-messagecontinue": "അധികം സന്ദേശ ഫലങ്ങൾ ലഭ്യമായിരിക്കുമ്പോൾ, തുടരാൻ ഇതുപയോഗിക്കുക.",
+ "apihelp-query+notifications-param-messageunreadfirst": "വായിക്കാത്ത വിവരദായക അറിയിപ്പുകൾ ആദ്യം പ്രദർശിപ്പിക്കണോ.",
+ "apihelp-query+notifications-example-1": "അറിയിപ്പുകൾ പട്ടികയാക്കുക",
+ "apihelp-query+notifications-example-2": "അറിയിപ്പുകൾ വിഭാഗമനുസരിച്ച് എണ്ണം നൽകി വർഗ്ഗീകരിച്ച് പട്ടികയാക്കുക"
+}
diff --git a/Echo/i18n/mn.json b/Echo/i18n/mn.json
new file mode 100644
index 00000000..d1eef177
--- /dev/null
+++ b/Echo/i18n/mn.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Wisdom"
+ ]
+ },
+ "echo-notification-alert": "{{PLURAL:$1|Сануулга ($1)|Сануулга ($1)|100=Сануулга (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Мэдээ ($1)|Мэдээ ($1)|100=Мэдээ (99+)}}"
+}
diff --git a/Echo/i18n/mr.json b/Echo/i18n/mr.json
new file mode 100644
index 00000000..501581c3
--- /dev/null
+++ b/Echo/i18n/mr.json
@@ -0,0 +1,113 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Nikhil.kawale",
+ "Niraj Suryawanshi",
+ "Prabodh1987",
+ "Sankoswal",
+ "V.narsikar",
+ "संतोष दहिवळ"
+ ]
+ },
+ "echo-desc": "अधिसूचना प्रणाली",
+ "prefs-echo": "अधिसूचना",
+ "prefs-emailsettings": "विपत्र ऐच्छिके",
+ "prefs-displaynotifications": "प्रदर्शित करण्याचे पर्याय",
+ "prefs-echosubscriptions": "ह्या उपक्रमाबद्दल कळवावे",
+ "prefs-newmessageindicator": "नवीन संदेश निर्देशक",
+ "echo-pref-send-me": "मला पाठवा:",
+ "echo-pref-send-to": "ला पाठवा:",
+ "echo-pref-email-format": "विपत्र प्रारुप:",
+ "echo-pref-web": "वेब",
+ "echo-pref-email": "ई-मेल",
+ "echo-pref-email-frequency-never": "ईमेलद्वारे मला अधिसूचना पाठविण्यात येऊ नये",
+ "echo-pref-email-frequency-immediately": "वैयक्तीक अधिसूचना त्या जश्या प्राप्त होतील तेंव्हा",
+ "echo-pref-email-frequency-daily": "अधिसूचनांचा दैनिक सारांश",
+ "echo-pref-email-frequency-weekly": "अधिसूचनांचा साप्ताहिक सारांश",
+ "echo-pref-email-format-html": "एचटीएमएल",
+ "echo-pref-email-format-plain-text": "साधा मजकूर",
+ "echo-pref-notify-show-link": "माझ्या साधनपेटीत अधिसूचना दाखवा",
+ "echo-pref-new-message-indicator": "चर्चापान संदेश दर्शक माझ्या साधनपेटीत दाखवा",
+ "echo-learn-more": "अधिक जाणून घ्या",
+ "echo-new-messages": "तुमच्यासाठी नवीन संदेश आहेत",
+ "echo-category-title-edit-user-talk": "चर्चा पान {{PLURAL:$1|संदेश}}",
+ "echo-category-title-article-linked": "पान {{PLURAL:$1|दुवा|दुवे}}",
+ "echo-category-title-reverted": "संपादन {{PLURAL:$1|उलटवा}}",
+ "echo-category-title-mention": "{{PLURAL:$1|उल्लेख}}",
+ "echo-category-title-other": "{{PLURAL:$1|इतर}}",
+ "echo-category-title-system": "{{PLURAL:$1|प्रणाली}}",
+ "echo-pref-tooltip-edit-user-talk": "माझ्या चर्चापानावर कोणी संदेश किंवा उत्तर टाकल्यास मला कळवा.",
+ "echo-pref-tooltip-article-linked": "मी तयार केलेल्या लेख पानाचा दुवा कोणी दुसरऱ्या लेख पानात दिल्यास मला कळवा.",
+ "echo-pref-tooltip-reverted": "मी केलेले संपादन जर कोणी 'रद्द करा' किंवा रोलबॅक साधन वापरून उलटवित असेल तर मला कळवा.",
+ "echo-pref-tooltip-mention": "माझ्या सदस्यपानाचा दुवा जर कोणी इतर कुठल्याही चर्चापानात दिल्यास मला कळवा.",
+ "echo-no-agent": "[कोणीच नाही]",
+ "echo-no-title": "[कोणतेच पान नाही]",
+ "echo-error-no-formatter": "अधिसूचनेसाठी कोणतेच प्रारुपण निश्चित नाही.",
+ "echo-error-preference": "त्रूटी: सदस्य पसंतीक्रम स्थापता आला नाही.",
+ "echo-error-token": "त्रूटी:सदस्य बिल्ला शोधू शकलो नाही.",
+ "notifications": "अधिसूचना",
+ "tooltip-pt-notifications": "आपल्या अधिसूचना",
+ "echo-specialpage": "अधिसूचना",
+ "echo-anon": "अधिसूचना मिळण्यास, [$1 create an account] किंवा [$2 log in].",
+ "echo-none": "आपल्यासाठी काहीच अधिसूचना नाहीत.",
+ "echo-more-info": "अधिक माहिती",
+ "echo-feedback": "प्रतिक्रिया",
+ "notification-link-text-view-message": "संदेश बघा",
+ "notification-link-text-view-mention": "उल्लेख बघा",
+ "notification-link-text-view-changes": "बदल बघा",
+ "notification-link-text-view-page": "पान बघा",
+ "notification-link-text-view-edit": "संपादन बघा",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|ने}} आपल्या [[User talk:$2#$3|चर्चा पानावर]] संदेश टाकला.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|ने}} एक संदेश आपल्या चर्चा पानावर \"[[User talk:$2#$3|$4]]\" या मथळ्याखाली टाकला.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|ने}} आपल्या [[User talk:$2#$3|चर्चा पानावर]] एक संदेश टाकला.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|ने}} ''[[User talk:$2#$3|$4]]'' या मथळ्याखाली आपल्या चर्चा पानावर एक संदेश टाकला.",
+ "notification-page-linked": "[[:$2]] ला [[:$3]] वरून {{GENDER:$1|दुवा दिल्या गेला}}. [[Special:WhatLinksHere/$2|या पानाचे सर्व दुवे बघा]].",
+ "notification-page-linked-flyout": "[[:$2]] ला [[:$3]] वरुन {{GENDER:$1|दुवा दिल्या गेला}}.",
+ "notification-add-comment2": "[[User:$1|$1]] ने \"[[$3|$2]]\" वर, \"$4\" चर्चा पानावर{{GENDER:$1|शेरा टाकला}}.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] ने [[$3]]वर नविन विषय \"$2\" {{GENDER:$1|टाकला}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]]ने आपणास एक संदेश {{GENDER:$1|पाठविला}}:\"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]]ने \"[[$3#$2|$2]]\" बाबत आपल्या चर्चापानावर {{GENDER:$1|शेरा टाकला}}.",
+ "notification-mention": "[[User:$1|$1]]ने \"[[:$3#$2|$4]]\" मध्ये $5 चर्चापानावर आपला {{GENDER:$1|उल्लेख केला}}.",
+ "notification-mention-flyout": "$1 ने \"[[:$3#$2|$4]]\" मध्ये $5 चर्चापानावर आपला {{GENDER:$1|उल्लेख केला}}",
+ "notification-user-rights": "आपले सदस्य अधिकार [[User:$1|$1]]द्वारा [[Special:Log/rights/$1| {{GENDER:$1|बदलविण्यात आले}}]]. $2. [[Special:ListGroupRights|अधिक माहिती घ्या]]",
+ "notification-user-rights-flyout": "आपले सदस्य अधिकार $1 द्वारा {{GENDER:$1|बदलविण्यात आले}}.$2. [[Special:ListGroupRights|अधिक माहिती घ्या]]",
+ "notification-user-rights-add": "आपण आता {{PLURAL:$2|या गटाचे|या गटांचे}} सदस्य आहात:$1",
+ "notification-user-rights-remove": "आपण यापुढे {{PLURAL:$2|या गटाचे|या गटांचे}} सदस्य नाहीत:\n$1",
+ "notification-new-user": "$1! या {{SITENAME}}वर आपले स्वागत. आपण येथे आल्यामुळे आम्हास आनंद झाला.",
+ "notification-reverted2": "आपले/ली{{PLURAL:$4|संपादन [[:$2]]वर|संपादने [[:$2]]वर}} [[User:$1|$1]]ने {{GENDER:$1|उलटवली}}. $3",
+ "notification-reverted-flyout2": "आपले/ली {{PLURAL:$4|$2वरील संपादन|$2वरील संपादने}} $1ने {{GENDER:$1|उलटविलीत}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 ने {{SITENAME}}वर आपल्यासाठी एक संदेश {{GENDER:$1|टाकला}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 ने आपल्या चर्चा पानावर एक संदेश {{GENDER:$1|टाकला}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 ने \"$2\" मधील आपल्या चर्चा पानावर एक संदेश {{GENDER:$1|टाकला}}.",
+ "notification-page-linked-email-subject": "{{SITENAME}}वर आपले पान जोडल्या गेले आहे",
+ "notification-page-linked-email-batch-body": "$2 ला $3शी {{GENDER:$1|दुव्याने जोडण्यात आले आहे}}.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|आपले {{SITENAME}} वरील संपादन {{GENDER:$1|उलटविले गेले}}|आपली {{SITENAME}} वरील संपादने {{GENDER:$1|उलटवविली गेली}}}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|आपले $2 वरील संपादन|आपली $2 वरील संपादने}} $1 ने {{GENDER:$1|उलटविली}}.",
+ "notification-mention-email-subject": "$1 ने आपला {{SITENAME}} वर {{GENDER:$1|उल्लेख केला}}",
+ "notification-mention-email-batch-body": "$1 ने आपला \"$3\" मध्ये $4 चर्चापानावर {{GENDER:$1|उल्लेख केला}}.",
+ "notification-user-rights-email-subject": "{{SITENAME}} वर आपले सदस्य अधिकार बदलले आहेत",
+ "notification-user-rights-email-batch-body": "$1द्वारा आपले सदस्य अधिकार {{GENDER:$1|बदलविल्या गेलेत}}. $2.",
+ "echo-email-subject-default": "{{SITENAME}} वर एक नविन अधिसूचना",
+ "echo-email-body-default": "{{SITENAME}}वर आपणासाठी एक नविन अधिसूचना आहे:\n\n$1",
+ "echo-email-batch-body-default": "आपणासाठी एक नविन अधिसूचना आहे.",
+ "echo-email-footer-default": "$2\n\nआम्ही आपणास पाठविण्याच्या विपत्रांवर नियंत्रणासाठी, आपला पसंतीक्रम तपासा:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "आम्ही आपणास पाठविलेल्या विपत्रांवर नियंत्रणासाठी, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">आपला पसंतीक्रम तपासा</a>.<br />\n$1",
+ "echo-overlay-link": "सर्व अधिसूचना",
+ "echo-overlay-title": "<b>अधिसूचना</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|अधिसूचना}}</b> ($2 पैकी $1 न वाचलेल्या)",
+ "echo-mark-all-as-read": "वाचले म्हणून खूण करा",
+ "echo-date-today": "आज",
+ "echo-date-yesterday": "काल",
+ "echo-load-more-error": "अधिक निकाल देण्यापोटी एक त्रूटी घडली.",
+ "notification-edit-talk-page-bundle": "$1 व $3 {{PLURAL:$4|इतरानी|इतरांनी}} आपल्या [[User talk:$2|चर्चा पानावर]] एक संदेश {{GENDER:$1|टाकला}}.",
+ "notification-page-linked-bundle": "$2 हे पान $3 व $4 यापासून, इतर {{PLURAL:$5|पानाशी|पानांशी}}{{GENDER:$1|जोडल्या गेले}}. [[Special:WhatLinksHere/$2|या पानाशी जोडलेले सर्व दुवे बघा]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 व $2 {{PLURAL:$3|इतरानी|इतरांनी}} आपल्या चर्चा पानावर एक संदेश {{GENDER:$1|टाकला}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2ला $3शी व $4 इतर {{PLURAL:$5|पानाशी|पानांशी}} {{GENDER:$1|दुव्याने जोडल्या गेले}}.",
+ "echo-email-batch-subject-daily": "आपल्यासाठी {{SITENAME}}वर {{PLURAL:$2|एक नविन अधिसूचना आहे|नविन अधिसूचना आहेत}}",
+ "echo-email-batch-subject-weekly": "आपल्यासाठी या आठवड्यात {{SITENAME}}वर {{PLURAL:$2|एक नविन अधिसूचना आहे|नविन अधिसूचना आहेत}}",
+ "echo-email-batch-body-intro-daily": "नमस्कार $1,\nआपण {{SITENAME}}वर केलेल्या आजच्या क्रियाकलापांचा सारांश येथे आहे.",
+ "echo-email-batch-body-intro-weekly": "नमस्कार $1,\nआपण {{SITENAME}}वर केलेल्या या आठवड्याच्या क्रियाकलापांचा सारांश येथे आहे.",
+ "echo-email-batch-link-text-view-all-notifications": "सर्व अधिसूचना पहा",
+ "echo-rev-deleted-text-view": "या पानाची आवृत्ती दाबण्यात आलेली आहे."
+}
diff --git a/Echo/i18n/ms.json b/Echo/i18n/ms.json
new file mode 100644
index 00000000..f7697c1c
--- /dev/null
+++ b/Echo/i18n/ms.json
@@ -0,0 +1,114 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia",
+ "Pizza1016",
+ "Aviator"
+ ]
+ },
+ "echo-desc": "Sistem pemberitahuan",
+ "prefs-echo": "Pemberitahuan",
+ "prefs-emailsettings": "Pilihan e-mel",
+ "prefs-displaynotifications": "Pilihan paparan",
+ "prefs-echosubscriptions": "Beritahu saya tentang peristiwa-peristiwa ini",
+ "prefs-newmessageindicator": "Indikator pesanan baru",
+ "echo-pref-send-me": "Hantarkan saya:",
+ "echo-pref-send-to": "Hantar ke:",
+ "echo-pref-email-format": "Format e-mel:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mel",
+ "echo-pref-email-frequency-never": "Jangan hantar sebarang pemberitahuan e-mel kepada saya",
+ "echo-pref-email-frequency-immediately": "Pemberitahuan satu persatu",
+ "echo-pref-email-frequency-daily": "Ringkasan pemberitahuan harian",
+ "echo-pref-email-frequency-weekly": "Ringkasan pemberitahuan mingguan",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Teks biasa",
+ "echo-pref-notify-show-link": "Paparkan pemberitahuan di palang alat saya",
+ "echo-pref-new-message-indicator": "Paparkan indikator pesanan dari halaman perbincangan pada palang alat saya",
+ "echo-learn-more": "Ketahui lebih lanjut",
+ "echo-new-messages": "Anda mempunyai pesanan baru",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Pesanan|Pesanan-pesanan}} laman perbincangan",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Pautan}} halaman",
+ "echo-category-title-reverted": "{{PLURAL:$1|Pembalikan}} suntingan",
+ "echo-category-title-mention": "{{PLURAL:$1|Sebutan}}",
+ "echo-category-title-other": "{{PLURAL:$1|Lain-lain}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Perubahan hak pengguna|Perubahan-perubahan hak pengguna}}",
+ "echo-pref-tooltip-edit-user-talk": "Beritahu saya apabila seseorang mengirim pesanan atau membalas di laman perbincangan saya.",
+ "echo-pref-tooltip-article-linked": "Beritahu saya apabila seseorang membuat pautan ke suatu halaman yang pernah saya wujudkan dari halaman rencana.",
+ "echo-pref-tooltip-reverted": "Beritahu saya apabila seseorang mengundurkan suntingan saya dengan menggunakan alat 'batalkan' atau 'undur'.",
+ "echo-pref-tooltip-mention": "Beritahu saya apaila seseorang membuat pautan ke laman pengguna saya.",
+ "echo-pref-tooltip-user-rights": "Beritahu saya apabila seseorang mengubah hak-hak pengguna saya.",
+ "echo-no-agent": "[Tiada Sesiapa]",
+ "echo-no-title": "[Tiada laman]",
+ "echo-error-no-formatter": "Tiada pemformatan ditetap untuk pemberitahuan.",
+ "echo-error-preference": "Ralat: Keutamaan pengguna tidak boleh ditetapkan.",
+ "echo-error-token": "Ralat: Token pengguna tidak dapat didapati.",
+ "notifications": "Pemberitahuan",
+ "tooltip-pt-notifications": "Pemberitahuan anda",
+ "echo-specialpage": "Pemberitahuan",
+ "echo-anon": "Untuk menerima pemberitahuan, sila [$1 buka akaun] atau [$2 log masuk].",
+ "echo-none": "Tiada pemberitahuan untuk anda.",
+ "echo-more-info": "Maklumat lanjut",
+ "echo-feedback": "Maklum balas",
+ "notification-link-text-view-message": "Lihat pesanan",
+ "notification-link-text-view-mention": "Lihat sebutan",
+ "notification-link-text-view-changes": "Lihat perubahan",
+ "notification-link-text-view-page": "Lihat laman",
+ "notification-link-text-view-edit": "Lihat suntingan",
+ "notification-edit-talk-page2": "[[User:$1|$1]] telah {{GENDER:$1|meninggalkan}} sebuah pesanan pada [[User talk:$2#$3|laman perbincangan]] anda.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] telah {{GENDER:$1|meninggalkan}} sebuah pesanan pada laman perbincangan anda di \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 telah {{GENDER:$1|meninggalkan}} sebuah pesanan pada [[User talk:$2#$3|laman perbincangan]] anda.",
+ "notification-edit-talk-page-flyout-with-section": "$1 telah {{GENDER:$1|meninggalkan}} sebuah pesanan pada laman perbincangan anda di \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] telah {{GENDER:$1|dipautkan}} dari [[:$3]]. [[Special:WhatLinksHere/$2|Lihat semua pautan ke halaman ini]].",
+ "notification-page-linked-flyout": "[[:$2]] telah {{GENDER:$1|dipautkan}} dari [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] telah {{GENDER:$1|mengulas}} tentang \"[[$3|$2]]\" pada laman perbincangan \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] telah mengepos topik baru, \"$2\", di [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] telah {{GENDER:$1|mengirim}} pesanan kepada anda: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] telah {{GENDER:$1|mengulas}} tentang \"[[$3#$2|$2]]\" pada laman perbincangan anda.",
+ "notification-mention": "[[User:$1|$1]] telah {{GENDER:$1|menyebut}} anda pada laman perbincangan $5 di \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 telah {{GENDER:$1|menyebut}} anda di laman perbincangan $5 di [[:$3#$2|$4]].",
+ "notification-user-rights": "Hak-hak pengguna anda telah [[Special:Log/rights/$1|{{GENDER:$1|diubah}}]] oleh [[User:$1|$1]]. $2. [[Special:ListGroupRights|Ketahui lebih lanjut]]",
+ "notification-user-rights-flyout": "Hak-hak pengguna anda telah {{GENDER:$1|diubah}} oleh \t$1. $2. [[Special:ListGroupRights|Ketahui lebih lanjut]]",
+ "notification-user-rights-add": "Anda kini menganggotai {{PLURAL:$2|kumpulan|kumpulan-kumpulan ini:}} $1",
+ "notification-user-rights-remove": "Anda tidak lagi menganggotai {{PLURAL:$2|kumpulan|kumpulan-kumpulan ini:}} $1",
+ "notification-new-user": "Selamat datang ke {{SITENAME}}, $1! Dengan sukacita kami menyambut kedatangan anda.",
+ "notification-reverted2": "{{PLURAL:$4|Suntingan|Suntingan-suntingan}} anda di [[:$2]] telah {{GENDER:$1|dibalikkan}} oleh [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Suntingan|Suntingan-suntingan}} anda di $2 telah {{GENDER:$1|dibalikkan}} oleh $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 telah {{GENDER:$1|meninggalkan}} pesanan untuk anda di {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 telah {{GENDER:$1|meninggalkan}} pesanan untuk anda di laman perbincangan anda:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 telah {{GENDER:$1|meninggalkan}} sebuah pesanan pada laman perbincangan anda di \"$2\".",
+ "notification-page-linked-email-subject": "Halaman anda telah dipautkan dengan {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 telah {{GENDER:$1|dipautkan}} dari $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Suntingan|Suntingan-suntingan}} telah {{GENDER:$1|diundurkan}} di {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Suntingan|Suntingan-suntingan}} anda di $2 telah {{GENDER:$1|diundurkan}} oleh $1",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|menyebut}} anda di {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 telah {{GENDER:$1|menyebut}} anda di laman perbincangan $4 di \"$3\".",
+ "notification-user-rights-email-subject": "Hak-hak pengguna anda telah berubah di {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Hak-hak pengguna anda telah {{GENDER:$1|diubah}} oleh $1. $2",
+ "echo-email-subject-default": "Pemberitahuan baru di {{SITENAME}}",
+ "echo-email-body-default": "Anda menerima pemberitahuan baru di {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Anda mempunyai pemberitahuan baru",
+ "echo-email-footer-default": "$2\n\nUntuk mengubah pesanan-pesanan e-mel yang anda hendak kami hantar, semak keutamaan anda:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Untuk mengawal e-mel yang kami hantar kepada anda, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">semak keutamaan anda</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Pesanan ($1)|100=Pesanan (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Pesanan ($1)|Pesanan ($1)|100=Pesanan (99+)}}",
+ "echo-notification-message-text-only": "Pesanan",
+ "echo-overlay-link": "Semua pemberitahuan",
+ "echo-overlay-title": "<b>Pemberitahuan</b>",
+ "echo-overlay-title-overflow": "<b>Pemberitahuan</b> (memaparkan $1 daripada $2 yang belum dibaca)",
+ "echo-mark-all-as-read": "Tanda semua sebagai dibaca",
+ "echo-date-today": "Hari ini",
+ "echo-date-yesterday": "Semalam",
+ "echo-load-more-error": "Ralat berlaku ketika mengambil lebih banyak hasil.",
+ "notification-edit-talk-page-bundle": "$1 dan $3 {{PLURAL:$4|orang lain}} telah {{GENDER:$1|meninggalkan}} sebuah pesanan pada [[User talk:$2|laman perbincangan]] anda.",
+ "notification-page-linked-bundle": "$2 telah {{GENDER:$1|dipautkan}} dari $3 dan $4 {{PLURAL:$5|laman}} yang lain. [[Special:WhatLinksHere/$2|Lihat semua pautan ke laman ini]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 dan $2 {{PLURAL:$3|orang lain}} telah {{GENDER:$1|meninggalkan}} sebuah pesanan pada laman perbincangan anda.",
+ "notification-page-linked-email-batch-bundle-body": "$2 telah {{GENDER:$1|dipautkan}} dari $3 dan $4 {{PLURAL:$5|laman}} lain.",
+ "echo-email-batch-subject-daily": "Anda ada {{PLURAL:$2|satu|beberapa}} pemberitahuan baru di {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Anda ada {{PLURAL:$2|satu|beberapa}} pemberitahuan baru di {{SITENAME}} minggu ini",
+ "echo-email-batch-body-intro-daily": "$1,\nYang berikut adalah ringkasan kegiatan hari ini di {{SITENAME}} untuk rujukan anda",
+ "echo-email-batch-body-intro-weekly": "$1,\nYang berikut adalah ringkasan kegiatan minggu ini di {{SITENAME}} untuk rujukan anda",
+ "echo-email-batch-link-text-view-all-notifications": "Baca semua pemberitahuan",
+ "echo-rev-deleted-text-view": "Semakan halaman ini telah digantung"
+}
diff --git a/Echo/i18n/mt.json b/Echo/i18n/mt.json
new file mode 100644
index 00000000..d44177f7
--- /dev/null
+++ b/Echo/i18n/mt.json
@@ -0,0 +1,110 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Chrisportelli",
+ "Leli Forte",
+ "MTSap"
+ ]
+ },
+ "echo-desc": "Sistema ta' notifika",
+ "prefs-echo": "Notifiki",
+ "prefs-emailsettings": "Għażliet għall-posta elettronika",
+ "prefs-displaynotifications": "Għażla ta' kif trid tara n-notifiki",
+ "prefs-echosubscriptions": "Għarrafni meta jiġru dawn",
+ "prefs-newmessageindicator": "Sinjal ta' messaġġi ġodda",
+ "echo-pref-send-me": "Ibgħatli:",
+ "echo-pref-send-to": "Ibgħat lil:",
+ "echo-pref-email-format": "Format tal-posta elettronika:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Posta elettronika",
+ "echo-pref-email-frequency-never": "Tibgħatli l-ebda notifika bil-posta elettronika",
+ "echo-pref-email-frequency-immediately": "In-notifiki individwali kif jidħlu",
+ "echo-pref-email-frequency-daily": "Sommarju ta' kuljum tan-notifiki",
+ "echo-pref-email-frequency-weekly": "Sommarju ta' kull ġimgħa tan-notifiki",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Test normali",
+ "echo-pref-notify-show-link": "Uri n-notifiki fl-iżbarra tal-għodda",
+ "echo-pref-new-message-indicator": "Uri s-sinjal tal-messaġġi l-ġodda fil-paġna tad-diskussjoni tiegħi fl-iżbarra tal-għodda",
+ "echo-learn-more": "Aktar tagħrif",
+ "echo-new-messages": "Għandek messaġġi ġodda",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Messaġġ|Messaġġi}} fuq il-paġna ta' diskussjoni",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Ħolqa|Ħoloq}} ma' paġna",
+ "echo-category-title-reverted": "{{PLURAL:$1|Modifika annullata|Modifiki annullati}}",
+ "echo-category-title-mention": "Fejn {{PLURAL:$1|issemmejt}}",
+ "echo-category-title-other": "{{PLURAL:$1|Ieħor/Oħra|Oħrajn}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-pref-tooltip-edit-user-talk": "Għarrafni meta xi ħadd jiktibli messaġġ jew iweġibni fuq il-paġna tad-diskussjoni tiegħi.",
+ "echo-pref-tooltip-article-linked": "Għarrafni meta xi ħadd joħloq ħolqa minn artiklu għal xi paġna li ħlaqt jien.",
+ "echo-pref-tooltip-reverted": "Għarrafni meta xi ħadd permezz tal-għodda tal-annullament (undo) jew tat-treġġigħ lura (rollback) jannulla xi modifika li għamilt jien.",
+ "echo-pref-tooltip-mention": "Għarrafni meta xi ħadd joħloq ħolqa minn xi paġna tad-diskussjoni għall-paġna tal-utent tiegħi.",
+ "echo-no-agent": "[Ħadd]",
+ "echo-no-title": "[L-ebda paġna]",
+ "echo-error-no-formatter": "L-ebda formattazzjoni definita għan-notifiki",
+ "echo-error-preference": "Żball: Il-preferenzi tal-utent ma setgħux jiġu ssettjati.",
+ "echo-error-token": "Żball: It-token tal-utent ma setax jiġi rkuprat.",
+ "notifications": "Notifiki",
+ "tooltip-pt-notifications": "In-notifiki tiegħek",
+ "echo-specialpage": "Notifiki",
+ "echo-anon": "Sabiex tirċievi n-notifiki, [$1 oħloq kont] jew [$2 idħol fil-kont].",
+ "echo-none": "M'għandek l-ebda notifika",
+ "echo-more-info": "Aktar informazzjoni",
+ "echo-feedback": "Kummenti",
+ "notification-link-text-view-message": "Ara l-messaġġ",
+ "notification-link-text-view-mention": "Ara fejn issemmejt",
+ "notification-link-text-view-changes": "Ara l-bidliet",
+ "notification-link-text-view-page": "Ara l-paġna",
+ "notification-link-text-view-edit": "Ara l-modifika",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|ħalla|ħalliet}} messaġġ fuq il-[[User talk:$2#$3|paġna tal-utent]] tiegħek.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|ħalla|ħalliet}} messaġġ fuq il-paġna tad-diskussjoni tiegħek f'\"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|ħalla|ħalliet}} messaġġ fuq il-[[User talk:$2#$3|paġna tad-diskussjoni]] tiegħek.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|ħalla|ħalliet}} messaġġ fil-paġna tad-diskussjoni tiegħek f' \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] {{GENDER:$1|inħalqitilha}} ħolqa minn [[:$3]]. [[Special:WhatLinksHere/$2|Ara l-ħoloq għal din il-paġna kollha]].",
+ "notification-page-linked-flyout": "[[:$2]] {{GENDER:$1|inħalqitilha}} ħolqa minn [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|ħalla|ħalliet}} kumment \"[[$3|$2]]\" fuq il-paġna tad-diskussjoni ta' \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|beda|bdiet}} suġġett ġdid \"$2\" fuq [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|bagħatlek|bagħtitlek}} messaġġ: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|ħalla|ħalliet}} kumment dwar \"[[$3#$2|$2]]\" fuq il-paġna tad-diskussjoni tiegħek.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|semmiek|semmietek}} fuq il-paġna tad-diskussjoni ta' $5 f' \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|semmiek|semmietek}} fuq il-paġna tad-diskussjoni ta' $5 f' \"[[:$3#$2|$4]]\".",
+ "notification-user-rights": "Id-drittijiet tiegħek ta' utent [[Special:Log/rights/$1|ġew {{GENDER:$1|modifikati}}]] minn [[User:$1|$1]]. $2. [[Special:ListGroupRights|Ara iżjed]]$1$1",
+ "notification-user-rights-flyout": "Id-drittijiet tiegħek ta' utent ġew {{GENDER:$1|modifikati}} minn $1. $2. [[Special:ListGroupRights|Ara iżjed]]",
+ "notification-user-rights-add": "Issa int membru ta' {{PLURAL:$2|dan il-grupp|dawn il-gruppi}}: $1",
+ "notification-user-rights-remove": "Int m'għadikx membru ta' {{PLURAL:$2|dan il-grupp|dawn il-gruppi}}: $1",
+ "notification-new-user": "Merħba fuq {{SITENAME}}, $1! Qed nieħdu gost li ġejt hawn.",
+ "notification-reverted2": "Il-{{PLURAL:$4|modifika|modifiki}} fuq [[:$2]] {{PLURAL:$4|ġiet annullata|ġew annullati}} {{GENDER:$1|minn}} [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "Il-{{PLURAL:$4|modifika|modifiki}} tiegħek fuq $2 {{PLURAL:$4|ġiet annullata|ġew annullati}} {{GENDER:$1|minn}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|ħallielek|ħallietlek}} messaġġ fuq {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|ħalla|ħalliet}} messaġġ fuq il-paġna tad-diskussjoni tiegħek:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|ħalla|ħalliet}} messaġġ fil-paġna tad-diskussjoni tiegħek f' \"$2\".",
+ "notification-page-linked-email-subject": "Inħolqot ħolqa għall-paġna tiegħek fuq {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 {{GENDER:$1|inħalqitilha}} ħolqa minn $3.",
+ "notification-reverted-email-subject2": "Il-{{PLURAL:$3|modifika tiegħek ġiet annullata|modifiki tiegħek ġew annullati}} {{GENDER:$1|fuq}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "Il-{{PLURAL:$3|modifika|modifiki}} tiegħek fuq $2 {{PLURAL:$3|ġiet annullata|ġew annullati}} {{GENDER:$1|minn}} $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|semmiek|semmietek}} fuq {{SITENAME}}$1",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|semmiek|semmietek}} fuq il-paġna tad-diskussjoni ta' $4 f' \"$3\".",
+ "notification-user-rights-email-subject": "Id-drittijiet tiegħek ta' utent fuq {{SITENAME}} inbidlu.",
+ "notification-user-rights-email-batch-body": "Id-drittijiet tiegħek ta' utent {{GENDER:$1|biddilhom|biddlithom}} $1. $2.",
+ "echo-email-subject-default": "Notifika ġdida fuq {{SITENAME}}",
+ "echo-email-body-default": "Għandek notifika ġdida fuq {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Għandek notifika ġdida.",
+ "echo-email-footer-default": "$2\n\nBiex tkun taf liema posta elettronika tasallek, iċċekkja l-preferenzi tiegħek: \n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Biex tikkontrolla liema posta elettronika nibagħtulek, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">iċċekkja l-preferenzi tiegħek</a>.<br /> \n$1",
+ "echo-overlay-link": "In-notifiki kollha",
+ "echo-overlay-title": "<b>Notifiki</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notifiki}}</b> (qegħdin jidhru $1 minn $2 li ma nqrawx)",
+ "echo-mark-all-as-read": "Immarkahom kollha bħala li nqraw",
+ "echo-date-today": "Illum",
+ "echo-date-yesterday": "Ilbieraħ",
+ "echo-load-more-error": "Sar żball waqt li kienu qegħdin jinkisbu iktar riżultati.",
+ "notification-edit-talk-page-bundle": "$1 u $3 {{PLURAL:$4|ieħor/oħra|oħrajn}} {{GENDER:$1|ħallew}} messaġġ fuq il-[[User talk:$2|paġna tad-diskussjoni]] tiegħek.",
+ "notification-page-linked-bundle": "$2 {{GENDER:$1|saritilha ħolqa}} minn $3 u $4 {{PLURAL:$5|paġna|paġni}} oħra. [[Special:WhatLinksHere/$2|Ara l-ħoloq kollha għal din il-paġna]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 u $2 {{PLURAL:$3|ieħor/oħra|oħra}} {{GENDER:$1|ħalla/ħalliet|ħallew}} messaġġ fuq il-paġna tad-diskussjoni tiegħek.",
+ "notification-page-linked-email-batch-bundle-body": "$2 saritilha {{GENDER:$1|ħolqa}} minn $3 u $4 {{PLURAL:$5|paġna|paġni}} oħra.",
+ "echo-email-batch-subject-daily": "Għandek {{PLURAL:$2|notifika ġdida|notifiki ġodda}} fuq {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Għandek {{PLURAL:$2|notifika ġdida|notifiki ġodda}} fuq {{SITENAME}} dil-Ġimgħa",
+ "echo-email-batch-body-intro-daily": "X'hemm $1,\nDan hu s-sommarju tal-attività tal-lum fuq {{SITENAME}} biex tista' tarah.",
+ "echo-email-batch-body-intro-weekly": "X'hemm $1,\nDan hu s-sommarju tal-attività ta' din il-ġimgħa fuq {{SITENAME}} biex tista' tarah.",
+ "echo-email-batch-link-text-view-all-notifications": "Ara n-notifiki kollha",
+ "echo-rev-deleted-text-view": "Din ir-reviżjoni tal-paġna ġiet soppressa."
+}
diff --git a/Echo/i18n/nap.json b/Echo/i18n/nap.json
new file mode 100644
index 00000000..38bff407
--- /dev/null
+++ b/Echo/i18n/nap.json
@@ -0,0 +1,104 @@
+{
+ "@metadata": {
+ "authors": [
+ "C.R.",
+ "Chelin"
+ ]
+ },
+ "echo-desc": "Sistema 'e notifiche",
+ "prefs-echo": "Mmasciate",
+ "prefs-emailsettings": "Opziune e-mail",
+ "prefs-displaynotifications": "Opziune 'e visualizzazione",
+ "prefs-echosubscriptions": "Famme sapè ncopp'a sti avvenimente",
+ "prefs-newmessageindicator": "Barra d' 'e mmasciate nove",
+ "echo-pref-send-me": "Manna a mme:",
+ "echo-pref-send-to": "Manna a:",
+ "echo-pref-email-format": "Furmato e-mail:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Nun me mannà notifeche e-mail",
+ "echo-pref-email-frequency-immediately": "Mmasciate a uno a uno comme traseno",
+ "echo-pref-email-frequency-daily": "Nu riepilego a juorno a juorno d' 'e mmasciate",
+ "echo-pref-email-frequency-weekly": "Nu riepilego a semmana a semmana d' 'e mmasciate",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Testo nurmale",
+ "echo-pref-notify-show-link": "Fà vedè 'e mmasciate ncopp' 'a barra 'e strumiente mia",
+ "echo-pref-new-message-indicator": "Fa verè nnicature d' 'e mmasciate ncopp' 'a paggena 'e chiacchiera cu na mmasciata dint' 'a barra 'e strumiente",
+ "echo-learn-more": "Mpara 'e cchiù",
+ "echo-new-messages": "Avite mmasciate nove",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mmasciate}} d' 'a paggena 'e chiacchiere",
+ "echo-category-title-article-linked": "Paggena {{PLURAL:$1|cullegamiento|cullegamiente}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Cagnamiento 'arrepigliato|Cagnamiente 'arrepigliate}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Menzione|Menziune}}",
+ "echo-category-title-other": "{{PLURAL:$1|Ati}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Cagna 'o deritto|Cagna 'e deritte}} utente",
+ "echo-pref-tooltip-edit-user-talk": "Famme nu tuzzuleo quanno coccheruno mannasse na mmasciata o rispunnesse ncopp' 'a paggena 'e chiacchiera mia.",
+ "echo-pref-tooltip-article-linked": "Famme nu tuzzuleo quanno coccheruno se cullegasse a na paggena ca io avesse criato 'a na voce.",
+ "echo-pref-tooltip-reverted": "Famme nu tuzzuleo quanno coccheruno annullasse nu cagnamiento ca io stesso aggio fatto, ausanno 'o strumiento 'e annulla.",
+ "echo-pref-tooltip-mention": "Famme nu tuzzuleo quanno coccheruno se cullegasse 'a paggena utente mia.",
+ "echo-pref-tooltip-user-rights": "Famme nu tuzzuleo quanno coccheruno cagnasse 'e deritte utente mieie.",
+ "echo-no-agent": "[Nisciuno]",
+ "echo-no-title": "[Nisciuna paggena]",
+ "echo-error-no-formatter": "Nisciuna furmattazione è stata definita p' 'e tuzzulee.",
+ "echo-error-preference": "Errore: Non se ponno mpustà 'e preferenze 'e ll'utente",
+ "echo-error-token": "Errore: Nun se riesce a piglià 'o token 'utente",
+ "notifications": "Mmasciate",
+ "tooltip-pt-notifications": "'E notifiche vuoste",
+ "echo-specialpage": "Mmasciate",
+ "echo-anon": "Pe' ricevere notifiche, <span class=\"plainlinks\">[$1 crìa nu cunto] o <span class=\"plainlinks\">[$2 tràse].",
+ "echo-none": "Nun tiene notifiche.",
+ "echo-more-info": "Cchiù nfurmaziune",
+ "echo-feedback": "Commenti",
+ "notification-link-text-view-message": "Vire mmasciata",
+ "notification-link-text-view-mention": "Vire menziona",
+ "notification-link-text-view-changes": "Vire 'e cagnamiente",
+ "notification-link-text-view-page": "Vire 'a paggena",
+ "notification-link-text-view-edit": "Vire 'o cagnamiento",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|t'ha lassato}} na mmasciata dint' 'a [[User talk:$2#$3|paggena 'e chiacchiera]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|t'ha lassato}} na mmasciata dint'a \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|t'ha lassato}} na mmasciata dint' 'a [[User talk:$2#$3|paggena 'e chiacchiera]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|ha lassato}} na mmasciata int'a paggena 'e chiacchiera d' 'a toja int'a \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] fuje {{GENDER:$1|cullegato}} 'a [[:$3]]. [[Special:WhatLinksHere/$2|Vedite tutt' 'e link a sta paggena]].",
+ "notification-page-linked-flyout": "[[:$2]] è stata {{GENDER:$1|cullegata}} a [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|lassaje nu commento}} ncopp'a \"[[$3|$2]]\" dint' 'a \"$4\" paggena 'e chiacchiera.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|ave mannato}} n'argomento nuovo \"$2\" ncopp'a [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|t'a mannato}} na mmasciata: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|lassaje nu commento}} ncopp'a \"[[$3#$2|$2]]\" dint' 'a paggena 'e chiacchiera vosta.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|facette 'o nomme vuosto}} dint' 'a $5 paggena 'e chiacchiera int'a \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|ave fatto 'o nomme}} vuosto dint' 'a $5 paggena 'e chiacchiera 'e \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|ave fatto 'o nomme}} vuoto int' 'a [[:$3|$2 paggena 'e chiacchiera]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|ha fatto 'o nomme}} vuosto dint' 'a [[:$3|$2 paggena 'e chiacchiera]].",
+ "notification-user-rights": "'E deritte 'utente [[Special:Log/rights/$1|so' state {{GENDER:$1|cagnate}}]] 'a [[User:$1|$1]]. $2. [[Special:ListGroupRights|Mparate 'e cchiù]]",
+ "notification-user-rights-flyout": "'E deritte vuoste so' state {{GENDER:$1|cagnate}} 'a $1. $2. [[Special:ListGroupRights|Mpara 'e cchiù]]",
+ "notification-user-rights-add": "Mo' site membre 'e {{PLURAL:$2|stu gruppo|sti gruppe}}: $1",
+ "notification-user-rights-remove": "Mo' nun site cchiù membre 'e {{PLURAL:$2|stu gruppo|sti gruppe}}: $1",
+ "notification-new-user": "Bemmenuto/a a {{SITENAME}}, $1! Nuje simmo cuntente 'e te veré ccà.",
+ "notification-reverted2": "{{PLURAL:$4|'O cagnamiento vuosto ncopp'a [[:$2]] è stato|'E cagnamiente vuoste ncopp' 'a [[:$2]] so' state}} {{GENDER:$1|annullate}} 'a [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|'O cagnamiento ncopp'a $2 vuosto è stato|'E cagnamiente vuoste ncopp' 'a $2 so state}} {{GENDER:$1|annullate}} 'a $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|t'ha lassato}} na mmasciata {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|lassaje}} na mmasciata dint'a paggena 'e chiacchiera toja:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|lassaje}} na mmasciata dint'a paggena 'e chiacchiera r' 'a vosta \"$2\".",
+ "notification-page-linked-email-subject": "'A paggena tuja fuje cullegata ncopp'a {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 è stata {{GENDER:$1|cullegata}} 'a $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|'O cangiamento vuosto è stato|'E cangiamiente vuoste so'}} state {{GENDER:$1|annullate}} ncopp'a {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|'O cagnamiento ncopp'a $2 vuosto è stato|'E cagnamiente vuoste ncopp' 'a $2 so state}} {{GENDER:$1|annullate}} 'a $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|facette 'o nomme}} vuosto ncopp'a {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|facette 'o nomme}} vuosto ncopp'a $4 paggena 'e chiacchiera dint'a \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|ha fatto 'o nomme}} vuosto dint' 'a paggena 'e chiacchiera 'e $2.",
+ "notification-user-rights-email-subject": "'E deritte utente vuoste so' state cagnate ncopp'a {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "'E deritte utente vuoste so' state {{GENDER:$1|cagnate}} 'a $1. $2.",
+ "echo-email-subject-default": "Notifica nova ncopp'a {{SITENAME}}",
+ "echo-email-body-default": "Avite na notifica nova ncopp'a {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "È arrevata na notifica nova.",
+ "echo-notification-alert": "{{PLURAL:$1|Avvertemiénto ($1)|Avvertemiénte ($1)|100=Avvertemiénte (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mmasciata ($1)|Mmasciate ($1)|100=Mmasciate (99+)}}",
+ "echo-notification-alert-text-only": "Avvise",
+ "echo-notification-message-text-only": "Mmasciate",
+ "echo-overlay-link": "Tutt' 'e notifiche vuoste",
+ "echo-overlay-title": "<b>Notifiche</b>",
+ "echo-mark-all-as-read": "Nzegna tutte cumme fossero lette",
+ "echo-date-today": "Ogge",
+ "echo-date-yesterday": "Aiere",
+ "echo-email-batch-link-text-view-all-notifications": "Vide tutte 'e notifiche"
+}
diff --git a/Echo/i18n/nb.json b/Echo/i18n/nb.json
new file mode 100644
index 00000000..16f27031
--- /dev/null
+++ b/Echo/i18n/nb.json
@@ -0,0 +1,138 @@
+{
+ "@metadata": {
+ "authors": [
+ "Danmichaelo",
+ "Jeblad",
+ "Laaknor",
+ "Njardarlogar"
+ ]
+ },
+ "echo-desc": "Varslingssystem",
+ "prefs-echo": "Varsler",
+ "prefs-emailsettings": "E-postinnstillinger",
+ "prefs-displaynotifications": "Visningsvalg",
+ "prefs-echosubscriptions": "Varsle meg om disse hendelsene",
+ "prefs-newmessageindicator": "Indikator for ny melding",
+ "echo-pref-send-me": "Send meg:",
+ "echo-pref-send-to": "Send til:",
+ "echo-pref-email-format": "Epost-format:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-post",
+ "echo-pref-email-frequency-never": "Ikke send meg e-postvarsler",
+ "echo-pref-email-frequency-immediately": "Individuelle varsler fortløpende",
+ "echo-pref-email-frequency-daily": "Daglige sammendrag av varsler",
+ "echo-pref-email-frequency-weekly": "Ukentlige sammendrag av varsler",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Ren tekst",
+ "echo-pref-notify-show-link": "Vis varslinger i verktøylinjen min",
+ "echo-pref-new-message-indicator": "Vis indikator for nye meldinger i verktøylinjen min",
+ "echo-learn-more": "Lær mer",
+ "echo-new-messages": "Du har nye meldinger",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Melding|Meldinger}} på diskusjonsside",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Sidelenke|Sidelenker}}",
+ "echo-category-title-reverted": "Tilbakestilling av {{PLURAL:$1|redigering|redigeringer}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Omtale|Omtaler}}",
+ "echo-category-title-other": "{{PLURAL:$1|Annet}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Endringer}} i brukerrettigheter",
+ "echo-pref-tooltip-edit-user-talk": "Varsle meg når noen skriver en melding eller svarer på diskusjonssiden min.",
+ "echo-pref-tooltip-article-linked": "Varsle meg når noen lenker fra en artikkel til en side jeg har opprettet.",
+ "echo-pref-tooltip-reverted": "Gi meg beskjed når noen tilbakestiller en av redigeringene mine.",
+ "echo-pref-tooltip-mention": "Varsle meg når noen lenker til brukersiden min.",
+ "echo-pref-tooltip-user-rights": "Varsle meg når noen endrer brukerrettighetene mine.",
+ "echo-no-agent": "[Ingen]",
+ "echo-no-title": "[Ingen side]",
+ "echo-error-no-formatter": "Ingen formatering definert for varselet",
+ "echo-error-preference": "Feil: Kunne ikke lagre brukervalg",
+ "echo-error-token": "Feil: Kunne ikke hente brukertegn",
+ "notifications": "Varsler",
+ "tooltip-pt-notifications": "Dine varsler",
+ "echo-specialpage": "Varsler",
+ "echo-anon": "For å motta varsler, [$1 opprett en konto] eller [$2 logg inn].",
+ "echo-none": "Du har ingen varsler.",
+ "echo-more-info": "Mer informasjon",
+ "echo-feedback": "Tilbakemelding",
+ "notification-link-text-view-message": "Vis melding",
+ "notification-link-text-view-mention": "Vis omtale",
+ "notification-link-text-view-changes": "Vis endringer",
+ "notification-link-text-view-page": "Vis side",
+ "notification-link-text-view-edit": "Vis redigering",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|skrev}} en melding på [[User talk:$2#$3|diskusjonssiden din]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|skrev}} en melding på diskusjonssiden din under «[[User talk:$2#$3|$4]]».",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|skrev}} en melding på [[User talk:$2#$3|diskusjonssiden din]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|skrev}} en melding på diskusjonssiden din under «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "[[:$2]] ble {{GENDER:$1|lenket til}} fra [[:$3]]. [[Special:WhatLinksHere/$2|Se alle lenker til denne siden]].",
+ "notification-page-linked-flyout": "[[:$2]] ble {{GENDER:$1|lenket til}} fra [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|kommenterte}} på ''[[$3|$2]]'' på diskusjonssiden ''$4''",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|postet}} en ny tråd ''$2'' på [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|sendte}} deg en melding: ''[[$3#$2|$2]]''",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|kommenterte}} på ''[[$3#$2|$2]]'' på diskusjonssiden din",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|nevnte}} deg i «[[:$3#$2|$4]]» på diskusjonssiden til $5.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|nevnte}} deg i «[[:$3#$2|$4]]» på diskusjonssiden til $5.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|nevnte}} deg på [[:$3|diskusjonssiden til «$2»]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|nevnte}} deg på [[:$3|diskusjonssiden til «$2»]].",
+ "notification-user-rights": "Brukerrettighetene dine [[Special:Log/rights/$1|ble {{GENDER:$1|endret}}]] av [[User:$1|$1]]. $2. [[Special:ListGroupRights|Lær mer]]",
+ "notification-user-rights-flyout": "Brukerrettighetene dine ble {{GENDER:$1|endret}} av $1. $2. [[Special:ListGroupRights|Lær mer]]",
+ "notification-user-rights-add": "Du er nå medlem av {{PLURAL:$2|denne gruppa|disse gruppene}}: $1",
+ "notification-user-rights-remove": "Du er ikke lenger medlem av {{PLURAL:$2|denne gruppa|disse gruppene}}: $1",
+ "notification-new-user": "Velkommen til {{SITENAME}}, $1! Hyggelig å se deg her.",
+ "notification-reverted2": "{{PLURAL:$4|Redigeringen din|Redigeringene dine}} på [[:$2]] har blitt {{GENDER:$1|tilbakestilt}} av [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Redigeringen din|Redigeringene dine}} på $2 har blitt {{GENDER:$1|tilbakestilt}} av $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|skrev}} en melding til deg på {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|skrev}} en melding på diskusjonssiden din:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|skrev}} en melding til deg under overskriften «$2» på diskussjonssiden din.",
+ "notification-page-linked-email-subject": "Siden din ble lenket til på {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 ble {{GENDER:$1|lenket}} til fra $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Redigeringen din|Redigeringene dine}} på {{SITENAME}} ble {{GENDER:$1|tilbakestilt}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Redigeringen din|Redigeringene dine}} på $2 har blitt {{GENDER:$1|tilbakestilt}} av $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|nevnte}} deg på {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|nevnte}} deg i «$3» på diskusjonssiden til $4.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|nevnte}} deg på diskusjonssiden til «$2».",
+ "notification-user-rights-email-subject": "Brukerrettighetene dine ble endret på {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Brukerrettighetene dine ble {{GENDER:$1|endret}} av $1. $2",
+ "echo-email-subject-default": "Nytt varsel på {{SITENAME}}",
+ "echo-email-body-default": "Du har et nytt varsel på {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Du har et nytt varsel",
+ "echo-email-footer-default": "$2\n\nFor å styre hva slags e-poster vi sender deg, sjekk innstillingene dine: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "For å kontrollere hvilke e-poster vi kan sende deg, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">sjekk innstillingene dine</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Varsel ($1)|Varsler ($1)|100=Varsler (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Melding ($1)|Meldinger ($1)|100=Meldinger (99+)}}",
+ "echo-notification-alert-text-only": "Varsler",
+ "echo-notification-message-text-only": "Meldinger",
+ "echo-overlay-link": "Alle varsler",
+ "echo-overlay-title": "<b>Varslinger</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Varsler}}</b> (viser $1 av $2 uleste)",
+ "echo-mark-all-as-read": "Merk alle som leste",
+ "echo-date-today": "I dag",
+ "echo-date-yesterday": "I går",
+ "echo-load-more-error": "En feil oppsto under henting av flere resultater.",
+ "notification-edit-talk-page-bundle": "$1 og $3 {{PLURAL:$4|annen|andre}} {{GENDER:$1|skrev}} en melding på [[User talk:$2|diskusjonssiden din]].",
+ "notification-page-linked-bundle": "$2 ble {{GENDER:$1|lenket til}} fra $3 og $4 {{PLURAL:$5|annen side|andre sider}}. [[Special:WhatLinksHere/$2|Se alle lenker til denne siden]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 og $2 {{PLURAL:$3|annen|andre}} {{GENDER:$1|skrev}} en melding på diskusjonssiden din",
+ "notification-page-linked-email-batch-bundle-body": "$2 ble {{GENDER:$1|lenket til}} fra $3 og $4 {{PLURAL:$5|annen side|andre sider}}",
+ "echo-email-batch-subject-daily": "Du har {{PLURAL:$2|ett nytt varsel|nye varsler}} på {{SITENAME}} i dag",
+ "echo-email-batch-subject-weekly": "Du har {{PLURAL:$2|ett nytt varsel|nye varsler}} på {{SITENAME}} denne uka",
+ "echo-email-batch-body-intro-daily": "Hei $1,\nHer er et sammendrag av dagens aktivitet på {{SITENAME}} for deg",
+ "echo-email-batch-body-intro-weekly": "Hei $1,\nHer er et sammendrag av ukas aktivitet på {{SITENAME}} for deg",
+ "echo-email-batch-link-text-view-all-notifications": "Vis alle varsler",
+ "echo-rev-deleted-text-view": "Denne siderevisjonen har blitt skjult",
+ "apihelp-echomarkread-description": "Merk varsler som leste for den aktuelle brukeren.",
+ "apihelp-echomarkread-param-list": "En liste over ID-er for varsler som skal merkes som lest.",
+ "apihelp-echomarkread-param-all": "Merk alle brukerens varsler som lest.",
+ "apihelp-echomarkread-param-sections": "En liste over seksjoner som skal markeres som leste.",
+ "apihelp-echomarkread-example-1": "Merk varsel 8 som lest",
+ "apihelp-echomarkread-example-2": "Merk alle varsler som leste",
+ "apihelp-query+notifications-description": "Hent ventende varsler for den aktuelle brukeren.",
+ "apihelp-query+notifications-param-prop": "Detaljer som skal forespørres.",
+ "apihelp-query+notifications-param-sections": "Seksjoner som skal hentes.",
+ "apihelp-query+notifications-param-groupbysection": "Hvorvidt varslene skal grupperes etter seksjon. Hver seksjon hentes hver for seg hvis gitt.",
+ "apihelp-query+notifications-param-format": "Hvis angitt blir varslene formatert på denne måten.",
+ "apihelp-query+notifications-param-limit": "Maks antall varsler som skal hentes.",
+ "apihelp-query+notifications-param-index": "Hvis angitt, en ordnet liste over ID-er for varsler som skal hentes",
+ "apihelp-query+notifications-param-alertcontinue": "Når flere resultater er tilgjengelig, bruk denne for å hente flere.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Hvorvidt uleste varsler skal vises først.",
+ "apihelp-query+notifications-param-messagecontinue": "Når flere resultater er tilgjengelig, bruk denne for å hente flere.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Hvorvidt uleste varsler skal vises først.",
+ "apihelp-query+notifications-example-1": "List varsler",
+ "apihelp-query+notifications-example-2": "List varsler, gruppert etter seksjon, med antall"
+}
diff --git a/Echo/i18n/nds-nl.json b/Echo/i18n/nds-nl.json
new file mode 100644
index 00000000..19595629
--- /dev/null
+++ b/Echo/i18n/nds-nl.json
@@ -0,0 +1,107 @@
+{
+ "@metadata": {
+ "authors": [
+ "Servien"
+ ]
+ },
+ "echo-desc": "Meldingssysteem",
+ "prefs-echo": "Melding",
+ "prefs-emailsettings": "Netpostinstellingen",
+ "prefs-displaynotifications": "Weergave-instellingen",
+ "prefs-echosubscriptions": "Stel mien op de heugte van disse gebeurtenissen",
+ "prefs-newmessageindicator": "Melding nieje berichten",
+ "echo-pref-send-me": "Stuur mien:",
+ "echo-pref-send-to": "Sturen naor:",
+ "echo-pref-email-format": "Netpostopmaak:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Netpost",
+ "echo-pref-email-frequency-never": "Gien meldingen per netpost sturen",
+ "echo-pref-email-frequency-immediately": "Individuele meldingen as ze binnenkoemen",
+ "echo-pref-email-frequency-daily": "n Dagelikse samenvatting van meldingen",
+ "echo-pref-email-frequency-weekly": "n Wekelikse samenvatting van meldingen",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Tekste zonder opmaak",
+ "echo-pref-notify-show-link": "Laot melding in mien warkbalke zien",
+ "echo-pref-new-message-indicator": "Laot meldingen over berichten op mien overlegzied in mien warkbalke zien",
+ "echo-learn-more": "Meer lezen",
+ "echo-new-messages": "Je hebben nieje berichten",
+ "echo-category-title-edit-user-talk": "Bericht{{PLURAL:$1||en}} op mien overlegzied",
+ "echo-category-title-article-linked": "Ziedverwiezing{{PLURAL:$1||en}}",
+ "echo-category-title-reverted": "Bewarking{{PLURAL:$1||en}} weerummedreid",
+ "echo-category-title-mention": "{{PLURAL:$1|Eneumd}}",
+ "echo-category-title-other": "{{PLURAL:$1|Overige}}",
+ "echo-category-title-system": "{{PLURAL:$1|Systeem}}",
+ "echo-pref-tooltip-edit-user-talk": "Stuur m'n n melding as der ene n niej bericht op mien overlegzied zet of as e antwoordt.",
+ "echo-pref-tooltip-article-linked": "Stuur m'n n melding as der ene n verwiezing maakt naor n zied die'k an-emaakt hebbe.",
+ "echo-pref-tooltip-reverted": "Stuur m'n n melding as der ene n bewarking die'k an-ebröcht hebbe weerummedreit mit de funksie ongedaonmaken of weerummedreien.",
+ "echo-pref-tooltip-mention": "Stuur m'n n melding as der ene n verwiezing maakt naor mien gebrukerszied vanaof n overlegzied.",
+ "echo-no-agent": "[Gien ene]",
+ "echo-no-title": "[Gien zied]",
+ "echo-error-no-formatter": "Der is gien opmaak in-esteld veur de melding.",
+ "echo-error-preference": "Fout: de gebrukersinstelling kon niet in-esteld wörden",
+ "echo-error-token": "Fout: t gebrukerstoken kon niet op-ehaold wörden",
+ "notifications": "Meldingen",
+ "tooltip-pt-notifications": "Joew meldingen",
+ "echo-specialpage": "Meldingen",
+ "echo-anon": "[$1 Maak n gebrukerskonto n] of [$2 meld je eigen an] a'j meldingen ontvangen willen.",
+ "echo-none": "Je hebben gien meldingen.",
+ "echo-more-info": "Meer informasie",
+ "echo-feedback": "Kommentaar",
+ "notification-link-text-view-message": "Bericht bekieken",
+ "notification-link-text-view-mention": "Vermelding bekieken",
+ "notification-link-text-view-changes": "Verschil bekieken",
+ "notification-link-text-view-page": "Zied bekieken",
+ "notification-link-text-view-edit": "Bewarking bekieken",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|hef n bericht achtereleuten}} op joew [[User talk:$2#$3|overlegzied]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|hef}} n bericht op joew overlegzied achtereleuten in t onderwarp \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|hef n bericht achtereleuten}} op joew [[User talk:$2#$3|overlegzied]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|hef}} n bericht op joew overlegzied achtereleuten in t onderwarp \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] is {{GENDER:$1|ekoppeld}} vanaof [[:$3]]:[[Special:WhatLinksHere/$2|alle verwiezingen naor disse zied bekieken]].",
+ "notification-page-linked-flyout": "[[:$2]] is {{GENDER:$1|ekoppeld}} vanaof [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|hef ereageerd}} op \"[[$3|$2]]\" op de overlegzied \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|hef}} n niej onderwarp \"$2\" op [[$3]] ezet.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|hef}} joe n bericht estuurd: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|hef ereageerd}} op \"[[$3#$2|$2]]\" op joew overlegzied",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|hef}} joe eneumd op de overlegzied van $5 in \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|hef}} joe eneumd op de overlegzied van $5 in \"[[:$3#$2|$4]]\".",
+ "notification-user-rights": "[[Special:Log/rights/$1|Joew gebrukersrechten]] bin {{GENDER:$1|ewiezigd}} deur [[User:$1|$1]]. $2. [[Special:ListGroupRights|Meer informasie]]",
+ "notification-user-rights-flyout": "Joew gebrukersrechten bin {{GENDER:$1|ewiezigd}} deur $1. $2. [[Special:ListGroupRights|Meer informasie]]",
+ "notification-user-rights-add": "Je bin noen lid van disse groep{{PLURAL:$2||en}}: $1",
+ "notification-user-rights-remove": "Je bin noen gien lid meer van disse groep{{PLURAL:$2||en}}: $1",
+ "notification-new-user": "Welkom op {{SITENAME}}, $1! Goed da'j der bin.",
+ "notification-reverted2": "Joew {{PLURAL:$4|bewarking op [[:$2]] is|bewarkingen op [[:$2]] bin}} {{GENDER:$1|weerummedreid}} deur [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "Joew {{PLURAL:$4|bewarking op $2 is|bewarkingen op $2 bin}} {{GENDER:$1|weerummedreid}} deur $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|hef}} n bericht veur joe achtereleuten op {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|hef}} n bericht achtereleuten op joew overlegzied:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|hef}} n bericht achtereleuten op joew overlegzied in \"$2\".",
+ "notification-page-linked-email-subject": "n Zied die'j an-emaakt hebbe is ekoppeld op {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 is {{GENDER:$1|ekoppeld}} vanaof $3.",
+ "notification-reverted-email-subject2": "Joew {{PLURAL:$3|bewarking op {{SITENAME}} is|bewarkingen op {{SITENAME}} bin}} {{GENDER:$1|weerummedreid}}",
+ "notification-reverted-email-batch-body2": "Joew {{PLURAL:$3|bewarking op $2 is|bewarkingen op $2 bin}} {{GENDER:$1|weerummedreid}} deur $1",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|hef}} joe eneumd op {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|hef}} joe eneumd op de overlegzied van $4 in \"$3\"",
+ "notification-user-rights-email-subject": "Joew gebrukersrechten op {{SITENAME}} bin ewiezigd",
+ "notification-user-rights-email-batch-body": "Joew gebrukersrechten bin {{GENDER:$1|ewiezigd}} deur $1. $2",
+ "echo-email-subject-default": "Nieje melding op {{SITENAME}}",
+ "echo-email-body-default": "Je hebben n nieje melding op {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Je hebben n nieje melding.",
+ "echo-email-footer-default": "$2\n\nVolg de volgende verwiezing um te bepaolen hokken netberichten wie joe sturen:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Gao naor <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">mien veurkeuren</a> um te bepaolen hokken netberichten wie joe sturen.<br />\n$1",
+ "echo-overlay-link": "Alle meldingen",
+ "echo-overlay-title": "<b>Meldingen</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Meldingen}}</b> ($1 van $2 he'j nog niet elezen)",
+ "echo-mark-all-as-read": "Alles as elezen markeren",
+ "echo-date-today": "Vandage",
+ "echo-date-yesterday": "Gisteren",
+ "echo-load-more-error": "Der is wat mis egaon bie t ophaolen van meer resultaoten.",
+ "notification-edit-talk-page-bundle": "$1 en $3 {{PLURAL:$4|aandere gebruker|aandere gebrukers}} hebben n bericht {{GENDER:$1|achtereleuten}} op joew [[User talk:$2|overlegzied]].",
+ "notification-page-linked-bundle": "$2 is {{GENDER:$1|ekoppeld}} vanaof $3 en $4 aandere {{PLURAL:$5|zied|ziejen}}. [[Special:WhatLinksHere/$2|Alle verwiezingen naor disse zied bekieken]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 en $2 {{PLURAL:$3|aandere gebruker|aandere gebrukers}} {{GENDER:$1|hebben}} n bericht op joew overlegzied achtereleuten.",
+ "notification-page-linked-email-batch-bundle-body": "$2 is {{GENDER:$1|ekoppeld}} vanaof $3 en $4 aandere {{PLURAL:$5|zied|ziejen}}",
+ "echo-email-batch-subject-daily": "Je hebben {{PLURAL:$2|n nieje melding|nieje meldingen}} op {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Je hebben disse weke {{PLURAL:$2|n nieje melding|nieje meldingen}} op {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Huj $1,\nHier he'j n samenvatting van de aktiviteiten op {{SITENAME}} van vandage",
+ "echo-email-batch-body-intro-weekly": "Huj $1,\nHier he'j n samenvatting van de aktiviteiten op {{SITENAME}} van disse weke.",
+ "echo-email-batch-link-text-view-all-notifications": "Alle mededelingen bekieken",
+ "echo-rev-deleted-text-view": "Disse ziedversie is onderdrokt."
+}
diff --git a/Echo/i18n/nds.json b/Echo/i18n/nds.json
new file mode 100644
index 00000000..e8ea73b2
--- /dev/null
+++ b/Echo/i18n/nds.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joachim Mos"
+ ]
+ },
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-Mail",
+ "echo-category-title-other": "Annere"
+}
diff --git a/Echo/i18n/ne.json b/Echo/i18n/ne.json
new file mode 100644
index 00000000..a0e60d41
--- /dev/null
+++ b/Echo/i18n/ne.json
@@ -0,0 +1,110 @@
+{
+ "@metadata": {
+ "authors": [
+ "सरोज कुमार ढकाल"
+ ]
+ },
+ "echo-desc": "जानकारी प्रणाली",
+ "prefs-echo": "जानकारीहरू",
+ "prefs-emailsettings": "इमेल विकल्पहरु",
+ "prefs-displaynotifications": "प्रदर्शन विकल्पहरू",
+ "prefs-echosubscriptions": "निम्न घटनाहरूबारे मलाई जानकारी गराउने",
+ "prefs-newmessageindicator": "नयाँ जानकारी सुचक",
+ "echo-pref-send-me": "मलाई पठाउने:",
+ "echo-pref-send-to": "पठाउने:",
+ "echo-pref-email-format": "इमेल ढाँचा :",
+ "echo-pref-web": "वेब",
+ "echo-pref-email": "इमेल",
+ "echo-pref-email-frequency-never": "मलाई कुनै पनि इमेल जानकारी नपठाउने",
+ "echo-pref-email-frequency-immediately": "जानकारीहरू जस्ताको तस्तै जसै हुन्छन्",
+ "echo-pref-email-frequency-daily": "दैनिक जानकारीको सारांश",
+ "echo-pref-email-frequency-weekly": "साप्ताहिक जानकारीको सारांश",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "साधारण पाठ",
+ "echo-pref-notify-show-link": "मेरो टुलबारमा देखाउने",
+ "echo-pref-new-message-indicator": "टुलबारमा मेरो वार्तालाप पृष्ठको सन्देश पनि देखाउने",
+ "echo-learn-more": "थप जानकारी",
+ "echo-new-messages": "तपाईंको लागि नयाँ सन्देशहरू छन्",
+ "echo-category-title-edit-user-talk": "वार्तालाप पृष्ठ {{PLURAL:$1|सन्देश|सन्देशहरू}}",
+ "echo-category-title-article-linked": "पृष्ठ {{PLURAL:$1|लिङ्क|लिङ्कहरू}}",
+ "echo-category-title-reverted": "सम्पादन {{PLURAL:$1|रिभर्ट|रिभर्टहरू}}",
+ "echo-category-title-mention": "{{PLURAL:$1|नाम लिइयो|नामहरू लिइयो}}",
+ "echo-category-title-other": "{{PLURAL:$1|अरु}}",
+ "echo-category-title-system": "{{PLURAL:$1|प्रणाली}}",
+ "echo-pref-tooltip-edit-user-talk": "कसैले मेरो वार्तालाप पृष्ठमा सन्देश छोडेमा जानकारी गराउनुहोस् ।",
+ "echo-pref-tooltip-article-linked": "कसैले मैले सिर्जना गरेको पृष्ठमा लिङ्क जोडेमा जानकारी गराउनुहोस ।",
+ "echo-pref-tooltip-reverted": "जब कसैले मैले बनाएको सम्पादन उल्ट्याउँदछ मलाई जानकारी गराउनुहोस्, अनडु र रोलब्याक उपकरण प्रयोग गरेर।",
+ "echo-pref-tooltip-mention": "जब कसैले मेरो प्रयोगकर्ता पृष्ठलाई कुनै पनि वार्ता पृष्ठबाट लिङ्क गर्छ मलाई जानकारी गराउनुहोस्।",
+ "echo-no-agent": "[कोही पनि हैन]",
+ "echo-no-title": "[कुनै पनि पृष्ठ हैन]",
+ "echo-error-no-formatter": "जानकारीको लागि कुनै पनि ढाँचा खुलाइएको छैन ।",
+ "echo-error-preference": "त्रुटि: प्रयोगकर्ता अभिरुचीहरू मिलाउन सकिएन ।",
+ "echo-error-token": "त्रुटी: प्रयोगकर्ता टोकन प्राप्त गर्न सकिएन ।",
+ "notifications": "जानकारीहरू",
+ "tooltip-pt-notifications": "तपाईँका जानकारीहरू",
+ "echo-specialpage": "जानकारीहरू",
+ "echo-anon": "जानकारीहरू प्राप्त गर्न, [$1 एउटा खाता खोल्नुहोस्] वा [$2 प्रवेश गर्नुहोस्]",
+ "echo-none": "तपाईँको लागि नयाँ जानकारी छैन ।",
+ "echo-more-info": "थप जानकारी",
+ "echo-feedback": "प्रतिक्रिया",
+ "notification-link-text-view-message": "सन्देश हेर्ने",
+ "notification-link-text-view-mention": "नाम लिइएको हेर्ने",
+ "notification-link-text-view-changes": "परिवर्तन हेर्ने",
+ "notification-link-text-view-page": "पृष्ठ हेर्ने",
+ "notification-link-text-view-edit": "सम्पादन हेर्ने",
+ "notification-edit-talk-page2": "[[User:$1|$1]] ले तपाईँको [[User talk:$2#$3|वार्ता पृष्ठ]]मा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}}।",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] ले तपाईँको वार्ता पृष्ठमा \"[[User talk:$2#$3|$4]]\"मा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}}।",
+ "notification-edit-talk-page-flyout2": "$1ले तपाईँको [[User talk:$2#$3|वार्ता पृष्ठ]]मा सन्देश {{GENDER:$1|छोड्नुभएको छ}} ।",
+ "notification-edit-talk-page-flyout-with-section": "$1 ले तपाईँको वार्ता पृष्ठमा \"[[User talk:$2#$3|$4]]\" मा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}}।",
+ "notification-page-linked": "[[:$2]] [[:$3]] बाट {{GENDER:$1|लिङ्क भयो}}। [[Special:WhatLinksHere/$2|यस पृष्ठसँग भएको सबै लिङ्कहरू हेर्नुहोस्]]।",
+ "notification-page-linked-flyout": "[[:$3]] मा [[:$2]] {{GENDER:$1|जोडियो }}",
+ "notification-add-comment2": "[[User:$1|$1]] ले \"[[$3|$2]]\" मा \"$4\" वार्तालाप पृष्ठमा {{GENDER:$1|टिप्पणी गर्नुभयो}}।",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] ले [[$3]] मा एउटा नयाँ विषय \"$2\" {{GENDER:$1|पोस्ट गर्नुभयो}}।",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] ले तपाईँलाई एउटा सन्देश: \"[[$3#$2|$2]]\" {{GENDER:$1|पठाउनुभयो}}।",
+ "notification-add-comment-yours2": "[[User:$1|$1]] ले \"[[$3#$2|$2]]\" मा तपाईँको वार्तालाप पृष्ठमा {{GENDER:$1|टिप्पणी गर्नुभयो}}।",
+ "notification-mention": "[[User:$1|$1]] ले \"[[:$3#$2|$4]]\" मा $5 वार्ता पृष्ठमा तपाईँलाई {{GENDER:$1|उल्लेख गर्नुभयो}}।",
+ "notification-mention-flyout": "$1 ले तपाईँलाई $5 वार्ता पृष्ठमा \"[[:$3#$2|$4]]\" मा {{GENDER:$1|उल्लेख गर्नुभयो}}।",
+ "notification-mention-nosection": "[[User:$1|$1]] ले तपाईँलाई [[:$3|$2 वार्ता पृष्ठ]] मा {{GENDER:$1|उल्लेख गर्नुभयो}}।",
+ "notification-mention-nosection-flyout": "$1 ले तपाईँलाई [[:$3|$2 वार्ता पृष्ठ]] मा {{GENDER:$1|उल्लेख गर्नुभयो}}।",
+ "notification-user-rights": "तपाईँको प्रयोगकर्ता अधिकारहरू [[Special:Log/rights/$1| [[User:$1|$1]] द्वारा {{GENDER:$1|परिवर्तन गरियो}}]]। $2. [[Special:ListGroupRights|थप जानकारी]]",
+ "notification-user-rights-flyout": "तपाईँको प्रयोगकर्ता अधिकारहरू $1 द्वारा {{GENDER:$1|परिवर्तन गरियो}}। $2. [[Special:ListGroupRights|थप जानकारी]]",
+ "notification-user-rights-add": "अब तपाईँ {{PLURAL:$2|यो समूह|यी समूहहरू}}: $1 को एउटा सदस्य हुनुहुन्छ।",
+ "notification-user-rights-remove": "अब तपाईँ {{PLURAL:$2|यो समूह|यी समूहहरू}}: $1 को सदस्य हुनुहुन्न।",
+ "notification-new-user": "{{SITENAME}} मा स्वागत, $1! तपाईँ यहाँ हुनुहुन्छ हामी खुसी छौँ।",
+ "notification-reverted2": "तपाईँको {{PLURAL:$4|सम्पादन [[:$2]] मा |सम्पादनहरू [[:$2]] मा}} [[User:$1|$1]] द्वारा {{GENDER:$1|उल्ट्याइएको छ}}। $3",
+ "notification-reverted-flyout2": "तपाईँको {{PLURAL:$4|सम्पादन $2 मा |सम्पादनहरू $2 मा}} $1 द्वारा {{GENDER:$1|उल्ट्याइएको छ}}। $3",
+ "notification-edit-talk-page-email-subject2": "$1 ले तपाईँलाई {{SITENAME}} मा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 तपाईँको वार्ता पृष्ठमा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 तपाईँको वार्ता पृष्ठमा \"$2\" मा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}} ।",
+ "notification-page-linked-email-subject": "तपाईँको पृष्ठ {{SITENAME}} मा जोडियो",
+ "notification-page-linked-email-batch-body": "$2 $3 बाट {{GENDER:$1|जोडियो}}।",
+ "notification-reverted-email-subject2": "तपाईँको {{PLURAL:$3|सम्पादन |सम्पादनहरू}} {{SITENAME}} मा {{GENDER:$1|उल्ट्याइयो}}",
+ "notification-reverted-email-batch-body2": "तपाईँको {{PLURAL:$3|सम्पादन $2 मा |सम्पादन $2 मा}} $1 द्वारा {{GENDER:$1|उल्ट्याइयो}}।",
+ "notification-mention-email-subject": "$1 ले तपाईँलाई {{SITENAME}} मा {{GENDER:$1|उल्लेख गर्नुभयो}}",
+ "notification-mention-email-batch-body": "$1 ले तपाईँलाई $4 वार्ता पृष्ठमा \"$3\" मा {{GENDER:$1|उल्लेख गर्नुभयो}}।",
+ "notification-mention-nosection-email-batch-body": "$1 ले तपाईँलाई वार्ता पृष्ठमा $2 मा {{GENDER:$1|उल्लेख गर्नुभयो}}।",
+ "notification-user-rights-email-subject": "तपाईँको प्रयोगकर्ता अधिकारहरू {{SITENAME}} मा परिवर्तन भएका छन्।",
+ "notification-user-rights-email-batch-body": "तपाईँको प्रयोगकर्ता अधिकारहरू $1 द्वारा {{GENDER:$1|परिवर्तन गरियो}}। $2.",
+ "echo-email-subject-default": " {{SITENAME}} मा नयाँ सूचनाहरू",
+ "echo-email-body-default": "तपाईँका लागि {{SITENAME}} मा नयाँ सूचनाहरू छन्:\n\n$1",
+ "echo-email-batch-body-default": "तपाईँको लागि नयाँ सूचना छ ।",
+ "echo-email-footer-default": "$2\n\nहामीले तपाईँलाई कुन इमेलहरू पठाउने नियन्त्रण गर्न, आफ्नो प्राथमिकताहरू जाँच्नुहोस्:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "हामीले तपाईँलाई कुन इमेलहरू पठाउने नियन्त्रण गर्न, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">check your preferences</a>.<br />\n$1",
+ "echo-overlay-link": "सबै जानकारीहरु",
+ "echo-overlay-title": "<b>जानकारीहरू</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|जानकारीहरू}}</b> ($2 मध्येका $1 नहेरिएका जानकारीहरू )",
+ "echo-mark-all-as-read": "सबै पढिएको भनि चिनो लगाउने",
+ "echo-date-today": "आज",
+ "echo-date-yesterday": "हिजो",
+ "echo-load-more-error": "थप नतिजाहरू प्राप्त गर्दा त्रुटि हुन गयो ।",
+ "notification-edit-talk-page-bundle": "$1 र $3 {{PLURAL:$4|अन्य}} ले तपाईँको [[User talk:$2|वार्ता पृष्ठ]] मा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}}।",
+ "notification-page-linked-bundle": "$2 $3 र $4 अन्य {{PLURAL:$5|पृष्ठ|पृष्ठहरू}}बाट {{GENDER:$1|जोडियो}}। [[Special:WhatLinksHere/$2|यस पृष्ठसँग जोडिएका सबै हेर्नुहोस्]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 र $2 {{PLURAL:$3|अन्य}} ले तपाईँको वार्ता पृष्ठमा एउटा सन्देश {{GENDER:$1|छोड्नुभएको छ}}।",
+ "notification-page-linked-email-batch-bundle-body": "$2 $3 र $4 अन्य {{PLURAL:$5|पृष्ठ|पृष्ठहरू}} बाट {{GENDER:$1|जोडियो}}।",
+ "echo-email-batch-subject-daily": "तपाईँसँग {{SITENAME}} मा {{PLURAL:$2|नयाँ सूचना|नयाँ सूचनाहरू}} छ",
+ "echo-email-batch-subject-weekly": "तपाईँसँग {{SITENAME}} मा यो हप्ता {{PLURAL:$2|नयाँ सूचना|नयाँ सूचनाहरू}} छ",
+ "echo-email-batch-body-intro-daily": "नमस्ते $1,\nयहाँ तपाईँको लागि {{SITENAME}} मा आजको गतिविधिको एउटा सारांश छ।",
+ "echo-email-batch-body-intro-weekly": "नमस्ते $1,\nयहाँ तपाईँको लागि {{SITENAME}} मा यो हप्ताको गतिविधिको एउटा सारांश छ।",
+ "echo-email-batch-link-text-view-all-notifications": "सबै सूचनाहरू हेर्नुहोस्",
+ "echo-rev-deleted-text-view": "यो पृष्ठको पुनरावलोकन दबाइएको छ ।"
+}
diff --git a/Echo/i18n/nl-informal.json b/Echo/i18n/nl-informal.json
new file mode 100644
index 00000000..2a12dc1d
--- /dev/null
+++ b/Echo/i18n/nl-informal.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Siebrand"
+ ]
+ },
+ "tooltip-pt-notifications": "Jouw meldingen",
+ "echo-none": "Je hebt geen meldingen.",
+ "echo-email-body-default": "Je hebt een nieuwe melding op {{SITENAME}}:\n\n$1",
+ "echo-email-footer-default": "$2\n\nVolg de volgende koppeling om je e-mailvoorkeuren te wijzigen of om je uit te schrijven:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-batch-subject-daily": "Je hebt vandaag {{PLURAL:$2|0=geen meldingen|één melding|$1 meldingen}}",
+ "echo-email-batch-subject-weekly": "Je hebt deze week {{PLURAL:$2|0=geen meldingen|één melding|$1 meldingen}}"
+}
diff --git a/Echo/i18n/nl.json b/Echo/i18n/nl.json
new file mode 100644
index 00000000..81648d02
--- /dev/null
+++ b/Echo/i18n/nl.json
@@ -0,0 +1,129 @@
+{
+ "@metadata": {
+ "authors": [
+ "Edokter",
+ "Kippenvlees1",
+ "Mathonius",
+ "Nemo bis",
+ "Rcdeboer",
+ "Romaine",
+ "SPQRobin",
+ "Siebrand",
+ "Southparkfan",
+ "User555",
+ "Whaledad",
+ "JurgenNL",
+ "Sjoerddebruin",
+ "Mar(c)"
+ ]
+ },
+ "echo-desc": "Meldingensysteem",
+ "prefs-echo": "Meldingen",
+ "prefs-emailsettings": "E-mailinstellingen",
+ "prefs-displaynotifications": "Weergaveopties",
+ "prefs-echosubscriptions": "Informeer mij over deze gebeurtenissen",
+ "prefs-newmessageindicator": "Melding nieuwe berichten",
+ "echo-pref-send-me": "Wanneer verzenden:",
+ "echo-pref-send-to": "Verzenden naar:",
+ "echo-pref-email-format": "E-mailopmaak:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "U geen meldingen via e-mail sturen",
+ "echo-pref-email-frequency-immediately": "Individuele meldingen wanneer ze binnenkomen",
+ "echo-pref-email-frequency-daily": "Een dagelijkse samenvatting van meldingen",
+ "echo-pref-email-frequency-weekly": "Een wekelijkse samenvatting van meldingen",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Platte tekst",
+ "echo-pref-notify-show-link": "Meldingen weergeven in mijn werkbalk",
+ "echo-pref-new-message-indicator": "Overlegpaginaberichtenindicator in mijn werkbalk weergeven",
+ "echo-learn-more": "Meer lezen",
+ "echo-new-messages": "U heeft nieuwe berichten",
+ "echo-category-title-edit-user-talk": "Bericht{{PLURAL:$1||en}} op mijn overlegpagina",
+ "echo-category-title-article-linked": "Paginakoppeling{{PLURAL:$1||en}}",
+ "echo-category-title-reverted": "Bewerking{{PLURAL:$1||en}} teruggedraaid",
+ "echo-category-title-mention": "{{PLURAL:$1|Genoemd}}",
+ "echo-category-title-other": "{{PLURAL:$1|Overige}}",
+ "echo-category-title-system": "{{PLURAL:$1|Systeem}}",
+ "echo-category-title-user-rights": "Gebruikersrechtenwijziging{{PLURAL:$1||en}}",
+ "echo-pref-tooltip-edit-user-talk": "Informeer mij wanneer iemand een bericht of antwoord op mijn overlegpagina plaatst.",
+ "echo-pref-tooltip-article-linked": "Informeer mij wanneer iemand in een artikel een link aanbrengt naar een pagina die ik heb aangemaakt.",
+ "echo-pref-tooltip-reverted": "Informeer mij wanneer iemand een bewerking van mij terugdraait met behulp van \"ongedaan maken\" of \"terugdraaien\".",
+ "echo-pref-tooltip-mention": "Informeer mij wanneer iemand een koppeling naar mijn gebruikerspagina plaatst.",
+ "echo-pref-tooltip-user-rights": "Informeer mij wanneer iemand mijn gebruikersrechten wijzigt.",
+ "echo-no-agent": "[Niemand]",
+ "echo-no-title": "[Geen pagina]",
+ "echo-error-no-formatter": "Er is geen opmaak ingesteld voor deze melding.",
+ "echo-error-preference": "Fout: de gebruikersinstelling kon niet ingesteld worden",
+ "echo-error-token": "Fout: het gebruikerstoken kon niet opgehaald worden",
+ "notifications": "Meldingen",
+ "tooltip-pt-notifications": "Uw meldingen",
+ "echo-specialpage": "Meldingen",
+ "echo-anon": "[$1 Maak een gebruiker aan] of [$2 meld u aan] als u meldingen wilt ontvangen.",
+ "echo-none": "U hebt geen meldingen.",
+ "echo-more-info": "Meer info",
+ "echo-feedback": "Terugkoppeling",
+ "notification-link-text-view-message": "Bericht bekijken",
+ "notification-link-text-view-mention": "Vermelding bekijken",
+ "notification-link-text-view-changes": "Wijzigingen bekijken",
+ "notification-link-text-view-page": "Pagina bekijken",
+ "notification-link-text-view-edit": "Bewerking bekijken",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|heeft een bericht geplaatst}} op uw [[User talk:$2#$3|overlegpagina]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|heeft}} een bericht achtergelaten op uw overlegpagina in het onderwerp \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|heeft een bericht geplaatst}} op uw [[User talk:$2#$3|overlegpagina]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|heeft}} een bericht achtergelaten op uw overlegpagina onder het kopje \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] is {{GENDER:$1|gekoppeld}} vanaf [[:$3]]. [[Special:WhatLinksHere/$2|Alle koppelingen naar deze pagina bekijken]].",
+ "notification-page-linked-flyout": "[[:$2]] is {{GENDER:$1|gekoppeld}} vanaf [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|heeft gereageerd}} op \"[[$3|$2]]\" op de overlegpagina \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|heeft}} een nieuw onderwerp \"$2\" geplaatst op [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|heeft}} u een bericht gezonden: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|heeft gereageerd}} op \"[[$3#$2|$2]]\" op uw overlegpagina",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|heeft}} u genoemd op de overlegpagina van $5 onder \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|heeft}} u genoemd op de overlegpagina van $5 onder \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] heeft u {{GENDER:$1|genoemd}} op de [[:$3|overlegpagina van $2]].",
+ "notification-mention-nosection-flyout": "$1 heeft u {{GENDER:$1|genoemd}} op de [[:$3|overlegpagina van $2]].",
+ "notification-user-rights": "[[Special:Log/rights/$1|Uw gebruikersrechten]] zijn {{GENDER:$1|gewijzigd}} door [[User:$1|$1]]. $2. [[Special:ListGroupRights|Meer informatie]]",
+ "notification-user-rights-flyout": "Uw gebruikersrechten zijn {{GENDER:$1|gewijzigd}} door $1. $2. [[Special:ListGroupRights|Meer informatie]]",
+ "notification-user-rights-add": "U bent nu lid van deze groep{{PLURAL:$2||en}}: $1",
+ "notification-user-rights-remove": "U bent niet langer lid van deze groep{{PLURAL:$2||en}}: $1",
+ "notification-new-user": "Welkom op {{SITENAME}}, $1! We zijn blij dat u er bent.",
+ "notification-reverted2": "Uw {{PLURAL:$4|bewerking op [[:$2]] is|bewerkingen op [[:$2]] zijn}} {{GENDER:$1|teruggedraaid}} door [[User:$1|$1]]: $3",
+ "notification-reverted-flyout2": "Uw {{PLURAL:$4|bewerking op $2 is|bewerkingen op $2 zijn}} {{GENDER:$1|teruggedraaid}} door $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|heeft}} een bericht voor u achtergelaten op {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|heeft}} een bericht achtergelaten op uw overlegpagina:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|heeft}} een bericht achtergelaten op uw overlegpagina onder \"$2\".",
+ "notification-page-linked-email-subject": "Een pagina die u hebt aangemaakt is gekoppeld vanaf {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 is {{GENDER:$1|gekoppeld}} vanaf $3",
+ "notification-reverted-email-subject2": "Uw {{PLURAL:$3|bewerking op {{SITENAME}} is|bewerkingen op {{SITENAME}} zijn}} {{GENDER:$1|teruggedraaid}}",
+ "notification-reverted-email-batch-body2": "Uw {{PLURAL:$3|bewerking op $2 is|bewerkingen op $2 zijn}} {{GENDER:$1|teruggedraaid}} door $1",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|heeft}} u genoemd op {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|heeft}} u genoemd op de overlegpagina van $4 onder \"$3\"",
+ "notification-mention-nosection-email-batch-body": "$1 heeft u {{GENDER:$1|genoemd}} op de overlegpagina van $2.",
+ "notification-user-rights-email-subject": "Uw gebruikersrechten op {{SITENAME}} zijn gewijzigd",
+ "notification-user-rights-email-batch-body": "Uw gebruikersrechten zijn {{GENDER:$1|gewijzigd}} door $1. $2",
+ "echo-email-subject-default": "Nieuwe melding op {{SITENAME}}",
+ "echo-email-body-default": "U hebt een nieuwe melding op {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "U hebt een nieuwe melding",
+ "echo-email-footer-default": "$2\n\nVolg de volgende koppeling om te bepalen welke e-mails wij u zenden:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Ga naar <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">uw voorkeuren</a> om te bepalen welke e-mails wij u zenden.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Melding ($1)|Meldingen ($1)|100=Meldingen (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Bericht ($1)|Berichten ($1)|100=Berichten (99+)}}",
+ "echo-notification-alert-text-only": "Meldingen",
+ "echo-notification-message-text-only": "Berichten",
+ "echo-overlay-link": "Alle meldingen",
+ "echo-overlay-title": "<b>Meldingen</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Meldingen}}</b> ($1 van $2 ongelezen)",
+ "echo-mark-all-as-read": "Alles als gelezen markeren",
+ "echo-date-today": "Vandaag",
+ "echo-date-yesterday": "Gisteren",
+ "echo-load-more-error": "Er is een fout opgetreden tijdens het ophalen van meer resultaten.",
+ "notification-edit-talk-page-bundle": "$1 en $3 {{PLURAL:$4|andere|anderen}} hebben een bericht {{GENDER:$1|geplaatst}} op uw [[User talk:$2|overlegpagina]].",
+ "notification-page-linked-bundle": "$2 is {{GENDER:$1|gekoppeld}} vanaf $3 en $4 andere pagina{{PLURAL:$5||'s}}. [[Special:WhatLinksHere/$2|Alle koppelingen naar deze pagina bekijken]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 and $2 {{PLURAL:$3|andere gebruiker|andere gebruikers}} {{GENDER:$1|hebben}} een bericht op uw overlegpagina geplaatst",
+ "notification-page-linked-email-batch-bundle-body": "$2 is {{GENDER:$1|gekoppeld}} vanaf $3 en $4 andere pagina{{PLURAL:$5||'s}}",
+ "echo-email-batch-subject-daily": "U heeft vandaag {{PLURAL:$2|0=geen nieuwe meldingen|een nieuwe melding|nieuwe meldingen}} op {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "U heeft deze week {{PLURAL:$2|0=geen nieuwe meldingen|een nieuwe melding|nieuwe meldingen}} op {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Hallo $1,\nHier is een samenvatting voor u van de activiteiten van vandaag op {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Hallo $1,\nHier is een samenvatting voor u van de activiteiten van deze week op {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Alle mededelingen bekijken",
+ "echo-rev-deleted-text-view": "Deze paginaversie is onderdrukt."
+}
diff --git a/Echo/i18n/nn.json b/Echo/i18n/nn.json
new file mode 100644
index 00000000..a22c8a0a
--- /dev/null
+++ b/Echo/i18n/nn.json
@@ -0,0 +1,108 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Njardarlogar"
+ ]
+ },
+ "echo-desc": "Meldingssystem",
+ "prefs-echo": "Meldingar",
+ "prefs-emailsettings": "E-postval",
+ "prefs-displaynotifications": "Visingsval",
+ "prefs-echosubscriptions": "Meld meg om desse hendingane",
+ "prefs-newmessageindicator": "Ny melding-indikator",
+ "echo-pref-send-me": "Send meg:",
+ "echo-pref-send-to": "Send til:",
+ "echo-pref-email-format": "E-postformat",
+ "echo-pref-web": "Nett",
+ "echo-pref-email": "E-post",
+ "echo-pref-email-frequency-never": "Ikkje send meg e-postmeldingar",
+ "echo-pref-email-frequency-immediately": "Einkskilde meldingar etter kvart som dei kjem inn",
+ "echo-pref-email-frequency-daily": "Eit dagleg samandrag av meldingar",
+ "echo-pref-email-frequency-weekly": "Eit vekentleg samandrag av meldingar",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Rein tekst",
+ "echo-pref-notify-show-link": "Vis meldingar på verktøylina mi",
+ "echo-pref-new-message-indicator": "Vis indikatoren for diskusjonssidemeldingar på verktøylina mi",
+ "echo-learn-more": "Lær meir",
+ "echo-new-messages": "Du har nye meldingar",
+ "echo-category-title-edit-user-talk": "Diskusjonssidemelding{{PLURAL:$1||ar}}",
+ "echo-category-title-article-linked": "Sidelenkje{{PLURAL:$1||r}}",
+ "echo-category-title-reverted": "Attenderulling av endring{{PLURAL:$1||ar}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Omtale|Omtaler}}",
+ "echo-category-title-other": "{{PLURAL:$1|Anna}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-pref-tooltip-edit-user-talk": "Meld meg når nokon skriv ei melding eller svarar på diskusjonssida mi.",
+ "echo-pref-tooltip-article-linked": "Meld meg når nokon lenkjer frå ein artikkel til ei side eg har oppretta.",
+ "echo-pref-tooltip-reverted": "Meld meg når nokon fjernar ei endring eg gjorde ved bruk av angre- eller attenderullingsverktøyet.",
+ "echo-pref-tooltip-mention": "Meld meg når nokon lenkjer til brukarsida mi frå ei kva som helst diskusjonsside.",
+ "echo-no-agent": "[Ingen]",
+ "echo-no-title": "[Inga side]",
+ "echo-error-no-formatter": "Inga formatering definert for meldinga.",
+ "echo-error-preference": "Feil: kunne ikkje lagra brukarval.",
+ "echo-error-token": "Feil: kunne ikkje henta brukartoken.",
+ "notifications": "Meldingar",
+ "tooltip-pt-notifications": "Meldingane dine",
+ "echo-specialpage": "Meldingar",
+ "echo-anon": "For å få meldingar, [$1 opprett ein konto] eller [$2 logg inn].",
+ "echo-none": "Du har ingen meldingar.",
+ "echo-more-info": "Meir info",
+ "echo-feedback": "Attendemelding",
+ "notification-link-text-view-message": "Sjå melding",
+ "notification-link-text-view-mention": "Sjå omtale",
+ "notification-link-text-view-changes": "Sjå endringar",
+ "notification-link-text-view-page": "Sjå side",
+ "notification-link-text-view-edit": "Sjå endring",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|la att}} ei melding på [[User talk:$2#$3|diskusjonssida]] di.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|la att}} ei melding på diskusjonssida di under bolken «[[User talk:$2#$3|$4]]».",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|la att}} ei melding på [[User talk:$2#$3|diskusjonssida]] di.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|la att}} ei melding på diskusjonssida di under bolken «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "[[:$2]] vart {{GENDER:$1|lenkja}} til frå [[:$3]]. [[Special:WhatLinksHere/$2|Sjå alle lenkjene til sida]].",
+ "notification-page-linked-flyout": "[[:$2]] vart {{GENDER:$1|lenkja}} til frå [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|kommenterte}} emnet «[[$3|$2]]» på diskusjonssida «$4».",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|la inn}} det nye emnet «$2» på [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|sende}} deg ei melding: «[[$3#$2|$2]]».",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|kommenterte}} emnet «[[$3#$2|$2]]» på diskusjonssida di.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|nemnde}} deg på diskusjonssida til $5 under bolken «[[:$3#$2|$4]]».",
+ "notification-mention-flyout": "$1 {{GENDER:$1|nemnde}} deg på diskusjonssida til $5 under bolken «[[:$3#$2|$4]]».",
+ "notification-user-rights": "Brukarrettane dine [[Special:Log/rights/$1|vart {{GENDER:$1|endra}}]] av [[User:$1|$1]]. $2. [[Special:ListGroupRights|Lær meir]]",
+ "notification-user-rights-flyout": "Brukarrettane dine vart {{GENDER:$1|endra}} av $1. $2. [[Special:ListGroupRights|Lær meir]]",
+ "notification-user-rights-add": "Du er no ein medlem av {{PLURAL:$2|denne gruppa|desse gruppene}}: $1",
+ "notification-user-rights-remove": "Du er ikkje lenger medlem av {{PLURAL:$2|denne gruppa|desse gruppene}}: $1",
+ "notification-new-user": "Velkomen til {{SITENAME}}, $1! Me er glade for at du er her.",
+ "notification-reverted2": "{{PLURAL:$4|Endringa di|Endringane dine}} på [[:$2]] vart {{GENDER:$1|fjerna}} av [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Endringa di|Endringane dine}} på $2 vart {{GENDER:$1|fjerna}} av $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|la att}} ei melding til deg på {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|la att}} ei melding på diskusjonssida di:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|la att}} ei melding på diskusjonssida di under «$2».",
+ "notification-page-linked-email-subject": "Sida di vart lenkja til på {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 vart {{GENDER:$1|lenkja til}} frå $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Endringa di|Endringane dine}} vart {{GENDER:$1|fjerna}} på {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Endringa di|Endringane dine}} på $2 vart {{GENDER:$1|fjerna}} av $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|nemnde}} deg på {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|nemnde}} deg på diskusjonssida til $4 under bolken «$3».",
+ "notification-user-rights-email-subject": "Brukarrettane dine har endra seg på {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Brukarrettane dine vart {{GENDER:$1|endra}} av $1. $2.",
+ "echo-email-subject-default": "Ny melding på {{SITENAME}}",
+ "echo-email-body-default": "Du har ei ny melding på {{SITENAME}}: $1",
+ "echo-email-batch-body-default": "Du har ei ny melding.",
+ "echo-email-footer-default": "$2\n\nFor å styra kva for e-postar me sender til deg, sjå til innstillingane dine:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "For å styra kva for e-postar me sender til deg, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">sjå til innstillingane dine</a>.<br />\n$1",
+ "echo-overlay-link": "Alle meldingar",
+ "echo-overlay-title": "<b>Meldingar</b>",
+ "echo-overlay-title-overflow": "<b>Meldingar</b> (viser $1 av $2 ulesne)",
+ "echo-mark-all-as-read": "Merk alle som lesne",
+ "echo-date-today": "I dag",
+ "echo-date-yesterday": "I går",
+ "echo-load-more-error": "Det oppstod ein feil under henting av fleire resultat.",
+ "notification-edit-talk-page-bundle": "$1 og {{PLURAL:$4|ein annan|$3 andre}} {{GENDER:$1|la att}} ei melding til deg på [[User talk:$2|diskusjonssida]] di.",
+ "notification-page-linked-bundle": "$2 vart {{GENDER:$1|lenkja til}} frå $3 og {{PLURAL:$5|ei anna side|$4 andre sider}}. [[Special:WhatLinksHere/$2|Sjå alle lenkjene til sida]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 og {{PLURAL:$3|ein annan|$2 andre}} {{GENDER:$1|la att}} ei melding på diskusjonssida di.",
+ "notification-page-linked-email-batch-bundle-body": "$2 vart {{GENDER:$1|lenkja til}} frå $3 og {{PLURAL:$5|ei anna side|$4 andre sider}}.",
+ "echo-email-batch-subject-daily": "Du har {{PLURAL:$2|ei ny melding|nye meldingar}} på {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Du har {{PLURAL:$2|ei ny melding|nye meldingar}} på {{SITENAME}} denne veka",
+ "echo-email-batch-body-intro-daily": "Hei $1.\nHer er eit samandrag av aktiviteten i dag på {{SITENAME}} for deg.",
+ "echo-email-batch-body-intro-weekly": "Hei $1.\nHer er eit samandrag av aktiviteten denne veka på {{SITENAME}} for deg.",
+ "echo-email-batch-link-text-view-all-notifications": "Sjå alle meldingane",
+ "echo-rev-deleted-text-view": "Denne sideversjonen er vorten løynd."
+}
diff --git a/Echo/i18n/oc.json b/Echo/i18n/oc.json
new file mode 100644
index 00000000..4723cb23
--- /dev/null
+++ b/Echo/i18n/oc.json
@@ -0,0 +1,107 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cedric31"
+ ]
+ },
+ "echo-desc": "Sistèma de notificacions",
+ "prefs-echo": "Notificacions",
+ "prefs-emailsettings": "Opcions del corrièr electronic",
+ "prefs-displaynotifications": "Opcions d'afichatge",
+ "prefs-echosubscriptions": "M'avisar d'aqueles eveniments",
+ "prefs-newmessageindicator": "Indicador de messatge novèl",
+ "echo-pref-send-me": "Me mandar :",
+ "echo-pref-send-to": "Mandar a :",
+ "echo-pref-email-format": "Format de corrièr electronic :",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Corrièr electronic",
+ "echo-pref-email-frequency-never": "Me mandar pas cap de notificacion per corrièr electronic",
+ "echo-pref-email-frequency-immediately": "Notificacions individualas al fial de l'aiga",
+ "echo-pref-email-frequency-daily": "Un resumit quotidian de las notificacions",
+ "echo-pref-email-frequency-weekly": "Un resumit setmanièr de las notificacions",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Tèxte brut",
+ "echo-pref-notify-show-link": "Afichar las notificacions dins ma barra d'aisinas",
+ "echo-pref-new-message-indicator": "Afichar l’indicador de messatge sus la pagina de discussion dins ma barra d’aisinas",
+ "echo-learn-more": "Ne saber mai",
+ "echo-new-messages": "Avètz de messatges novèls",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Messatge|Messatges}} de la pagina de discussion",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Article ligat|Articles ligats}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Modificacion anullada|Modificacions anulladas}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Mencion|Mencions}}",
+ "echo-category-title-other": "{{PLURAL:$1|Autres}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistèma}}",
+ "echo-pref-tooltip-edit-user-talk": "M'avisar quand qualqu’un publica un messatge o respond sus ma pagina de discussion.",
+ "echo-pref-tooltip-article-linked": "M'avisar quand qualqu’un fa referéncia a una pagina qu’ai creada a partir d’una pagina d’article.",
+ "echo-pref-tooltip-reverted": "M'avisar quand qualqu’un anulla una modificacion qu’ai facha, en utilizant l’aisina anullacion o retorn arrièr",
+ "echo-pref-tooltip-mention": "M'avisar quand qualqu’un fa referéncia a ma pagina d'utilizaire.",
+ "echo-no-agent": "[Pas degun]",
+ "echo-no-title": "[Pas cap de pagina]",
+ "echo-error-no-formatter": "Cap de mesa en forma pas definida per la notificacion",
+ "echo-error-preference": "Error : Impossible de definir la preferéncia d'utilizaire",
+ "echo-error-token": "Error : Impossible de recuperar lo geton de l’utilizaire",
+ "notifications": "Notificacions",
+ "tooltip-pt-notifications": "Vòstras notificacions",
+ "echo-specialpage": "Notificacions",
+ "echo-anon": "Per recebre de notificacions, [$1 creatz un compte] o [$2 connectatz-vos].",
+ "echo-none": "Avètz pas recebut cap de notificacion.",
+ "echo-more-info": "Mai d'informacion",
+ "echo-feedback": "Vejaires",
+ "notification-link-text-view-message": "Afichar lo messatge",
+ "notification-link-text-view-mention": "Afichar la mencion",
+ "notification-link-text-view-changes": "Afichar las modificacions",
+ "notification-link-text-view-page": "Afichar la pagina",
+ "notification-link-text-view-edit": "Afichar la modificacion",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|a daissat}} un messatge sus vòstra [[User talk:$2#$3|pagina de discussion]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] a daissat un messatge sus vòstra pagina de discussion dins la [[User talk:$2#$3|seccion ''$4'']].",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|a daissat}} un messatge sus vòstra [[User talk:$2#$3|pagina de discussion]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 a daissat un messatge sus vòstra pagina de discussion dins la [[User talk:$2#$3|seccion ''$4'']].",
+ "notification-page-linked": "[[:$2]] es estat {{GENDER:$1|referenciat}} dempuèi [[:$3]]. [[Special:WhatLinksHere/$2|Veire totes los ligams cap a aquesta pagina]].",
+ "notification-page-linked-flyout": "[[:$2]] es estat {{GENDER:$1|referenciat}} dempuèi [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|a fach un comentari}} dins « [[$3|$2]] » sus la pagina de discussion « $4 »",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|a publicat}} un subjècte novèl \"$2\" sus [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vos {{GENDER:$1|a mandat}} un messatge : \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|a fach un comentari}} dins ''[[$3#$2|$2]]'' sus vòstra pagina de discussion",
+ "notification-mention": "[[User:$1|$1]] vos {{GENDER:$1|a mencionat|a mencionada}} sus la pagina de discussion de $5 dins la [[:$3#$2|seccion ''$4'']].",
+ "notification-mention-flyout": "$1 vos {{GENDER:$1|a mencionat|a mencionada}} sus la pagina de discussion de $5 dins la [[:$3#$2|seccion ''$4'']].",
+ "notification-user-rights": "Vòstres dreches d’utilizaire [[Special:Log/rights/$1|son estats {{GENDER:$1|modificats}}]] per [[User:$1|$1]]. $2. [[Special:ListGroupRights|Ne saber mai]]",
+ "notification-user-rights-flyout": "Vòstres dreches d’utilizaire {{GENDER:$1|son estats modificats}} per $1. $2. [[Special:ListGroupRights|Ne saber mai]]",
+ "notification-user-rights-add": "Ara sètz membre d'{{PLURAL:$2|aqueste grop|aquestes gropes}} : $1",
+ "notification-user-rights-remove": "Sètz pas mai membre d'{{PLURAL:$2|aqueste grop|aquestes gropes}} : $1",
+ "notification-new-user": "Benvenguda sus {{SITENAME}}, $1 ! Sèm uroses de vos veire aicí.",
+ "notification-reverted2": "{{PLURAL:$4|Vòstra modificacion sus [[:$2]] es estada|Vòstras modificacions sus [[:$2]] son estadas}} {{GENDER:$1|anullada}}{{PLURAL:$4||s}} per [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Vòstra modificacion sus $2 es estada|Vòstras modificacions sus $2 son estadas}} {{GENDER:$1|anullada}}{{PLURAL:$4||s}} per $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|a daissat}} un messatge sus vòstra pagina de discussion sus {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|a daissat}} un messatge sus vòstra pagina de discussion :",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 a daissat un messatge sus vòstra pagina de discussion dins ''$2''.",
+ "notification-page-linked-email-subject": "Vòstra pagina es estada referenciada sus {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 es estat {{GENDER:$1|referenciat}} dempuèi $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Vòstra modificacion es estada anullada|Vòstras modificacions son estadas anulladas}} {{GENDER:$1|}} sus {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Vòstra modification sus $2 es estada anullada|Vòstras modificacions sus $2 son estadas anulladas}} {{GENDER:$1|}} per $1",
+ "notification-mention-email-subject": "$1 vos {{GENDER:$1|a mencionat|a mencionada}} sus {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 vos {{GENDER:$1|a mencionat|a mencionada}} sus la pagina de discussion de $4 dins ''$3''.",
+ "notification-user-rights-email-subject": "Vòstres dreches d’utilizaire son estats modificats sus {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Vòstres dreches d’utilizaire {{GENDER:$1|son estats modificats}} per $1. $2",
+ "echo-email-subject-default": "Novèla notificacion sus {{SITENAME}}",
+ "echo-email-body-default": "Avètz una novèla notificacion sus {{SITENAME}} :\n\n$1",
+ "echo-email-batch-body-default": "Avètz una novèla notificacion",
+ "echo-email-footer-default": "$2\n\nPer verificar quines corrièrs electronics vos mandam, anatz dins vòstras preferéncias :\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Per contrarotlar los corrièrs electronics que vos mandam, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">verificatz vòstras preferéncias</a><br />\n$1",
+ "echo-overlay-link": "Totas las notificacions",
+ "echo-overlay-title": "<b>Notificacions</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notificacion|Notificacions}}</b> ($1 sus $2 {{PLURAL:$1|pas legida d'afichada|pas legidas d'afichadas}})",
+ "echo-mark-all-as-read": "Marcar tot coma legit",
+ "echo-date-today": "Uèi",
+ "echo-date-yesterday": "Ièr",
+ "echo-load-more-error": "Una error s'es producha en analisant mai de resultats.",
+ "notification-edit-talk-page-bundle": "$1 e $3 {{PLURAL:$4|autre|autres}} {{GENDER:$1|an daissat}} un messatge sus vòstra [[User talk:$2|pagina de discussion]].",
+ "notification-page-linked-bundle": "$2 es estat {{GENDER:$1|referenciat}} dempuèi $3 e $4 {{PLURAL:$5|autra pagina|autras paginas}}. [[Special:WhatLinksHere/$2|Veire totes los ligams cap a aquesta pagina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e $2 {{PLURAL:$3|autre|autres}} an {{GENDER:$1|daissat}} un messatge sus vòstra pagina de discussion.",
+ "notification-page-linked-email-batch-bundle-body": "$2 a été {{GENDER:$1|ligat}} dempuèi $3 e $4 {{PLURAL:$5|autra pagina|autras paginas}}",
+ "echo-email-batch-subject-daily": "Avètz {{PLURAL:$2|una novèla notificacion|de novèlas notificacions}} uèi sus {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Avètz {{PLURAL:$2|una novèla notificacion|de novèlas notificacions}} sus {{SITENAME}} aquesta setmana",
+ "echo-email-batch-body-intro-daily": "Bonjorn $1,\nAquí per vos un resumit de l’activitat d’uèi sus {{SITENAME}}",
+ "echo-email-batch-body-intro-weekly": "Bonjorn $1,\nAquí per vos un resumit de l’activitat de la setmana sus {{SITENAME}}",
+ "echo-email-batch-link-text-view-all-notifications": "Veire totas las notificacions",
+ "echo-rev-deleted-text-view": "Aquesta revision de pagina es estada suprimida"
+}
diff --git a/Echo/i18n/or.json b/Echo/i18n/or.json
new file mode 100644
index 00000000..0ed9a548
--- /dev/null
+++ b/Echo/i18n/or.json
@@ -0,0 +1,69 @@
+{
+ "@metadata": {
+ "authors": [
+ "MKar",
+ "Psubhashish"
+ ]
+ },
+ "echo-desc": "ସୂଚନା ପ୍ରଣାଳି",
+ "prefs-echo": "ସୂଚନା ସମୂହ",
+ "prefs-emailsettings": "ଇମେଲ ବିକଳ୍ପ",
+ "prefs-displaynotifications": "ଦେଖଣା ବିକଳ୍ପ",
+ "prefs-echosubscriptions": "ଏହି ଘଟଣା ସଂପର୍କରେ ମତେ ସୂଚନା ଦିଅନ୍ତୁ",
+ "prefs-newmessageindicator": "ନୂଆ ବାର୍ତ୍ତା ସୂଚକ",
+ "echo-pref-send-me": "ମୋ ପାଖକୁ ପଠାନ୍ତୁ",
+ "echo-pref-send-to": "ଏହାଙ୍କ ପାଖକୁ ପଠାନ୍ତୁ",
+ "echo-pref-email-format": "ଇମେଲ ଶୈଳୀ",
+ "echo-pref-web": "ୱେବ",
+ "echo-pref-email": "ଇ-ମେଲ",
+ "echo-pref-email-frequency-never": "ମୋ ପାଖକୁ କୌଣସି ଇ-ମେଲ ସୂଚନା ପଠାନ୍ତୁ ନାହିଁ",
+ "echo-pref-email-frequency-immediately": "ପ୍ରତ୍ୟେକ ସୂଚନା ଅସିବା ମତେ",
+ "echo-pref-email-frequency-daily": "ସୂଚନାର ଦୈନିକ ସାରମର୍ମ",
+ "echo-pref-email-frequency-weekly": "ସୂଚନାର ସାପ୍ତାହିକ ସାରମର୍ମ",
+ "echo-pref-email-format-html": "ଏଚଟିଏମଏଲ",
+ "echo-pref-email-format-plain-text": "ସାଦା ଲେଖା",
+ "echo-pref-notify-show-link": "ମୋ ଟୁଲବାରରେ ସୂଚନା ସବୁ ଦେଖାନ୍ତୁ",
+ "echo-pref-new-message-indicator": "ମୋ ଟୁଲବାରରେ ଆଲୋଚନା ପୃଷ୍ଠା ବାର୍ତ୍ତ ସୂଚକ ଦେଖାନ୍ତୁ",
+ "echo-learn-more": "ଅଧିକ ଶିଖନ୍ତୁ",
+ "echo-new-messages": "ଆପଣଙ୍କ ପାଇଁ ଏକ ନୂଆ ବାର୍ତ୍ତା ଅଛି",
+ "echo-category-title-edit-user-talk": "ଆଲୋଚନା ପୃଷ୍ଠା {{PLURAL:$1|ବାର୍ତ୍ତା|ଏକାଧିକ ବାର୍ତ୍ତା}}",
+ "echo-category-title-article-linked": "ପୃଷ୍ଠା {{PLURAL:$1|ଲିଙ୍କ|ଏକାଧିକ ଲିଙ୍କ}}",
+ "echo-category-title-reverted": "ସଂପାଦନା {{PLURAL:$1|ପଶ୍ଚାତକରଣ|ଏକାଧିକ ପଶ୍ଚାତକରଣ}}",
+ "echo-category-title-other": "{{PLURAL:$1|ଅନ୍ୟାନ୍ୟ}}",
+ "echo-category-title-system": "{{PLURAL:$1|ସିଷ୍ଟମ}}",
+ "echo-pref-tooltip-edit-user-talk": "ମୋ ଆଲୋଚନା ପୃଷ୍ଠାରେ କେହି ବାର୍ତ୍ତା ପଠାଇଲେ କିମ୍ବା ଉତ୍ତର ଦେଲେ ମୋତେ ସୂଚିତ କରନ୍ତୁ",
+ "echo-pref-tooltip-article-linked": "ମୁଁ ତିଆରି କରିଥିବା ପୃଷ୍ଠାକୁ କେହି ପ୍ରସଙ୍ଗ ପୃଷ୍ଠାରେ ସଂଯୋଗ କଲେ ମୋତେ ସୂଚିତ କରନ୍ତୁ",
+ "echo-pref-tooltip-reverted": "ମୋର ସଂପାଦନାକୁ କେହି ରୋଲବ୍ୟାକ ଟୁଲ ବା ପଛକୁ ଫେରାଇବା ଟୁଲ ବ୍ୟବହାର କରି ପଶ୍ଚାତକରଣ କଲେ ମୋତେ ସୂଚନା ଦିଅନ୍ତୁ",
+ "echo-pref-tooltip-mention": "ମୋର ବ୍ୟବହାରକାରୀ ପୃଷ୍ଠାକୁ କେହି ଜଣେ କୌଣସି ଆଲୋଚନା ପୃଷ୍ଠାରୁ ସଂଯୋଗ କଲେ ମୋତେ ସୂଚୀତ କରନ୍ତୁ",
+ "echo-no-agent": "[କେହି ନୁହେଁ]",
+ "echo-no-title": "[କୌଣସି ପୃଷ୍ଠା ନାହିଁ]",
+ "echo-error-no-formatter": "ସୂଚନା ନିମନ୍ତେ କୌଣସି ନିର୍ଦ୍ଦିଷ୍ଟ ଶୈଳୀ ନାହିଁ",
+ "echo-error-preference": "ତୃଟି:ବ୍ୟବହାରକାରୀ ପସନ୍ଦ ସ୍ଥାପନ କରାଯାଇପାରିଲା ନାହିଁ",
+ "echo-error-token": "ତୃଟି:ବ୍ୟବହାରକାରୀ ଟୋକନ ଅଣାଯାଇ ପାରିଲା ନାହିଁ",
+ "notifications": "ସୂଚନା",
+ "tooltip-pt-notifications": "ଆପଣଙ୍କ ପାଇଁ ସୂଚନା",
+ "echo-specialpage": "ସୂଚନା",
+ "echo-anon": "ସୂଚନା ପ୍ରାପ୍ତି ନିମନ୍ତେ, [$1 ନୂଆ ଖାତା ଖୋଲନ୍ତୁ] କିମ୍ବା [$2 ଲଗ ଇନ କରନ୍ତୁ].",
+ "echo-none": "ଆପଣଙ୍କ ନିମନ୍ତେ କୌଣସି ସୂଚନା ନାହିଁ",
+ "echo-more-info": "ଅଧିକ ତଥ୍ୟ",
+ "echo-feedback": "ମତାମତ",
+ "notification-link-text-view-message": "ବାର୍ତ୍ତା ଦେଖନ୍ତୁ",
+ "notification-link-text-view-mention": "ସୂଚିତ ହୋଇଥିବା ପୃଷ୍ଠା ଦେଖନ୍ତୁ",
+ "notification-link-text-view-changes": "ସମସ୍ତ ବଦଳ ଦେଖନ୍ତୁ",
+ "notification-link-text-view-page": "ପୃଷ୍ଠା ଦେଖନ୍ତୁ",
+ "notification-link-text-view-edit": "ସମ୍ପାଦନା ଦେଖନ୍ତୁ",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|left}} ଆପଣଙ୍କ ପାଇଁ ଗୋଟିଏ ବାର୍ତ୍ତ ଅଛି [[User talk:$2#$3|ଆଲୋଚନା ପୃଷ୍ଠାରେ]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|left}} ଆପଣଙ୍କ ପାଇଁ ଗୋଟିଏ ବାର୍ତ୍ତା ଅଛି ଆପଣଙ୍କ ଆଲୋଚନା ପୃଷ୍ଠାରେ \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|left}} ଗୋଟିଏ ବାର୍ତ୍ତ ଆପଣଙ୍କ [[User talk:$2#$3|ଆଲୋଚନା ପୃଷ୍ଠା]]ରେ.",
+ "echo-overlay-link": "ସମସ୍ତ ସୂଚନା",
+ "echo-overlay-title": "<b>ସୂଚନାବଳୀ</b>",
+ "echo-mark-all-as-read": "ସବୁ ପଢ଼ା ସରିଛି ବୋଲି ଚିହ୍ନ ଦିଅନ୍ତୁ",
+ "echo-date-today": "ଆଜି",
+ "echo-date-yesterday": "ଗତ କାଲି",
+ "echo-load-more-error": "ଅଧିକ ଫଳଗୁଡ଼ିକୁ ଖୋଜୁଥିବା ବେଳେ କିଛିଗୋଟେ ଅସୁବିଧା ହେଲା ।",
+ "echo-email-batch-subject-weekly": "ଆପଣଙ୍କ ପାଇଁ {{SITENAME}}ରେ ଚଳିତ ସପ୍ତାହର {{PLURAL:$2|ଗୋଟିଏ ନୂଆ ବାର୍ତ୍ତ|ଏକାଧିକ ନୂଆ ବାର୍ତ୍ତା}} ଅଛି",
+ "echo-email-batch-body-intro-daily": "ନମସ୍କାର $1,\nଆପଣଙ୍କ ପାଇଁ ଏହା ହେଉଛି {{SITENAME}}ରେ ଚଳିତ ସପ୍ତାହର କାର୍ଯ୍ୟାବଳୀର ସାରମର୍ମ",
+ "echo-email-batch-body-intro-weekly": "ନମସ୍କାର $1,\nଆପଣଙ୍କ ପାଇଁ ଏହା ହେଉଛି {{SITENAME}}ରେ ଏହି ସପ୍ତାହର କାର୍ଯ୍ୟାବଳୀର ସାରମର୍ମ",
+ "echo-email-batch-link-text-view-all-notifications": "ସମସ୍ତ ସୂଚନା ଦେଖନ୍ତୁ",
+ "echo-rev-deleted-text-view": "ଏହି ପୃଷ୍ଠାର ପୁନରାବୃତି ଇତିହାସ ଉହ୍ୟ କରିଦିଆଯାଇଛି"
+}
diff --git a/Echo/i18n/pa.json b/Echo/i18n/pa.json
new file mode 100644
index 00000000..6ecacdcd
--- /dev/null
+++ b/Echo/i18n/pa.json
@@ -0,0 +1,110 @@
+{
+ "@metadata": {
+ "authors": [
+ "Satdeep gill",
+ "Babanwalia"
+ ]
+ },
+ "echo-desc": "ਸੂਚਨਾ ਪ੍ਰਣਾਲੀ",
+ "prefs-echo": "ਸੂਚਨਾਵਾਂ",
+ "prefs-emailsettings": "ਈ-ਮੇਲ ਆਪਸ਼ਨ",
+ "prefs-displaynotifications": "ਪ੍ਰਗਟਾਓ ਆਪਸ਼ਨ",
+ "prefs-echosubscriptions": "ਮੈਨੂੰ ਇਸ ਤਰ੍ਹਾਂ ਦੇ ਸਬੱਬਾਂ ਬਾਰੇ ਨੋਟੀਫਾਈ ਕਰੋ",
+ "prefs-newmessageindicator": "ਨਵਾਂ ਸੁਨੇਹਾ ਸੂਚਕ",
+ "echo-pref-send-me": "ਮੈਨੂੰ ਭੇਜੋ:",
+ "echo-pref-send-to": "ਭੇਜੋ:",
+ "echo-pref-email-format": "ਈ-ਮੇਲ ਫਾਰਮੈਟ",
+ "echo-pref-web": "ਵੈੱਬ",
+ "echo-pref-email": "ਈ-ਮੇਲ",
+ "echo-pref-email-frequency-never": "ਮੈਨੂੰ ਈ-ਮੇਲ ਸੂਚਨਾਵਾਂ ਨਾ ਭੇਜੋ",
+ "echo-pref-email-frequency-immediately": "ਖਾਸ ਸੂਚਨਾਵਾਂ ਜਿਵੇਂ ਉਹ ਆਈਆਂ",
+ "echo-pref-email-frequency-daily": "ਸੂਚਨਾਵਾਂ ਦਾ ਰੋਜ਼ਾਨਾ ਸਾਰ",
+ "echo-pref-email-frequency-weekly": "ਸੂਚਨਾਵਾਂ ਦਾ ਹਫਤਾਵਰ ਸਾਰ",
+ "echo-pref-email-format-html": "ਐਚ.ਟੀ.ਮੈਲ.ਐਲ.",
+ "echo-pref-email-format-plain-text": "ਸਰਲ ਟੈਕਸਟ",
+ "echo-pref-notify-show-link": "ਮੇਰੀ ਟੂਲਬਾਰ ਵਿੱਚ ਸੂਚਨਾਵਾਂ ਵਿਖਾਓ",
+ "echo-pref-new-message-indicator": "ਮੇਰੀ ਟੂਲਬਾਰ ਵਿੱਚ ਗੱਲ-ਬਾਤ ਪੰਨਾ ਸੂਚਕ ਵਿਖਾਓ",
+ "echo-learn-more": "ਹੋਰ ਜਾਣੋ",
+ "echo-new-messages": "ਤੁਹਾਡੇ ਲਈ ਨਵੇਂ ਸੁਨੇਹੇ ਹਨ।",
+ "echo-category-title-edit-user-talk": "ਗੱਲ-ਬਾਤ ਪੰਨਾ {{PLURAL:$1|ਸੁਨੇਹਾ|ਸੁਨੇਹੇ}}",
+ "echo-category-title-article-linked": "ਪੰਨਾ {{PLURAL:$1|ਲਿੰਕ}}",
+ "echo-category-title-reverted": "ਸੋਧ {{PLURAL:$1|ਰੱਦ ਕੀਤਾ|ਰੱਦ ਕੀਤੇ}}",
+ "echo-category-title-mention": "{{PLURAL:$1|ਜ਼ਿਕਰ}}",
+ "echo-category-title-other": "{{PLURAL:$1|ਹੋਰ}}",
+ "echo-category-title-system": "{{PLURAL:$1|ਪ੍ਰਣਾਲੀ}}",
+ "echo-pref-tooltip-edit-user-talk": "ਜਦ ਕੋਈ ਮੇਰੇ ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਉੱਤੇ ਸੁਨੇਹਾ ਲਿਖੇ ਜਾਂ ਕਿਸੇ ਸੁਨੇਹੇ ਦਾ ਜਵਾਬ ਦੇਵੇ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਦਿਉ।",
+ "echo-pref-tooltip-article-linked": "ਜਦ ਕੋਈ ਉਸ ਪੰਨੇ ਨਾਲ ਜੁੜਦਾ ਹੈ ਜੋ ਮੈਂ ਕਿਸੇ ਲੇਖ ਦੇ ਪੰਨੇ ਤੋਂ ਬਣਾਇਆ ਸੀ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਦੇਵੋ।",
+ "echo-pref-tooltip-reverted": "ਜਦ ਕੋਈ ਮੇਰੀ ਕੀਤੀ ਸੋਧ ਨੂੰ, ਕੋਈ ਟੂਲ ਵਰਤ ਕੇ ਰੱਦ ਕਰ ਦਿੰਦਾ ਹੈ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਦੇਵੋ।",
+ "echo-pref-tooltip-mention": "ਜਦ ਕੋਈ ਕਿਸੇ ਗੱਲ-ਬਾਤ ਪੰਨੇ ਤੋਂ ਮੇਰੇ ਵਰਤੋਂਕਾਰ ਪੰਨੇ ਤੇ ਜੁੜਦਾ ਹੈ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਦੇਵੋ।",
+ "echo-no-agent": "[ਕੋਈ ਨਹੀਂ]",
+ "echo-no-title": "[ਕੋਈ ਪੰਨਾ ਨਹੀਂ]",
+ "echo-error-no-formatter": "ਸੂਚਨਾ ਲਈ ਕੋਈ ਫਾਰਮੈਟ ਨਹੀਂ ਹੈ।",
+ "echo-error-preference": "ਭੁੱਲ: ਵਰਤੋਂਕਾਰ ਤਰਜੀਹ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ।",
+ "echo-error-token": "ਭੁੱਲ: ਵਰਤੋਂਕਾਰ ਪਛਾਣ ਲੱਭੀ ਨਹੀਂ ਜਾ ਸਕੀ।",
+ "notifications": "ਸੂਚਨਾਵਾਂ",
+ "tooltip-pt-notifications": "ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ",
+ "echo-specialpage": "ਸੂਚਨਾਵਾਂ",
+ "echo-anon": "ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, [$1 ਖਾਤਾ ਬਣਾਉ] ਜਾਂ [$2 ਲਾਗ ਇਨ ਕਰੋ]।",
+ "echo-none": "ਤੁਹਾਡੇ ਲਈ ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ ਹੈ।",
+ "echo-more-info": "ਹੋਰ ਜਾਣਕਾਰੀ",
+ "echo-feedback": "ਫ਼ੀਡਬੈਕ",
+ "notification-link-text-view-message": "ਸੁਨੇਹਾ ਵੇਖੋ",
+ "notification-link-text-view-mention": "ਜ਼ਿਕਰ ਦੇਖੋ",
+ "notification-link-text-view-changes": "ਤਬਦੀਲੀਆਂ ਵੇਖੋ",
+ "notification-link-text-view-page": "ਪੰਨਾ ਦੇਖੋ",
+ "notification-link-text-view-edit": "ਸੋਧ ਦੇਖੋ",
+ "notification-edit-talk-page2": "[[User:$1|$1]] ਨੇ ਤੁਹਾਡੇ [[User talk:$2#$3|ਗੱਲ-ਬਾਤ ਸਫ਼ੇ]] 'ਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ}} ਹੈ।",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] ਨੇ \"[[User talk:$2#$3|$4]]\" ਵਿਚਲੇ ਤੁਹਾਡੇ ਗੱਲ-ਬਾਤ ਸਫ਼ੇ 'ਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ}} ਹੈ।",
+ "notification-edit-talk-page-flyout2": "$1 ਨੇ ਤੁਹਾਡੇ [[User talk:$2#$3|ਗੱਲਬਾਤ ਸਫ਼ੇ]] ਉੱਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ ਹੈ}}।",
+ "notification-edit-talk-page-flyout-with-section": "$1 ਨੇ \"[[User talk:$2#$3|$4]]\" ਵਿਚਲੇ ਤੁਹਾਡੇ ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਉੱਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ ਹੈ}}।",
+ "notification-page-linked": "[[:$2]] ਨੂੰ [[:$3]] ਤੋਂ {{GENDER:$1|ਜੋੜਿਆ}} ਸੀ। [[Special:WhatLinksHere/$2|ਇਸ ਪੰਨੇ ਨਾਲ ਜੁੜਦੇ ਸਾਰੇ ਲਿੰਕ ਵੇਖੋ]]।",
+ "notification-page-linked-flyout": "[[:$2]] ਨੂੰ [[:$3]] ਤੋਂ {{GENDER:$1|ਜੋੜਿਆ}} ਸੀ।",
+ "notification-add-comment2": "[[User:$1|$1]] ਨੇ \"$4\" ਗੱਲ-ਬਾਤ ਪੰਨੇ ਉੱਤੇ \"[[$3|$2]]\" ਉੱਤੇ {{GENDER:$1|ਟਿੱਪਣੀ ਕੀਤੀ}}।",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] ਨੇ [[$3]] ਉੱਤੇ ਇੱਕ ਨਵਾਂ ਵਿਸ਼ਾ \"$2\" {{GENDER:$1|ਪਾਇਆ}}",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] ਨੇ ਤੁਹਾਨੂੰ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਭੇਜਿਆ ਹੈ}}: \"[[$3#$2|$2]]\"।",
+ "notification-add-comment-yours2": "[[User:$1|$1]] ਨੇ ਤੁਹਾਡੇ ਗੱਲ-ਬਾਤ ਪੰਨੇ ਉੱਤੇ \"[[$3#$2|$2]]\" ਉੱਤੇ {{GENDER:$1|ਟਿੱਪਣੀ ਕੀਤੀ ਹੈ}}।",
+ "notification-mention": "[[User:$1|$1]] ਨੇ \"[[:$3#$2|$4]]\" ਵਿੱਚ $5 ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਉੱਤੇ ਤੁਹਾਡਾ {{GENDER:$1|ਜ਼ਿਕਰ ਕੀਤਾ ਹੈ}}",
+ "notification-mention-flyout": "$1 ਨੇ \"[[:$3#$2|$4]]\" ਵਿੱਚ $5 ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਉੱਤੇ ਤੁਹਾਡਾ {{GENDER:$1|ਜ਼ਿਕਰ ਕੀਤਾ ਹੈ}}",
+ "notification-user-rights": "ਤੁਹਾਡੇ ਵਰਤੋਂਕਾਰ ਅਧਿਕਾਰ [[User:$1|$1]] ਦੁਆਰਾ [[Special:Log/rights/$1|{{GENDER:$1|ਬਦਲ ਦਿੱਤੇ ਗਏ ਸਨ}}]]। $2। [[Special:ListGroupRights|ਹੋਰ ਜਾਣੋ]]",
+ "notification-user-rights-flyout": "ਤੁਹਾਡੇ ਵਰਤੋਂਕਾਰ ਅਧਿਕਾਰ $1 ਦੁਆਰਾ {{GENDER:$1|ਬਦਲ ਦਿੱਤੇ ਗਏ}} ਸਨ। $2।[[Special:ListGroupRights|ਹੋਰ ਜਾਣੋ]]",
+ "notification-user-rights-add": "ਹੁਣ ਤੁਸੀਂ {{PLURAL:$2|ਇਸ ਸਮੂਹ|ਇਨ੍ਹਾਂ ਸਮੂਹਾਂ}} ਦੇ ਮੈਂਬਰ ਹੋ: $1",
+ "notification-user-rights-remove": "ਹੁਣ ਤੁਸੀਂ {{PLURAL:$2|ਇਸ ਸਮੂਹ|ਇਨ੍ਹਾਂ ਸਮੂਹਾਂ}} ਦੇ ਮੈਂਬਰ ਨਹੀਂ ਹੋ: $1",
+ "notification-new-user": "{{SITENAME}} ਉੱਤੇ ਤੁਹਾਡਾ ਸਵਾਗਤ ਹੈ, $1! ਤੁਹਾਡੇ ਇਥੇ ਆਉਣ ਉੱਤੇ ਸਾਨੂੰ ਖੁਸ਼ੀ ਹੋਈ।",
+ "notification-reverted2": "ਤੁਹਾਡੀ {{PLURAL:$4|[[:$2]] ਉੱਤੇ ਸੋਧ|[[:$2]] ਉੱਤੇ ਸੋਧਾਂ}} ਨੂੰ [[User:$1|$1]] ਨੇ {{GENDER:$1|ਰੱਦ ਕਰ ਦਿੱਤਾ}} ਹੈ। $3",
+ "notification-reverted-flyout2": "ਤੁਹਾਡੀ {{PLURAL:$4|$2 ਉੱਤੇ ਸੋਧ|$2 ਉੱਤੇ ਸੋਧਾਂ}} ਨੂੰ $1 ਨੇ {{GENDER:$1|ਰੱਦ ਕਰ ਦਿੱਤਾ}} ਹੈ। $3",
+ "notification-edit-talk-page-email-subject2": "$1 ਨੇ {{SITENAME}} ਉੱਤੇ ਤੁਹਾਡੇ ਲਈ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ ਹੈ}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 ਨੇ ਤੁਹਾਡੇ ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਉੱਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ}} ਹੈ:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 ਨੇ ਤੁਹਾਡੇ \"$2\" ਵਿਚਲੇ ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਉੱਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ}} ਹੈ।",
+ "notification-page-linked-email-subject": "{{SITENAME}} ਉੱਤੇ ਤੁਹਾਡਾ ਪੰਨਾ ਜੁੜਦਾ ਹੈ",
+ "notification-page-linked-email-batch-body": "$2 ਨੂੰ $3 ਤੋਂ {{GENDER:$1|ਜੋੜਿਆ ਗਿਆ}}।",
+ "notification-reverted-email-subject2": "ਤੁਹਾਡੀ {{SITENAME}} ਉੱਤੇ {{PLURAL:$3|ਸੋਧ|ਸੋਧਾਂ}} ਨੂੰ {{GENDER:$1|ਰੱਦ ਕਰ ਦਿੱਤਾ}} ਸੀ।",
+ "notification-reverted-email-batch-body2": "ਤੁਹਾਡੀ {{PLURAL:$3|$2 ਉੱਤੇ ਸੋਧ|$2 ਉੱਤੇ ਸੋਧਾਂ}} ਨੂੰ $1 ਨੇ {{GENDER:$1|ਰੱਦ ਕਰ ਦਿੱਤਾ}} ਹੈ।",
+ "notification-mention-email-subject": "$1 ਨੇ {{SITENAME}} ਉੱਤੇ ਤੁਹਾਡਾ {{GENDER:$1|ਜ਼ਿਕਰ ਕੀਤਾ ਹੈ}}",
+ "notification-mention-email-batch-body": "$1 ਨੇ \"$3\" ਵਿੱਚ $4 ਗੱਲ-ਬਾਤ ਪੰਨੇ ਉੱਤੇ ਤੁਹਾਡਾ {{GENDER:$1|ਜ਼ਿਕਰ ਕੀਤਾ ਹੈ}}",
+ "notification-user-rights-email-subject": "{{SITENAME}} ਉੱਤੇ ਤੁਹਾਡੇ ਵਰਤੋਂਕਾਰ ਅਧਿਕਾਰ ਬਦਲ ਗਏ ਹਨ",
+ "notification-user-rights-email-batch-body": "ਤੁਹਾਡੇ ਵਰਤੋਂਕਾਰ ਅਧਿਕਾਰ $1. $2 ਦੁਆਰਾ {{GENDER:$1|ਬਦਲੇ ਗਏ}}।",
+ "echo-email-subject-default": "{{SITENAME}} ਉੱਤੇ ਨਵੀਂ ਸੂਚਨਾ",
+ "echo-email-body-default": "ਤੁਹਾਡੇ ਲਈ {{SITENAME}} ਉੱਤੇ ਨਵੀਂ ਸੂਚਨਾ ਹੈ:\n\n$1",
+ "echo-email-batch-body-default": "ਤੁਹਾਡੇ ਲਈ ਇੱਕ ਨਵੀਂ ਸੂਚਨਾ ਹੈ।",
+ "echo-email-footer-default": "$2\n\nਅਸੀਂ ਤੁਹਾਨੂੰ ਕਿਹੜੇ ਈ-ਮੇਲ ਭੇਜਦੇ ਹਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਆਪਣੀਆਂ ਤਰਜੀਹਾਂ ਵੇਖੋ:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "ਅਸੀਂ ਤੁਹਾਨੂੰ ਕਿਹੜੇ ਈ-ਮੇਲ ਭੇਜਦੇ ਹਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">ਆਪਣੀਆਂ ਤਰਜੀਹਾਂ ਵੇਖੋ</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|ਚੌਕਸੀ ($1)|ਚੌਕਸੀਆਂ ($1)|100=ਚੌਕਸੀਆਂ (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|ਸੁਨੇਹਾ ($1)|ਸੁਨੇਹੇ ($1)|100=ਸੁਨੇਹੇ (99+)}}",
+ "echo-overlay-link": "ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ",
+ "echo-overlay-title": "<b>ਸੂਚਨਾਵਾਂ</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|ਸੂਚਨਾ|ਸੂਚਨਾਵਾਂ}}</b> ($2 ਨਾ-ਪੜ੍ਹੀਆਂ 'ਚੋਂ $1 ਵਿਖਾ ਰਿਹਾ ਹੈ)",
+ "echo-mark-all-as-read": "ਸਾਰੀਆਂ ਨੂੰ ਪੜ੍ਹਿਆਂ ਵਜੋਂ ਨਿਸ਼ਾਨੀ ਲਾਓ",
+ "echo-date-today": "ਅੱਜ",
+ "echo-date-yesterday": "ਬੀਤੀ ਕੱਲ",
+ "echo-load-more-error": "ਹੋਰ ਨਤੀਜੇ ਖੋਜਣ ਦੌਰਾਨ ਇੱਕ ਭੁੱਲ ਹੋ ਗਈ।",
+ "notification-edit-talk-page-bundle": "$1 ਅਤੇ $3 {{PLURAL:$4|ਹੋਰ|ਹੋਰਾਂ}} ਨੇ ਤੁਹਾਡੇ [[User talk:$2|ਗੱਲ-ਬਾਤ ਸਫ਼ੇ]] ਉੱਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ}} ਹੈ।",
+ "notification-page-linked-bundle": "$2 ਨੂੰ $3 ਅਤੇ $4 ਹੋਰ {{PLURAL:$5|ਪੰਨਾ|ਪੰਨੇ}} ਤੋਂ {{GENDER:$1|ਜੋੜਿਆ}} ਸੀ।\n[[Special:WhatLinksHere/$2|ਇਸ ਪੰਨੇ ਉੱਤੇ ਜੁੜਦੇ ਸਾਰੇ ਲਿੰਕ ਵੇਖੋ]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 ਅਤੇ $2 {{PLURAL:$3|ਹੋਰ|ਹੋਰਾਂ}} ਨੇ ਤੁਹਾਡੇ ਗੱਲ-ਬਾਤ ਸਫ਼ੇ ਉੱਤੇ ਇੱਕ ਸੁਨੇਹਾ {{GENDER:$1|ਛੱਡਿਆ}} ਹੈ।",
+ "notification-page-linked-email-batch-bundle-body": "$2 ਨੂੰ $3 ਅਤੇ $4 ਹੋਰ {{PLURAL:$5|ਪੰਨਾ|ਪੰਨੇ}} ਤੋਂ {{GENDER:$1|ਜੋੜਿਆ}} ਸੀ।",
+ "echo-email-batch-subject-daily": "ਤੁਹਾਡੇ ਲਈ {{SITENAME}} ਉੱਤੇ {{PLURAL:$2|ਇੱਕ ਨਵੀਂ ਸੂਚਨਾ|ਨਵੀਆਂ ਸੂਚਨਾਵਾਂ}} ਹਨ।",
+ "echo-email-batch-subject-weekly": "ਤੁਹਾਡੇ ਲਈ {{SITENAME}} ਉੱਤੇ ਇਸ ਹਫਤੇ {{PLURAL:$2|ਇੱਕ ਨਵੀਂ ਸੂਚਨਾ|ਨਵੀਆਂ ਸੂਚਨਾਵਾਂ}} ਹਨ।",
+ "echo-email-batch-body-intro-daily": "ਸਤਿ ਸ਼੍ਰੀ ਅਕਾਲ $1,\nਤੁਹਾਡੇ ਲਈ {{SITENAME}} ਉੱਤੇ ਅੱਜ ਦੀ ਸਰਗਰਮੀ ਦਾ ਸਾਰ।",
+ "echo-email-batch-body-intro-weekly": "ਸਤਿ ਸ਼੍ਰੀ ਅਕਾਲ $1,\nਤੁਹਾਡੇ ਲਈ {{SITENAME}} ਉੱਤੇ ਹਫਤਾਵਰ ਸਰਗਰਮੀ ਦਾ ਸਾਰ।",
+ "echo-email-batch-link-text-view-all-notifications": "ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਦੇਖੋ",
+ "echo-rev-deleted-text-view": "ਇਸ ਪੰਨੇ ਦੀ ਸੁਧਾਈ ਨੂੰ ਰੋਕ ਦਿੱਤਾ ਗਿਆ ਹੈ।"
+}
diff --git a/Echo/i18n/pfl.json b/Echo/i18n/pfl.json
new file mode 100644
index 00000000..58d2173f
--- /dev/null
+++ b/Echo/i18n/pfl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Manuae"
+ ]
+ },
+ "tooltip-pt-notifications": "Doi Bnochrischdigunge"
+}
diff --git a/Echo/i18n/pl.json b/Echo/i18n/pl.json
new file mode 100644
index 00000000..8be41699
--- /dev/null
+++ b/Echo/i18n/pl.json
@@ -0,0 +1,131 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ankry",
+ "Base",
+ "BeginaFelicysym",
+ "Chrumps",
+ "Faren",
+ "Matma Rex",
+ "Odie2",
+ "Przemub",
+ "Tar Lócesilion",
+ "WTM",
+ "Woytecr",
+ "Wpedzich",
+ "Tsca",
+ "Peter Bowman"
+ ]
+ },
+ "echo-desc": "System powiadomień",
+ "prefs-echo": "Powiadomienia",
+ "prefs-emailsettings": "Opcje e-maila",
+ "prefs-displaynotifications": "Opcje wyświetlania",
+ "prefs-echosubscriptions": "Powiadom mnie o tych zdarzeniach",
+ "prefs-newmessageindicator": "Informacje o nowych wiadomościach",
+ "echo-pref-send-me": "Wysyłaj mi:",
+ "echo-pref-send-to": "Wyślij na adres:",
+ "echo-pref-email-format": "Format e-maila:",
+ "echo-pref-web": "Na stronie",
+ "echo-pref-email": "Przez e‐mail",
+ "echo-pref-email-frequency-never": "Nie wysyłaj powiadomień e-mailem",
+ "echo-pref-email-frequency-immediately": "Każde powiadomienie osobno",
+ "echo-pref-email-frequency-daily": "Dzienne podsumowanie",
+ "echo-pref-email-frequency-weekly": "Tygodniowe podsumowanie",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Zwykły tekst",
+ "echo-pref-notify-show-link": "Pokazuj powiadomienia w pasku narzędzi",
+ "echo-pref-new-message-indicator": "Pokazuj informację o nowej wiadomości w pasku osobistym",
+ "echo-learn-more": "Dowiedz się więcej",
+ "echo-new-messages": "Masz nowe wiadomości",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Wpis|Wpisy}} w dyskusji",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Link|Linki}} do moich artykułów",
+ "echo-category-title-reverted": "{{PLURAL:$1|Rewert|Rewerty}} edycji",
+ "echo-category-title-mention": "{{PLURAL:$1|Wzmianka|Wzmianki}}",
+ "echo-category-title-other": "{{PLURAL:$1|Inne zdarzenie|Inne zdarzenia}}",
+ "echo-category-title-system": "{{PLURAL:$1|Zdarzenie systemowe|Zdarzenia systemowe}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Zmiana uprawnień|Zmiany uprawnień}}",
+ "echo-pref-tooltip-edit-user-talk": "Powiadom mnie, kiedy ktoś napisze nową wiadomość albo odpowie na mojej stronie dyskusji.",
+ "echo-pref-tooltip-article-linked": "Powiadom mnie, kiedy ktoś umieści w artykule link do strony utworzonej przeze mnie.",
+ "echo-pref-tooltip-reverted": "Powiadom mnie, kiedy ktoś wycofa moją edycję korzystając z narzędzia „anuluj” albo „cofnij”.",
+ "echo-pref-tooltip-mention": "Powiadom mnie, kiedy ktoś umieści link do mojej strony użytkownika.",
+ "echo-pref-tooltip-user-rights": "Powiadamiaj mnie, gdy ktoś zmieni moje uprawnienia.",
+ "echo-no-agent": "[Nikt]",
+ "echo-no-title": "[Brak strony]",
+ "echo-error-no-formatter": "Nie określono formatowania dla powiadomień",
+ "echo-error-preference": "Błąd: Nie można ustawić preferencji użytkownika",
+ "echo-error-token": "Błąd: Nie można pobrać tokenu",
+ "notifications": "Powiadomienia",
+ "tooltip-pt-notifications": "Twoje powiadomienia",
+ "echo-specialpage": "Powiadomienia",
+ "echo-anon": "Aby otrzymywać powiadomienia, [$1 załóż konto] lub [$2 zaloguj się].",
+ "echo-none": "Nie masz żadnych powiadomień.",
+ "echo-more-info": "Więcej informacji",
+ "echo-feedback": "Opinie",
+ "notification-link-text-view-message": "Zobacz wiadomość",
+ "notification-link-text-view-mention": "Zobacz wzmiankę",
+ "notification-link-text-view-changes": "Zobacz zmiany",
+ "notification-link-text-view-page": "Zobacz stronę",
+ "notification-link-text-view-edit": "Zobacz edycję",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|napisał|napisała}} do ciebie na twojej [[User talk:$2#$3|stronie dyskusji]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|napisał|napisała}} do Ciebie na Twojej stronie dyskusji, w wątku „[[User talk:$2#$3|$4]]”.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|napisał|napisała}} do ciebie na twojej [[User talk:$2#$3|stronie dyskusji]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|napisał|napisała}} do Ciebie na Twojej stronie dyskusji, w wątku „[[User talk:$2#$3|$4]]”.",
+ "notification-page-linked": "W artykule [[:$3]] {{GENDER:$1|umieszczono}} link do artykułu [[:$2]]. [[Special:WhatLinksHere/$2|Pokaż wszystkie linkujące do artykułu $2]].",
+ "notification-page-linked-flyout": "W artykule [[:$3]] {{GENDER:$1|umieszczono}} link do artykułu [[:$2]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|umieścił|umieściła}} komentarz do „[[$3|$2]]” na stronie dyskusji „$4”",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|umieścił|umieściła}} komentarz w nowym wątku „$2” na stronie [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|wysłał|wysłała}} ci wiadomość: „[[$3#$2|$2]]”",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|umieścił|umieściła}} komentarz do „[[$3#$2|$2]]” na twojej stronie dyskusji",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|wspomniał|wspomniała}} o Tobie na stronie $5 w wątku „[[:$3#$2|$4]]”.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|wspomniał|wspomniała}} o Tobie w wątku „[[:$3#$2|$4]]” na stronie $5.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|wspomniał|wspomniała}} o Tobie na [[:$3|stronie $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|wspomniał|wspomniała}} o Tobie na [[:$3|stronie $2]].",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|{{GENDER:$1|zmienił|zmieniła}}]] twoje uprawnienia. $2. [[Special:ListGroupRights|Dowiedz się więcej]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|zmienił|zmieniła}} twoje uprawnienia. $2. [[Special:ListGroupRights|Dowiedz się więcej]]",
+ "notification-user-rights-add": "Należysz teraz do {{PLURAL:$2|tej grupy|tych grup}}: $1",
+ "notification-user-rights-remove": "Od teraz nie należysz już do {{PLURAL:$2|tej grupy|tych grup}}: $1",
+ "notification-new-user": "Witaj w {{grammar:MS.lp|{{SITENAME}}}}, $1! Cieszymy się, że tu jesteś.",
+ "notification-reverted2": "[[User:$1|$1]] {{GENDER:$1|wycofał|wycofała}} {{PLURAL:$4|Twoją edycję|Twoje edycje}} na stronie [[:$2]] $3",
+ "notification-reverted-flyout2": "$1 {{GENDER:$1|wycofał|wycofała}} {{PLURAL:$4|Twoją edycję|Twoje edycje}} na stronie $2 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|napisał|napisała}} do Ciebie w {{grammar:MS.lp|{{SITENAME}}}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|napisał|napisała}} do ciebie na twojej stronie dyskusji:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|napisał|napisała}} do Ciebie na Twojej stronie dyskusji w wątku „$2”.",
+ "notification-page-linked-email-subject": "W {{grammar:MS.lp|{{SITENAME}}}} ktoś wstawił link do twojej strony",
+ "notification-page-linked-email-batch-body": "Na stronie $3 {{GENDER:$1|umieszczono}} link do strony $2",
+ "notification-reverted-email-subject2": "$1 {{GENDER:$1|wycofał|wycofała}} {{PLURAL:$3|twoją edycję|twoje edycje}} w {{grammar:MS.lp|{{SITENAME}}}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|wycofał|wycofała}} {{PLURAL:$3|Twoją edycję|Twoje edycje}} na stronie $2",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|wspomniał|wspomniała}} o Tobie w {{grammar:MS.lp|{{SITENAME}}}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|wspomniał|wspomniała}} o Tobie na stronie $4 w wątku „$3”.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|wspomniał|wspomniała}} o Tobie na stronie $2.",
+ "notification-user-rights-email-subject": "W {{grammar:MS.lp|{{SITENAME}}}} zostały zmienione twoje uprawnienia",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|zmienił|zmieniła}} twoje uprawnienia. $2",
+ "echo-notification-count": "$1+",
+ "echo-email-subject-default": "Nowe powiadomienie w {{grammar:MS.lp|{{SITENAME}}}}",
+ "echo-email-body-default": "Masz nowe powiadomienie w {{grammar:MS.lp|{{SITENAME}}}}:\n\n$1",
+ "echo-email-batch-body-default": "Masz nowe powiadomienie",
+ "echo-email-footer-default": "$2\n\nMożesz wybrać, jakie e-maile chcesz otrzymywać, w swoich preferencjach: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Możesz wybrać, jakie e-maile chcesz otrzymywać <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">w swoich preferencjach</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Powiadomienie ($1)|Powiadomienia ($1)|100=Powiadomienia (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Wiadomość ($1)|Wiadomości ($1)|100=Wiadomości (ponad 99)}}",
+ "echo-notification-alert-text-only": "Powiadomienia",
+ "echo-notification-message-text-only": "Wiadomości",
+ "echo-overlay-link": "Wszystkie powiadomienia",
+ "echo-overlay-title": "<b>Powiadomienia</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Powiadomienie|Powiadomienia}}</b> (wyświetlono $1 z $2 nieprzeczytanych)",
+ "echo-mark-all-as-read": "Oznacz wszystkie jako przeczytane",
+ "echo-date-today": "Dzisiaj",
+ "echo-date-yesterday": "Wczoraj",
+ "echo-load-more-error": "Wystąpił błąd przy pobieraniu kolejnych wyników.",
+ "notification-edit-talk-page-bundle": "$1 i {{PLURAL:$4|ktoś inny|$3 inni|$3 innych}} napisali do ciebie na twojej [[User talk:$2|stronie dyskusji]].",
+ "notification-page-linked-bundle": "Na stronie $3 i na {{PLURAL:$5|innej stronie|$4 innych stronach}} {{GENDER:$1|umieszczono}} link do strony $2: [[Special:WhatLinksHere/$2|pokaż wszystkie linkujące do tej strony]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 i {{PLURAL:$3|ktoś inny|$2 inni|$2 innych}} {{GENDER:$1|napisali}} do ciebie na twojej stronie dyskusji.",
+ "notification-page-linked-email-batch-bundle-body": "Na stronie $3 i na {{PLURAL:$5|innej stronie|$4 innych stronach}} {{GENDER:$1|umieszczono}} link do strony $2",
+ "echo-email-batch-subject-daily": "Masz {{PLURAL:$2|nowe powiadomienie|nowe powiadomienia}} w {{grammar:MS.lp|{{SITENAME}}}}",
+ "echo-email-batch-subject-weekly": "Masz {{PLURAL:$2|nowe powiadomienie|nowe powiadomienia}} w {{grammar:MS.lp|{{SITENAME}}}} z tego tygodnia",
+ "echo-email-batch-body-intro-daily": "Cześć, $1!\nW {{grammar:MS.lp|{{SITENAME}}}} czeka na ciebie dzisiejsze podsumowanie powiadomień.",
+ "echo-email-batch-body-intro-weekly": "Cześć, $1!\nW {{grammar:MS.lp|{{SITENAME}}}} czeka na ciebie podsumowanie powiadomień z ostatniego tygodnia.",
+ "echo-email-batch-link-text-view-all-notifications": "Zobacz wszystkie powiadomienia",
+ "echo-rev-deleted-text-view": "Ta wersja strony została ukryta",
+ "apihelp-query+notifications-example-1": "Spis powiadomień"
+}
diff --git a/Echo/i18n/pms.json b/Echo/i18n/pms.json
new file mode 100644
index 00000000..1b47c333
--- /dev/null
+++ b/Echo/i18n/pms.json
@@ -0,0 +1,136 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt"
+ ]
+ },
+ "echo-desc": "Sistema ëd notìfiche",
+ "prefs-echo": "Notìfiche",
+ "prefs-emailsettings": "Opsion ëd pòsta eletrònica",
+ "prefs-displaynotifications": "Opsion ëd visualisassion",
+ "prefs-echosubscriptions": "Aviseme ëd si eveniment",
+ "prefs-newmessageindicator": "Marca ëd mëssagi neuv",
+ "echo-pref-send-me": "Mandeme:",
+ "echo-pref-send-to": "Mandé a:",
+ "echo-pref-email-format": "Formà ëd mëssagi:",
+ "echo-pref-web": "Aragnà",
+ "echo-pref-email": "Mëssagi",
+ "echo-pref-email-frequency-never": "Mandeme gnun-e notìfiche për pòsta eletrònica",
+ "echo-pref-email-frequency-immediately": "Notìfiche andividuaj com che a rivo",
+ "echo-pref-email-frequency-daily": "Un resumé cotidian dle notìfiche",
+ "echo-pref-email-frequency-weekly": "Un resumé ebdomadari dle notìfiche",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Mach test",
+ "echo-pref-notify-show-link": "Smon-e le notìfiche an mia bara d'utiss",
+ "echo-pref-new-message-indicator": "Smon-e la marca ëd mëssagi an la pàgina ëd ciaciarade an mia bara d'utiss",
+ "echo-learn-more": "Savèjne 'd pì",
+ "echo-new-messages": "A l'ha 'd mëssagi neuv",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|mëssagi}} ëd la pàgina ëd ciaciarade",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Liura|Liure}} a dle pàgine",
+ "echo-category-title-reverted": "{{PLURAL:$1|Anulament}} ëd modìfiche",
+ "echo-category-title-mention": "{{PLURAL:$1|Mension}}",
+ "echo-category-title-other": "{{PLURAL:$1|Àutr}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Modìfica|Modìfiche}} dij drit dj'utent",
+ "echo-pref-tooltip-edit-user-talk": "Aviseme cand cheidun a pùblica un mëssagi o a rëspond su mia pàgina ëd ciaciarade.",
+ "echo-pref-tooltip-article-linked": "Aviseme cand cheidun a buta na liura a na pàgina che mi i l'hai creà da na pàgina d'artìcol.",
+ "echo-pref-tooltip-reverted": "Aviseme cand cheidun a anula na modìfica che mi i l'hai fàit, an dovrand l'utiss d'anulament o d'artorn andaré.",
+ "echo-pref-tooltip-mention": "Aviseme cand cheidun a buta na liura vers mia pàgina d'utent.",
+ "echo-pref-tooltip-user-rights": "Aviseme cand cheidun a modìfica ij mè drit d'utent.",
+ "echo-no-agent": "[Gnun]",
+ "echo-no-title": "[Gnun-a pàgina]",
+ "echo-error-no-formatter": "Gnun formà definì për la notìfica",
+ "echo-error-preference": "Eror: Impossìbil definì ël gust utent.",
+ "echo-error-token": "Eror: Impossìbil arcuperé ël geton dl'utent.",
+ "notifications": "Notìfiche",
+ "tooltip-pt-notifications": "Toe notìfiche",
+ "echo-specialpage": "Notìfiche",
+ "echo-anon": "Për arseive dle notìfiche, <span class=\"plainlinks\">[$1 ch'a crea un cont] o <span class=\"plainlinks\">[$2 ch'a intra ant ël sistema].",
+ "echo-none": "A l'ha gnun-e notìfiche.",
+ "echo-more-info": "Pi d'anformassion",
+ "echo-feedback": "Opinion",
+ "notification-link-text-view-message": "Smon-e ël mëssagi",
+ "notification-link-text-view-mention": "Smon-e la rëspondensa",
+ "notification-link-text-view-changes": "Smon-e le modìfiche",
+ "notification-link-text-view-page": "Smon-e la pàgina",
+ "notification-link-text-view-edit": "Smon-e la modìfica",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|a l'ha lassà}} un mëssagi dzora a soa [[User talk:$2#$3|pàgina ëd ciaciarade]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|a l'ha lassà}} un mëssagi an soa pàgina ëd ciaciarade an «[[User talk:$2#$3|$4]]».",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|a l'ha lassà}} un mëssagi dzora soa [[User talk:$2#$3|pàgina ëd ciaciarade]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|a l'ha lassà}} un mëssagi su soa pàgina ëd ciaciarade an «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "[[:$2]] a l'é stàit {{GENDER:$1|colegà}} da [[:$3]]. [[Special:WhatLinksHere/$2|Vëdde tute le liure a costa pàgina]].",
+ "notification-page-linked-flyout": "[[:$2]] a l'é stàit {{GENDER:$1|colegà}} da [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|a l'ha comentà}} su «[[$3|$2]]» an sla pàgina ëd discussion «$4»",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|a l'ha publicà}} n'argoment neuv «$2» dzor [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|a l'ha manda}}te un mëssagi: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|a l'ha comentà}} dzor «[[$3#$2|$2]]» su soa pàgina ëd ciaciarade",
+ "notification-mention": "[[User:$1|$1]] a l'ha {{GENDER:$1|massionalo|massionala}} an sla pàgina ëd ciaciarade ëd $5 an «[[:$3#$2|$4]]».",
+ "notification-mention-flyout": "$1 {{GENDER:$1|a l'ha massionalo|a l'ha massionala}} ant la pàgina ëd discussion ëd $5 an «[[:$3#$2|$4]]».",
+ "notification-mention-nosection": "[[User:$1|$1]] a l'ha {{GENDER:$1|massionalo|massional}} ant la [[:$3|pàgina ëd discussion ëd $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|a l'ha massionalo|a l'ha massionala}} an sla [[:$3|pàgina ëd discussion ëd $2]].",
+ "notification-user-rights": "Ij sò drit d'utent [[Special:Log/rights/$1|a son ëstàit {{GENDER:$1|modificà}}]] da [[User:$1|$1]]. $2. [[Special:ListGroupRights|Savèjne ëd pi]]",
+ "notification-user-rights-flyout": "Ij sò drit d'utent a son ëstàit {{GENDER:$1|modificà}} da $1. $2. [[Special:ListGroupRights|Savèjne ëd pi]]",
+ "notification-user-rights-add": "Adess a l'é mèmber ëd {{PLURAL:$2|costa partìa|coste partìe}}: $1",
+ "notification-user-rights-remove": "A l'é pi nen mèmber ëd {{PLURAL:$2|costa partìa|coste partìe}}: $1",
+ "notification-new-user": "Bin-ëvnù su {{SITENAME}}, $1! I soma content ch'a l'é ambelessì.",
+ "notification-reverted2": "{{PLURAL:$4|Soa modìfica dzor [[:$2]] a l'é stàita|Soe modìfiche dzor [[:$2]] a son stàite}} {{GENDER:$1|ripristinà}} da [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Soa modìfica dzor $2 a l'é stàita|Soe modìfiche dzor $2 a son stàite}} {{GENDER:$1|ripristinà}} da $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 a l'ha {{GENDER:$1|lassaje}} un mëssagi su {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|a l'ha lassà}} un mëssadi dzora soa pàgina ëd ciaciarade:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|a l'ha lassà}} un mëssagi su soa pàgina ëd discussion an «$2».",
+ "notification-page-linked-email-subject": "Soa pàgina a l'é stàita sità su {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 a l'é stàit {{GENDER:$1|sità}} da $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Soa modìfica a l'é stàita|Soe modìfiche a son ëstàite}} {{GENDER:$1|anulà}} su {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Soa modìfica a $2 a l'é stàita|Soe modìfiche a $2 a son stàite}} {{GENDER:$1|anulà}} da $1.",
+ "notification-mention-email-subject": "$1 a l'ha {{GENDER:$1|massionalo|massionala}} su {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 a l'ha {{GENDER:$1|massionalo|massionala}} ant lapàgina ëd discussion ëd $4 an «$3».",
+ "notification-mention-nosection-email-batch-body": "$1 a l'ha {{GENDER:$1|massionalo|massionala}} ant la pàgina ëd discussion ëd $2.",
+ "notification-user-rights-email-subject": "Ij sò drit d'utent a son ëstàit modificà su {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Ij sò drit d'utent a son ëstàit {{GENDER:$1|modificà}} da $1. $2.",
+ "echo-email-subject-default": "Notìfiche neuve a {{SITENAME}}",
+ "echo-email-body-default": "It l'has na notìfica neuva a {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "A l'ha na neuva notìfica.",
+ "echo-email-footer-default": "$2\n\nPër controlé che mëssagi i-j mandoma, ch'a contròla ij sò gust:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Për controlé che mëssagi i-j mandoma, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">ch'a contròla ij sò gust</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Avis ($1)|100=Avis (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mëssagi ($1)|100=Mëssagi (99+)}}",
+ "echo-notification-alert-text-only": "Avis",
+ "echo-notification-message-text-only": "Mëssagi",
+ "echo-overlay-link": "Tute le notìfiche",
+ "echo-overlay-title": "<b>Notìfiche</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notìfiche}}</b> (as na mostro $1 ëd $2 nen lesùe)",
+ "echo-mark-all-as-read": "Marché tut tanme lesù",
+ "echo-date-today": "Ancheuj",
+ "echo-date-yesterday": "Jer",
+ "echo-load-more-error": "A l'é capitaje n'eror an recuperand pi d'arzultà.",
+ "notification-edit-talk-page-bundle": "$1 e $3 {{PLURAL:$4|àutr a l'ha|àutri a l'han}} {{GENDER:$1|lassà}} un mëssagi su soa [[User talk:$2|pàgina dle ciaciarade]].",
+ "notification-page-linked-bundle": "$2 a l'é stàit {{GENDER:$1|colegà}} da $3 e $4 {{PLURAL:$5|àutra pàgina|àutre pàgine}}. [[Special:WhatLinksHere/$2|Vëdde tute le liure a costa pàgina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e $2 {{PLURAL:$3|àutr|àutri}} a l'han {{GENDER:$1|lassà}} un mëssagi su soa pàgina dle ciaciarade.",
+ "notification-page-linked-email-batch-bundle-body": "$2 a l'é stàit {{GENDER:$1|colegà}} da $3 e $4 {{PLURAL:$5|àutra pàgina|àutre pàgine}}.",
+ "echo-email-batch-subject-daily": "A l'ha {{PLURAL:$2|na notìfica neuva|dle notìfiche neuve}} su {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "A l'ha {{PLURAL:$2|na notìfica neuva|dle notìfiche neuve}} su {{SITENAME}} sta sman-a",
+ "echo-email-batch-body-intro-daily": "Cerea $1\nValà un resumé dl'atività d'ancheuj su {{SITENAME}} për chiel.",
+ "echo-email-batch-body-intro-weekly": "Cerea $1,\nValà un resumé dl'atività dë sta sman-a su {{SITENAME}} për chiel.",
+ "echo-email-batch-link-text-view-all-notifications": "Vëdde tute le notìfiche",
+ "echo-rev-deleted-text-view": "Costa revision ëd pàgina a l'é stàita scancelà.",
+ "apihelp-echomarkread-description": "Marché le notìfiche coma lesùe për l'utent atual.",
+ "apihelp-echomarkread-param-list": "Na lista d'ID ëd notìfica da marché coma lesù.",
+ "apihelp-echomarkread-param-all": "Si definì, a marca tute le notìfiche ëd n'utent coma lesùe.",
+ "apihelp-echomarkread-param-sections": "Na lista ëd session da marché coma lesùe.",
+ "apihelp-echomarkread-example-1": "Marché la notìtica 8 coma lesùa",
+ "apihelp-echomarkread-example-2": "Marché tute le notìfiche coma lesùe",
+ "apihelp-query+notifications-description": "Oten-e le notìfiche an atèisa për l'utent atual.",
+ "apihelp-query+notifications-param-prop": "Detaj da ciamé.",
+ "apihelp-query+notifications-param-sections": "Le session ëd notìfica da ciamé.",
+ "apihelp-query+notifications-param-groupbysection": "S'a venta argropé j'arzultà për session. Minca na session a l'é analisà për sò cont s'a l'é definì.",
+ "apihelp-query+notifications-param-format": "Si spessificà, le notìfiche a sarà mandà ant ës formà.",
+ "apihelp-query+notifications-param-limit": "Ël nùmer màssim ëd notìfiche da mandé.",
+ "apihelp-query+notifications-param-index": "Si spessificà, na lista d'ID ëd notìfica, an órdin, a sarà smonùa.",
+ "apihelp-query+notifications-param-alertcontinue": "Cand a son disponìbij vàire arzultà d'alerta, dovré sòn për andé anans.",
+ "apihelp-query+notifications-param-alertunreadfirst": "S'a venta smon-e prima le notìfiche dij mëssagi nen lesù.",
+ "apihelp-query+notifications-param-messagecontinue": "Cand vàire arzultà ëd mëssagi a son disponìbij, dovré sòn për andé anans.",
+ "apihelp-query+notifications-param-messageunreadfirst": "S'a venta smon-e prima le notìfiche d'alerta nen lesùe.",
+ "apihelp-query+notifications-example-1": "Listé le modìfiche",
+ "apihelp-query+notifications-example-2": "Lista dle notìfiche, argropà për session, con ij conteur"
+}
diff --git a/Echo/i18n/ps.json b/Echo/i18n/ps.json
new file mode 100644
index 00000000..57caa510
--- /dev/null
+++ b/Echo/i18n/ps.json
@@ -0,0 +1,59 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahmed-Najib-Biabani-Ibrahimkhel"
+ ]
+ },
+ "echo-desc": "د يادگيرنو غونډال",
+ "prefs-echo": "يادگيرنې",
+ "prefs-emailsettings": "د برېښليک خوښنې",
+ "prefs-displaynotifications": "د ښکارېدنې خوښنې",
+ "prefs-echosubscriptions": "د دغو پېښو په اړه دې خبر شم",
+ "prefs-newmessageindicator": "نوی پيغام ښکاره کوونکی",
+ "echo-pref-send-me": "را ولېږه:",
+ "echo-pref-send-to": "ور ولېږه:",
+ "echo-pref-email-format": "برېښليک بڼه:",
+ "echo-pref-web": "وېبځی",
+ "echo-pref-email": "برېښليک",
+ "echo-pref-email-frequency-never": "برېښليکي يادگيرنې راته مه رالېږه",
+ "echo-pref-email-frequency-immediately": "د رارسېدو سره سمدلاسه فردي يادگيرنې",
+ "echo-pref-email-frequency-daily": "د يادگيرنو يو ورځينی لنډيز",
+ "echo-pref-email-frequency-weekly": "د يادگيرنو يو اونيز لنډيز",
+ "echo-pref-email-format-html": "اچ ټي ام اېل",
+ "echo-pref-email-format-plain-text": "ساده متن",
+ "echo-pref-notify-show-link": "يادگيرنې زما په توکپټه کې ښکاره کول",
+ "echo-pref-new-message-indicator": "زما په توکپټه کې د خبرو اترو پيغام ښودونکی ښکاره کول",
+ "echo-learn-more": "نور څه زده کول",
+ "echo-new-messages": "تاسې نوي پيغامونه لرئ",
+ "echo-category-title-edit-user-talk": "خبرو اترو مخ {{PLURAL:$1|پيغام|پيغامونه}}",
+ "echo-category-title-article-linked": "مخ {{PLURAL:$1|تړنه|تړنې}}",
+ "echo-category-title-other": "{{PLURAL:$1|نور}}",
+ "echo-category-title-system": "{{PLURAL:$1|غونډال}}",
+ "echo-no-agent": "[هېڅوک]",
+ "echo-no-title": "[هېڅ مخ]",
+ "notifications": "يادگيرنې",
+ "tooltip-pt-notifications": "ستاسې يادگيرنې",
+ "echo-specialpage": "يادگيرنې",
+ "echo-anon": "د يادگيرنو د ترلاسه کولو لپاره، [$1 يو گڼون جوړ کړۍ] او يا هم [$2 کې ننوځۍ].",
+ "echo-none": "تاسې هېڅ يادگيرنې نه لرئ.",
+ "echo-more-info": "نور مالومات",
+ "echo-feedback": "غبرگون",
+ "notification-link-text-view-message": "پيغام کتل",
+ "notification-link-text-view-mention": "يادگيرنه کتل",
+ "notification-link-text-view-changes": "بدلونونه کتل",
+ "notification-link-text-view-page": "مخ کتل",
+ "notification-link-text-view-edit": "سمون کتل",
+ "notification-new-user": "$1 {{SITENAME}} ته ښه راغلې!، موږ خوښ يو چې تاسې دلته ياست.",
+ "notification-edit-talk-page-email-batch-body2": "$1 ستاسې د خبرو اترو په مخ يو پيغام {{GENDER:$1|پرېښوده}}:",
+ "echo-email-subject-default": "په {{SITENAME}} باندې نوې يادگيرنه",
+ "echo-email-body-default": "تاسې په {{SITENAME}} باندې يوه نوې يادگيرنه لرئ:\n\n$1",
+ "echo-email-batch-body-default": "تاسې يوه نوې يادگيرنه لرئ.",
+ "echo-overlay-link": "ټولې يادگيرنې",
+ "echo-overlay-title": "<b>يادگيرنې</b>",
+ "echo-overlay-title-overflow": "<b>يادگيرنې</b> (د$2 څخه $1 نالوستلي ښکاره کول)",
+ "echo-mark-all-as-read": "ټول لوستی په نخښه کول",
+ "echo-date-today": "نن",
+ "echo-date-yesterday": "پرون",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 او $2 {{PLURAL:$3|نور|نورو}} يو پيغام ستاسې د خبرو اترو په مخ {{GENDER:$1|پرېښوده}}.",
+ "echo-email-batch-link-text-view-all-notifications": "ټولې يادگيرنې کتل"
+}
diff --git a/Echo/i18n/pt-br.json b/Echo/i18n/pt-br.json
new file mode 100644
index 00000000..d6c05334
--- /dev/null
+++ b/Echo/i18n/pt-br.json
@@ -0,0 +1,120 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cainamarques",
+ "Helder.wiki",
+ "HenriqueCrang",
+ "Luckas",
+ "Raylton P. Sousa",
+ "TheGabrielZaum",
+ "Rodrigo codignoli",
+ "Dianakc",
+ "He7d3r"
+ ]
+ },
+ "echo-desc": "Sistema de notificações",
+ "prefs-echo": "Notificações",
+ "prefs-emailsettings": "Opções de email",
+ "prefs-displaynotifications": "Opções de exibição",
+ "prefs-echosubscriptions": "Notifique-me sobre esses eventos",
+ "prefs-newmessageindicator": "Indicador de nova mensagem",
+ "echo-pref-send-me": "Envie-me:",
+ "echo-pref-send-to": "Envie para:",
+ "echo-pref-email-format": "Formato do email:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Email",
+ "echo-pref-email-frequency-never": "Não me envie notificações por email",
+ "echo-pref-email-frequency-immediately": "Notificações individuais conforme cheguem",
+ "echo-pref-email-frequency-daily": "Um resumo diário das notificações",
+ "echo-pref-email-frequency-weekly": "Um resumo semanal das notificações",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Texto simples",
+ "echo-pref-notify-show-link": "Exibir notificações na minha barra de ferramentas",
+ "echo-pref-new-message-indicator": "Exibir indicador de mensagem na página de discussão em minha barra de ferramentas",
+ "echo-learn-more": "Saiba mais",
+ "echo-new-messages": "Você tem novas mensagens",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mensagem|Mensagens}} na página de discussão",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Link|Links}} para a página",
+ "echo-category-title-reverted": "{{PLURAL:$1|Edição revertida|Edições revertidas}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Menção|Menções}}",
+ "echo-category-title-other": "{{PLURAL:$1|Outro|Outros}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema|Sistemas}}",
+ "echo-pref-tooltip-edit-user-talk": "Notifique-me quando alguém publicar ou responder em minha página de discussão.",
+ "echo-pref-tooltip-article-linked": "Notifique-me quando alguém criar um link através de artigo para uma página criada por mim.",
+ "echo-pref-tooltip-reverted": "Notifique-me quando alguém reverter uma edição minha utilizando a função desfazer ou a ferramenta de reversão.",
+ "echo-pref-tooltip-mention": "Notifique-me quando alguém criar ligações à minha página de usuário em qualquer página de discussão.",
+ "echo-no-agent": "[Ninguém]",
+ "echo-no-title": "[Nenhuma página]",
+ "echo-error-no-formatter": "Nenhum formato definido para notificações",
+ "echo-error-preference": "Erro: Não foi possível configurar as preferências do usuário.",
+ "echo-error-token": "Erro: Não foi possível receber token do usuário.",
+ "notifications": "Notificações",
+ "tooltip-pt-notifications": "Suas notificações",
+ "echo-specialpage": "Notificações",
+ "echo-anon": "Para receber notificações, [$1 crie uma conta] ou [$2 registre-se].",
+ "echo-none": "Você não tem notificações.",
+ "echo-more-info": "Mais informações",
+ "echo-feedback": "Comentários",
+ "notification-link-text-view-message": "Ver mensagem",
+ "notification-link-text-view-mention": "Ver menção",
+ "notification-link-text-view-changes": "Ver mudanças",
+ "notification-link-text-view-page": "Ver página",
+ "notification-link-text-view-edit": "Ver edição",
+ "notification-edit-talk-page2": "[[User:$1|$1]] deixou uma mensagem em sua [[User talk:$2#$3|página de discussão]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] deixou uma mensagem em sua página de discussão em \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 deixou uma mensagem em sua [[User talk:$2#$3|página de discussão]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 deixou uma mensagem em sua página de discussão em \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Foi criado um {{GENDER:$1|link}} à página [[:$2]] a partir de [[:$3]]. [[Special:WhatLinksHere/$2|Veja todos os links para esta página]].",
+ "notification-page-linked-flyout": "Foi criada uma {{GENDER:$1|ligação}} à página [[:$2]] a partir de [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] comentou em \"[[$3|$2]]\" na página de discussão \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] adicionou um novo tópico \"$2\" em [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] enviou-lhe uma mensagem: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] comentou em \"[[$3#$2|$2]]\" na sua página de discussão.",
+ "notification-mention": "[[User:$1|$1]] mencionou você na página de discussão $5 em \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 mencionou você na página de discussão $5 em \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] mencionou você na [[:$3|página de discussão de $2]].",
+ "notification-mention-nosection-flyout": "$1 mencionou você na [[:$3|página de discussão de $2]].",
+ "notification-user-rights": "Seus direitos de usuário [[Special:Log/rights/$1|foram alterados]] {{GENDER:$1|pelo|pela|por}} [[User:$1|$1]]. $2. [[Special:ListGroupRights|Saiba mais]]",
+ "notification-user-rights-flyout": "Seus direitos de usuário foram alterados {{GENDER:$1|pelo|pela|por}} $1. $2. [[Special:ListGroupRights|Saiba mais]]",
+ "notification-user-rights-add": "Você agora é membro {{PLURAL:$2|deste grupo|destes grupos}}: $1",
+ "notification-user-rights-remove": "Você não é mais membro {{PLURAL:$2|deste grupo|destes grupos}}: $1",
+ "notification-new-user": "Bem-vindo(a) ao site {{SITENAME}}, $1! Estamos felizes por você estar aqui.",
+ "notification-reverted2": "{{PLURAL:$4|Sua edição em [[:$2]] foi revertida|Suas edições em [[:$2]] foram revertidas}} {{GENDER:$1|pelo|pela|por}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Sua edição em $2 foi revertida|Suas edições em $2 foram revertidas}} {{GENDER:$1|pelo|pela|por}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 deixou uma mensagem para você em {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 deixou uma mensagem na sua página de discussão:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 deixou uma mensagem na sua página de discussão em \"$2\".",
+ "notification-page-linked-email-subject": "A sua página foi ligada no {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "A página $2 foi {{GENDER:$1|ligada}} a partir de $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Sua edição foi revertida|Suas edições foram revertidas}} {{GENDER:$1|em}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Sua edição em $2 foi revertida|Suas edições em $2 foram revertidas}} {{GENDER:$1|pelo|pela|por}} $1.",
+ "notification-mention-email-subject": "$1 mencionou você em {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 mencionou você na página de discussão de $4 em \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 mencionou você na página de discussão de $2.",
+ "notification-user-rights-email-subject": "Seus direitos de usuários mudaram na {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Seus direitos de usuário foram alterados por $1. $2.",
+ "echo-email-subject-default": "Nova notificação em {{SITENAME}}",
+ "echo-email-body-default": "Você tem uma nova notificação em {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Você tem uma nova notificação.",
+ "echo-email-footer-default": "$2\n\nPara controlar quais emails enviamos a você, confira suas preferências: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Para controlar quais emails enviamos a você, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">confira suas preferências</a>.<br /> $1",
+ "echo-notification-alert": "{{PLURAL:$1|Alerta ($1)|Alertas ($1)|100=Alertas (+99)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mensagem ($1)|Mensagens ($1)|100=Mensagens (+99)}}",
+ "echo-overlay-link": "Todas as notificações",
+ "echo-overlay-title": "<b>Notificações</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notificação|Notificações}}</b> (exibindo $1 de $2 não lidas)",
+ "echo-mark-all-as-read": "Marcas todas como lidas",
+ "echo-date-today": "Hoje",
+ "echo-date-yesterday": "Ontem",
+ "echo-load-more-error": "Um erro ocorreu ao carregar mais resultados.",
+ "notification-edit-talk-page-bundle": "$1 e $3 {{PLURAL:$4|outro|outros}} deixaram uma mensagem em sua [[User talk:$2|página de discussão]].",
+ "notification-page-linked-bundle": "Foram criados {{GENDER:$1|links}} à página $2 em $3 e $4 {{PLURAL:$5|outra página|outras páginas}}. [[Special:WhatLinksHere/$2|Veja todos os links para esta página]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e $2 {{PLURAL:$3|outro|outros}} deixaram uma mensagem em sua página de discussão.",
+ "notification-page-linked-email-batch-bundle-body": "Foram criados {{GENDER:$1|links}} à página $2 em $3 e $4 {{PLURAL:$5|outra página|outras páginas}}.",
+ "echo-email-batch-subject-daily": "Você tem {{PLURAL:$2|uma nova notificação|novas notificações}} em {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Você tem {{PLURAL:$2|uma nova notificação|novas notificações}} em {{SITENAME}} esta semana",
+ "echo-email-batch-body-intro-daily": "Olá $1,\nAqui está um resumo diário de atividades em {{SITENAME}} para você.",
+ "echo-email-batch-body-intro-weekly": "Olá $1,\nAqui está um resumo semanal de atividades em {{SITENAME}} para você.",
+ "echo-email-batch-link-text-view-all-notifications": "Ver todas as notificações",
+ "echo-rev-deleted-text-view": "Esta revisão foi ocultada."
+}
diff --git a/Echo/i18n/pt.json b/Echo/i18n/pt.json
new file mode 100644
index 00000000..6214ad84
--- /dev/null
+++ b/Echo/i18n/pt.json
@@ -0,0 +1,123 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cainamarques",
+ "GoEThe",
+ "Helder.wiki",
+ "Imperadeiro98",
+ "Lijealso",
+ "Polyethylen",
+ "Vitorvicentevalente",
+ "He7d3r"
+ ]
+ },
+ "echo-desc": "Sistema de notificações",
+ "prefs-echo": "Notificações",
+ "prefs-emailsettings": "Opções de e-mail",
+ "prefs-displaynotifications": "Opções de visualização",
+ "prefs-echosubscriptions": "Notifique-me sobre estes eventos",
+ "prefs-newmessageindicator": "Indicador de nova mensagem",
+ "echo-pref-send-me": "Envie-me:",
+ "echo-pref-send-to": "Envie para:",
+ "echo-pref-email-format": "Formato de e-mail:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Não me envie notificações por e-mail",
+ "echo-pref-email-frequency-immediately": "Notificações individuais conforme cheguem",
+ "echo-pref-email-frequency-daily": "Um resumo diário de notificações",
+ "echo-pref-email-frequency-weekly": "Um resumo semanal de notificações",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Texto simples",
+ "echo-pref-notify-show-link": "Mostrar notificações na minha barra de ferramentas",
+ "echo-pref-new-message-indicator": "Mostrar indicador de mensagem na página de discussão na minha barra de ferramentas",
+ "echo-learn-more": "Saiba mais",
+ "echo-new-messages": "Tem novas mensagens",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mensagem|Mensagens}} na página de discussão",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Ligação|Ligações}} para a página",
+ "echo-category-title-reverted": "{{PLURAL:$1|Edição revertida|Edições revertidas}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Menção|Menções}}",
+ "echo-category-title-other": "{{PLURAL:$1|Outro|Outros}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema|Sistemas}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|alteração de privilégios de utilizador|alterações de privilégios de utilizador}}",
+ "echo-pref-tooltip-edit-user-talk": "Notificar-me quando alguém publicar na minha página de discussão.",
+ "echo-pref-tooltip-article-linked": "Notificar-me quando alguém interligar uma página criada por mim numa outra.",
+ "echo-pref-tooltip-reverted": "Notificar-me quando alguém reverter uma edição minha, ao utilizar a função desfazer ou a ferramenta de reversão.",
+ "echo-pref-tooltip-mention": "Notificar-me quando alguém mencionar a minha página de utilizador.",
+ "echo-pref-tooltip-user-rights": "Notificar-me quando os meus privilégios de utilizador forem alterados.",
+ "echo-no-agent": "[Ninguém]",
+ "echo-no-title": "[Nenhuma página]",
+ "echo-error-no-formatter": "Sem formato definido para notificações",
+ "echo-error-preference": "Erro: não foi possível configurar as preferências do utilizador",
+ "echo-error-token": "Erro: Não foi possível receber o toque do utilizador.",
+ "notifications": "Notificações",
+ "tooltip-pt-notifications": "As suas notificações",
+ "echo-specialpage": "Notificações",
+ "echo-anon": "Para receber notificações, [$1 crie uma conta] ou [$2 entre] na sua.",
+ "echo-none": "Não tem notificações.",
+ "echo-more-info": "Mais informações",
+ "echo-feedback": "Comentários",
+ "notification-link-text-view-message": "Ver mensagem",
+ "notification-link-text-view-mention": "Ver menção",
+ "notification-link-text-view-changes": "Ver mudanças",
+ "notification-link-text-view-page": "Ver página",
+ "notification-link-text-view-edit": "Ver edição",
+ "notification-edit-talk-page2": "[[User:$1|$1]] deixou uma mensagem na sua [[User talk:$2#$3|página de discussão]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] deixou uma mensagem na sua página de discussão na secção \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 deixou uma mensagem na sua [[User talk:$2#$3|página de discussão]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 deixou uma mensagem na sua página de discussão na secção \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] foi {{GENDER:$1|ligada}} a partir de [[:$3]]. [[Special:WhatLinksHere/$2|Ver todas as páginas afluentes a esta]].",
+ "notification-page-linked-flyout": "[[:$2]] foi {{GENDER:$1|ligada}} a partir de [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] comentou em \"[[$3|$2]]\" na página de discussão de \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] criou o novo tópico \"$2\" em [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] enviou-lhe uma mensagem: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] comentou na secção \"[[$3#$2|$2]]\" na sua página de discussão.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|mencionou}} você na página de discussão $5, na secção \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|mencionou}} você na página de discussão $5, na secção \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|mencionou}} você na [[:$3|página de discussão de $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|mencionou}} você na [[:$3|página de discussão de $2]].",
+ "notification-user-rights": "Os seus privilégios de {{GENDER:$1|utilizador}} [[Special:Log/rights/$1|foram]] alterados por [[User:$1|$1]]. $2. [[Special:ListGroupRights|Saiba mais]]",
+ "notification-user-rights-flyout": "Os seus privilégios de {{GENDER:$1|utilizador|utilizadora}} foram alterados por $1. $2. [[Special:ListGroupRights|Saiba mais]]",
+ "notification-user-rights-add": "É agora membro {{PLURAL:$2|deste grupo|destes grupos}}: $1",
+ "notification-user-rights-remove": "Já não é membro {{PLURAL:$2|deste grupo|destes grupos}}: $1",
+ "notification-new-user": "Bem-vindo(a) a {{SITENAME}}, $1! Estamos contentes por se ter juntado a nós.",
+ "notification-reverted2": "{{PLURAL:$4|A sua edição em [[:$2]] foi revertida|As suas edições em [[:$2]] foram revertidas}} por [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|A sua edição em $2 foi revertida|As suas edições em $2 foram revertidas}} {{GENDER:$1|pelo|pela|por}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|deixou-lhe}} uma mensagem em {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 deixou-lhe uma mensagem {{GENDER:$1|na}} {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|deixou-lhe}} uma mensagem na sua página de discussão na secção \"$2\".",
+ "notification-page-linked-email-subject": "A sua página foi ligada em {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "A página $2 foi {{GENDER:$1|ligada}} a partir de $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|A sua edição foi revertida|As suas edições foram revertidas}} {{GENDER:$1|}} em {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|A sua edição em $2 foi revertida|As suas edições em $2 foram revertidas}} por $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|mencionou}} você em {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|mencionou}} você na página de discussão $4, na secção \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|mencionou}} você na página de discussão $2.",
+ "notification-user-rights-email-subject": "Os seus privilégios de utilizador foram alterados em {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Os seus privilégios de utilizador foram {{GENDER:$1|alterados}} por $1. $2.",
+ "echo-email-subject-default": "Nova notificação em {{SITENAME}}",
+ "echo-email-body-default": "Tem uma nova notificação em {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Tem uma nova notificação.",
+ "echo-email-footer-default": "$2\n\nPara controlar quais os e-mails que deseja receber, consulte as suas preferências: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Para controlar quais os e-mails que deseja receber, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">consulte as suas preferências</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Alerta ($1)|Alertas ($1)|100=Alertas (+99)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mensagem ($1)|Mensagens ($1)|100=Mensagens (+99)}}",
+ "echo-notification-alert-text-only": "Alertas",
+ "echo-notification-message-text-only": "Mensagens",
+ "echo-overlay-link": "Todas as notificações",
+ "echo-overlay-title": "<b>Notificações</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notificações}}</b> (a mostrar $1 de $2 não lidas)",
+ "echo-mark-all-as-read": "Marcas todas como lidas",
+ "echo-date-today": "Hoje",
+ "echo-date-yesterday": "Ontem",
+ "echo-load-more-error": "Ocorreu um erro ao carregar mais resultados.",
+ "notification-edit-talk-page-bundle": "$1 e $3 {{PLURAL:$4|outro|outros}} {{GENDER:$1|deixaram}} uma mensagem na sua [[User talk:$2|página de discussão]].",
+ "notification-page-linked-bundle": "$2 foi {{GENDER:$1|ligada}} a partir de $3 e $4 {{PLURAL:$5|outra página|outras páginas}}. [[Special:WhatLinksHere/$2|Veja todas as páginas ligadas a esta]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e $2 {{PLURAL:$3|outro|outros}} {{GENDER:$1|deixaram}} uma mensagem na sua página de discussão.",
+ "notification-page-linked-email-batch-bundle-body": "$2 foi {{GENDER:$1|ligada}} a partir de $3 e $4 para {{PLURAL:$5|outra página|outras páginas}}.",
+ "echo-email-batch-subject-daily": "Tem {{PLURAL:$2|uma nova notificação|novas notificações}} em {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Tem {{PLURAL:$2|uma nova notificação|novas notificações}} em {{SITENAME}} esta semana",
+ "echo-email-batch-body-intro-daily": "Olá $1,\nAqui está um resumo da actividade de hoje em {{SITENAME}} para si.",
+ "echo-email-batch-body-intro-weekly": "Olá $1,\nAqui está um resumo da actividade desta semana em {{SITENAME}} para si.",
+ "echo-email-batch-link-text-view-all-notifications": "Ver todas as notificações",
+ "echo-rev-deleted-text-view": "A revisão desta página foi suprimida."
+}
diff --git a/Echo/i18n/qqq.json b/Echo/i18n/qqq.json
new file mode 100644
index 00000000..147423d8
--- /dev/null
+++ b/Echo/i18n/qqq.json
@@ -0,0 +1,160 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Beta16",
+ "Geraki",
+ "Jduranboger",
+ "Kaganer",
+ "Kghbln",
+ "Krenair",
+ "Lloffiwr",
+ "Minh Nguyen",
+ "Mormegil",
+ "Nemo bis",
+ "Nike",
+ "Pxos",
+ "Raymond",
+ "Shirayuki",
+ "Siebrand",
+ "Toliño",
+ "Urhixidur",
+ "రహ్మానుద్దీన్",
+ "Liuxinyu970226",
+ "Purodha",
+ "Umherirrender"
+ ]
+ },
+ "echo-desc": "{{desc|name=Echo|url=https://www.mediawiki.org/wiki/Extension:Echo}} The [https://www.mediawiki.org/wiki/Help:Notifications Mediawiki help] page gives notes on the terminology in this extension.",
+ "prefs-echo": "Name of preferences section for Echo notifications.\n{{Identical|Notification}}",
+ "prefs-emailsettings": "Header for the section of preferences that deals with how often notification emails are sent out and what address they are sent to.\n{{Identical|E-mail option}}",
+ "prefs-displaynotifications": "Header for the section of preferences that deals with how notifications are displayed",
+ "prefs-echosubscriptions": "Header for the section of preferences that deals with which notifications the user receives",
+ "prefs-newmessageindicator": "Header for the section of preferences that deals with talk page message alerts",
+ "echo-pref-send-me": "Label for the following email delivery options:\n* {{msg-mw|Echo-pref-email-frequency-never}}\n* {{msg-mw|Echo-pref-email-frequency-immediately}} (default)\n* {{msg-mw|Echo-pref-email-frequency-daily}}\n* {{msg-mw|Echo-pref-email-frequency-weekly}}",
+ "echo-pref-send-to": "Label for the address to send email notifications to.",
+ "echo-pref-email-format": "Label for individual email notification format, the label will be updated once HTML email is ready for email digest.\n\nUsed as label for the select box which has the following options:\n* {{msg-mw|Echo-pref-email-format-html}}\n* {{msg-mw|Echo-pref-email-format-plain-text}}",
+ "echo-pref-web": "Label for list of notifications which are delivered on the web. In other words, on the wiki itself rather by email or another method. This should be kept very short.",
+ "echo-pref-email": "Label for list of notifications which are delivered via email. This should be kept very short.\n{{Identical|E-mail}}",
+ "echo-pref-email-frequency-never": "Option for users who don't want to receive any email notifications\n\nSee also:\n* {{msg-mw|Echo-pref-email-frequency-immediately}}\n* {{msg-mw|Echo-pref-email-frequency-daily}}\n* {{msg-mw|Echo-pref-email-frequency-weekly}}",
+ "echo-pref-email-frequency-immediately": "Option for users who want to receive email for each notification as it occurs",
+ "echo-pref-email-frequency-daily": "Option for users who want to receive a daily digest of email notifications",
+ "echo-pref-email-frequency-weekly": "Option for users who want to receive a weekly digest of email notifications",
+ "echo-pref-email-format-html": "Option for users who want to receive HTML email notification.\n\nSee also:\n* {{msg-mw|Echo-pref-email-format}}\n{{Identical|HTML}}",
+ "echo-pref-email-format-plain-text": "Option for users who want to receive plain text email notification.\n\nSee also:\n* {{msg-mw|Echo-pref-email-format}}\n{{Identical|Plain text}}",
+ "echo-pref-notify-show-link": "Label for a preference which enables the 'Notifications' link in the header and associated fly-out panel",
+ "echo-pref-new-message-indicator": "Label for a preference which enables the new talk page message alert",
+ "echo-learn-more": "Text for link to more information about a topic.\n{{Identical|Learn more}}",
+ "echo-new-messages": "Message to let the user know that they have new talk page messages, displayed in the personal menu (top-right corner on Vector and Monobook).\n\nKeep this message short. It '''should not''' end in a full stop.",
+ "echo-category-title-edit-user-talk": "This is a short title for notification category.\n\nUsed in a list of options under the heading {{msg-mw|Prefs-echosubscriptions}} in Special:Preferences. As far as I can see this always needs to be a plural for an unspecified number.\n\nIt used to be used as <code>$1</code> in {{msg-mw|Echo-dismiss-message}}, but this message is no longer used, apparently.\n\nParameters:\n* $1 - number of messages, for PLURAL support\n{{Related|Echo-category-title}}",
+ "echo-category-title-article-linked": "This is a short title for notification category.\n\nUsed in a list of options under the heading {{msg-mw|Prefs-echosubscriptions}} in Special:Preferences. As far as I can see this always needs to be a plural for an unspecified number.\n\nIt used to be used as <code>$1</code> in {{msg-mw|Echo-dismiss-message}}, but this message is no longer used, apparently.\n\nParameters:\n* $1 - number of messages, for PLURAL support\n{{Related|Echo-category-title}}",
+ "echo-category-title-reverted": "This is a short title for notification category.\n\nUsed in a list of options under the heading {{msg-mw|Prefs-echosubscriptions}} in Special:Preferences. As far as I can see this always needs to be a plural for an unspecified number.\n\nIt used to be used as <code>$1</code> in {{msg-mw|Echo-dismiss-message}}, but this message is no longer used, apparently.\n\nParameters:\n* $1 - number of messages, for PLURAL support\n{{Related|Echo-category-title}}",
+ "echo-category-title-mention": "This is a short title for notification category.\n\nUsed in a list of options under the heading {{msg-mw|Prefs-echosubscriptions}} in Special:Preferences. As far as I can see this always needs to be a plural for an unspecified number.\n\nIt used to be used as <code>$1</code> in {{msg-mw|Echo-dismiss-message}}, but this message is no longer used, apparently.\n\nParameters:\n* $1 - number of messages, for PLURAL support\n{{Related|Echo-category-title}}\n{{Identical|Mention}}",
+ "echo-category-title-other": "This is a short title for notification category.\n\nUsed in a list of options under the heading {{msg-mw|Prefs-echosubscriptions}} in Special:Preferences. As far as I can see this always needs to be a plural for an unspecified number.\n\nIt used to be used as <code>$1</code> in {{msg-mw|Echo-dismiss-message}}, but this message is no longer used, apparently.\n\nParameters:\n* $1 - number of messages, for PLURAL support\n{{Related|Echo-category-title}}\n{{Identical|Other}}",
+ "echo-category-title-system": "This is a short title for notification category.\n\nUsed in a list of options under the heading {{msg-mw|Prefs-echosubscriptions}} in Special:Preferences. As far as I can see this always needs to be a plural for an unspecified number.\n\nIt used to be used as <code>$1</code> in {{msg-mw|Echo-dismiss-message}}, but this message is no longer used, apparently.\n\nParameters:\n* $1 - number of messages, for PLURAL support\n{{Related|Echo-category-title}}\n{{Identical|System}}",
+ "echo-category-title-user-rights": "This is a short title for notification category.\n\nUsed in a list of options under the heading {{msg-mw|Prefs-echosubscriptions}} in Special:Preferences. As far as I can see this always needs to be a plural for an unspecified number.\n\nIt used to be used as <code>$1</code> in {{msg-mw|Echo-dismiss-message}}, but this message is no longer used, apparently.\n\nParameters:\n* $1 - number of messages, for PLURAL support\n{{Related|Echo-category-title}}",
+ "echo-pref-tooltip-edit-user-talk": "This is a short description of the edit-user-talk notification category.\n{{Related|Echo-pref-tooltip}}",
+ "echo-pref-tooltip-article-linked": "This is a short description of the article-linked notification category.\n{{Related|Echo-pref-tooltip}}",
+ "echo-pref-tooltip-reverted": "This is a short description of the tooltip-reverted notification category.\n{{Related|Echo-pref-tooltip}}",
+ "echo-pref-tooltip-mention": "This is a short description of the mention notification category.\n{{Related|Echo-pref-tooltip}}",
+ "echo-pref-tooltip-user-rights": "This is a short description of the user rights changes notification category\n{{Related|Echo-pref-tooltip}}",
+ "echo-no-agent": "Shown in place of a username in a notification\n\tif the notification has no specified user.",
+ "echo-no-title": "Shown in place of a page title in a notification if the notification has no specified page title.",
+ "echo-error-no-formatter": "Error message displayed when no formatting has been defined for a notification. In other words, the extension doesn't know how to properly display the notification.",
+ "echo-error-preference": "Error message displayed when request to set user preference fails",
+ "echo-error-token": "Error message displayed when request to get user token fails",
+ "notifications": "{{doc-special|Notifications}}\n{{Identical|Notification}}",
+ "tooltip-pt-notifications": "This is used for the title (mouseover text) of the notifications user tool.",
+ "echo-specialpage": "Special page title for Special:Notifications.\n{{Identical|Notification}}",
+ "echo-anon": "Error message shown to users who try to visit [[Special:Notifications]] as an anon.\n\nParameters:\n* $1 - URL of signup page, with returnto pointing to Special:Notifications\n* $2 - URL of login page, with returnto pointing to Special:Notifications",
+ "echo-none": "Message shown to users who have no notifications. Also shown in the overlay.",
+ "echo-more-info": "This is used for the title (mouseover text) of an icon that links to a page with more information about the Echo extension.\n{{Identical|More information}}",
+ "echo-feedback": "Text for a link that goes to a feedback survey shown at [[Special:Notifications]].\n{{Identical|Feedback}}",
+ "echo-quotation-marks": "Unused at this time.\n\n{{optional}}\nPuts the edit summary in quotation marks. Only translate if different than English.\n\nParameters:\n* $1 - ...",
+ "notification-link-text-view-message": "Label for button that links to a message on your talk page.\n{{Identical|View message}}",
+ "notification-link-text-view-mention": "Label for button that links to a discussion where you were mentioned.",
+ "notification-link-text-view-changes": "Label for button that links to a \"diff\" view showing changes made to a page. This is an alternative to the wording in {{msg-mw|notification-link-text-view-edit}}, which serves essentially the same function.\n{{Identical|View changes}}",
+ "notification-link-text-view-page": "Label for button that links to a page.\n{{Identical|View page}}",
+ "notification-link-text-view-edit": "Label for button that links to a \"diff\" view showing an edit made to a page. This is an alternative to the wording in {{msg-mw|notification-link-text-view-changes}}, which serves essentially the same function.",
+ "notification-edit-talk-page2": "Format for displaying notifications of a user talk page being edited. Parameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the current user's name, used in the link to their talk page\n* $3 - the section title of the discussion, if any, used in the link to their talk page\nSee also:\n* {{msg-mw|Notification-edit-talk-page-flyout2}}\n* {{msg-mw|Notification-add-talkpage-topic2}}\n* left is for verb left.",
+ "notification-edit-talk-page-with-section": "Format for displaying notifications of a user talk page being edited with a new section or new comment.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the username of current user, used in the link to their talk page\n* $3 - the section title of the discussion, if any, used in the link to their talk page\n* $4 - the raw section title text",
+ "notification-edit-talk-page-flyout2": "Flyout-specific format for displaying notifications of a user talk page being edited.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the current user's name, used in the link to their talk page\n* $3 - the section title of the discussion, if any, used in the link to their talk page\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-add-talkpage-topic2}}",
+ "notification-edit-talk-page-flyout-with-section": "Flyout-specific format for displaying notifications of a user talk page being edited with a new section or new comment.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the username of current user, used in the link to their talk page\n* $3 - the section title of the discussion, if any, used in the link to their talk page\n* $4 - the raw section title text",
+ "notification-page-linked": "Format for displaying notifications of articles being linked. Parameters:\n* $1 - the username of the person who linked the page, plain text. Can be used for GENDER.\n* $2 - the page being linked\n* $3 - the page linked from\nSee also:\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
+ "notification-page-linked-flyout": "Flyout-specific format for displaying notifications of articles being linked.\n\nParameters:\n* $1 - the username of the person who linked the page, plain text. Can be used for GENDER.\n* $2 - the page being linked\n* $3 - the page linked from\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
+ "notification-add-comment2": "Format for displaying notifications of a comment being added to an existing discussion.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the section title of the discussion\n* $3 - a link to a page and section\n* $4 - the page on which the discussion exists, plain text\nSee also:\n* {{msg-mw|Notification-add-comment-yours2}}",
+ "notification-add-talkpage-topic2": "Format for displaying notifications of a new discussion being added. Parameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the section title of the discussion\n* $3 - the page on which the discussion was added, plain text\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-flyout2}}",
+ "notification-add-talkpage-topic-yours2": "Parameters:\n* $1 - a username, plain text. Can be used for GENDER.\n* $2 - a page section\n* $3 - a page title",
+ "notification-add-comment-yours2": "Parameters:\n* $1 - a username, plain text; can be used for GENDER\n* $2 - discussion name\n* $3 - link to user talk page\nSee also:\n* {{msg-mw|Notification-add-comment2}}",
+ "notification-mention": "Format for displaying notifications of a comment in a specific section including a link to another user's user page.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER\n* $2 - the section title of the discussion\n* $3 - the page title of the discussion\n* $4 - the raw section title text\n* $5 - the title text without namespace (a page title in any namespace)",
+ "notification-mention-flyout": "Flyout-specific format for displaying notifications of a comment in a specific section.\nParameters:\n* $1 - the username of the person who mentioned you, plain text. Can be used for GENDER.\n* $2 - the section title of the discussion\n* $3 - the page title of the discussion\n* $4 - the raw section title text\n* $5 - the title text without namespace (a page title in any namespace)",
+ "notification-mention-nosection": "Format for displaying notifications of a comment including a link to another user's user page. Parameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER\n* $2 - the title text without namespace (a page title in any namespace)\n* $3 - the page title of the discussion",
+ "notification-mention-nosection-flyout": "Flyout-specific format for displaying notifications of a comment.\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER\n* $2 - the title text without namespace (a page title in any namespace)\n* $3 - the page title of the discussion",
+ "notification-user-rights": "Format for displaying notifications of a user right change in notification page.\n\nParameters:\n* $1 - the username of the person who made the user right change. Can be used for GENDER support.\n* $2 - a semicolon separated list of {{msg-mw|Notification-user-rights-add}}, {{msg-mw|Notification-user-rights-remove}}",
+ "notification-user-rights-flyout": "Format for displaying notifications of a user right change in notification flyout. Parameters:\n* $1 - the username of the person who made the user right change. Can be used for GENDER support\n* $2 - a semicolon separated list of {{msg-mw|notification-user-rights-add}}, {{msg-mw|notification-user-rights-remove}}",
+ "notification-user-rights-add": "Message indicating that a user was added to a user group. Parameters:\n* $1 - a comma separated list of user group names\n* $2 - the number of user groups, this is used for PLURAL support\nSee also:\n* {{msg-mw|Notification-user-rights-remove}}",
+ "notification-user-rights-remove": "Message indicating that a user was removed from a user group. Parameters:\n* $1 - a comma separated list of user group names\n* $2 - the number of user groups, this is used for PLURAL support\nSee also:\n* {{msg-mw|Notification-user-rights-add}}",
+ "notification-new-user": "Text of the welcome notification. Parameters:\n* $1 - the name of the new user\nSee also:\n* {{msg-mw|Guidedtour-tour-gettingstarted-start-title}}",
+ "notification-reverted2": "Format for displaying notifications of a user's edit being reverted. Parameters:\n* $1 - the username of the person who reverted, plain text. Can be used for GENDER.\n* $2 - the page that was reverted, formatted\n* $3 - a diff link which is labeled {{msg-mw|Showdiff}}\n* $4 - the number of edits that were reverted. NOTE: This will only be set to 1 or 2, with 2 actually meaning 'an unknown number greater than 0'.\n{{Related|Notification-reverted}}",
+ "notification-reverted-flyout2": "Flyout-specific format for displaying notifications of a user's edit being reverted.\n\nParameters:\n* $1 - the username of the person who reverted, plain text. Can be used for GENDER.\n* $2 - the page that was reverted, formatted\n* $3 - a diff link which is labeled {{msg-mw|Showdiff}}\n* $4 - the number of edits that were reverted. NOTE: This will only be set to 1 or 2, with 2 actually meaning \"an unknown number greater than 0\".\n{{Related|Notification-reverted}}",
+ "notification-edit-talk-page-email-subject2": "Email subject. Parameters:\n* $1 - a username which can be used for gender support",
+ "notification-edit-talk-page-email-batch-body2": "First line of the email notification for a talk page edit. The following line completes it with the description of the message in question, that is its edit summary.\n\nParameters:\n* $1 - a username (which also links to the userpage of the user in question, in the HTML version)\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-email-subject2}}\n* {{msg-mw|Notification-edit-talk-page-flyout2}}",
+ "notification-edit-talk-page-email-batch-body-with-section": "Email notification for talk page edit with new section or new comment. Parameters:\n* $1 - a username\n* $2 - the raw section title text",
+ "notification-page-linked-email-subject": "E-mail subject.\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}",
+ "notification-page-linked-email-batch-body": "Email notification for page being linked. Parameters:\n* $1 - the username of the person who linked the page, plain text. Can be used for GENDER.\n* $2 - the page being linked\n* $3 - the page linked from\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
+ "notification-reverted-email-subject2": "Email subject. Parameters:\n* $1 - a username\n* $2 - (Unused) a page title\n* $3 - the number of reverts\n{{Related|Notification-reverted}}",
+ "notification-reverted-email-batch-body2": "Email notification for page revert. Parameters:\n* $1 - a username\n* $2 - a page title\n* $3 - the number of revert\n{{Related|Notification-reverted}}",
+ "notification-mention-email-subject": "Email subject. Parameters:\n* $1 - a username\nSee also:\n* {{msg-mw|Notification-mention}}\n* {{msg-mw|Notification-mention-flyout}}\n* {{msg-mw|Notification-mention-email-batch-body}}",
+ "notification-mention-email-batch-body": "E-mail notification batch body. Parameters:\n* $1 - a username, plaintext. Can be used for gender support\n* $2 - (Unused) talk page title\n* $3 - the raw section title text\n* $4 - the title text without namespace (a page title in any namespace)\n\nSee also:\n* {{msg-mw|Notification-mention}}\n* {{msg-mw|Notification-mention-flyout}}\n* {{msg-mw|Notification-mention-email-subject}}",
+ "notification-mention-nosection-email-batch-body": "E-mail notification batch body. Parameters:\n* $1 - a username, plaintext. Can be used for gender support\n* $2 - the title text without namespace (a page title in any namespace)\n\nSee also:\n* {{msg-mw|Notification-mention-nosection}}\n* {{msg-mw|Notification-mention-nosection-flyout}}\n* {{msg-mw|Notification-mention-email-subject}}",
+ "notification-user-rights-email-subject": "E-mail subject for user rights notification\n\nSee also:\n* {{msg-mw|Notification-user-rights}}\n* {{msg-mw|Notification-user-rights-flyout}}\n* {{msg-mw|Notification-user-rights-email-batch-body}}",
+ "notification-user-rights-email-batch-body": "Email notification batch body. Parameters:\n* $1 - a user name, plaintext. Can be used for gender support.\n* $2 - a semicolon separated list of {{msg-mw|notification-user-rights-add}}, {{msg-mw|notification-user-rights-remove}}",
+ "echo-notification-count": "{{optional}}\nThe new notification count next to notification link, for example: 99+\n\nParameters:\n* $1 - the count",
+ "echo-email-subject-default": "Default subject for Echo e-mail notifications",
+ "echo-email-body-default": "Default message content for Echo email notifications. Parameters:\n* $1 - a plain text description of the notification",
+ "echo-email-batch-body-default": "Default message for Echo e-mail digest notifications",
+ "echo-email-footer-default": "Default footer content for Echo text e-mail notifications. Parameters:\n* $1 - the address of the organization that sent the email\n* $2 - \"-------...\" ({{msg-mw|echo-email-batch-separator}})\n\nFor HTML version, see {{msg-mw|echo-email-footer-default-html}}.",
+ "echo-email-footer-default-html": "Default footer content for Echo html e-mail notifications. Parameters:\n* $1 - the address of the organization that sent the email\n* $2 - the URL to the notification preference page\nFor plain-text version, see {{msg-mw|Echo-email-footer-default}}.",
+ "echo-notification-alert": "Label for alert notifications (= non discussion notifications) tab in Echo overlay. Parameters:\n* $1 - the number of unread alerts. The number cannot be higher than 100.\nSee also:\n* {{msg-mw|Echo-notification-message}}\n{{Identical|Alert}}",
+ "echo-notification-message": "Label for message notifications (= discussion notifications) tab in Echo overlay. Parameters:\n* $1 - the number of unread messages. The number cannot be higher than 100.\nSee also:\n* {{msg-mw|Echo-notification-alert}}\n{{Identical|Message}}",
+ "echo-notification-alert-text-only": "Label for alert notifications (= non discussion notifications) tab in Echo overlay without alert notification count next to it\n{{Identical|Alert}}",
+ "echo-notification-message-text-only": "Label for message notifications (= discussion notifications) tab in Echo overlay without message notification count next to it\n{{Identical|Message}}",
+ "echo-overlay-link": "Link to \"all notifications\" at the bottom of the overlay.\n{{Identical|All notifications}}",
+ "echo-overlay-title": "Title at the top of the notifications overlay. Should include bold tags.\n{{Identical|Notification}}",
+ "echo-overlay-title-overflow": "Title at the top of the notifications overlay when there are additional unread notifications that are not being shown.\n\nParameters:\n* $1 - the number of unread notifications being shown\n* $2 - the total number of unread notifications that exist",
+ "echo-mark-all-as-read": "Text for button that marks all unread notifications as read. Keep this short as possible.\n{{Identical|Mark all as read}}",
+ "echo-date-today": "The header text for today's notification section.\n{{Identical|Today}}",
+ "echo-date-yesterday": "The header text for yesterday's notification section.\n{{Identical|Yesterday}}",
+ "echo-load-more-error": "Error message for errors in loading more notifications",
+ "notification-edit-talk-page-bundle": "Bundled message for edit-user-talk notification. Parameters:\n* $1 - the name of the user who performed the action, which can be used for gender support\n* $2 - the name of the user being addressed\n* $3 - the count of other action performers, could be a number or {{msg-mw|Echo-notification-count}}. e.g. \"7\" or \"99+\"\n* $4 - a number used for plural support relating to $3 (likely identical to $3 it that is a number, and 100 otherwise)\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-email-batch-body2}}\n* {{msg-mw|Notification-edit-talk-page-email-subject2}}",
+ "notification-page-linked-bundle": "Bundled message for page-linked notification. Parameters:\n* $1 - the username who performs the action, which can be used for gender support\n* $2 - the page title\n* $3 - the page linked from\n* $4 - the count of other action performers, could be number or {{msg-mw|Echo-notification-count}}. e.g. 7 others or 99+ others\n* $5 - a number used for plural support (numeric version of $4)\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
+ "notification-edit-user-talk-email-batch-bundle-body": "Bundled message for edit-user-talk email digest notification. Parameters:\n* $1 - the username who performs the action, which can be used for gender support\n* $2 - the count of other action performers, could be number or {{msg-mw|echo-notification-count}}\n* $3 - a number used for plural support\n\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-flyout2}}\n* {{msg-mw|Notification-edit-talk-page-email-batch-body2}}\n* {{msg-mw|Notification-edit-talk-page-email-subject2}}",
+ "notification-page-linked-email-batch-bundle-body": "Bundled message for page-linked email digest notification. Parameters:\n* $1 - the username who performs the action, which can be used for gender support\n* $2 - the link-to page title\n* $3 - the link-from page title\n* $4 - the count of other link-from page title, can be number or {{msg-mw|echo-notification-count}}\n* $5 - a number used for plural support (numeric version of $4)\n\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
+ "echo-email-batch-separator": "{{optional}}\nEmail batch content separator",
+ "echo-email-batch-bullet": "{{optional}}",
+ "echo-email-batch-subject-daily": "Daily email batch subject.\n* $1 - (Unused) could be a numeric count or \"10+\". See also: {{msg-mw|Echo-notification-count|optional message}}.\n* $2 - a numeric count, this is used for plural support\nSee also:\n* {{msg-mw|Echo-email-batch-subject-weekly}}",
+ "echo-email-batch-subject-weekly": "Weekly email batch subject. Parameters:\n* $1 - (Unused) could be a numeric count or \"10+\". See also: {{msg-mw|Echo-notification-count|optional message|notext=1}}\n* $2 - a numeric count, this is used for plural support\nSee also:\n* {{msg-mw|Echo-email-batch-subject-daily}}",
+ "echo-email-batch-body-intro-daily": "Introduction text for daily email digest. Parameters:\n* $1 - a username\nSee also:\n* {{msg-mw|Echo-email-batch-body-intro-weekly}}",
+ "echo-email-batch-body-intro-weekly": "Introduction text for weekly email digest. Parameters:\n* $1 - a username\nSee also:\n* {{msg-mw|Echo-email-batch-body-intro-daily}}",
+ "echo-email-batch-link-text-view-all-notifications": "The link text for the primary action in daily and weekly email digest",
+ "echo-rev-deleted-text-view": "Short message displayed instead of edit content when revision text is suppressed.",
+ "apihelp-echomarkread-description": "{{doc-apihelp-description|echomarkread}}",
+ "apihelp-echomarkread-param-list": "{{doc-apihelp-param|echomarkread|list}}",
+ "apihelp-echomarkread-param-all": "{{doc-apihelp-param|echomarkread|all}}",
+ "apihelp-echomarkread-param-sections": "{{doc-apihelp-param|echomarkread|sections}}",
+ "apihelp-echomarkread-example-1": "{{doc-apihelp-example|echomarkread}}",
+ "apihelp-echomarkread-example-2": "{{doc-apihelp-example|echomarkread}}",
+ "apihelp-query+notifications-description": "{{doc-apihelp-description|query+notifications}}",
+ "apihelp-query+notifications-param-prop": "{{doc-apihelp-param|query+notifications|prop}}",
+ "apihelp-query+notifications-param-sections": "{{doc-apihelp-param|query+notifications|sections}}",
+ "apihelp-query+notifications-param-groupbysection": "{{doc-apihelp-param|query+notifications|groupbysection}}",
+ "apihelp-query+notifications-param-format": "{{doc-apihelp-param|query+notifications|format}}",
+ "apihelp-query+notifications-param-limit": "{{doc-apihelp-param|query+notifications|limit}}",
+ "apihelp-query+notifications-param-index": "{{doc-apihelp-param|query+notifications|index}}",
+ "apihelp-query+notifications-param-alertcontinue": "{{doc-apihelp-param|query+notifications|alertcontinue}}",
+ "apihelp-query+notifications-param-alertunreadfirst": "{{doc-apihelp-param|query+notifications|alertunreadfirst}}",
+ "apihelp-query+notifications-param-messagecontinue": "{{doc-apihelp-param|query+notifications|messagecontinue}}",
+ "apihelp-query+notifications-param-messageunreadfirst": "{{doc-apihelp-param|query+notifications|messageunreadfirst}}",
+ "apihelp-query+notifications-example-1": "{{doc-apihelp-example|query+notifications}}",
+ "apihelp-query+notifications-example-2": "{{doc-apihelp-example|query+notifications}}"
+}
diff --git a/Echo/i18n/qu.json b/Echo/i18n/qu.json
new file mode 100644
index 00000000..efde9770
--- /dev/null
+++ b/Echo/i18n/qu.json
@@ -0,0 +1,37 @@
+{
+ "@metadata": {
+ "authors": [
+ "AlimanRuna"
+ ]
+ },
+ "prefs-echo": "Willaykuykuna",
+ "echo-pref-send-me": "Kachamuway:",
+ "echo-pref-send-to": "Kayman kachay:",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Qillqalla",
+ "echo-learn-more": "Astawan yachay",
+ "echo-new-messages": "Musuq willaykunam qhawanayki kachkan",
+ "notifications": "Willaykuykuna",
+ "tooltip-pt-notifications": "Qampaq willaykuna",
+ "echo-specialpage": "Willaykuykuna",
+ "notification-link-text-view-message": "Willasqata qhaway",
+ "notification-link-text-view-changes": "Hukchasqakunata qhaway",
+ "notification-edit-talk-page2": "[[User:$1|$1]] sutiyuq ruraqqa qampaq {{GENDER:$1|willaynintam}} [[User talk:$2#$3|rimanakuy p'anqaykipi]] saqisurqanki.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] sutiyuq ruraqqa qampaq {{GENDER:$1|willaynintam}} rimanakuy p'anqaykipi [[User talk:$2#$3|$4]]-pi saqisurqanki.",
+ "notification-edit-talk-page-flyout2": "$1 qampaq {{GENDER:$1|willaynintam}} [[User talk:$2#$3|rimanakuy p'anqaykipi]] saqisurqanki.",
+ "notification-edit-talk-page-flyout-with-section": "$1 qampaq {{GENDER:$1|willaynintam}} rimanakuy p'anqaykipi [[User talk:$2#$3|$4]]-pi saqisurqanki.",
+ "notification-mention": "[[User:$1|$1]] qammanta rimaspa {{GENDER:$1|qillqarqan}} $5 rimanakuy p'anqapi \"[[:$3#$2|$4]]\" nisqapim.",
+ "notification-mention-flyout": "$1 qammanta rimaspa {{GENDER:$1|qillqarqan}} $5 rimanakuy p'anqapi \"[[:$3#$2|$4]]\" nisqapim.",
+ "notification-reverted2": "[[User:$1|$1]] sutiyuq ruraqqa [[:$2]] nisqapi qampa {{PLURAL:$4|llamk'apusqaykita|llamk'apusqaykikunata}} {{GENDER:$1|kutichirqanmi}}. $3",
+ "notification-reverted-flyout2": "$1 sutiyuq ruraqqa $2 nisqapi qampa {{PLURAL:$4|llamk'apusqaykita|llamk'apusqaykikunata}} {{GENDER:$1|kutichirqanmi}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 sutiyuq {{GENDER:$1|ruraqqa}} willasqantam saqisurqanki {{SITENAME}} nisqapi.",
+ "notification-edit-talk-page-email-batch-body2": "$1 sutiyuq {{GENDER:$1|ruraqqa}} rimanakuy p'anqaykipi willasqantam saqirqan:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 sutiyuq {{GENDER:$1|ruraqqa}} rimanakuy p'anqaykipi willasqantam saqisurqanki \"$2\" nisqapi.",
+ "echo-email-footer-default": "$2\n\nKachasunayku e-chaski qillqakunata kamachinaykipaqqa, allinkachinaykikunata llanchiy:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Kachasunayku e-chaski qillqakunata kamachinaykipaqqa, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">allinkachinaykikunata llanchiy</a>.<br />\n$1",
+ "echo-overlay-link": "Tukuy qampaq willaykuykuna",
+ "echo-overlay-title": "<b>Willaykuykuna</b>",
+ "notification-edit-talk-page-bundle": "$1, $3 {{PLURAL:$4|wakinpas|wakinkunapas}} qampaq {{GENDER:$1|willaynintam}} [[User talk:$2|rimanakuy p'anqaykipi]] saqisurqanki.",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1, $2 wakin {{PLURAL:$3|ruraqpas|ruraqkunapas}} willayninta rimanakuy p'anqaykipim {{GENDER:$1|qillqamusurqanki}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Tukuy willaykuykunata qhaway"
+}
diff --git a/Echo/i18n/rm.json b/Echo/i18n/rm.json
new file mode 100644
index 00000000..58855ec4
--- /dev/null
+++ b/Echo/i18n/rm.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kazu89"
+ ]
+ },
+ "echo-new-messages": "Ti has novs messadis"
+}
diff --git a/Echo/i18n/ro.json b/Echo/i18n/ro.json
new file mode 100644
index 00000000..66b87712
--- /dev/null
+++ b/Echo/i18n/ro.json
@@ -0,0 +1,119 @@
+{
+ "@metadata": {
+ "authors": [
+ "Firilacroco",
+ "Minisarm",
+ "Reception123",
+ "Stelistcristi"
+ ]
+ },
+ "echo-desc": "Sistem de notificări",
+ "prefs-echo": "Notificări",
+ "prefs-emailsettings": "Setări pentru e-mail",
+ "prefs-displaynotifications": "Opțiuni de afișare",
+ "prefs-echosubscriptions": "Notifică-mă despre aceste evenimente",
+ "prefs-newmessageindicator": "Indicator de mesaj nou",
+ "echo-pref-send-me": "Trimite-mi:",
+ "echo-pref-send-to": "Trimite la:",
+ "echo-pref-email-format": "Formatul e-mailului:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Nu-mi trimite nicio notificare prin e-mail",
+ "echo-pref-email-frequency-immediately": "Notificări individuale pe măsură ce sosesc",
+ "echo-pref-email-frequency-daily": "Un rezumat zilnic al notificărilor",
+ "echo-pref-email-frequency-weekly": "Un rezumat săptămânal al notificărilor",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Text brut",
+ "echo-pref-notify-show-link": "Arată notificări în bara mea de instrumente",
+ "echo-pref-new-message-indicator": "Arată indicator pentru mesajele din pagina de discuții în bara mea de instrumente",
+ "echo-learn-more": "Aflați mai multe",
+ "echo-new-messages": "Aveți mesaje noi",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mesaj|Mesaje}} în pagina de discuții",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Legătură|Legături}} către pagină",
+ "echo-category-title-reverted": "{{PLURAL:$1|Revenire|Reveniri}} asupra modificărilor",
+ "echo-category-title-mention": "{{PLURAL:$1|Menționare|Menționări}}",
+ "echo-category-title-other": "{{PLURAL:$1|Altele}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Schimbare a drepturilor de utilizator|Schimbări ale drepturilor de utilizator}}",
+ "echo-pref-tooltip-edit-user-talk": "Notifică-mă când cineva publică un mesaj sau răspunde pe pagina mea de discuții.",
+ "echo-pref-tooltip-article-linked": "Notifică-mă atunci când cineva introduce într-un articol o legătură către una din paginile pe care le-am creat.",
+ "echo-pref-tooltip-reverted": "Notifică-mă atunci când cineva, folosind uneltele de anulare sau revenire, revine asupra unei modificări făcută de mine.",
+ "echo-pref-tooltip-mention": "Notifică-mă când cineva face referire la pagina mea de utilizator.",
+ "echo-pref-tooltip-user-rights": "Anunță-mă când cineva îmi schimbă drepturile de autor.",
+ "echo-no-agent": "[Nimeni]",
+ "echo-no-title": "[Nicio pagină]",
+ "echo-error-no-formatter": "Nicio formatare definită pentru această notificare.",
+ "echo-error-preference": "Eroare: Nu s-au putut stabili preferințele utilizatorului.",
+ "echo-error-token": "Eroare: Nu s-a putut prelua jetonul utilizatorului.",
+ "notifications": "Notificări",
+ "tooltip-pt-notifications": "Notificările dumneavoastră",
+ "echo-specialpage": "Notificări",
+ "echo-anon": "Pentru a primi notificări, [$1 creați-vă un cont] sau [$2 autentificați-vă].",
+ "echo-none": "Nu aveți nicio notificare.",
+ "echo-more-info": "Mai multe informații",
+ "echo-feedback": "Reacții",
+ "notification-link-text-view-message": "Vezi mesajul",
+ "notification-link-text-view-mention": "Vezi menționarea",
+ "notification-link-text-view-changes": "Vezi schimbările",
+ "notification-link-text-view-page": "Vezi pagina",
+ "notification-link-text-view-edit": "Vezi modificarea",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|a lăsat}} un mesaj pe [[User talk:$2#$3|pagina dumneavoastră de discuții]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|a lăsat}} un mesaj pe pagina dumneavoastră de discuții, în cadrul secțiunii „[[User talk:$2#$3|$4]]”.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|a lăsat}} un mesaj pe [[User talk:$2#$3|pagina dumneavoastră de discuții]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|a lăsat}} un mesaj pe pagina dumneavoastră de discuții, în cadrul secțiunii „[[User talk:$2#$3|$4]]”.",
+ "notification-page-linked": "[[:$2]] a fost {{GENDER:$1|menționată}} în [[:$3]]: [[Special:WhatLinksHere/$2|Vedeți toate legăturile către această pagină]].",
+ "notification-page-linked-flyout": "[[:$2]] a fost {{GENDER:$1|menționată}} în [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|a comentat}} subiectul „[[$3|$2]]” din pagina de discuție „$4”.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|a pornit}} un nou subiect („$2”) pe [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|v-a trimis}} un mesaj: „[[$3#$2|$2]]”.",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|a comentat}} subiectul „[[$3#$2|$2]]” de pe pagina dumneavoastră de discuții.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|v-a menționat}} pe pagina de discuții a paginii $5, în cadrul secțiunii „[[:$3#$2|$4]]”.",
+ "notification-mention-flyout": "$1 {{GENDER:$1|v-a menționat}} pe pagina de discuții a paginii $5, în cadrul secțiunii „[[:$3#$2|$4]]”.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|v-a menționat}} pe [[:$3|pagina de discuție a paginii $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|v-a menționat}} pe [[:$3|pagina de discuție a paginii $2]].",
+ "notification-user-rights": "Drepturile dumneavoastră de utilizator [[Special:Log/rights/$1|au fost {{GENDER:$1|schimbate}}]] de către [[User:$1|$1]]. $2. [[Special:ListGroupRights|Aflați mai multe]]",
+ "notification-user-rights-flyout": "Drepturile dumneavoastră de utilizator au fost {{GENDER:$1|schimbate}} de către $1. $2. [[Special:ListGroupRights|Aflați mai multe]]",
+ "notification-user-rights-add": "Sunteți acum membru al {{PLURAL:$2|acestui grup|acestor grupuri}}: $1",
+ "notification-user-rights-remove": "Nu mai sunteți membru al {{PLURAL:$2|acestui grup|acestor grupuri}}: $1",
+ "notification-new-user": "Bine ați venit la {{SITENAME}}, $1! Ne bucurăm că sunteți aici.",
+ "notification-reverted2": "{{PLURAL:$4|Modificarea dumneavoastră asupra paginii [[:$2]] a|Modificările dumneavoastră asupra paginii [[:$2]] au}} fost {{GENDER:$1|înlăturat}}{{PLURAL:$4|ă|e}} de către [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Modificarea dumneavoastră asupra paginii $2 a|Modificările dumneavoastră asupra paginii $2 au}} fost {{GENDER:$1|înlăturat}}{{PLURAL:$4|ă|e}} de către $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|v-a lăsat}} un mesaj la {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|a lăsat}} un mesaj pe pagina dumneavoastră de discuții:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|a lăsat}} un mesaj pe pagina dumneavoastră de discuții, în cadrul secțiunii „$2”.",
+ "notification-page-linked-email-subject": "Pagina dumnevoastră a fost menționată la {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 a fost {{GENDER:$1|menționată}} în $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Modificarea dumneavoastră a fost|Modificările dumneavoastră au fost}} {{GENDER:$1|înlăturat}}{{PLURAL:$3|ă|e}} la {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Modificarea dumneavoastră asupra paginii $2 a fost|Modificările dumneavoastră asupra paginii $2 au fost}} {{GENDER:$1|înlăturat}}{{PLURAL:$3|ă|e}} de către $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|v-a menționat}} la {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|v-a menționat}} pe pagina de discuții a paginii $4, în secțiunea „$3”.",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|v-a menționat}} pe pagina de discuție a paginii $2.",
+ "notification-user-rights-email-subject": "Drepturile dumneavoastră de utilizator s-au schimbat la {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Drepturile dumneavoastră de utilizator au fost {{GENDER:$1|schimbate}} de către $1. $2",
+ "echo-email-subject-default": "Notificare nouă la {{SITENAME}}",
+ "echo-email-body-default": "Aveți o notificare nouă la {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Aveți o notificare nouă.",
+ "echo-email-footer-default": "$2\n\nPentru a avea controlul asupra tipurilor de e-mailuri pe care vi le trimitem, verificați-vă preferințele:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Pentru a controla e-mailurile pe care vi le trimitem, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">verificați-vă preferințele</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Alertă ($1)|Alerte ($1)|100=Alerte (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Mesaj ($1)|Mesaje ($1)|100=Mesaje (99+)}}",
+ "echo-notification-alert-text-only": "Alerte",
+ "echo-notification-message-text-only": "Mesaje",
+ "echo-overlay-link": "Toate notificările",
+ "echo-overlay-title": "<b>Notificări</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notificări}}</b> (se afișează $1 din $2 necitite)",
+ "echo-mark-all-as-read": "Marchează toate ca citite",
+ "echo-date-today": "Astăzi",
+ "echo-date-yesterday": "Ieri",
+ "echo-load-more-error": "A apărut o eroare în timpul obținerii mai multor rezultate.",
+ "notification-edit-talk-page-bundle": "$1 și încă {{PLURAL:$4|altcineva|alți $3}} {{GENDER:$1|au lăsat}} un mesaj pe [[User talk:$2|pagina dumneavoastră de discuții]].",
+ "notification-page-linked-bundle": "$2 a fost {{GENDER:$1|menționată}} în $3 și încă {{PLURAL:$5|o pagină|alte $4 pagini}}. [[Special:WhatLinksHere/$2|Vedeți toate legăturile către această pagină]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 și încă {{PLURAL:$3|altcineva|alți $2}} {{GENDER:$1|au lăsat}} un mesaj pe pagina dumneavoastră de discuții.",
+ "notification-page-linked-email-batch-bundle-body": "$2 a fost {{GENDER:$1|menționată}} în $3 și încă {{PLURAL:$5|o pagină|alte $4 pagini}}.",
+ "echo-email-batch-subject-daily": "Aveți {{PLURAL:$2|o notificare nouă|notificări noi}} la {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Aveți {{PLURAL:$2|o notificare nouă|notificări noi}} la {{SITENAME}} în această săptămână",
+ "echo-email-batch-body-intro-daily": "Bună ziua $1,\nAveți aici un rezumat al activității de astăzi la {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Bună ziua $1,\nAveți aici un rezumat al activității din această săptămână la {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Vezi toate notificările",
+ "echo-rev-deleted-text-view": "Această versiune a paginii a fost suprimată."
+}
diff --git a/Echo/i18n/roa-tara.json b/Echo/i18n/roa-tara.json
new file mode 100644
index 00000000..125eea80
--- /dev/null
+++ b/Echo/i18n/roa-tara.json
@@ -0,0 +1,111 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras",
+ "C.R."
+ ]
+ },
+ "echo-desc": "Sisteme de notifiche",
+ "prefs-echo": "Notificaziune",
+ "prefs-emailsettings": "'Mbostaziune de l'email",
+ "prefs-displaynotifications": "Opziune de visualizzazzione",
+ "prefs-echosubscriptions": "Notificame sus a ste avveneminde",
+ "prefs-newmessageindicator": "Indicatore de messàgge nuève",
+ "echo-pref-send-me": "Manne a me:",
+ "echo-pref-send-to": "Manne a:",
+ "echo-pref-email-format": "Formate de l'email:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "No sce mannanne nisciuna mail de notifiche",
+ "echo-pref-email-frequency-immediately": "Le notifiche individuale a cumme trasene",
+ "echo-pref-email-frequency-daily": "'Nu riepiloghe sciurnaliere de le notifiche",
+ "echo-pref-email-frequency-weekly": "'Nu riepiloghe sumanale de le notifiche",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Teste semblice",
+ "echo-pref-notify-show-link": "Fà vedè le notifiche sus 'a barre de le struminde meje",
+ "echo-pref-new-message-indicator": "Fà vedè le 'ndicature de le messàgge sus a pàgene de le 'ngazzaminde jndr'à barre de le struminde meje",
+ "echo-learn-more": "'Mbare de cchiù",
+ "echo-new-messages": "Tu è messàgge nuève",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Messàgge}} d'a pàgene de le 'ngazzaminde",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Collegamende|Collegaminde}} d'a pàgene",
+ "echo-category-title-reverted": "Annulle {{PLURAL:$1|'u cangiamende|le cangiaminde}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Menzione}}",
+ "echo-category-title-other": "{{PLURAL:$1|Otre}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sisteme}}",
+ "echo-pref-tooltip-edit-user-talk": "Notificame quacche quacchedune manne 'nu messàgge o responne sus 'a pàgene de le 'ngazzaminde meje.",
+ "echo-pref-tooltip-article-linked": "Notificame quacche quacchedune se colleghe a 'na pàgene ca ije agghie ccrejate da 'na vôsce.",
+ "echo-pref-tooltip-reverted": "Notificame quanne quacchedune annulle 'nu cangiamende ca agghie fatte ije, ausanne 'u strumende de annullamende.",
+ "echo-pref-tooltip-mention": "Notificame quanne quacchedune se colleghe a pàgena utende meje.",
+ "echo-pref-tooltip-user-rights": "Notificame quanne quacchedune cange le deritte de utende meje.",
+ "echo-no-agent": "[Nisciune]",
+ "echo-no-title": "[Nisciuna vôsce]",
+ "echo-error-no-formatter": "Nisciune formattazzione ha state definite pa notifiche",
+ "echo-error-preference": "Errore: Non ge pozze 'mbostà le preferenze de l'utende",
+ "echo-error-token": "Errore: Non ge riesche a pigghià 'u gettone de l'utende",
+ "notifications": "Notificaziune",
+ "tooltip-pt-notifications": "Le notifiche tune",
+ "echo-specialpage": "Notificaziune",
+ "echo-anon": "Pe ricevere notifiche, <span class=\"plainlinks\">[$1 ccreje 'nu cunde] o <span class=\"plainlinks\">[$2 tràse].",
+ "echo-none": "Non ge tìne notifiche.",
+ "echo-more-info": "Cchiù 'mbormaziune",
+ "echo-feedback": "Segnalazione",
+ "notification-link-text-view-message": "'Ndruche 'u messàgge",
+ "notification-link-text-view-mention": "'Ndruche 'a menzione",
+ "notification-link-text-view-changes": "'Ndruche le cangiaminde",
+ "notification-link-text-view-page": "'Ndruche 'a pàgene",
+ "notification-link-text-view-edit": "'Ndruche 'u cangiamende",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|ha lassate}} 'nu messàgge sus 'a [[User talk:$2#$3|pàgene de le 'ngazzaminde]] tune.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|ave lassate}} 'nu messàgge sus 'a pàgene de le 'ngazzaminde toje jndr'à \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|ha lassate}} 'nu messàgge sus 'a [[User talk:$2#$3|pàgene de le 'ngazzaminde]] tune.",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|ave lassate}} 'nu messàgge sus 'a pàgene de le 'ngazzaminde toje jndr'à \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] ha state {{GENDER:$1|appundate}} da [[:$3]]. [[Special:WhatLinksHere/$2|'Ndruche tutte le collegaminde a sta pàgene]].",
+ "notification-page-linked-flyout": "[[:$2]] ere {{GENDER:$1|appondate}} da [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|ave commendate}} sus a \"[[$3|$2]]\" sus a pàgene de le 'ngazzaminde \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|ave mannate}} 'n'argomende nuève \"$2\" sus a [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|t'ha mannate}} 'nu messàgge: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|ave commendate}} sus a \"[[$3#$2|$2]]\" sus 'a pàgene de le 'ngazzaminde tune",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|t'ave menzionate}} sus a pàgene de le 'ngazzaminde $5 jndr'à \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|t'ave menzionate}} sus a pàgene de le 'ngazzaminde $5 jndr'à \"[[:$3#$2|$4]]\".",
+ "notification-user-rights": "Le deritte de l'utende [[Special:Log/rights/$1|onne state {{GENDER:$1|cangiate}}]] da [[User:$1|$1]]. $2. [[Special:ListGroupRights|'Mbare de cchiù]]",
+ "notification-user-rights-flyout": "Le deritte tune onne state {{GENDER:$1|cangiate}} da $1. $2. [[Special:ListGroupRights|'Mbare de cchiù]]",
+ "notification-user-rights-add": "Tu mò si nu memenre de {{PLURAL:$2|stu gruppe|ste gruppe}}: $1",
+ "notification-user-rights-remove": "No ge sì cchiù 'nu membre de {{PLURAL:$2|stu gruppe|ste gruppe}}: $1",
+ "notification-new-user": "Bovègne jndr'à {{SITENAME}}, $1! Nuje sime cundende ca ste aqquà.",
+ "notification-reverted2": "{{PLURAL:$4|'U cangiamende tune sus a [[:$2]] ha|Le cangiaminde sus a [[:$2]] onne}} state {{GENDER:$1|annullate}} da [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "Your {{PLURAL:$4|'U cangiamende tune sus a $2 ha|Le cangiaminde tune sus a $2 onne}} state {{GENDER:$1|annullate}} by $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|t'ha lassate}} 'nu messàgge sus a {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|t'ha lassate}} 'nu messàgge sus 'a pàgene de le 'ngazzaminde tune:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|t'ha lassate}} 'nu messàgge sus 'a pàgene de le 'ngazzaminde tune jndr'à \"$2\".",
+ "notification-page-linked-email-subject": "'A pàgena toje ha state collegate sus a {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 ere {{GENDER:$1|collegate}} da $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|'U cangiamende tune ha state|Le cangiaminde tune onne}} state {{GENDER:$1|annullate}} sus a {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|'U cangiamende tune sus a $2 ha state|Le cangiaminde tune sus a $2 onne}} state {{GENDER:$1|annullate}} da $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|t'ave menzionate}} sus a {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|'ave menzionate}} sus a pàgene de le 'ngazzaminde $4 jndr'à \"$3\".",
+ "notification-user-rights-email-subject": "Le deritte utende tune onne state cangiate sus a {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Le deritte utende tune onne state {{GENDER:$1|cangiate}} da $1. $2.",
+ "echo-email-subject-default": "Notifica nove sus a {{SITENAME}}",
+ "echo-email-body-default": "Tu è 'na notifica nove sus a {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Tu è 'na notifica nove",
+ "echo-email-footer-default": "$2\n\nPe condrollà quale email t'amme mannate, verifiche le prefenze tune:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Pe condrollà quale email t'amme mannate, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">condrolle le preferenze tune</a>.<br />\n$1",
+ "echo-notification-message-text-only": "Messàgge",
+ "echo-overlay-link": "Tutte le notificaziune",
+ "echo-overlay-title": "<b>Notifiche</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notifiche}}</b> (face 'ndrucà $1 de $2 non lette)",
+ "echo-mark-all-as-read": "Signe tutte cumme a lette",
+ "echo-date-today": "Osce",
+ "echo-date-yesterday": "Ajere",
+ "echo-load-more-error": "Ha assute 'n'errore mendre analizzave le resultate.",
+ "notification-edit-talk-page-bundle": "$1 e $3 {{PLURAL:$4|otre}} {{GENDER:$1|t'onne lassate}} 'nu messàgge sus a toje [[User talk:$2|pàgene de le 'ngazzaminde]].",
+ "notification-page-linked-bundle": "$2 ha state {{GENDER:$1|appundate}} da $3 e $4 otre {{PLURAL:$5|pàgene|pàggene}}. [[Special:WhatLinksHere/$2|'Ndruche tutte le collegaminde a sta pàgene]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e $2 {{PLURAL:$3|otre}} {{GENDER:$1|t'onne lassate}} 'nu messàgge sus 'a pàgene de le 'ngazzaminde toje.",
+ "notification-page-linked-email-batch-bundle-body": "$2 ha state {{GENDER:$1|appundate}} da $3 e $4 otre {{PLURAL:$5|pàgene|pàggene}}.",
+ "echo-email-batch-subject-daily": "Tu è {{PLURAL:$2|'na notifica|notifiche}} nove sus a {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Tu è {{PLURAL:$2|'na notifica|notifiche}} nove STA SUMàNE sus a {{SITENAME}}",
+ "echo-email-batch-body-intro-daily": "Cià $1,\nAqquà ste 'u rieploghe de l'attività de osce sus a {{SITENAME}} pe te.",
+ "echo-email-batch-body-intro-weekly": "Cià $1,\nAqquà ste 'u rieploghe de l'attività d'a sumàne sus a {{SITENAME}} pe te.",
+ "echo-email-batch-link-text-view-all-notifications": "'Ndruche tutte le notifiche",
+ "echo-rev-deleted-text-view": "Sta revisione d'a pàgene ha state accise",
+ "apihelp-query+notifications-example-1": "Elenghe de le notifiche"
+}
diff --git a/Echo/i18n/ru.json b/Echo/i18n/ru.json
new file mode 100644
index 00000000..783bc2a9
--- /dev/null
+++ b/Echo/i18n/ru.json
@@ -0,0 +1,144 @@
+{
+ "@metadata": {
+ "authors": [
+ "AVRS",
+ "Amire80",
+ "Base",
+ "DCamer",
+ "David1010",
+ "Iluvatar",
+ "KPu3uC B Poccuu",
+ "Kaganer",
+ "Kalan",
+ "Okras",
+ "Orsa",
+ "ShinePhantom",
+ "Soul Train",
+ "Sunpriat",
+ "Чаховіч Уладзіслаў",
+ "Doff"
+ ]
+ },
+ "echo-desc": "Система уведомлений",
+ "prefs-echo": "Уведомления",
+ "prefs-emailsettings": "Настройки эл. почты",
+ "prefs-displaynotifications": "Настройки отображения",
+ "prefs-echosubscriptions": "Сообщать мне об этих событиях",
+ "prefs-newmessageindicator": "Индикатор нового сообщения",
+ "echo-pref-send-me": "Присылать мне:",
+ "echo-pref-send-to": "Отправлять в:",
+ "echo-pref-email-format": "Формат писем:",
+ "echo-pref-web": "Веб",
+ "echo-pref-email": "Эл. почта",
+ "echo-pref-email-frequency-never": "Не присылать мне уведомления по эл. почте",
+ "echo-pref-email-frequency-immediately": "Отдельные уведомления по мере их поступления",
+ "echo-pref-email-frequency-daily": "Ежедневная сводка уведомлений",
+ "echo-pref-email-frequency-weekly": "Еженедельная сводка уведомлений",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Простой текст",
+ "echo-pref-notify-show-link": "Показать уведомления в моей панели инструментов",
+ "echo-pref-new-message-indicator": "Показать в моей панели инструментов индикатор сообщений на странице обсуждения",
+ "echo-learn-more": "Узнать больше",
+ "echo-new-messages": "У вас есть новые сообщения",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|1=сообщение|сообщения}} на странице обсуждения",
+ "echo-category-title-article-linked": "{{PLURAL:$1|1=ссылка|ссылки}} на страницы",
+ "echo-category-title-reverted": "{{PLURAL:$1|1=отмена|отмены}} правок",
+ "echo-category-title-mention": "{{PLURAL:$1|1=упоминание|упоминания}}",
+ "echo-category-title-other": "{{PLURAL:$1|1=прочее|прочие}}",
+ "echo-category-title-system": "{{PLURAL:$1|1=системное|системные}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|изменение|изменения}} прав участника",
+ "echo-pref-tooltip-edit-user-talk": "Сообщать мне, когда кто-то посылает сообщение или отвечает на моей странице обсуждения.",
+ "echo-pref-tooltip-article-linked": "Сообщать мне, когда кто-то ссылается в статьях на созданную мной страницу",
+ "echo-pref-tooltip-reverted": "Сообщать мне, когда кто-то отменил мою правку, используя функцию отмены или отката.",
+ "echo-pref-tooltip-mention": "Сообщать мне, когда кто-то ссылается на мою страницу участника.",
+ "echo-pref-tooltip-user-rights": "Сообщать мне, когда кто-то изменяет мои права участника.",
+ "echo-no-agent": "[Никто]",
+ "echo-no-title": "[Нет страницы]",
+ "echo-error-no-formatter": "Форматирование не определено для уведомления",
+ "echo-error-preference": "Ошибка: Не удалось задать настройки участника",
+ "echo-error-token": "Ошибка: не удалось получить маркер участника (user token)",
+ "notifications": "Уведомления",
+ "tooltip-pt-notifications": "Ваши уведомления",
+ "echo-specialpage": "Уведомления",
+ "echo-anon": "Чтобы получать уведомления, [$1 создайте учётную запись] или [$2 представьтесь].",
+ "echo-none": "Вы не получали уведомлений.",
+ "echo-more-info": "Подробнее",
+ "echo-feedback": "Обратная связь",
+ "echo-quotation-marks": "«$1»",
+ "notification-link-text-view-message": "Просмотр сообщения",
+ "notification-link-text-view-mention": "Просмотр упоминания",
+ "notification-link-text-view-changes": "Просмотр изменений",
+ "notification-link-text-view-page": "Просмотр страницы",
+ "notification-link-text-view-edit": "Просмотр правки",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|оставил|оставила}} сообщение на вашей [[User talk:$2#$3|странице обсуждения]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|оставил|оставила}} сообщение на вашей странице обсуждения \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|оставил|оставила}} сообщение на вашей [[User talk:$2#$3|странице обсуждения]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|оставил|оставила}} сообщение на вашей странице обсуждения \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "На [[:$2]] {{GENDER:$1|сослались}} из [[:$3]]. [[Special:WhatLinksHere/$2|См. все ссылки на эту страницу]].",
+ "notification-page-linked-flyout": "[[:$2]] была {{GENDER:$1|связана}} с [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|прокомментировал|прокомментировала}} тему \"[[$3|$2]]\" на странице обсуждения \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|добавил|добавила}} новую тему \"$2\" на странице [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|отправил|отправила}} вам сообщение: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|прокомментировал|прокомментировала}} тему \"[[$3#$2|$2]]\" на вашей странице обсуждения.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|упомянул|упомянула}} вас на странице обсуждения $5 в разделе \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|упомянул|упомянула}} вас на странице обсуждения $5 в разделе \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] упомянул{{GENDER:$1||а}} вас на [[:$3|странице обсуждения $2]].",
+ "notification-mention-nosection-flyout": "$1 упомянул{{GENDER:$1||а}} вас на [[:$3|странице обсуждения $2]].",
+ "notification-user-rights": "Ваши права пользователя [[Special:Log/rights/$1|{{GENDER:$1|изменил|изменила}}]] [[User:$1|$1]]. $2. [[Special:ListGroupRights|Подробнее]]",
+ "notification-user-rights-flyout": "Права пользователя {{GENDER:$1|изменил|изменила}} $1. $2. [[Special:ListGroupRights|Подробнее]]",
+ "notification-user-rights-add": "Теперь вы входите в {{PLURAL:$2|1=следующую группу|следующие группы}}: $1",
+ "notification-user-rights-remove": "Вы больше не входите в {{PLURAL:$2|1=следующую группу|следующие группы}}: $1",
+ "notification-new-user": "Добро пожаловать в {{SITENAME}}, $1! Мы рады, что вы здесь.",
+ "notification-reverted2": "{{PLURAL:$4|1=Вашу правку|Ваши правки}} на странице [[:$2]] {{GENDER:$1|отменил|отменила}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|1=Вашу правку|Ваши правки}} на странице $2 {{GENDER:$1|отменил|отменила}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|Участник|Участница}} $1 {{GENDER:$1|оставил|оставила}} вам сообщение на сайте «{{SITENAME}}»",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|Участник|Участница}} $1 {{GENDER:$1|оставил|оставила}} сообщение на вашей странице обсуждения:",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|Участник|Участница}} $1 {{GENDER:$1|оставил|оставила}} вам сообщение на вашей странице обсуждения в разделе (теме) «$2»",
+ "notification-page-linked-email-subject": "На сайте «{{SITENAME}}» появилась ссылка на созданную вами страницу",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|Участник|участница}} $1 {{GENDER:$1|сослался|сослалась}} на $2 из $3",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Кто-то}} отменил {{PLURAL:$3|1=вашу правку|ваши правки}} на сайте «{{SITENAME}}»",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|1=Ваша правка на странице «$2» была отменена|Ваши правки на странице «$2» были отменены}} {{GENDER:$1|участником|участницей}} $1.",
+ "notification-mention-email-subject": "{{GENDER:$1|Участник|Участница}} $1 {{GENDER:$1|упомянул|упомянула}} вас на сайте «{{SITENAME}}»",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|упомянул|упомянула}} Вас на странице обсуждения $4 в разделе «$3».",
+ "notification-mention-nosection-email-batch-body": "$1 упомянул{{GENDER:$1||а}} вас на странице обсуждения $2.",
+ "notification-user-rights-email-subject": "Ваши права на сайте «{{SITENAME}}» были изменены",
+ "notification-user-rights-email-batch-body": "Ваши права были изменены {{GENDER:$1|участником|участницей}} $1. $2.",
+ "echo-notification-count": "$1+",
+ "echo-email-subject-default": "Новые уведомления на сайте «{{SITENAME}}»",
+ "echo-email-body-default": "У вас есть новое уведомление на сайте «{{SITENAME}}»:\n\n$1",
+ "echo-email-batch-body-default": "У вас есть новое уведомление",
+ "echo-email-footer-default": "$2\n\nДля контроля за тем, какие сообщения отправляются вам по эл. почте, проверьте свои персональные настройки:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Для контроля за тем, какие сообщения отправляются вам по эл. почте, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">проверьте свои персональные настройки</a><br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Оповещение ($1)|Оповещения ($1)|100=Оповещения (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Сообщение ($1)|Сообщения ($1)|100=Сообщения (99+)}}",
+ "echo-notification-alert-text-only": "Оповещения",
+ "echo-notification-message-text-only": "Сообщения",
+ "echo-overlay-link": "Все уведомления",
+ "echo-overlay-title": "<b>Уведомления</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Уведомления}}</b> ({{PLURAL:$1|показано|показаны}} $1 из $2 {{PLURAL:$2|непрочитанного|непрочитанных}})",
+ "echo-mark-all-as-read": "Отметить всё прочтённым",
+ "echo-date-today": "Сегодня",
+ "echo-date-yesterday": "Вчера",
+ "echo-load-more-error": "Произошла ошибка при получении дополнительных результатов.",
+ "notification-edit-talk-page-bundle": "$1 и $3 {{PLURAL:$4|1=другой участник|других участников|других участника}} оставили сообщение на вашей [[User talk:$2|странице обсуждения]].",
+ "notification-page-linked-bundle": "На страницу «$2» есть {{GENDER:$1|ссылка}} со страницы «$3» и ещё $4 {{PLURAL:$5|страницы|страниц}}. [[Special:WhatLinksHere/$2|См. все ссылки на эту страницу]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 и $2 {{PLURAL:$3|другой участник|других участникa|других участников}} оставили сообщения на вашей странице обсуждения.",
+ "notification-page-linked-email-batch-bundle-body": "На страницу «$2» есть {{GENDER:$1|ссылка}} со страницы «$3» и ещё {{PLURAL:$5|$4 страницы|$4 страниц|1=одной страницы}}",
+ "echo-email-batch-bullet": "•",
+ "echo-email-batch-subject-daily": "Вы получили {{PLURAL:$2|$2 новое уведомление|$2 новых уведомления|$2 новых уведомлений|1=новое уведомление}} в проекте «{{SITENAME}}»",
+ "echo-email-batch-subject-weekly": "На этой неделе вы получили {{PLURAL:$2|$2 новое уведомление|$2 новых уведомления|$2 новых уведомлений|1=новое уведомление}} в проекте «{{SITENAME}}»",
+ "echo-email-batch-body-intro-daily": "Привет, $1!\nВот краткий обзор сегодняшней деятельности в {{SITENAME}} для вас.",
+ "echo-email-batch-body-intro-weekly": "Привет, $1!\nВот краткий недельный обзор деятельности в {{SITENAME}} для вас.",
+ "echo-email-batch-link-text-view-all-notifications": "Посмотреть все уведомления",
+ "echo-rev-deleted-text-view": "Эта версия страницы была скрыта",
+ "apihelp-echomarkread-description": "Отметить уведомления как прочитанные для текущего пользователя.",
+ "apihelp-echomarkread-param-list": "Список ID уведомлений для отметки прочитанными.",
+ "apihelp-echomarkread-param-all": "Если задано, отметает все уведомления пользователя как прочитанные.",
+ "apihelp-echomarkread-example-2": "Отметить все уведомления как прочитанные",
+ "apihelp-query+notifications-param-groupbysection": "Следует ли группировать результат по разделам. Если задано, каждый раздел извлекается отдельно.",
+ "apihelp-query+notifications-param-format": "Если определено, уведомления будут возвращены отформатированными таким образом.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Нужно ли показывать непрочитанные уведомления о сообщениях в первую очередь.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Нужно ли показывать непрочитанные уведомления о оповещениях в первую очередь.",
+ "apihelp-query+notifications-example-1": "Список уведомлений",
+ "apihelp-query+notifications-example-2": "Список уведомлений, сгруппированных по разделам, с указанием количества"
+}
diff --git a/Echo/i18n/rue.json b/Echo/i18n/rue.json
new file mode 100644
index 00000000..36e515fe
--- /dev/null
+++ b/Echo/i18n/rue.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dicto23456"
+ ]
+ },
+ "tooltip-pt-notifications": "Ваші сповіщення"
+}
diff --git a/Echo/i18n/sa.json b/Echo/i18n/sa.json
new file mode 100644
index 00000000..0fe6afd0
--- /dev/null
+++ b/Echo/i18n/sa.json
@@ -0,0 +1,50 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Shubha"
+ ]
+ },
+ "echo-desc": "सूचनाव्यवस्था",
+ "prefs-echo": "सूचनाः",
+ "prefs-emailsettings": "ईपत्र-विकल्पाः",
+ "prefs-displaynotifications": "प्रदर्शन-विकल्पाः",
+ "prefs-echosubscriptions": "एतेषां घटनानां विषये मां सूचयतु",
+ "prefs-newmessageindicator": "नूतनसन्देशसूचकम्",
+ "echo-pref-send-me": "मह्यं प्रेष्यताम्:",
+ "echo-pref-send-to": "एतस्मै प्रेष्यताम्",
+ "echo-pref-email-format": "ईपत्र-प्रारूपः:",
+ "echo-pref-web": "विश्वव्यापिजालम्",
+ "echo-pref-email": "ईपत्रम्",
+ "echo-pref-email-frequency-never": "ईपत्रसन्देशाः मा प्रेष्यन्ताम्",
+ "echo-pref-email-frequency-immediately": "प्रत्येकसूचना यथा प्राप्यते",
+ "echo-pref-email-frequency-daily": "प्रतिदिनस्य सन्देशानां सारांशाः",
+ "echo-pref-email-frequency-weekly": "प्रतिसप्ताहस्य सन्देशानां सारांश:",
+ "echo-pref-email-format-html": "एच् टि एम् एल्",
+ "echo-pref-email-format-plain-text": "सरलपठ्यम्",
+ "echo-pref-notify-show-link": "उपकरणपट्टिकायां सूचनाः दर्श्यन्ताम्",
+ "echo-pref-new-message-indicator": "मम साधनापट्टिकायां चर्चापुटस्य सन्देशः दर्श्यताम्",
+ "echo-learn-more": "अधिकं ज्ञायताम्",
+ "echo-new-messages": "भवते नूतनसन्देशाः सन्ति",
+ "echo-category-title-edit-user-talk": "चर्चापुटम् {{PLURAL:$1|सन्देशः|सन्देशाः}}",
+ "echo-category-title-article-linked": "पुटम् {{PLURAL:$1|सम्पर्कतन्तुः|सम्पर्कतन्तवः}}",
+ "echo-category-title-reverted": "सम्पाद्यताम् {{PLURAL:$1|revert|reverts}}",
+ "echo-category-title-mention": "{{PLURAL:$1|उल्लेखः|उल्लेखाः}}",
+ "echo-category-title-other": "{{PLURAL:$1|अन्यत्}}",
+ "echo-category-title-system": "{{PLURAL:$1|व्यवस्था}}",
+ "echo-pref-tooltip-edit-user-talk": "केनापि मह्यं सन्देशः प्रेषितः चेत्, मम चर्चापुटे उत्तरितं चेत् मां सूचयन्तु",
+ "echo-pref-tooltip-article-linked": "मया निर्मितेन पुटेन सह यदि अन्येन सम्पर्कतन्तुः योज्यते तर्हि मां सूचयन्तु |",
+ "echo-pref-tooltip-reverted": "मया कृतं सम्पादनं यदि अन्यः पूर्ववत् परिवर्तयेत् तर्हि सूच्यताम् |",
+ "echo-pref-tooltip-mention": "कस्यचित् चर्चापुटस्य सम्पर्कतन्तुः मम योजकपुटेन सह योज्यते चेत् सूच्यताम् |",
+ "echo-no-agent": "[कोपि नास्ति]",
+ "echo-no-title": "[न किञ्चित् पुटं विद्यते]",
+ "echo-error-no-formatter": "सूचनानां प्रारूपः न रचितः |",
+ "echo-error-preference": "दोषः: योजकस्य इष्टतमानि न निर्दिष्टानि |",
+ "notifications": "सूचनाः",
+ "tooltip-pt-notifications": "भवतः सूचनाः",
+ "echo-specialpage": "सूचनाः",
+ "echo-none": "भवते सूचनाः न विद्यन्ते |",
+ "echo-more-info": "अधिकं विवरणम्",
+ "echo-feedback": "प्रतिस्पन्दः",
+ "notification-link-text-view-message": "सन्देशः दृश्यताम्"
+}
diff --git a/Echo/i18n/sah.json b/Echo/i18n/sah.json
new file mode 100644
index 00000000..4935ef97
--- /dev/null
+++ b/Echo/i18n/sah.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kaganer",
+ "HalanTul"
+ ]
+ },
+ "tooltip-pt-notifications": "Эйиэхэ биллэриилэр",
+ "notification-reverted2": "{{PLURAL:$4|1=Эн көннөрүүгүн|Эн көннөрүүлэргин}} [[:$2]] сирэйгэ [[User:$1|$1]] {{GENDER:$1|көтүрбүт}}. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|1=Эн көннөрүүгүн|Эн көннөрүүлэргин}} $2 сирэйгэ $1 {{GENDER:$1|көтүрбүт}}. $3",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Ким эрэ}} {{PLURAL:$3|1=эн көннөрүүгүн|эн көннөрүүлэргин}} «{{SITENAME}}» ситим-сиргэ көтүрбүт",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|1=Эн көннөрүүҥ «$2» сирэйгэ|Эн көннөрүүлэриҥ «$2» сирэйгэ}} $1 кыттааччынан {{PLURAL:$3|1=көтүрүллүбүтэ|көтүрүллүбүттэрэ}}."
+}
diff --git a/Echo/i18n/scn.json b/Echo/i18n/scn.json
new file mode 100644
index 00000000..648df826
--- /dev/null
+++ b/Echo/i18n/scn.json
@@ -0,0 +1,107 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gmelfi"
+ ]
+ },
+ "echo-desc": "Sistema di nutifica",
+ "prefs-echo": "Nutìfichi",
+ "prefs-emailsettings": "Upzioni email",
+ "prefs-displaynotifications": "Upzioni di visualizzazzioni",
+ "prefs-echosubscriptions": "Mànnami na nutìfica supra sti abbinimenti",
+ "prefs-newmessageindicator": "Barra dî missaggi novi",
+ "echo-pref-send-me": "Mànnami:",
+ "echo-pref-send-to": "Manna a:",
+ "echo-pref-email-format": "Furmatu email:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Nnirizzu email:",
+ "echo-pref-email-frequency-never": "Nun mannàrimi nudda nutìfica via email",
+ "echo-pref-email-frequency-immediately": "Nutìfichi sìnguli pi ogni abbinimentu",
+ "echo-pref-email-frequency-daily": "Nu riepìlugu giuranlieru dî nutìfichi",
+ "echo-pref-email-frequency-weekly": "Nu riepìlugu dî nutìfichi dâ simana",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Testu nurmali",
+ "echo-pref-notify-show-link": "Visualizza li nutìfichi ntâ mè barra dî strummenta",
+ "echo-pref-new-message-indicator": "Ammùscia la barra dê missaggi novi supra la mè pàggina di discussioni ntâ barra dî strummenta",
+ "echo-learn-more": "Pi sapìrinni cchiossai",
+ "echo-new-messages": "Vossìa havi missaggi novi",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Missaggiu|Missaggi}} supra la pàggina di discussioni",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Liami|Liama}} a na pàggina",
+ "echo-category-title-reverted": "{{PLURAL:$1|Canciamentu annullatu|Canciamenti annullati}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Minzioni}}",
+ "echo-category-title-other": "{{PLURAL:$1|Àutru}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-pref-tooltip-edit-user-talk": "Abbìsami quannu quarcunu mi scrivi nu missaggiu o arrispunni ntâ mè pàggina di discussioni.",
+ "echo-pref-tooltip-article-linked": "Abbìsami quannu quarcunu cullèga, di na vuci, na pàggina ca criai.",
+ "echo-pref-tooltip-reverted": "Abbìsami quannu quarcunu annulla nu canciamentu ca fici, usannu li funzioni annulla o rollback.",
+ "echo-pref-tooltip-mention": "Abbìsami quannu quarcunu cullèga la mè pàggina utenti di na qualunqui pàggina di discussioni.",
+ "echo-no-agent": "[Nuddu]",
+ "echo-no-title": "[Nudda pàggina]",
+ "echo-error-no-formatter": "Nudda furnattazzioni difinuta pê nutìfichi",
+ "echo-error-preference": "Erruri: mpussibbili mpustari li prifirenzi di l'utenti",
+ "echo-error-token": "Erruri: mpussìbbili ricupirari token utenti",
+ "notifications": "Nutìfichi",
+ "tooltip-pt-notifications": "Tutti li nutìfichi",
+ "echo-specialpage": "Nutìfichi",
+ "echo-anon": "Pi arriciviri li nutìfichi, [$1 arriggistrati] o [$2 trasi].",
+ "echo-none": "Nun arricivistru nutìfichi",
+ "echo-more-info": "Àutri nfurmazzioni",
+ "echo-feedback": "Cummenti",
+ "notification-link-text-view-message": "Talìa lu missaggiu",
+ "notification-link-text-view-mention": "Talìa la minzioni",
+ "notification-link-text-view-changes": "Talìa li canciamenti",
+ "notification-link-text-view-page": "Talìa la pàggina",
+ "notification-link-text-view-edit": "Talìa lu canciamentu",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|lasssau}} nu missaggiu supra la tò [[User talk:$2#$3|pàggina di discussioni]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|lassau}} nu missaggiu ntâ tò pàggina di discussioni n '[[User talk:$2#$3|$4]]'.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|lassau}} nu missaggiu supra la tò [[User talk:$2#$3|pàggina di discussioni]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|lassau}} nu missaggiu ntâ tò pàggina di discussioni n '[[User talk:$2#$3|$4]]'.",
+ "notification-page-linked": "[[:$2]] fu {{GENDER:$1|culligata}} di [[:$3]]. [[Special:WhatLinksHere/$2|Talìa tutti li liami a sta pàggina]].",
+ "notification-page-linked-flyout": "[[:$2]] fu {{GENDER:$1|culligata}} di [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|lassau nu cummentu}} arriguardu a \"[[$3|$2]]\" ntâ pàggina di discussioni di \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|juncìu}} n'argumentu novu \"$2\" supra [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] ti {{GENDER:$1|mannàu}} nu missaggiu: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|lassau nu cummentu}} arriguardu a \"[[$3#$2|$2]]\" ntâ tò pàggina di discussioni",
+ "notification-mention": "[[User:$1|$1]] ti {{GENDER:$1|mintuviau}} supra la pàggina di discussioni di $5 n '[[:$3#$2|$4]]'.",
+ "notification-mention-flyout": "$1 ti {{GENDER:$1|mintuviàu}} supra la pàggina di discussioni di $5 n '[[:$3#$2|$4]]'.",
+ "notification-user-rights": "Li tò diritti utenti [[Special:Log/rights/$1|foru {{GENDER:$1|canciati}}]] di [[User:$1|$1]]. $2. [[Special:ListGroupRights|Pi sapìrinni cchiossai]]",
+ "notification-user-rights-flyout": "Li tò diritti utenti foru {{GENDER:$1|canciati}} di $1. $2. [[Special:ListGroupRights|Pi sapìrinni cchiossai]]",
+ "notification-user-rights-add": "Ora si membru di {{PLURAL:$2|stu gruppu|sti gruppa}}: $1",
+ "notification-user-rights-remove": "Nun si cchiù membru di {{PLURAL:$2|stu gruppu|sti gruppa}}: $1",
+ "notification-new-user": "Bimminutu/a supra {{SITENAME}}, $1! Semu filici ca tu si ccà.",
+ "notification-reverted2": "{{PLURAL:$4|Lu tò canciamentu|Li tò canciamenti}} supra [[:$2]] {{PLURAL:$4|fu annullatu|foru annullati}} {{GENDER:$1|di}} [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Lu tò canciamentu|Li tò canciamenti}} supra $2 {{PLURAL:$4|fu annullatu|foru annullati}} {{GENDER:$1|di}} $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 ti {{GENDER:$1|lassau}} nu missaggiu n {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|lassau}} nu missaggiu supra la tò pàggina di discussioni:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|lassau}} nu missaggiu supra la tò pàggina di discussioni n $2.",
+ "notification-page-linked-email-subject": "La tò pàggina fu liata a {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 fu {{GENDER:$1|culligata}} di $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Lu tò canciamentu fu annullatu|Li tò canciamenti foru annullati}} {{GENDER:$1|supra}} {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Lu tò canciamentu supra $2 fu annullatu|Li tò canciamenti supra $2 foru annullati}} {{GENDER:$1|di}} $1 $3",
+ "notification-mention-email-subject": "$1 ti {{GENDER:$1|mintuviàu}} su {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 ti {{GENDER:$1|mintuviàu}} supra la pàggina di discussioni di $4 n '$3'.",
+ "notification-user-rights-email-subject": "Li tò diritti utenti foru canciati supra {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Li tò dirirtti utenti foru {{GENDER:$1|canciati}} di $1. $2",
+ "echo-email-subject-default": "Nutìfica nova supra {{SITENAME}}",
+ "echo-email-body-default": "Vossìa havi na nutìfica nova supra {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Vossìa havi na nutìfica nova",
+ "echo-email-footer-default": "$2\n\nPi cuntrullari quali email ti vènunu mannati, cuntrolla li tò prifirenzi:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Pi virificari quali email ti sunu mannati, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">cuntrolla li tò prifirenzi</a><br />\n$1",
+ "echo-overlay-link": "Tutti li nutìfichi",
+ "echo-overlay-title": "<b>Nutìfichi</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Nutifica|Nutìfichi}}</b> (ammusciati $1 di $2 nunu ligghiuti)",
+ "echo-mark-all-as-read": "Sinna tutti comu ligghiuti",
+ "echo-date-today": "Ogghi",
+ "echo-date-yesterday": "Ieri",
+ "echo-load-more-error": "Si virificau n'erruri ntô ricùpiru di àutri risurtati.",
+ "notification-edit-talk-page-bundle": "$1 e {{PLURAL:$4|n'autru utenti|àutri $3 utenti}} {{GENDER:$1|lassaru}} nu missaggiu ntâ tò [[User talk:$2|pàggina di discussioni]].",
+ "notification-page-linked-bundle": "$2 fu {{GENDER:$1|culligata}} di $3 e {{PLURAL:$5|n'àutra pàggina|àutri $4 pàggini}}. [[Special:WhatLinksHere/$2|Talìa tutti li culligamenti a sta pàggina]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 e {{PLURAL:$3|n'àutru|àutri $2}} {{GENDER:$1|lassaru}} nu missaggiu supra la tò pàggina di discussioni",
+ "notification-page-linked-email-batch-bundle-body": "$2 fu {{GENDER:$1|culligata}} di $3 e {{PLURAL:$5|n'àutra pàggina|àutri $4 pàggini}}",
+ "echo-email-batch-subject-daily": "Vossia havi {{PLURAL:$2|na nutìfica nova|nutìfichi novi}} supra {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Vossia havi {{PLURAL:$2|na nutìfica nova|nutìfichi novi}} supra {{SITENAME}} sta simana",
+ "echo-email-batch-body-intro-daily": "Sabbinirica $1,\neccu na sìntisi di l'attivitati di ogghi supra {{SITENAME}} pi vossia",
+ "echo-email-batch-body-intro-weekly": "Sabbinirica $1,\neccu na sìntisi di l'attivitati di sta siamana supra {{SITENAME}} pi Vossia",
+ "echo-email-batch-link-text-view-all-notifications": "Talìa tutti li canciamenti",
+ "echo-rev-deleted-text-view": "Sta virsioni dâ pàggina fu supprimuta"
+}
diff --git a/Echo/i18n/sdh.json b/Echo/i18n/sdh.json
new file mode 100644
index 00000000..9a683441
--- /dev/null
+++ b/Echo/i18n/sdh.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kurdbuddha"
+ ]
+ },
+ "echo-pref-web": "وێب",
+ "echo-pref-email": "ئیمەیل",
+ "echo-notification-message-text-only": "پەیامەیل"
+}
diff --git a/Echo/i18n/sh.json b/Echo/i18n/sh.json
new file mode 100644
index 00000000..c22749aa
--- /dev/null
+++ b/Echo/i18n/sh.json
@@ -0,0 +1,107 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kolega2357"
+ ]
+ },
+ "echo-desc": "Obavještajni sistem",
+ "prefs-echo": "Obavještenja",
+ "prefs-emailsettings": "Email opcije",
+ "prefs-displaynotifications": "Opcije prikaza",
+ "prefs-echosubscriptions": "Obavijesti me o tim događajima",
+ "prefs-newmessageindicator": "Indikator za nove poruke",
+ "echo-pref-send-me": "Pošalji mi:",
+ "echo-pref-send-to": "Pošalji:",
+ "echo-pref-email-format": "Format e-pošte:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-pošta",
+ "echo-pref-email-frequency-never": "Ne šalji mi obavještenja preko e-pošte",
+ "echo-pref-email-frequency-immediately": "Lična obavještenja kako dolaze u",
+ "echo-pref-email-frequency-daily": "Dnevni sažetak obavještenja",
+ "echo-pref-email-frequency-weekly": "Nedeljni sažetak obavještenja",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Obični tekst",
+ "echo-pref-notify-show-link": "Pokaži obavještenja u mojoj alatnoj traci",
+ "echo-pref-new-message-indicator": "Pokaži indikator da je dobijena poruka na stranici za razgovor u mojoj alatnoj traci",
+ "echo-learn-more": "Saznajte više",
+ "echo-new-messages": "Imate nove poruke.",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Poruke}} na stranici za razgovor",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Linkovi na stranicu}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Vraćanje izmjena}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Spominjanje|Spominjanja}}",
+ "echo-category-title-other": "{{PLURAL:$1|Ostalo}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-pref-tooltip-edit-user-talk": "Obavijesti me kada neko ostavi poruku ili odgovor na mojoj stranici za razgovor.",
+ "echo-pref-tooltip-article-linked": "Obavijesti me kada neko linkuje na stranicu koju sam napravio od stranice članaka.",
+ "echo-pref-tooltip-reverted": "Obavijesti me kada neko vrati uređivanje koje sam napravio/la, korištenjem naredbe undo ili alatom za vraćanje.",
+ "echo-pref-tooltip-mention": "Obavijesti me kada me neko spomene na nekoj stranici za razgovor.",
+ "echo-no-agent": "[Niko]",
+ "echo-no-title": "[Nema stranice]",
+ "echo-error-no-formatter": "Nema formatiranja određenog za obavještavanje.",
+ "echo-error-preference": "Greška: Nemoguće odrediti korisničke postavke.",
+ "echo-error-token": "Greška: Nemoguće ponovo pronaći korisničku oznaku.",
+ "notifications": "Obavještenja",
+ "tooltip-pt-notifications": "Vaša obavještenja",
+ "echo-specialpage": "Obavještenja",
+ "echo-anon": "Da biste primili obaveštenja, morate se [[Special:UserLogin|prijaviti]] ili [[Special:Userlogin/signup|napraviti račun]].",
+ "echo-none": "Nemate obavještenja",
+ "echo-more-info": "Više informacija",
+ "echo-feedback": "Povratna informacija",
+ "notification-link-text-view-message": "Pogledaj poruku",
+ "notification-link-text-view-mention": "Pogledajte spominjanje",
+ "notification-link-text-view-changes": "Pogledaj izmjene",
+ "notification-link-text-view-page": "Pogledaj stranicu",
+ "notification-link-text-view-edit": "Pogledaj uređivanje",
+ "notification-edit-talk-page2": "[[User:$1|$1]] vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj [[User talk:$2#$3|stranici za razgovor]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj [[User talk:$2#$3|stranici za razgovor]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "Stranica [[:$2]] je {{GENDER:$1|povezana}} sa stranicom [[:$3]]. [[Special:WhatLinksHere/$2|Pogledajte sve veze prema ovoj stranici]].",
+ "notification-page-linked-flyout": "[[:$2]] je {{GENDER:$1|povezana}} sa [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] je {{GENDER:$1|ostavio|ostavila}} komentar na \"[[$3|$2]]\" na \"$4\" stranici za razgovor.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] je {{GENDER:$1|postavio|postavila}} novu temu \"$2\" na [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vam je {{GENDER:$1|poslao|poslala}} poruku: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] je {{GENDER:$1|komentarisao|komentarisala}} temu \"[[$3#$2|$2]]\" na vašoj stranici za razgovor.",
+ "notification-mention": "[[User:$1|$1]] vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $5 u \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $5 u \"[[:$3#$2|$4]]\".",
+ "notification-user-rights": "Vaša korisnička prava [[Special:Log/rights/$1|su bila {{GENDER:$1|izmijenjena}}]] od strane [[User:$1|$1]]. $2. [[Special:ListGroupRights|Saznajte više]]",
+ "notification-user-rights-flyout": "Vaša korisnička prava su bila {{GENDER:$1|izmijenjena}} od strane $1. $2. [[Special:ListGroupRights|Saznajte više]]",
+ "notification-user-rights-add": "Od sada ste član {{PLURAL:$2|ove grupe|ovih grupa}}: $1",
+ "notification-user-rights-remove": "Više niste član {{PLURAL:$2|ove grupe|ovih grupa}}: $1",
+ "notification-new-user": "$1, dobro došli na {{SITENAME}}! Drago nam je što ste ovdje.",
+ "notification-reverted2": "{{PLURAL:$4|Vaša izmjena na [[:$2]] je poništena|Vaše izmjene na [[:$2]] su vraćene}} {{GENDER:$1|od}} strane [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Vaša izmjena na $2 je poništena|Vaše izmjene na $2 su vraćene}} {{GENDER:$1|od}} strane $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u \"$2\".",
+ "notification-page-linked-email-subject": "Vaša stranica je povezana na {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 je {{GENDER:$1|povezana}} sa $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Vaša izmjena je {{GENDER:$1|poništena}}|Vaše izmjene su {{GENDER:$1|poništene}}}} na {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Vaša izmjena na $2 je poništena|Vaše izmjene na $2 su vraćene}} {{GENDER:$1|od}} strane $1.",
+ "notification-mention-email-subject": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $4 u \"$3\".",
+ "notification-user-rights-email-subject": "Vaša korisnička prava su se promijenila na {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Vaša korisnička prava su {{GENDER:$1|promjenjena}} od strane $1. $2",
+ "echo-email-subject-default": "Novo obavještenje na {{SITENAME}}",
+ "echo-email-body-default": "Imate novo obavještenje na {{SITENAME}}: \n\n$1",
+ "echo-email-batch-body-default": "Imate novo obavještenje.",
+ "echo-email-footer-default": "$2\n\nDa kontrolišete koje vam email poruke šaljemo, provjerite svoje postavke:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Da kontrolišete koje vam email poruke šaljemo, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">provjerite vaše postavke</a>.<br />\n$1",
+ "echo-overlay-link": "Sva obavještenja",
+ "echo-overlay-title": "<b>Obavještenja</b>",
+ "echo-overlay-title-overflow": "<b>Obavještenja</b> (prikaz $1 od $2 nepročitanih)\n<b>Obavještenja</b> (prikaz $1 od $2 nepročitanih)",
+ "echo-mark-all-as-read": "Označi sve kao pročitano",
+ "echo-date-today": "Danas",
+ "echo-date-yesterday": "Juče",
+ "echo-load-more-error": "Greška se pojavila za vrijeme dobavljanja više rezultata.",
+ "notification-edit-talk-page-bundle": "$1 i $3 {{PLURAL:$4|ostali|ostale}} {{GENDER:$1|ostavili}} su poruku na vašoj [[User talk:$2|stranici za razgovor]].",
+ "notification-page-linked-bundle": "$2 je {{GENDER:$1|povezana}} sa $3 i $4 {{PLURAL:$5|druge stranice|drugih stranica}}. [[Special:WhatLinksHere/$2|Pogledaj sve linkove na ovu stranicu]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 i $2 {{PLURAL:$3|ostali|ostalih}} {{GENDER:$1|ostavili}} su poruku na vašoj stranici za razgovor.",
+ "notification-page-linked-email-batch-bundle-body": "Stranica $2 je {{GENDER:$1|povezana}} sa $3 i $4 {{PLURAL:$5|druge stranice|drugih stranica}}.",
+ "echo-email-batch-subject-daily": "Imate {{PLURAL:$2|novo obavještenje|nova obavještenja}} na {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Imate {{PLURAL:$2|novo obavještenje|nova obavještenja}} na {{SITENAME}} ove nedelje",
+ "echo-email-batch-body-intro-daily": "Zdravo $1,\nOvo je sažetak današnjih aktivnosti na {{SITENAME}} za Vas.",
+ "echo-email-batch-body-intro-weekly": "Zdravo $1,\nOvo je sažetak nedeljnih aktivnosti na {{SITENAME}} za Vas.",
+ "echo-email-batch-link-text-view-all-notifications": "Vidi sve notifikacije",
+ "echo-rev-deleted-text-view": "Revizija ove stranice je zabranjena."
+}
diff --git a/Echo/i18n/si.json b/Echo/i18n/si.json
new file mode 100644
index 00000000..261cfb7d
--- /dev/null
+++ b/Echo/i18n/si.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "echo-desc": "නිවේදන පද්ධතිය",
+ "prefs-echo": "නිවේදන",
+ "prefs-displaynotifications": "විකල්ප පෙන්වන්න",
+ "echo-pref-email-frequency-never": "මට විද්‍යුත්-තැපැල් නිවේදන කිසිවක් එවන්න එපා",
+ "echo-pref-email-frequency-immediately": "තනි තනි නිවේදන ඒවා එන විට",
+ "echo-pref-email-frequency-daily": "නිවේදනවල දෛනික සාරාංශයක්",
+ "echo-pref-email-frequency-weekly": "නිවේදනවල සතිපතා සාරාංශයක්",
+ "echo-no-agent": "[කිසිවෙකු නැත]",
+ "echo-no-title": "[පිටුවක් නොමැත]",
+ "echo-error-no-formatter": "නිවේදනය සඳහා කිසිදු ආකෘතියක් දක්වා නොමැත",
+ "notifications": "නිවේදන",
+ "tooltip-pt-notifications": "ඔබේ නිවේදන",
+ "echo-specialpage": "නිවේදන",
+ "echo-anon": "නිවේදන ලබා ගැනීම සඳහා, [$1 ගිණුමක් තනන්න] හෝ [$2 ප්‍රවිෂ්ට වන්න].",
+ "echo-none": "ඔබට නිවේදන කිසිවක් නොමැත.",
+ "notification-new-user": "{{SITENAME}} වෙත පිළිගනිමු, $1!",
+ "echo-email-subject-default": "{{SITENAME}} හී නව නිවේදනයක්",
+ "echo-email-body-default": "ඔබට {{SITENAME}} හීදී නව නිවේදනයක් ඇත:\n\n$1",
+ "echo-overlay-link": "සියලුම නිවේදන",
+ "echo-overlay-title": "<b>නිවේදන</b>",
+ "echo-overlay-title-overflow": "මගේ නිවේදන (නොකියවූ ඒවා $1 න් $2 පෙන්වමින්)",
+ "echo-date-today": "අද",
+ "echo-date-yesterday": "පෙරදින",
+ "echo-load-more-error": "තවත් ප්‍රතිඑල පමුනුවිමේදී දෝෂයක් හට ගැනුණි.",
+ "echo-email-batch-subject-daily": "ඔබට අද {{PLURAL:$2|නිවේදන}} $1 ඇත",
+ "echo-email-batch-subject-weekly": "ඔබට මෙම සතියේ {{PLURAL:$2|නිවේදන}} $1 ඇත"
+}
diff --git a/Echo/i18n/sk.json b/Echo/i18n/sk.json
new file mode 100644
index 00000000..b9c8f9a2
--- /dev/null
+++ b/Echo/i18n/sk.json
@@ -0,0 +1,87 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sudo77(new)"
+ ]
+ },
+ "echo-desc": "Notifikačný systém",
+ "prefs-echo": "Upozornenia",
+ "prefs-emailsettings": "Možnosti e-mailu",
+ "prefs-displaynotifications": "Možnosti zobrazenia",
+ "prefs-echosubscriptions": "Upozornite ma na tieto udalosti",
+ "prefs-newmessageindicator": "Indikátor nových správ",
+ "echo-pref-send-me": "Posielajte mi:",
+ "echo-pref-send-to": "Posielať na:",
+ "echo-pref-email-format": "Formát e-mailu:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Neposielajte mi žiadne upozornenia e-mailom",
+ "echo-pref-email-frequency-immediately": "Jednotlivé upozornenia ako prichádzajú",
+ "echo-pref-email-frequency-daily": "Denný súhrn upozornení",
+ "echo-pref-email-frequency-weekly": "Týždenný súhrn upozornení",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Obyčajný text",
+ "echo-pref-notify-show-link": "Zobrazovať upozornenia v mojom paneli nástrojov",
+ "echo-pref-new-message-indicator": "Zobraziť indikátor diskusných správ v mojom paneli nástrojov",
+ "echo-learn-more": "Ďalšie informácie",
+ "echo-new-messages": "Máte nové správy",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|správu|správy}} v diskusii",
+ "echo-category-title-article-linked": "{{PLURAL:$1|odkaz|odkazy}} na stránku",
+ "echo-category-title-reverted": "{{PLURAL:$1|vrátenú úpravu|vrátené úpravy}}",
+ "echo-category-title-mention": "{{PLURAL:$1|zmienku|zmienky}}",
+ "echo-category-title-other": "{{PLURAL:$1|inú udalosť|iné udalosti}}",
+ "echo-category-title-system": "{{PLURAL:$1|systémovú udalosť|systémové udalosti}}",
+ "echo-pref-tooltip-edit-user-talk": "Upozornite ma, keď mi niekto na mojej diskusnej stránke napíše správu alebo odpovie.",
+ "echo-pref-tooltip-article-linked": "Upozornite ma, keď niekto na stránku, ktorú som založil, odkáže z článku.",
+ "echo-pref-tooltip-reverted": "Upozornite ma, keď niekto vráti úpravu, ktorú som urobil, pomocou nástrojov vrátiť alebo rollback.",
+ "echo-pref-tooltip-mention": "Upozornite ma, keď v akejkoľvek diskusii niekto odkáže na moju redaktorskú stránku.",
+ "echo-no-agent": "[Nikto]",
+ "echo-no-title": "[Žiadna stránka]",
+ "echo-error-no-formatter": "Upozornenie nemá definované formátovanie",
+ "echo-error-preference": "Chyba: Nepodarilo sa uložiť užívateľské nastavenie",
+ "notifications": "Upozornenia",
+ "tooltip-pt-notifications": "Vaše upozornenia",
+ "echo-specialpage": "Upozornenia",
+ "echo-anon": "Ak chcete dostávať upozornenia, musíte si [$1 vytvoriť účet] alebo [$2 sa prihlásiť].",
+ "echo-none": "Nemáte žiadne upozornenia.",
+ "echo-more-info": "Viac informácií",
+ "echo-feedback": "Spätná väzba",
+ "notification-link-text-view-message": "Zobraziť správu",
+ "notification-link-text-view-mention": "Zobraziť zmienku",
+ "notification-link-text-view-changes": "Zobraziť zmeny",
+ "notification-link-text-view-page": "Zobraziť stránku",
+ "notification-link-text-view-edit": "Zobraziť úpravu",
+ "notification-edit-talk-page2": "[[User:$1|$1]] vám {{GENDER:$1|napísal|napísala}} na [[User talk:$2#$3|vašu diskusnú stránku]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] vám {{GENDER:$1|napísal|napísala}} na vašu diskusnú stránku v sekcii „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 vám {{GENDER:$1|napísal|napísala}} na [[User talk:$2#$3|vašu diskusnú stránku]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 vám {{GENDER:$1|napísal|napísala}} na vašu diskusnú stránku v sekcii „[[User talk:$2#$3|$4]]“.",
+ "notification-page-linked": "Na stránku [[:$3]] {{GENDER:$1|bol pridaný}} odkaz na stránku [[:$2]]. [[Special:WhatLinksHere/$2|Zobraziť všetky odkazy na túto stránku]].",
+ "notification-page-linked-flyout": "Na stránku [[:$3]] {{GENDER:$1|bol pridaný}} odkaz na stránku [[:$2]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|pridal|pridala}} komentár k „[[$3|$2]]“ na stránke „$4“",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|pridal|pridala}} komentár na novú tému „$2“ na stránke „[[$3]]“",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vám {{GENDER:$1|poslal|poslala}} správu: „[[$3#$2|$2]]“",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|pridal|pridala}} komentár k „[[$3#$2|$2]]“ na vašej diskusnej stránke",
+ "notification-mention": "[[User:$1|$1]] vás {{GENDER:$1|spomenul|spomenula}} v diskusii {{GENDER:$5|redaktora|redaktorky}} $5 v sekcii „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 vás {{GENDER:$1|spomenul|spomenula}} v diskusii {{GENDER:$5|redaktora|redaktorky}} $5 v sekcii „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] vás {{GENDER:$1|spomenul|spomenula}} v [[:$3|diskusii ku stránke $2]].",
+ "notification-mention-nosection-flyout": "$1 vás {{GENDER:$1|spomenul|spomenula}} v [[:$3|diskusii ku stránke $2]].",
+ "notification-edit-talk-page-email-subject2": "$1 vám na {{grammar:6sg|{{SITENAME}}}} {{GENDER:$1|napísal|napísla}} správu.",
+ "notification-edit-talk-page-email-batch-body2": "$1 vám {{GENDER:$1|napísal|napísala}} na vašu diskusnú stránku:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 vám {{GENDER:$1|napísal|napísala}} na vašu diskusnú stránku k sekcii „$2“.",
+ "notification-page-linked-email-subject": "Na {{grammar:6sg|{{SITENAME}}}} niekto odkázal na vašu stránku.",
+ "notification-page-linked-email-batch-body": "Na stránku $3 {{GENDER:$1|bol pridaný}} odkaz na stránku $2",
+ "notification-reverted-email-subject2": "$1 {{GENDER:$1|revertoval|revertovala}} {{PLURAL:$3|vašu úpravu|vaše úpravy}} na {{grammar:6sg|{{SITENAME}}}}",
+ "notification-reverted-email-batch-body2": "$1 {{GENDER:$1|revertoval|revertovala}} {{PLURAL:$3|vašu úpravu|vaše úpravy}} stránky $2.",
+ "notification-mention-email-subject": "$1 vás {{GENDER:$1|spomenul|spomenula}} na {{grammar:6sg|{{SITENAME}}}}",
+ "notification-mention-email-batch-body": "$1 vás {{GENDER:$1|spomenul|spomenula}} v diskusii {{GENDER:$4|redaktora|redaktorky}} $4 v sekcii „$3“.",
+ "notification-mention-nosection-email-batch-body": "$1 vás {{GENDER:$1|spomenul|spomenula}} v diskusii ku stránke $2.",
+ "notification-user-rights-email-subject": "Na {{grammar:6sg|{{SITENAME}}}} boli zmenené vaše redaktorské práva",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|zmenil|zmenila}} vaše redaktorské práva. $2",
+ "echo-email-batch-body-default": "Máte nové upozornenie",
+ "echo-overlay-link": "Všetky upozornenia",
+ "echo-overlay-title": "<b>Upozornenia</b>",
+ "echo-mark-all-as-read": "Označiť všetko ako prečítané",
+ "echo-date-today": "Dnes",
+ "echo-date-yesterday": "Včera",
+ "echo-email-batch-link-text-view-all-notifications": "Zobraziť všetky upozornenia"
+}
diff --git a/Echo/i18n/sl.json b/Echo/i18n/sl.json
new file mode 100644
index 00000000..d0d42795
--- /dev/null
+++ b/Echo/i18n/sl.json
@@ -0,0 +1,116 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dbc334",
+ "Eleassar",
+ "Matej1234",
+ "Pinky sl",
+ "Yerpo"
+ ]
+ },
+ "echo-desc": "Sistem obvestil",
+ "prefs-echo": "Obvestila",
+ "prefs-emailsettings": "Možnosti e-pošte",
+ "prefs-displaynotifications": "Možnosti prikaza",
+ "prefs-echosubscriptions": "Obvesti me o naslednjih dogodkih",
+ "prefs-newmessageindicator": "Kazalnik novih sporočil",
+ "echo-pref-send-me": "Pošlji mi:",
+ "echo-pref-send-to": "Pošlji:",
+ "echo-pref-email-format": "Format e-pošte:",
+ "echo-pref-web": "Splet",
+ "echo-pref-email": "E-pošta",
+ "echo-pref-email-frequency-never": "Ne pošiljaj mi nobenih e-poštnih obvestil",
+ "echo-pref-email-frequency-immediately": "Posamezna obvestila, kot prihajajo",
+ "echo-pref-email-frequency-daily": "Dnevni povzetek obvestil",
+ "echo-pref-email-frequency-weekly": "Tedenski povzetek obvestil",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Neoblikovano besedilo",
+ "echo-pref-notify-show-link": "Prikaži obvestila v orodni vrstici",
+ "echo-pref-new-message-indicator": "V orodni vrstici prikaži kazalnik sporočil na pogovornih straneh",
+ "echo-learn-more": "Več o tem",
+ "echo-new-messages": "Imate nova sporočila",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Sporočilo|Sporočila}} na pogovornih straneh",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Povezava|Povezave}} na pogovornih straneh",
+ "echo-category-title-reverted": "{{PLURAL:$1|Vračanje|Vračanja}} urejanj",
+ "echo-category-title-mention": "{{PLURAL:$1|Omemba|Omembe}}",
+ "echo-category-title-other": "{{PLURAL:$1|Drugo}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Sprememba|Spremembi|Spremembe}} uporabniških pravic",
+ "echo-pref-tooltip-edit-user-talk": "Obvesti me, ko nekdo na moji pogovorni strani objavi sporočilo ali odgovori.",
+ "echo-pref-tooltip-article-linked": "Obvesti me, ko nekdo doda povezavo na stran, ki sem jo ustvaril.",
+ "echo-pref-tooltip-reverted": "Obvesti me, ko nekdo z orodjem za razveljavitev ali vrnitev vrne urejanje, ki sem ga napravil.",
+ "echo-pref-tooltip-mention": "Obvesti me, ko nekdo doda povezavo na mojo uporabniško stran.",
+ "echo-pref-tooltip-user-rights": "Obvesti me, ko nekdo spremeni moje uporabniške pravice.",
+ "echo-no-agent": "[Nihče]",
+ "echo-no-title": "[Nobena stran]",
+ "echo-error-no-formatter": "Za obvestilo ni določeno nobeno oblikovanje.",
+ "echo-error-preference": "Napaka: ni bilo mogoče nastaviti uporabniških nastavitev.",
+ "echo-error-token": "Napaka: ni bilo mogoče pridobiti uporabnikovega žetona.",
+ "notifications": "Obvestila",
+ "tooltip-pt-notifications": "Vaša obvestila",
+ "echo-specialpage": "Obvestila",
+ "echo-anon": "Za prejemanje obvestil [$1 si ustvarite račun] ali [$2 se prijavite].",
+ "echo-none": "Nimate obvestil.",
+ "echo-more-info": "Več informacij",
+ "echo-feedback": "Povratne informacije",
+ "notification-link-text-view-message": "Ogled sporočila",
+ "notification-link-text-view-mention": "Ogled omembe",
+ "notification-link-text-view-changes": "Ogled sprememb",
+ "notification-link-text-view-page": "Ogled strani",
+ "notification-link-text-view-edit": "Ogled urejanja",
+ "notification-edit-talk-page2": "[[User:$1|$1]] je na vaši [[User talk:$2#$3|pogovorni strani]] {{GENDER:$1|pustil|pustila}} sporočilo.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] je {{GENDER:$1|pustil|pustila}} sporočilo na vaši pogovorni strani v razdelku »[[User talk:$2#$3|$4]]«.",
+ "notification-edit-talk-page-flyout2": "$1 je na vaši [[User talk:$2#$3|pogovorni strani]]{{GENDER:$1|pustil|pustila}} sporočilo.",
+ "notification-edit-talk-page-flyout-with-section": "$1 je {{GENDER:$1|pustil|pustila}} sporočilo na vaši pogovorni strani v razdelku »[[User talk:$2#$3|$4]]«.",
+ "notification-page-linked": "Na strani »[[:$3]]« je bila {{GENDER:$1|dodana}} povezava na stran »[[:$2]]«. [[Special:WhatLinksHere/$2|Ogled vseh povezav na to stran]].",
+ "notification-page-linked-flyout": "Na strani »[[:$3]]« je bila {{GENDER:$1|dodana povezava}} na stran »[[:$2]]«.",
+ "notification-add-comment2": "[[User:$1|$1]] je o »[[$3|$2]]« {{GENDER:$1|komentiral|komentirala}} na pogovorni strani »$4«.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] je na strani »[[$3]]« {{GENDER:$1|objavil|objavila}} novo temo »$2«.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vam je {{GENDER:$1|poslal|poslala}} sporočilo: »[[$3#$2|$2]]«.",
+ "notification-add-comment-yours2": "[[User:$1|$1]] je na vaši pogovorni strani {{GENDER:$1|komentiral|komentirala}} o temi »[[$3#$2|$2]]«.",
+ "notification-mention": "[[User:$1|$1]] vas je {{GENDER:$1|omenil|omenila}} na pogovorni strani strani »$5« v razdelku »[[:$3#$2|$4]]«.",
+ "notification-mention-flyout": "$1 vas je {{GENDER:$1|omenil|omenila}} v razdelku »[[:$3#$2|$4]]« na pogovorni strani uporabnika »$5«.",
+ "notification-mention-nosection": "[[User:$1|$1]] vas je {{GENDER:$1|omenil|omenila|omenil(-a)}} na [[:$3|pogovorni strani $2]].",
+ "notification-mention-nosection-flyout": "$1 vas je {{GENDER:$1|omenil|omenila|omenil(-a)}} na [[:$3|pogovorni strani $2]].",
+ "notification-user-rights": "Vaše uporabniške pravice [[Special:Log/rights/$1|je {{GENDER:$1|spremenil|spremenila}}]] {{GENDER:$1|uporabnik|uporabnica}} [[User:$1|$1]]. $2. [[Special:ListGroupRights|Več o tem]].",
+ "notification-user-rights-flyout": "Vaše uporabniške pravice je {{GENDER:$1|spremenil|spremenila}} {{GENDER:$1|uporabnik|uporabnica}} $1. $2. [[Special:ListGroupRights|Več o tem]].",
+ "notification-user-rights-add": "Odslej ste član {{PLURAL:$2|naslednje skupine|naslednjih skupin}}: $1",
+ "notification-user-rights-remove": "Niste več član {{PLURAL:$2|naslednje skupine|naslednjih skupin}}: $1",
+ "notification-new-user": "Pozdravljeni v {{GRAMMAR:dajalnik|{{SITENAME}}}}, $1! Veseli smo, da ste tu.",
+ "notification-reverted2": "{{PLURAL:$4|Vaše urejanje strani »[[:$2]]« je|Vaša urejanja strani »[[:$2]]« je}} {{GENDER:$1|uporabnik|uporabnica}} [[User:$1|$1]] {{GENDER:$1|vrnil|vrnila}}. $3.",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Vaše urejanje strani »$2«|Vaša urejanja strani »$2«}} je {{GENDER:$1|vrnil|vrnila}} {{GENDER:$1|uporabnik|uporabnica}} $1. $3.",
+ "notification-edit-talk-page-email-subject2": "V projektu {{SITENAME}} vam je {{GENDER:$1|uporabnik|uporabnica}} {{GENDER:$1|pustil|pustila}} sporočilo.",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|Uporabnik|Uporabnica}} vam je na pogovorni strani {{GENDER:$1|pustil|pustila}} sporočilo:",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|Uporabnik|Uporabnica}} vam je {{GENDER:$1|pustil|pustila}} sporočilo na pogovorni strani v razdelku »$2«.",
+ "notification-page-linked-email-subject": "V projektu {{SITENAME}} je bila dodana povezava na vašo stran",
+ "notification-page-linked-email-batch-body": "Stran »$2« je bila {{GENDER:$1|povezana}} s strani »$3«.",
+ "notification-reverted-email-subject2": "V {{GRAMMAR:dajalnik|{{SITENAME}}}} {{PLURAL:$3|je bilo|so bila}} {{PLURAL:$3|vaše urejanje|vaša urejanja}} {{GENDER:$1|{{PLURAL:$3|vrnjeno|vrnjena}}}}.",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Vaše urejanje|Vaša urejanja}} v {{GRAMMAR:mestnik|$2}} je {{GENER:$1|vrnil|vrnila}} $1.",
+ "notification-mention-email-subject": "V projektu {{SITENAME}} vas je {{GENDER:$1|omenil|omenila}} $1.",
+ "notification-mention-email-batch-body": "V razdelku »$3« na pogovorni strani {{GENDER:$4|uporabnika|uporabnice}} vas je {{GENDER:$1|omenil|omenila}} $1.",
+ "notification-mention-nosection-email-batch-body": "$1 vas je {{GENDER:$1|omenil|omenila|omenil(-a)}} na pogovorni strani $2.",
+ "notification-user-rights-email-subject": "V {{GRAMMAR:dajalnik|{{SITENAME}}}} so bile spremenjene vaše uporabniške pravice.",
+ "notification-user-rights-email-batch-body": "Vaše uporabniške pravice je {{GENDER:$1|spremenil|spremenila}} $1. $2.",
+ "echo-email-subject-default": "Novo obvestilo v {{GRAMMAR:dajalnik|{{SITENAME}}}}",
+ "echo-email-body-default": "V {{GRAMMAR:dajalnik|{{SITENAME}}}} imate novo obvestilo:\n\n$1",
+ "echo-email-batch-body-default": "Imate novo obvestilo.",
+ "echo-email-footer-default": "$2\n\nZa izbiro e-poštnih sporočil, ki jih želite prejemati, prilagodite svoje nastavitve:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Za izbiro e-poštnih sporočil, ki naj vam jih pošiljamo, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">preverite svoje nastavitve</a>.<br />\n$1",
+ "echo-overlay-link": "Vsa obvestila",
+ "echo-overlay-title": "<b>Obvestila</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Obvestila}}</b> ({{PLURAL:$1|prikazano|prikazani|prikazana|prikazanih}} $1 od $2 {{PLURAL:$2|neprebranega|neprebranih}})",
+ "echo-mark-all-as-read": "Označi vsa sporočila kot prebrana",
+ "echo-date-today": "Danes",
+ "echo-date-yesterday": "Včeraj",
+ "echo-load-more-error": "Pri pridobivanju dodatnih rezultatov je prišlo do napake.",
+ "notification-edit-talk-page-bundle": "$1 in $3 {{PLURAL:$4|drug|druga|drugih}} vam je na vaši [[User talk:$2|uporabniški strani]] {{GENDER:$1|pustilo}} sporočilo.",
+ "notification-page-linked-bundle": "Stran »$2« je bila »{{GENDER:$1|povezan|povezana}}« s strani »$3« in $4 {{PLURAL:$5|druge strani|drugih strani}}. [[Special:WhatLinksHere/$2|Ogled vseh povezav na to stran]].",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 in $2 {{PLURAL:$3|drug|druga|drugih}} vam je na pogovorni strani {{GENDER:$1|pustilo}} sporočilo.",
+ "notification-page-linked-email-batch-bundle-body": "Stran »$2« je bila {{GENDER:$1|povezan|povezana}} s strani »$3« in $4 {{PLURAL:$5|druge strani|drugih strani}}.",
+ "echo-email-batch-subject-daily": "V {{GRAMMAR:dajalnik|{{SITENAME}}}} imate {{PLURAL:$2|novo sporočilo|nova sporočila}}.",
+ "echo-email-batch-subject-weekly": "V {{GRAMMAR:dajalnik|{{SITENAME}}}} imate ta teden {{PLURAL:$2|eno novo sporočilo|nova sporočila}}.",
+ "echo-email-batch-body-intro-daily": "Pozdravljeni, $1,\ntu je za vas povzetek današnje aktivnosti v {{GRAMMAR:dajalnik|{{SITENAME}}}}.",
+ "echo-email-batch-body-intro-weekly": "Pozdravljeni, $1,\ntu je za vas povzetek aktivnosti preteklega tedna v {{GRAMMAR:dajalnik|{{SITENAME}}}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Ogled vseh obvestil",
+ "echo-rev-deleted-text-view": "Ta redakcija strani je bila izbrisana."
+}
diff --git a/Echo/i18n/so.json b/Echo/i18n/so.json
new file mode 100644
index 00000000..228a9464
--- /dev/null
+++ b/Echo/i18n/so.json
@@ -0,0 +1,39 @@
+{
+ "@metadata": {
+ "authors": [
+ "Abshirdheere"
+ ]
+ },
+ "prefs-echo": "Wargelinada",
+ "echo-new-messages": "Farriin cusub baa kuu taal",
+ "notifications": "Wargelinada",
+ "tooltip-pt-notifications": "Wargelinadaada",
+ "echo-specialpage": "Wargelin",
+ "echo-none": "Malahan wax wargelin ah.",
+ "echo-more-info": "Dheeraad",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|kuugu reebay|kuugu reebtay}} farriin [[User talk:$2#$3|bogga wadahadalka]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] kuugu {{GENDER:$1|dhaafay|dhaaftay}} farriin boggada wadahadalka ee \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|kuu dhigay|kuu dhigtay}} farriin [[User talk:$2#$3|bogga wadahadalka]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|wuxuu kuugu dhaafay|waxay kuu dhaaftay}} farriin boggaada wadahadalka taasoo ah \"[[User talk:$2#$3|$4]]\".",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|xusid}} kugula sameeyey $5 bogaa wadahadalka ee \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "$1 {{GENDER:$1|xusid}} kugula sameeyey $5 bogga wadahadalka \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|xusid}} kugula sameeyey [[:$3|$2 bogga wadahadalka]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|xusid}} kugula sameeyay [[:$3|$2 bogga wadahadalka]].",
+ "notification-user-rights": "Xuquuqaha isticmaalahaada [[Special:Log/rights/$1|waa la {{GENDER:$1|bedelay}}]] waxaana bedelay [[User:$1|$1]]. $2. [[Special:ListGroupRights|wax dheeraad ah ka ogoow]]",
+ "notification-user-rights-flyout": "Xuquuqda isticmaalahaada waa la {{GENDER:$1|bedelay}} waxaana bedelay $1. $2. [[Special:ListGroupRights|wax dheeraad ah ka sii ogoow]]",
+ "notification-user-rights-add": "Hadda waxaad ka midtahay xubin ka mid ah {{PLURAL:$2|kooxdaan|kooxahaan}}: $1",
+ "notification-new-user": "Ku soo dhowoow {{SITENAME}}, $1! Waan ku faraxsan-nahay inaad halkaan joogto.",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|ayaa kuugu dhaafay|ayaa kuugu dhaaftay}} farriin boggada wadahadalka:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|kuugu dhaafay|kuugu dhaaftay}} farriin boggaada wadahadalka ee \"$2\".",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|xusid}} kugula sameeyey $4 bogga wadahadalka ee \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|xusid}} kugula sameeyey $2 bogga wadahadalka.",
+ "notification-user-rights-email-batch-body": "Xuquuqda isticmaalahaada wax baa laga {{GENDER:$1|bedelay}} waxaana bedelay $1. $2.",
+ "echo-overlay-link": "Dhammaan wargelinada",
+ "echo-overlay-title": "<b>Wargelinada</b>",
+ "echo-mark-all-as-read": "Ka dhig dhammaan wax la aqriyey",
+ "echo-date-today": "Maanta",
+ "echo-date-yesterday": "Shalay",
+ "notification-edit-talk-page-bundle": "$1 iyo $3 {{PLURAL:$4|mid kale|kuwa kale}} {{GENDER:$1|kuugu daafay|kuugu dhaaftay}} farriin boggaada [[User talk:$2|wadahadalka]].",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 iyo $2 {{PLURAL:$3|mid kale|kuwa kale}} {{GENDER:$1|kuugu dhaafay|kuugu dhaaftay}} farriin boggada wadahadalka.",
+ "echo-email-batch-link-text-view-all-notifications": "Dhamaan eeg waegelinada"
+}
diff --git a/Echo/i18n/sq.json b/Echo/i18n/sq.json
new file mode 100644
index 00000000..89200995
--- /dev/null
+++ b/Echo/i18n/sq.json
@@ -0,0 +1,107 @@
+{
+ "@metadata": {
+ "authors": [
+ "Euriditi"
+ ]
+ },
+ "echo-desc": "Sistemi i njoftimeve",
+ "prefs-echo": "Njoftimet",
+ "prefs-emailsettings": "Opsionet e e-mailit",
+ "prefs-displaynotifications": "Shfaq opsionet",
+ "prefs-echosubscriptions": "Më njofto për këto raste",
+ "prefs-newmessageindicator": "Brezi i mesazhit të ri",
+ "echo-pref-send-me": "Më dërgo:",
+ "echo-pref-send-to": "Dërgo në:",
+ "echo-pref-email-format": "Formati i e-mailit:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-mail",
+ "echo-pref-email-frequency-never": "Mos më dërgo më njoftime me email",
+ "echo-pref-email-frequency-immediately": "Njoftimet individuale për çdo rast",
+ "echo-pref-email-frequency-daily": "Përmbledhje e përditshme e njoftimeve",
+ "echo-pref-email-frequency-weekly": "Përmbledhje javore e njoftimeve",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Tekst normal",
+ "echo-pref-notify-show-link": "Shfaq njoftimet në brezin e mjeteve",
+ "echo-pref-new-message-indicator": "Shfaq brezin e mesazheve të reja në faqen time të diskutimit në brezin e mjeteve",
+ "echo-learn-more": "Mëso më tepër",
+ "echo-new-messages": "Keni mesazhe të reja",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|mesazh|mesazhe}} në faqen e diskutimeve",
+ "echo-category-title-article-linked": "{{PLURAL:$1|lidhje|lidhje}} në një faqe",
+ "echo-category-title-reverted": "{{PLURAL:$1|Redaktim i kthyer|Redaktime të kthyera}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Përmëndje|Përmëndje}}",
+ "echo-category-title-other": "{{PLURAL:$1|Të tjera}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistemi}}",
+ "echo-pref-tooltip-edit-user-talk": "Më njofto kur dikush poston një mesazh të ri ose përgjigjet në faqet time të diskutimit.",
+ "echo-pref-tooltip-article-linked": "Më njofto kur dikush lidh, një faqe, me një faqe që kam krijuar unë.",
+ "echo-pref-tooltip-reverted": "Më njofto kur dikush kthen një ndryshim që kam bërë unë, duke përdorur funksionet zhbëj ose riktheje.",
+ "echo-pref-tooltip-mention": "Më njofto kur dikush lidh faqen time të përdoruesit me cilëndo faqe diskutimi.",
+ "echo-no-agent": "[Asnjeri]",
+ "echo-no-title": "[Asnjë faqe]",
+ "echo-error-no-formatter": "Asnjë përcaktim mbi formatimimin e njoftimeve.",
+ "echo-error-preference": "Gabim: Preferenca e përdoruesit nuk janë ruajtur.",
+ "echo-error-token": "Gabim: Sistemi nuk arriti të rigjejë shenjat e identifikimit.",
+ "notifications": "Njoftimet",
+ "tooltip-pt-notifications": "Njoftimet tuaja",
+ "echo-specialpage": "Njoftimet",
+ "echo-anon": "Për të marrë njoftime, [$1 regjistrohuni] ose [$2 hyni].",
+ "echo-none": "Nuk keni njoftime.",
+ "echo-more-info": "Më tepër informacion",
+ "echo-feedback": "Komente",
+ "notification-link-text-view-message": "Shiko mesazhin",
+ "notification-link-text-view-mention": "Shiko përmëndjen",
+ "notification-link-text-view-changes": "Shiko ndryshimet",
+ "notification-link-text-view-page": "Shiko faqen",
+ "notification-link-text-view-edit": "Shiko redaktimin",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|iu la}} një mesazh në [[User talk:$2#$3|faqen tuaj të diskutimeve]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|iu la}} një mesazh në faqen tuaj të diskutimeve në seksionin '[[User talk:$2#$3|$4]]'.",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|iu la}} një mesazh në [[User talk:$2#$3|faqen tuaj të diskutimeve]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|iu la}} një mesazh në faqen tuaj të diskutimeve në seksionin '[[User talk:$2#$3|$4]]'.",
+ "notification-page-linked": "[[:$2]] u {{GENDER:$1|lidh}} nga [[:$3]]. [[Special:WhatLinksHere/$2|Shiko të gjitha lidhjet me këtë faqe]].",
+ "notification-page-linked-flyout": "[[:$2]] u {{GENDER:$1|lidh}} nga [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|la një koment}} në lidhje me \"[[$3|$2]]\" në faqen e diskutimeve të \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|postoi}} një temë të re \"$2\" në [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] të {{GENDER:$1|dërgoi}} një mesazh: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|la një koment}} në lidhje me \"[[$3#$2|$2]]\" në faqen tuaj të diskutimeve.",
+ "notification-mention": "[[User:$1|$1]] iu {{GENDER:$1|përmëndi}} në faqen e diskutimeve $5 në '[[:$3#$2|$4]]'.",
+ "notification-mention-flyout": "$1 iu {{GENDER:$1|përmëndi}} në faqen e diskutimeve $5 në '[[:$3#$2|$4]]'.",
+ "notification-user-rights": "Të drejtat e tua të përdoruesit [[Special:Log/rights/$1|u {{GENDER:$1|ndryshuan}}]] nga [[User:$1|$1]]. $2. [[Special:ListGroupRights|Mëso më tepër]]",
+ "notification-user-rights-flyout": "Të drejtat e tua të përdoruesit u {{GENDER:$1|ndryshuan}} nga $1. $2. [[Special:ListGroupRights|Më tepër informacion]]",
+ "notification-user-rights-add": "Tashmë je anëtar i {{PLURAL:$2|këtij grupi|këtyre grupeve}}: $1",
+ "notification-user-rights-remove": "Ju nuk jeni më anëtar i {{PLURAL:$2|këtij grupi|këtyre grupeve}}: $1",
+ "notification-new-user": "Mirësevini në {{SITENAME}}, $1! Jemi të lumtur që ti je këtu.",
+ "notification-reverted2": "{{PLURAL:$4|Redaktimi juaj|Redaktimet e tua}} në [[:$2]] {{PLURAL:$4|u kthye|u kthyen}} {{GENDER:$1|nga}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Redaktimi juaj|Redaktimet e tua}} në $2 {{PLURAL:$4|u kthye|u kthyen}} {{GENDER:$1|nga}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|iu la}} një mesazh në {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|iu la}} një mesazh në faqen tuaj të diskutimeve:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|iu la}} një mesazh në faqen tuaj të diskutimeve në \"$2\".",
+ "notification-page-linked-email-subject": "Një faqe që keni krijuar u lidh në {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 u {{GENDER:$1|lidh}} nga $3",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Redaktimi juaj|Redaktimet tuaja}} {{GENDER:$1|u kthyen}} në {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Redaktimi juaj|Redaktimet e tua}} në $2 {{PLURAL:$3|u kthye|u kthyen}} {{GENDER:$1|nga}} $1",
+ "notification-mention-email-subject": "$1 të {{GENDER:$1|përmëndi}} në {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 të {{GENDER:$1|përmëndi}} në faqen e diskutimeve të $4 në seksionin '$3'.",
+ "notification-user-rights-email-subject": "Të drejtat e tua të përdoruesit u ndryshuan në {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Të drejtat e tua të përdoruesit u {{GENDER:$1|ndyshuan}} nga $1. $2",
+ "echo-email-subject-default": "Njoftim i ri në {{SITENAME}}",
+ "echo-email-body-default": "Keni një njoftim të ri në {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Keni një njoftim të ri.",
+ "echo-email-footer-default": "$2\n\nPër të kontrolluar se cili email do t'iu dërgohet, kontrolloni parapëlqimet tuaja:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Për të kontrolluar se cili email do t'iu dërgohet, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">kontrolloni parapëlqimet tuaja</a>.<br />\n$1",
+ "echo-overlay-link": "Të gjitha njoftimet",
+ "echo-overlay-title": "<b>Njoftimet</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Njoftime}}</b> (duke shfaqur $1 nga $2 të pa lexuara)",
+ "echo-mark-all-as-read": "Shënoji të gjitha si të lexuara",
+ "echo-date-today": "Sot",
+ "echo-date-yesterday": "Dje",
+ "echo-load-more-error": "Pati një gabim në ngarkimin e rezultateve shtesë.",
+ "notification-edit-talk-page-bundle": "$1 dhe {{PLURAL:$4|një përdorues tjetër|$3 përdorues të tjerë}} {{GENDER:$1|iu lanë}} një mesazh në [[User talk:$2|faqen tuaj të diskutimeve]].",
+ "notification-page-linked-bundle": "$2 u {{GENDER:$1|lidh}} nga $3 dhe {{PLURAL:$5|një faqe tjetër|$4 faqe të tjera}}. [[Special:WhatLinksHere/$2|Shfaq të gjitha lidhjet me këtë faqe]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 dhe {{PLURAL:$3|një tjetër|$2 të tjerë}} {{GENDER:$1|lanë}} një mesazh në faqen tuaj të diskutimeve",
+ "notification-page-linked-email-batch-bundle-body": "$2 u {{GENDER:$1|lidh}} nga $3 dhe {{PLURAL:$5|një tjetër faqe|$4 faqe të tjera}}",
+ "echo-email-batch-subject-daily": "Keni {{PLURAL:$2|një njoftim të ri|njoftime të reja}} në {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Keni {{PLURAL:$2|një njoftim të ri|njoftime të reja}} në {{SITENAME}} gjatë kësaj jave.",
+ "echo-email-batch-body-intro-daily": "Përshëndetje $1,\nkëtu është përmbledhja e aktivitetit të sotëm në {{SITENAME}} për ju.",
+ "echo-email-batch-body-intro-weekly": "Përshëndetje $1,\nkëtu është përmbledhja e aktivitetit javor në {{SITENAME}} për ju.",
+ "echo-email-batch-link-text-view-all-notifications": "Shfaq të gjitha njoftimet",
+ "echo-rev-deleted-text-view": "Ky version i faqes është fshirë."
+}
diff --git a/Echo/i18n/sr-ec.json b/Echo/i18n/sr-ec.json
new file mode 100644
index 00000000..cf915e3b
--- /dev/null
+++ b/Echo/i18n/sr-ec.json
@@ -0,0 +1,117 @@
+{
+ "@metadata": {
+ "authors": [
+ "Milicevic01",
+ "Rancher",
+ "Михајло Анђелковић"
+ ]
+ },
+ "echo-desc": "Обавештајни систем",
+ "prefs-echo": "Обавештења",
+ "prefs-emailsettings": "Поставке е-поште",
+ "prefs-displaynotifications": "Поставке приказа",
+ "prefs-echosubscriptions": "Обавести ме о следећим догађајима.",
+ "prefs-newmessageindicator": "Индикатор за нове поруке",
+ "echo-pref-send-me": "Пошаљи ми:",
+ "echo-pref-send-to": "Пошаљи на:",
+ "echo-pref-email-format": "Формат е-поште:",
+ "echo-pref-web": "Веб",
+ "echo-pref-email": "На е-пошту",
+ "echo-pref-email-frequency-never": "Не шаљи ми обавештења на е-пошту",
+ "echo-pref-email-frequency-immediately": "Појединачна обавештења чим се појаве",
+ "echo-pref-email-frequency-daily": "Дневни сажетак обавештења",
+ "echo-pref-email-frequency-weekly": "Седмични сажетак обавештења",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Чист текст",
+ "echo-pref-notify-show-link": "Прикажи обавештења у мојој траци алатки",
+ "echo-pref-new-message-indicator": "Прикажи индикатор када добијем поруку на страници за разговор",
+ "echo-learn-more": "Сазнајте више",
+ "echo-new-messages": "Имате нове поруке",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Поруке}} на страници за разговор",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Повезивање страница}}",
+ "echo-category-title-reverted": "Поништене {{PLURAL:$1|измене}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Спомињања}}",
+ "echo-category-title-other": "{{PLURAL:$1|Остало}}",
+ "echo-category-title-system": "{{PLURAL:$1|Систем}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Промена корисничких права}}",
+ "echo-pref-tooltip-edit-user-talk": "Обавештава вас када неко остави поруку на вашој страници за разговор.",
+ "echo-pref-tooltip-article-linked": "Обавештава вас када неко повеже чланак који сте ви направили са неком другом страницом.",
+ "echo-pref-tooltip-reverted": "Обавештава вас када неко поништи измену коју сте ви начинили.",
+ "echo-pref-tooltip-mention": "Обавештава вас кад вас неко спомене.",
+ "echo-pref-tooltip-user-rights": "Обавештава вас када неко промени ваша корисничка права.",
+ "echo-no-agent": "[Нико]",
+ "echo-no-title": "[Нема странице]",
+ "echo-error-no-formatter": "Није задато обликовање за обавештења",
+ "echo-error-preference": "Грешка: подешавања нису сачувана.",
+ "notifications": "Обавештења",
+ "tooltip-pt-notifications": "Ваша обавештења",
+ "echo-specialpage": "Обавештења",
+ "echo-anon": "Да би сте приступили овој страници морате се [$2 пријавити] или [$1 отворити налог].",
+ "echo-none": "Немате обавештења",
+ "echo-more-info": "Више информација",
+ "echo-feedback": "Повратне информације",
+ "notification-link-text-view-message": "Погледај поруку",
+ "notification-link-text-view-mention": "Види спомињање",
+ "notification-link-text-view-changes": "Погледај измене",
+ "notification-link-text-view-page": "Погледај страницу",
+ "notification-link-text-view-edit": "Погледај измену",
+ "notification-edit-talk-page2": "[[User:$1|$1]] вам је {{GENDER:$1|оставио|оставила}} поруку на вашој [[User talk:$2#$3|страници за разговор]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] вам је {{GENDER:$1|оставио|оставила}} поруку на вашој страници за разговор у „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 вам је {{GENDER:$1|оставио|оставила}} поруку на вашој [[User talk:$2#$3|страници за разговор]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 вам је {{GENDER:$1|оставио|оставила}} поруку на вашој страници за разговор у „[[User talk:$2#$3|$4]]“.",
+ "notification-page-linked": "Страница [[:$2]] је {{GENDER:$1|повезана}} са страницом [[:$3]]. [[Special:WhatLinksHere/$2|Погледајте све везе према овој страници]].",
+ "notification-page-linked-flyout": "[[:$2]] је {{GENDER:$1|повезана}} са [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] је {{GENDER:$1|прокоментарисао|прокоментарисала}} тему „[[$3|$2]]“ на страници за разговор „$4“.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] је {{GENDER:$1|поставио|поставила}} нову тему „$2“ на [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] вам је {{GENDER:$1|послао|послала}} поруку: „[[$3#$2|$2]]“.",
+ "notification-add-comment-yours2": "[[User:$1|$1]] је {{GENDER:$1|прокоментарисао|прокоментарисала}} тему „[[$3#$2|$2]]“ на вашој страници за разговор.",
+ "notification-mention": "[[User:$1|$1]] вас је {{GENDER:$1|спомену|споменула}} на страници за разговор $5 у „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 вас је {{GENDER:$1|споменуо|споменула}} на страници за разговор $5 у „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] вас је {{GENDER:$1|споменуо|споменула}} на [[:$3|страници за разговор $2]].",
+ "notification-mention-nosection-flyout": "$1 вас је {{GENDER:$1|споменуо|споменула}} на [[:$3|страници за разговор $2]].",
+ "notification-user-rights": "[[User:$1|$1]] је {{GENDER:$1|[[Special:Log/rights/$1|променио]]|[[Special:Log/rights/$1|променила]]}} ваша корисничка права. $2. [[Special:ListGroupRights|Сазнајте више]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|је променио|је променила}} ваша корисничка права. $2. [[Special:ListGroupRights|Сазнајте више]]",
+ "notification-user-rights-add": "Од сада сте члан {{PLURAL:$2|следеће групе|следећих група}}: $1",
+ "notification-user-rights-remove": "Више нисте члан {{PLURAL:$2|следеће групе|следећих група}}: $1",
+ "notification-new-user": "$1, добро дошли на пројекат {{SITENAME}}! Драго нам је што сте овде.",
+ "notification-reverted2": "{{PLURAL:$4|Ваша измена на страници [[:$2]] је поништена|Ваше измене на страници [[:$2]] су поништене}} од стране {{GENDER:$1|корисника|кориснице}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Ваша измена на страници $2 је поништена|Ваше измене на страници $2 су поништене}} од стране {{GENDER:$1|корисника|кориснице}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 вам је {{GENDER:$1|оставио|оставила}} поруку на пројекту {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 вам је {{GENDER:$1|оставио|оставила}} поруку на вашој страници за разговор:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 вам је {{GENDER:$1|оставио|оставила}} поруку на вашој страници за разговор у „$2“.",
+ "notification-page-linked-email-subject": "Ваша страница је повезана на пројекту {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "Страница $2 је {{GENDER:$1|повезана}} са $3.",
+ "notification-reverted-email-subject2": "{{GENDER:$1|{{PLURAL:$3|Ваша измена је поништена|Ваше измене су поништене}}}} на пројекту {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Ваша измена на страници $2 је поништена|Ваше измене на страници $2 су поништене}} од стране {{GENDER:$1|корисника|кориснице}} $1.",
+ "notification-mention-email-subject": "$1 вас је {{GENDER:$1|споменуо|споменула}} на {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 вас је {{GENDER:$1|споменуо|споменула}} на страници за разговор $4 у „$3“.",
+ "notification-mention-nosection-email-batch-body": "$1 вас је {{GENDER:$1|споменуо|споменула}} на страници за разговор $2.",
+ "notification-user-rights-email-subject": "Ваша корисничка права на пројекту {{SITENAME}} су промењена.",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|је променио|је променила}} ваша корисничка права. $2.",
+ "echo-email-subject-default": "Ново обавештење на {{SITENAME}}",
+ "echo-email-body-default": "Имате ново обавештење на пројекту {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Имате ново обавештење.",
+ "echo-email-footer-default": "$2\n\nДа би сте променили које поруке примате од нас идите у подешавања:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Да би сте променили које поруке примате од нас идите у <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">подешавања</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Обавештања ($1)|100=Обавештања (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Порука ($1)|100=Порука (99+)}}",
+ "echo-notification-alert-text-only": "Обавештења",
+ "echo-notification-message-text-only": "Поруке",
+ "echo-overlay-link": "Сва обавештења",
+ "echo-overlay-title": "<b>Обавештења</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Обавештења}}</b> (приказ $1 од $2 непрочитаних)",
+ "echo-mark-all-as-read": "Означи све прочитаним",
+ "echo-date-today": "Данас",
+ "echo-date-yesterday": "Јуче",
+ "echo-load-more-error": "Дошло је до грешке при добављању више резултата.",
+ "notification-edit-talk-page-bundle": "$1 и још $3 {{PLURAL:$4|корисник|корисника}} {{GENDER:$1|оставили}} су поруке на вашој [[User talk:$2|страници за разговор]].",
+ "notification-page-linked-bundle": "Страница $2 је {{GENDER:$1|повезана}} са $3 и $4 {{PLURAL:$5|друге странице|других страница}}. [[Special:WhatLinksHere/$2|Погледајте све везе према овој страници]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 и још $2 {{PLURAL:$3|1=један корисник|корисника}} {{GENDER:$1|оставили}} су поруке на вашој страници за разговор.",
+ "notification-page-linked-email-batch-bundle-body": "Страница $2 је {{GENDER:$1|повезана}} са $3 и $4 {{PLURAL:$5|друге странице|других страница}}.",
+ "echo-email-batch-subject-daily": "Имате {{PLURAL:$2|ново обавештење|нова обавештења}} на пројекту {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Имате {{PLURAL:$2|ново обавештење|нова обавештења}} на пројекту {{SITENAME}} ове седмице",
+ "echo-email-batch-body-intro-daily": "Здраво $1,\nОво је дневни сажетак данашњих активности на пројекту {{SITENAME}} за вас.",
+ "echo-email-batch-body-intro-weekly": "Здраво $1,\nОво је недељни сажетак активности на пројекту {{SITENAME}} за вас.",
+ "echo-email-batch-link-text-view-all-notifications": "Погледај сва обавештења",
+ "echo-rev-deleted-text-view": "Ова ревизија странице је потиснута."
+}
diff --git a/Echo/i18n/sr-el.json b/Echo/i18n/sr-el.json
new file mode 100644
index 00000000..248f3012
--- /dev/null
+++ b/Echo/i18n/sr-el.json
@@ -0,0 +1,115 @@
+{
+ "@metadata": {
+ "authors": [
+ "Milicevic01"
+ ]
+ },
+ "echo-desc": "Obaveštajni sistem",
+ "prefs-echo": "Obaveštenja",
+ "prefs-emailsettings": "Postavke e-pošte",
+ "prefs-displaynotifications": "Postavke prikaza",
+ "prefs-echosubscriptions": "Obavesti me o sledećim događajima.",
+ "prefs-newmessageindicator": "Indikator za nove poruke",
+ "echo-pref-send-me": "Pošalji mi:",
+ "echo-pref-send-to": "Pošalji na:",
+ "echo-pref-email-format": "Format e-pošte:",
+ "echo-pref-web": "Veb",
+ "echo-pref-email": "Na e-poštu",
+ "echo-pref-email-frequency-never": "Ne šalji mi obaveštenja na e-poštu",
+ "echo-pref-email-frequency-immediately": "Pojedinačna obaveštenja čim se pojave",
+ "echo-pref-email-frequency-daily": "Dnevni sažetak obaveštenja",
+ "echo-pref-email-frequency-weekly": "Sedmični sažetak obaveštenja",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Čist tekst",
+ "echo-pref-notify-show-link": "Prikaži obaveštenja u mojoj traci alatki",
+ "echo-pref-new-message-indicator": "Prikaži indikator kada dobijem poruku na stranici za razgovor",
+ "echo-learn-more": "Saznajte više",
+ "echo-new-messages": "Imate nove poruke",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Poruke}} na stranici za razgovor",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Povezivanje stranica}}",
+ "echo-category-title-reverted": "Poništene {{PLURAL:$1|izmene}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Spominjanja}}",
+ "echo-category-title-other": "{{PLURAL:$1|Ostalo}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Promena korisničkih prava}}",
+ "echo-pref-tooltip-edit-user-talk": "Obaveštava vas kada neko ostavi poruku na vašoj stranici za razgovor.",
+ "echo-pref-tooltip-article-linked": "Obaveštava vas kada neko poveže članak koji ste vi napravili sa nekom drugom stranicom.",
+ "echo-pref-tooltip-reverted": "Obaveštava vas kada neko poništi izmenu koju ste vi načinili.",
+ "echo-pref-tooltip-mention": "Obaveštava vas kad vas neko spomene.",
+ "echo-pref-tooltip-user-rights": "Obaveštava vas kada neko promeni vaša korisnička prava.",
+ "echo-no-agent": "[Niko]",
+ "echo-no-title": "[Nema stranice]",
+ "echo-error-no-formatter": "Nije zadato oblikovanje za obaveštenja",
+ "echo-error-preference": "Greška: podešavanja nisu sačuvana.",
+ "notifications": "Obaveštenja",
+ "tooltip-pt-notifications": "Vaša obaveštenja",
+ "echo-specialpage": "Obaveštenja",
+ "echo-anon": "Da bi ste pristupili ovoj stranici morate se [$2 prijaviti] ili [$1 otvoriti nalog].",
+ "echo-none": "Nemate obaveštenja",
+ "echo-more-info": "Više informacija",
+ "echo-feedback": "Povratne informacije",
+ "notification-link-text-view-message": "Pogledaj poruku",
+ "notification-link-text-view-mention": "Vidi spominjanje",
+ "notification-link-text-view-changes": "Pogledaj izmene",
+ "notification-link-text-view-page": "Pogledaj stranicu",
+ "notification-link-text-view-edit": "Pogledaj izmenu",
+ "notification-edit-talk-page2": "[[User:$1|$1]] vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj [[User talk:$2#$3|stranici za razgovor]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u „[[User talk:$2#$3|$4]]“.",
+ "notification-edit-talk-page-flyout2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj [[User talk:$2#$3|stranici za razgovor]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u „[[User talk:$2#$3|$4]]“.",
+ "notification-page-linked": "Stranica [[:$2]] je {{GENDER:$1|povezana}} sa stranicom [[:$3]]. [[Special:WhatLinksHere/$2|Pogledajte sve veze prema ovoj stranici]].",
+ "notification-page-linked-flyout": "[[:$2]] je {{GENDER:$1|povezana}} sa [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] je {{GENDER:$1|prokomentarisao|prokomentarisala}} temu „[[$3|$2]]“ na stranici za razgovor „$4“.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] je {{GENDER:$1|postavio|postavila}} novu temu „$2“ na [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] vam je {{GENDER:$1|poslao|poslala}} poruku: „[[$3#$2|$2]]“.",
+ "notification-add-comment-yours2": "[[User:$1|$1]] je {{GENDER:$1|prokomentarisao|prokomentarisala}} temu „[[$3#$2|$2]]“ na vašoj stranici za razgovor.",
+ "notification-mention": "[[User:$1|$1]] vas je {{GENDER:$1|spomenuo|spomenula}} na stranici za razgovor $5 u „[[:$3#$2|$4]]“.",
+ "notification-mention-flyout": "$1 vas je {{GENDER:$1|spomenuo|spomenula}} na stranici za razgovor $5 u „[[:$3#$2|$4]]“.",
+ "notification-mention-nosection": "[[User:$1|$1]] vas je {{GENDER:$1|spomenuo|spomenula}} na [[:$3|stranici za razgovor $2]].",
+ "notification-mention-nosection-flyout": "$1 vas je {{GENDER:$1|spomenuo|spomenula}} na [[:$3|stranici za razgovor $2]].",
+ "notification-user-rights": "[[User:$1|$1]] je {{GENDER:$1|[[Special:Log/rights/$1|promenio]]|[[Special:Log/rights/$1|promenila]]}} vaša korisnička prava. $2. [[Special:ListGroupRights|Saznajte više]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1|je promenio|je promenila}} vaša korisnička prava. $2. [[Special:ListGroupRights|Saznajte više]]",
+ "notification-user-rights-add": "Od sada ste član {{PLURAL:$2|sledeće grupe|sledećih grupa}}: $1",
+ "notification-user-rights-remove": "Više niste član {{PLURAL:$2|sledeće grupe|sledećih grupa}}: $1",
+ "notification-new-user": "$1, dobro došli na projekat {{SITENAME}}! Drago nam je što ste ovde.",
+ "notification-reverted2": "{{PLURAL:$4|Vaša izmena na stranici [[:$2]] je poništena|Vaše izmene na stranici [[:$2]] su poništene}} od strane {{GENDER:$1|korisnika|korisnice}} [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Vaša izmena na stranici $2 je poništena|Vaše izmene na stranici $2 su poništene}} od strane {{GENDER:$1|korisnika|korisnice}} $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 vam je {{GENDER:$1|ostavio|ostavila}} poruku na vašoj stranici za razgovor u „$2“.",
+ "notification-page-linked-email-subject": "Vaša stranica je povezana na projektu {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 je {{GENDER:$1|povezana}} sa $3.",
+ "notification-reverted-email-subject2": "{{GENDER:$1|{{PLURAL:$3|Vaša izmena je poništena|Vaše izmene su poništene}}}} na projektu {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Vaša izmena na stranici $2 je poništena|Vaše izmene na stranici $2 su poništene}} od strane {{GENDER:$1|korisnika|korisnice}} $1.",
+ "notification-mention-email-subject": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 vas je {{GENDER:$1|spomenuо|spomenula}} na stranici za razgovor $4 u „$3“.",
+ "notification-mention-nosection-email-batch-body": "$1 vas je {{GENDER:$1|spomenuo|spomenula}} na stranici za razgovor $2.",
+ "notification-user-rights-email-subject": "Vaša korisnička prava na projektu {{SITENAME}} su promenjena.",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1|je promenio|je promenila}} vaša korisnička prava. $2.",
+ "echo-email-subject-default": "Novo obaveštenje na {{SITENAME}}",
+ "echo-email-body-default": "Imate novo obaveštenje na {{SITENAME}}: \n\n$1",
+ "echo-email-batch-body-default": "Imate novo obaveštenje.",
+ "echo-email-footer-default": "$2\n\nDa bi ste promenili koje poruke primate od nas idite u podešavanja:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Da bi ste promenili koje poruke primate od nas idite u <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">podešavanja</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Obaveštanja ($1)|100=Obaveštanja (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Poruka ($1)|100=Poruka (99+)}}",
+ "echo-notification-alert-text-only": "Obaveštenja",
+ "echo-notification-message-text-only": "Poruke",
+ "echo-overlay-link": "Sva obaveštenja",
+ "echo-overlay-title": "<b>Obaveštenja</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Obaveštenja}}</b> (prikaz $1 od $2 nepročitanih)",
+ "echo-mark-all-as-read": "Označi sve pročitanim",
+ "echo-date-today": "Danas",
+ "echo-date-yesterday": "Juče",
+ "echo-load-more-error": "Došlo je do greške pri dobavljanju više rezultata.",
+ "notification-edit-talk-page-bundle": "$1 i još $3 {{PLURAL:$4|korisnik|korisnika}} {{GENDER:$1|ostavili}} su poruke na vašoj [[User talk:$2|stranici za razgovor]].",
+ "notification-page-linked-bundle": "Stranica $2 je {{GENDER:$1|povezana}} sa $3 i $4 {{PLURAL:$5|druge stranice|drugih stranica}}. [[Special:WhatLinksHere/$2|Pogledajte sve veze prema ovoj stranici]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 i još $2 {{PLURAL:$3|1=jedan korisnik|korisnika}} {{GENDER:$1|ostavili}} su poruke na vašoj stranici za razgovor.",
+ "notification-page-linked-email-batch-bundle-body": "Stranica $2 je {{GENDER:$1|povezana}} sa $3 i $4 {{PLURAL:$5|druge stranice|drugih stranica}}.",
+ "echo-email-batch-subject-daily": "Imate {{PLURAL:$2|novo obaveštenje|nova obaveštenja}} na {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Imate {{PLURAL:$2|novo obaveštenje|nova obaveštenja}} na projektu {{SITENAME}} ove sedmice",
+ "echo-email-batch-body-intro-daily": "Zdravo $1,\nOvo je dnevni sažetak današnjih aktivnosti na projektu {{SITENAME}} za vas.",
+ "echo-email-batch-body-intro-weekly": "Zdravo $1,\nOvo je nedeljni sažetak aktivnosti na projektu {{SITENAME}} za vas.",
+ "echo-email-batch-link-text-view-all-notifications": "Pogledaj sva obaveštenja",
+ "echo-rev-deleted-text-view": "Ova revizija stranice je potisnuta."
+}
diff --git a/Echo/i18n/sv.json b/Echo/i18n/sv.json
new file mode 100644
index 00000000..55743919
--- /dev/null
+++ b/Echo/i18n/sv.json
@@ -0,0 +1,147 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ainali",
+ "Dcastor",
+ "Edvinw",
+ "Jopparn",
+ "Lejonel",
+ "Skalman",
+ "Tobulos1",
+ "WikiPhoenix",
+ "Lokal Profil",
+ "MagnusA",
+ "Paracel63",
+ "Hangsna",
+ "NH"
+ ]
+ },
+ "echo-desc": "Aviseringssystem",
+ "prefs-echo": "Aviseringar",
+ "prefs-emailsettings": "E-postinställningar",
+ "prefs-displaynotifications": "Visningsalternativ",
+ "prefs-echosubscriptions": "Meddela mig om dessa händelser",
+ "prefs-newmessageindicator": "Indikator för nya meddelanden",
+ "echo-pref-send-me": "Skicka mig:",
+ "echo-pref-send-to": "Skicka till:",
+ "echo-pref-email-format": "E-postformat:",
+ "echo-pref-web": "Webb",
+ "echo-pref-email": "E-post",
+ "echo-pref-email-frequency-never": "Skicka mig inga aviseringar via e-post",
+ "echo-pref-email-frequency-immediately": "Enskilda aviseringar efterhand som de inkommer",
+ "echo-pref-email-frequency-daily": "En daglig sammanställning av aviseringar",
+ "echo-pref-email-frequency-weekly": "En veckovis sammanställning av aviseringar",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Oformaterad text",
+ "echo-pref-notify-show-link": "Visa aviseringar i min verktygsrad",
+ "echo-pref-new-message-indicator": "Visa symbolen för diskussionssidemeddelanden i min verktygsrad",
+ "echo-learn-more": "Läs mer",
+ "echo-new-messages": "Du har nya meddelanden",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Diskussionssidemeddelande|Diskussionssidemeddelanden}}",
+ "echo-category-title-article-linked": "Sid{{PLURAL:$1|länk|länkar}}",
+ "echo-category-title-reverted": "Redigerings{{PLURAL:$1|återställning|återställningar}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Omnämning|Omnämningar}}",
+ "echo-category-title-other": "{{PLURAL:$1|Annan|Andra}}",
+ "echo-category-title-system": "{{PLURAL:$1|System}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Användarrättighetsförändring|Användarrättighetsförändringar}}",
+ "echo-pref-tooltip-edit-user-talk": "Meddela mig när någon lämnar ett meddelande eller svarar på min diskussionssida.",
+ "echo-pref-tooltip-article-linked": "Meddela mig när någon länkar till en sida som jag skapat från en artikelsida.",
+ "echo-pref-tooltip-reverted": "Meddela mig när någon återställer en ändring som jag gjort, med hjälp av verktygen \"gör ogjord\" eller \"rulla tillbaka\".",
+ "echo-pref-tooltip-mention": "Meddela mig när någon länkar till min användarsida.",
+ "echo-pref-tooltip-user-rights": "Meddela mig när någon ändrar mina användarrättigheter.",
+ "echo-no-agent": "[Ingen]",
+ "echo-no-title": "[Ingen sida]",
+ "echo-error-no-formatter": "Ingen formatering definierad för avisering.",
+ "echo-error-preference": "Fel: Kunde inte spara användarvalet.",
+ "echo-error-token": "Fel: Det gick inte att hämta användarpolletten.",
+ "notifications": "Aviseringar",
+ "tooltip-pt-notifications": "Dina aviseringar",
+ "echo-specialpage": "Aviseringar",
+ "echo-anon": "För att ta emot aviseringar, [$1 skapa ett konto] eller [$2 logga in].",
+ "echo-none": "Du har inga aviseringar.",
+ "echo-more-info": "Mer information",
+ "echo-feedback": "Feedback",
+ "notification-link-text-view-message": "Visa meddelande",
+ "notification-link-text-view-mention": "Visa omnämnande",
+ "notification-link-text-view-changes": "Visa ändringar",
+ "notification-link-text-view-page": "Visa sida",
+ "notification-link-text-view-edit": "Visa redigering",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|lämnade}} ett meddelande på din [[User talk:$2#$3|diskussionssida]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|lämnade}} ett meddelande på din diskussionssida i \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|lämnade}} ett meddelande på din [[User talk:$2#$3|diskussionssida]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 lämnade ett meddelande på din diskussionsida i \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] {{GENDER:$1|länkades}} från [[:$3]]. [[Special:WhatLinksHere/$2|Se alla länkar till denna sida]].",
+ "notification-page-linked-flyout": "[[:$2]] {{GENDER:$1|länkades}} från [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|kommenterade}} \"[[$3|$2]]\" på diskussionssidan för \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|la in}} ett nytt ämne \"$2\" på [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|skickade}} ett meddelande till dig: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|kommenterade}} om \"[[$3#$2|$2]]\" på din diskussionssida.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|nämnde}} dig på [[$5]] i avsnittet \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "[[User:$1|$1]] {{GENDER:$1|nämnde}} dig på [[$5]] i avsnittet \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|nämnde}} dig på [[$3]].",
+ "notification-mention-nosection-flyout": "[[User:$1|$1]] {{GENDER:$1|nämnde}} dig på [[$3]].",
+ "notification-user-rights": "Dina användarrättigheter [[Special:Log/rights/$1|{{GENDER:$1|ändrades}}]] av [[User:$1|$1]]. $2. [[Special:ListGroupRights|Läs mer]]",
+ "notification-user-rights-flyout": "Dina användarrättigheter {{GENDER:$1|ändrades}} av $1. $2. [[Special:ListGroupRights|Läs mer]]",
+ "notification-user-rights-add": "Du är nu medlem i {{PLURAL:$2|denna grupp|dessa grupper}}: $1",
+ "notification-user-rights-remove": "Du är inte längre medlem i {{PLURAL:$2|denna grupp|dessa grupper}}: $1",
+ "notification-new-user": "Välkommen till {{SITENAME}}, $1! Vi är glada att du är här.",
+ "notification-reverted2": "{{PLURAL:$4|Din redigering|Dina redigeringar}} på [[:$2]] har {{GENDER:$1|återställts}} av [[User:$1|$1]]. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|Din redigering|Dina redigeringar}} på $2 har {{GENDER:$1|återställts}} av $1. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|lämnade}} ett meddelande till dig på {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|lämnade}} ett meddelande på din diskussionssida:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|lämnade}} ett meddelande på din diskussionssida i \"$2\".",
+ "notification-page-linked-email-subject": "Din sida länkades till på {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 {{GENDER:$1|länkades}} från $3.",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Din redigering blev|Dina redigeringar blev}} {{GENDER:$1|återställda}} på {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|Din redigering|Dina redigeringar}} på $2 har återställts av $1.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|nämnde}} dig på {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|nämnde}} dig på diskussionssidan för $4 i \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|nämnde}} dig på diskussionssidan för $2.",
+ "notification-user-rights-email-subject": "Dina användarrättigheter har ändrats på {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "Dina användarrättigheter har {{GENDER:$1|ändrats}} av $1. $2.",
+ "echo-email-subject-default": "Ny avisering på {{SITENAME}}",
+ "echo-email-body-default": "Du har en ny avisering på {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Du har en ny avisering.",
+ "echo-email-footer-default": "$2\n\nFör att hantera vilken e-post vi skickar dig, kontrollera dina inställningar:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "För att kontrollera vilka meddelanden vi e-postar till dig, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">kontrollera dina inställningar</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Systemmeddelande ($1)|100=Systemmeddelande (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Meddelande ($1)|Meddelanden ($1)|100=Meddelande (99+)}}",
+ "echo-notification-alert-text-only": "Systemmeddelanden",
+ "echo-notification-message-text-only": "Meddelanden",
+ "echo-overlay-link": "Alla aviseringar",
+ "echo-overlay-title": "<b>Aviseringar</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Avisering|Aviseringar}}</b> (visar $1 av $2 {{PLURAL:$2|oläst|olästa}})",
+ "echo-mark-all-as-read": "Markera alla som lästa",
+ "echo-date-today": "Idag",
+ "echo-date-yesterday": "Igår",
+ "echo-load-more-error": "Ett fel uppstod när fler resultat skulle hämtas.",
+ "notification-edit-talk-page-bundle": "$1 och $3 {{PLURAL:$4|andra}} {{GENDER:$1|lämnade}} ett meddelande på din [[User talk:$2|diskussionssida]].",
+ "notification-page-linked-bundle": "$2 {{GENDER:$1|länkades}} från $3 och $4 {{PLURAL:$5|annan sida|andra sidor}}. [[Special:WhatLinksHere/$2|Se alla länkar till denna sida]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 och $2 {{PLURAL:$3|annan|andra}} {{GENDER:$1|lämnade}} ett meddelande på din diskussionssida.",
+ "notification-page-linked-email-batch-bundle-body": "$2 {{GENDER:$1|länkades}} från $3 och $4 {{PLURAL:$5|annan sida|andra sidor}}.",
+ "echo-email-batch-subject-daily": "Du har {{PLURAL:$2|en ny avisering|nya aviseringar}} på {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Du har {{PLURAL:$2|en ny avisering|nya aviseringar}} på {{SITENAME}} den här veckan",
+ "echo-email-batch-body-intro-daily": "Hej $1,\nHär är en sammanfattning av dagens aktivitet på {{SITENAME}} för dig.",
+ "echo-email-batch-body-intro-weekly": "Hej $1,\nHär är en sammanfattning av veckans aktivitet på {{SITENAME}} för dig.",
+ "echo-email-batch-link-text-view-all-notifications": "Visa alla aviseringar",
+ "echo-rev-deleted-text-view": "Denna sidversion har dolts.",
+ "apihelp-echomarkread-description": "Markera aviseringar som lästa för den aktuella användaren.",
+ "apihelp-echomarkread-param-list": "En lista över aviserings-ID att markera som lästa.",
+ "apihelp-echomarkread-param-all": "Om angiven, markerar en användares alla aviseringar som lästa.",
+ "apihelp-echomarkread-param-sections": "En lista över avsnitt att markera som lästa.",
+ "apihelp-echomarkread-example-1": "Markera avisering 8 som läst",
+ "apihelp-echomarkread-example-2": "Markera alla aviseringar som lästa",
+ "apihelp-query+notifications-description": "Hämta aviseringar som väntar på aktuell användare.",
+ "apihelp-query+notifications-param-prop": "Detaljer som ska begäras.",
+ "apihelp-query+notifications-param-sections": "De aviseringsavsnitt som ska undersökas.",
+ "apihelp-query+notifications-param-groupbysection": "Om resultaten ska grupperas efter avsnitt. Om angivet hämtas vart avsnitt separat.",
+ "apihelp-query+notifications-param-format": "Om angivet, returneras aviseringar formaterade på detta sätt.",
+ "apihelp-query+notifications-param-limit": "Det maximala antalet aviseringar som ska returneras.",
+ "apihelp-query+notifications-param-index": "Om angivet, en lista över aviserings-ID, i ordning, kommer att returneras.",
+ "apihelp-query+notifications-param-alertcontinue": "När fler resultat finns för systemmeddelande, använd detta för att fortsätta.",
+ "apihelp-query+notifications-param-alertunreadfirst": "Om du vill visa olästa meddelandeaviseringar först.",
+ "apihelp-query+notifications-param-messagecontinue": "När fler meddelanden finns tillgängliga, använd detta för att fortsätta.",
+ "apihelp-query+notifications-param-messageunreadfirst": "Om du vill visa olästa systemmeddelandeaviseringar först.",
+ "apihelp-query+notifications-example-1": "Lista aviseringar",
+ "apihelp-query+notifications-example-2": "Listan aviseringar grupperade efter avsnitt, med antal"
+}
diff --git a/Echo/i18n/ta.json b/Echo/i18n/ta.json
new file mode 100644
index 00000000..228c6fed
--- /dev/null
+++ b/Echo/i18n/ta.json
@@ -0,0 +1,91 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jayarathina",
+ "Karthi.dr",
+ "Shanmugamp7",
+ "மதனாஹரன்",
+ "ElangoRamanujam"
+ ]
+ },
+ "echo-desc": "அறிவிப்பு முறைமை",
+ "prefs-echo": "அறிவிப்புகள்",
+ "prefs-emailsettings": "மின்னஞ்சல் விருப்பத்தேர்வுகள்",
+ "prefs-displaynotifications": "விருப்பத்தேர்வுகளைக் காட்டு",
+ "prefs-echosubscriptions": "இந்த நிகழ்வுகளை பற்றி எனக்கு அறிவி",
+ "prefs-newmessageindicator": "புதிய செய்தி குறிகாட்டி",
+ "echo-pref-send-me": "எனக்கு இவற்றை அனுப்பவும்:",
+ "echo-pref-send-to": "இம்மின்னஞ்சல் முகவரிக்கு அனுப்பவும்:",
+ "echo-pref-email-format": "மின்னஞ்சல் வடிவமைப்பு:",
+ "echo-pref-web": "இணையம்",
+ "echo-pref-email": "மின்னஞ்சல்",
+ "echo-pref-email-frequency-never": "எந்த மின்னஞ்சல் அறிவிப்புகளையும் எனக்கு அனுப்ப வேண்டாம்",
+ "echo-pref-email-frequency-immediately": "ஒவ்வொரு அறிவிப்புகளையும் அதன் அறிவிப்பு நேரத்திலேயே",
+ "echo-pref-email-frequency-daily": "தினமும் அறிவித்தல்களின் சுருக்கம்",
+ "echo-pref-email-frequency-weekly": "அறிவிப்புகளின் இவ்வார சுறுக்கம்",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "வெற்று உரை",
+ "echo-pref-notify-show-link": "என் கருவிப்பட்டியில் அறிவிப்புகளை காட்டு",
+ "echo-pref-new-message-indicator": "என் கருவிப்பட்டியில் பேச்சு பக்க செய்திகளின் குறிகாட்டியினை காட்டு",
+ "echo-learn-more": "மேலும் அறிய",
+ "echo-new-messages": "உங்களுக்கு புதிய செய்திகள் உள்ளன",
+ "echo-category-title-edit-user-talk": "பேச்சுப் பக்க {{PLURAL:$1|செய்தி|செய்திகள்}}",
+ "echo-category-title-article-linked": "பக்க {{PLURAL:$1|இணைப்பு|இணைப்புகள்}}",
+ "echo-category-title-mention": "{{PLURAL:$1|குறித்தல்|குறித்தல்கள்}}",
+ "echo-pref-tooltip-edit-user-talk": "என் பேச்சுப்பக்கத்தில் எனக்கு யாரேனும் செய்தி இட்டாலோ அல்லது மறுமொழி இட்டாலோ எனக்குத்தெரிவி",
+ "echo-pref-tooltip-article-linked": "நான் உருவாக்கிய கட்டுரை பக்கத்துக்கு வேறு ஒரு பக்கத்திலிருந்து யாராவது இணைப்புகள் இட்டால் எனக்கு தெரிவி.",
+ "echo-pref-tooltip-reverted": "நான் செய்த தொகுப்புகளை யாராவது மீளமை அல்லது முன்நிலையாக்குக கருவி கொண்டு மீளமைத்தால் எனக்கு தெரிவி.",
+ "echo-pref-tooltip-mention": "என் பயனர் பக்கத்துக்கு யாராவது இணைப்புகள் இட்டால் எனக்குத் தெரிவிக்கவும்.",
+ "echo-no-agent": "[யாருமில்லை]",
+ "echo-no-title": "[கட்டுரை இல்லை]",
+ "echo-error-no-formatter": "அறிவிப்புகளுக்கு எந்த வடிவமைப்பும் வரையறுக்கப்படவில்லை.",
+ "echo-error-preference": "பிழை: பயனர் விருப்ப தேர்வுகளை சேமிக்க இயவில்லை.",
+ "notifications": "அறிவிப்புகள்",
+ "tooltip-pt-notifications": "உங்கள் அறிவிப்புகள்",
+ "echo-specialpage": "அறிவிப்புகள்",
+ "echo-anon": "அறிவிப்புகளைப் பெறுவதற்கு [$1 ஒரு கணக்கை உருவாக்குங்கள்] அல்லது [$2 உள்நுழையுங்கள்].",
+ "echo-none": "உங்களுக்கு அறிவிப்பு ஏதும் இல்லை.",
+ "echo-more-info": "மேலதிக தகவல்",
+ "echo-feedback": "கருத்து",
+ "notification-link-text-view-message": "செய்தியினை பார்",
+ "notification-link-text-view-mention": "குறித்திருப்பதைக்காண்க",
+ "notification-link-text-view-changes": "மாற்றக்களை பார்",
+ "notification-link-text-view-page": "பக்கத்தை பார்",
+ "notification-link-text-view-edit": "தொகுப்பை பார்",
+ "notification-edit-talk-page2": "[[User:$1|$1]] உங்களுக்கு ஒரு செய்தியினை உங்களின் [[User talk:$2#$3|பேச்சுப்பக்கத்தில்]] {{GENDER:$1|விட்டுச்சென்றுள்ளார்}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] உங்களுக்கு ஒரு செய்தியினை உங்களின் பேச்சுப்பக்கத்தின் \"[[User talk:$2#$3|$4]]இல்\" {{GENDER:$1|விட்டுச்சென்றுள்ளார்}}.",
+ "notification-edit-talk-page-flyout2": "$1 ஒரு செய்தியினை உங்களின் [[User talk:$2#$3|பேச்சுப்பக்கத்தில்]] {{GENDER:$1|விட்டுச்சென்றுள்ளார்}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1 ஒரு செய்தியினை உங்களின் பேச்சுப்பக்கத்தின் \"[[User talk:$2#$3|$4]]இல்\" {{GENDER:$1|விட்டுச்சென்றுள்ளார்}}.",
+ "notification-page-linked": "[[:$2]] [[:$3]]இல் இருந்து {{GENDER:$1|இணைக்கப்பட்டுள்ளது}}. [[Special:WhatLinksHere/$2|இந்த பக்கத்துக்கான அனைத்து இணைப்புகளையும் பார்க்கவும்]].",
+ "notification-new-user": "$1 {{SITENAME}}க்கு உங்களை வரவேற்கிறோம்! உங்களின் வருகை எங்களுக்கு மகிழ்ச்சியளிக்கிறது.",
+ "notification-reverted2": "உங்களால் {{PLURAL:$4|[[:$2]]இல் செய்யப்பட்ட தொகுப்பு|[[:$2]]இல் செய்யப்பட்ட தொகுப்புகள்}} [[User:$1|$1]]ஆல் {{GENDER:$1|மீளமைக்கப்பட்டுள்ளது}}. $3",
+ "notification-reverted-flyout2": "உங்களால் {{PLURAL:$4|$2 இல் செய்யப்பட்ட தொகுப்பு|$2இல் செய்யப்பட்ட தொகுப்புகள்}} $1ஆல் {{GENDER:$1|மீளமைக்கப்பட்டுள்ளது}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{SITENAME}}இல் உங்களுக்கு ஒரு புதிய செய்தியினை விட்டுச்சென்றுள்ளார்",
+ "notification-edit-talk-page-email-batch-body2": "$1 உங்களின் பேச்சுப்பக்கத்தில் ஒரு செய்தியினை விட்டுச்சென்றுள்ளார்:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 உங்களின் பேச்சுப்பக்கத்தில் ஒரு செய்தியினை விட்டுச்சென்றுள்ளார் \"$2\".",
+ "notification-page-linked-email-subject": "{{SITENAME}}இல் உங்கள் பக்கம் இணைக்கப்பட்டுள்ளது",
+ "notification-page-linked-email-batch-body": "$2 $3இல் {{GENDER:$1|lஇணைக்கப்பட்டுள்ளது}}.",
+ "notification-reverted-email-subject2": "உங்களின் {{PLURAL:$3|தொகுப்பு|தொகுப்புகள்}} {{SITENAME}}இல் {{GENDER:$1|மீளமைக்கப்பட்டுள்ளது}}",
+ "notification-reverted-email-batch-body2": "உங்களால் {{PLURAL:$3|$2இல் செய்யப்பட்ட தொகுப்பு|$2இல் செய்யப்பட்ட தொகுப்புகள்}} $1ஆல் {{GENDER:$1|மீளமைக்கப்பட்டுள்ளது}}",
+ "notification-mention-email-subject": "$1 உங்களை {{SITENAME}}இல் குறிப்பிட்டுள்ளார்",
+ "notification-mention-email-batch-body": "$1 உங்களை $4இன் பேச்சுப்பக்கத்தில் \"$3\" பகுதியில் குறிப்பிட்டுள்ளார்.",
+ "echo-email-subject-default": "{{SITENAME}}இல் புதிய அறிவிப்புகள்",
+ "echo-email-body-default": "{{SITENAME}} இல் உங்களுக்கு ஒரு புதிய அறிவிப்பு உள்ளது:\n\n$1",
+ "echo-email-batch-body-default": "உங்களுக்கு ஒரு புதிய அறிவிப்பு உள்ளது",
+ "echo-notification-message-text-only": "தகவல்கள்",
+ "echo-overlay-link": "எல்லா அறிவிப்புகள்",
+ "echo-overlay-title": "<b>அறிவிப்புகள்</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|அறிவிப்புகள்}}</b> ($2இல் பார்க்கப்படாத $1 காட்டப்படுகின்றது)",
+ "echo-mark-all-as-read": "அனைத்தையும் படித்ததாய்க் குறித்துக் கொள்",
+ "echo-date-today": "இன்று",
+ "echo-date-yesterday": "நேற்று",
+ "echo-load-more-error": "மேலும் முடிவுகளைப் பெறும்போது பிழை ஏற்பட்டுள்ளது.",
+ "notification-page-linked-bundle": "$2 $3 மற்றும் $4 பிற {{PLURAL:$5|பக்கத்தில்|பக்கங்களில்}} {{GENDER:$1|இணைக்கப்பட்டுள்ளது}}. [[Special:WhatLinksHere/$2|இந்த பக்கத்துக்கான அனைத்து இணைப்புகளையும் பார்க்கவும்]]",
+ "notification-page-linked-email-batch-bundle-body": "$2 $3 மற்றும் $4 பிற {{PLURAL:$5|பக்கத்தில்|பக்கங்களில்}} {{GENDER:$1|இணைக்கப்பட்டுள்ளது}}.",
+ "echo-email-batch-subject-daily": "{{SITENAME}}இல் உங்களுக்கு {{PLURAL:$2|ஒரு புதிய செய்தி|புதிய செய்திகள்}} உள்ளன",
+ "echo-email-batch-subject-weekly": "இவ்வாரம் {{SITENAME}}இல் உங்களுக்கு {{PLURAL:$2|ஒரு புதிய செய்தி|புதிய செய்திகள்}} உள்ளன",
+ "echo-email-batch-body-intro-daily": "$1,\n{{SITENAME}}இல் உங்களுக்காக இன்றைய செயல்பாடுகளின் சுருக்கம் இதோ.",
+ "echo-email-batch-body-intro-weekly": "$1,\n{{SITENAME}}இல் உங்களுக்காக இந்த வார செயல்பாடுகளின் சுருக்கம் இதோ.",
+ "echo-email-batch-link-text-view-all-notifications": "எல்லா அறிவிப்புகளையும் பார்",
+ "echo-rev-deleted-text-view": "பக்கத்தின் இந்த திருத்தம் மறைக்கப்பட்டுள்ளது."
+}
diff --git a/Echo/i18n/tcy.json b/Echo/i18n/tcy.json
new file mode 100644
index 00000000..16c31982
--- /dev/null
+++ b/Echo/i18n/tcy.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "VASANTH S.N."
+ ]
+ },
+ "tooltip-pt-notifications": "ಈರೆನೆ ಸೂಚನೆಲು"
+}
diff --git a/Echo/i18n/te.json b/Echo/i18n/te.json
new file mode 100644
index 00000000..51d0cfb2
--- /dev/null
+++ b/Echo/i18n/te.json
@@ -0,0 +1,112 @@
+{
+ "@metadata": {
+ "authors": [
+ "Arjunaraoc",
+ "Chaduvari",
+ "Veeven",
+ "Visdaviva",
+ "రహ్మానుద్దీన్",
+ "వైజాసత్య"
+ ]
+ },
+ "echo-desc": "సూచన వ్యవస్థ",
+ "prefs-echo": "గమనింపులు",
+ "prefs-emailsettings": "ఈ-మెయిల్ ఐచ్ఛికాలు",
+ "prefs-displaynotifications": "ప్రదర్శన ఐచ్ఛికాలు",
+ "prefs-echosubscriptions": "ఈ సంఘటనల గురించి నాకు తెలియచేయి",
+ "prefs-newmessageindicator": "కొత్త సందేశపు సూచిక",
+ "echo-pref-send-me": "నాకు పంపు:",
+ "echo-pref-send-to": "పంపించు:",
+ "echo-pref-email-format": "ఇమెయిల్ ఫార్మాట్:",
+ "echo-pref-web": "అంతర్జాలం",
+ "echo-pref-email": "ఈ-మెయిల్",
+ "echo-pref-email-frequency-never": "నాకు ఈ-మెయిల్ సూచనలు పంపవద్దు",
+ "echo-pref-email-frequency-immediately": "ఒక్కో సూచన వచ్చినది వచ్చినట్టుగా పంపు",
+ "echo-pref-email-frequency-daily": "రోజువారి సూచనల సారాంశం",
+ "echo-pref-email-frequency-weekly": "వారం మొత్తం మీద సూచనల సారాంశం",
+ "echo-pref-email-format-html": "హెచ్.టి.ఎం.ఎల్",
+ "echo-pref-email-format-plain-text": "సాదా పాఠ్యం",
+ "echo-pref-notify-show-link": "నా టూల్‌బార్‌లో సూచనలను చూపించు",
+ "echo-pref-new-message-indicator": "నా టూల్‌బార్‌లో చర్చా పేజీ సందేశ-సూచికను చూపించు",
+ "echo-learn-more": "మరింత తెలుసుకోండి",
+ "echo-new-messages": "మీకు కొత్త సందేశాలు ఉన్నాయి",
+ "echo-category-title-edit-user-talk": "చర్చా పేజి {{PLURAL:$1|సందేశం|సందేశాలు}}",
+ "echo-category-title-article-linked": "పేజి {{PLURAL:$1|లంకె|లంకెలు}}",
+ "echo-category-title-reverted": "మార్చు {{PLURAL:$1|మళ్ళింపు|మళ్ళింపులు}}",
+ "echo-category-title-mention": "{{PLURAL:$1|పేరెన్నిక|పేరెన్నికలు}}",
+ "echo-category-title-other": "{{PLURAL:$1|ఇతర}}",
+ "echo-category-title-system": "{{PLURAL:$1|వ్యవస్థ}}",
+ "echo-pref-tooltip-edit-user-talk": "నా చర్చా పేజీలో ఎవరైనా సందేశం వ్రాసినా లేదా జవాబిచ్చినా నాకు తెలియపరుచు.",
+ "echo-pref-tooltip-article-linked": "నేను వ్యాసపు పేజీ నుండి సృష్టించిన పేజీని ఎవరయినా లంకె వేస్తే నాకు తెలియపరుచు.",
+ "echo-pref-tooltip-reverted": "నా మార్పును ఎవరయినా రద్దు చేసినా లేదా రోల్ బ్యాక్ పరికరం వాడి వెనక్కు మళ్ళించినా, నాకు తెలియపరుచు.",
+ "echo-pref-tooltip-mention": "ఎవరయినా నా వాడుకరి పేజీకి ఏదయినా చర్చా పేజీలో లంకె వేస్తే నాకు తెలియపరుచు.",
+ "echo-no-agent": "[ఎవరూ లేరు]",
+ "echo-no-title": "[ఏ పేజీ లేదు]",
+ "echo-error-no-formatter": "సూచనకు ఎలాంటి ఆకృతి నిర్దేశించబడలేదు.",
+ "echo-error-preference": "దోషం: వాడుకరి అభిరుచులు అమర్చడం కుదరలేదు.",
+ "echo-error-token": "దోషం: వాడుకరి చిహ్నం తిరిగితేవటం కుదరలేదు.",
+ "notifications": "సూచనలు",
+ "tooltip-pt-notifications": "మీకు సూచనలు",
+ "echo-specialpage": "సూచనలు",
+ "echo-anon": "సూచనలు పొందటానికి [$1 ఖాతా తెరవండి] లేదా [$2 లోనికి రండి]",
+ "echo-none": "మీకు ఏ సూచనలు లేవు",
+ "echo-more-info": "మరింత సమాచారం",
+ "echo-feedback": "ప్రతిస్పందన",
+ "notification-link-text-view-message": "సందేశాన్ని చూడు",
+ "notification-link-text-view-mention": "పేరెన్నికను చూడు",
+ "notification-link-text-view-changes": "మార్పులు చూడు",
+ "notification-link-text-view-page": "పేజీని చూడు",
+ "notification-link-text-view-edit": "మార్పును చూడు",
+ "notification-edit-talk-page2": "[[User:$1|$1]] మీ [[User talk:$2#$3|చర్చా పేజీ]]పై సందేశం {{GENDER:$1|చేర్చారు}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] మీ చర్చా పేజీపై \"[[User talk:$2#$3|$4]]\" వద్ద ఒక సందేశాన్ని {{GENDER:$1|చేర్చారు}}.",
+ "notification-edit-talk-page-flyout2": "$1 మీ [[User talk:$2#$3|చర్చాపేజీ]] పై ఒక సందేశం {{GENDER:$1|చేర్చారు}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1 మీ చర్చా పేజీలో \"[[User talk:$2#$3|$4]]\" వద్ద ఒక సందేశాన్ని {{GENDER:$1|చేర్చారు}}.",
+ "notification-page-linked": "[[:$3]] నుండి [[:$2]]కి {{GENDER:$1|లంకె వేసారు}}.\n[[Special:WhatLinksHere/$2|ఈ పేజీకి చేరుకోవటానికున్న అన్ని లంకెలను చూడు]].",
+ "notification-page-linked-flyout": "[[:$3]] నుండి [[:$2]] కి {{GENDER:$1|లంకె వేశారు}}.",
+ "notification-add-comment2": "[[User:$1|$1]] \"$4\" చర్చా పేజీలో \"[[$3|$2]]\" పై {{GENDER:$1|వ్యాఖ్యానించారు}}.",
+ "notification-add-talkpage-topic2": " [[User:$1|$1]] [[$3]] పై \"$2\" అనే ఒక కొత్త విషయాన్ని {{GENDER:$1|చేర్చారు}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] మీకు {{GENDER:$1|పంపిన సందేశం}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] మీ చర్చాపేజీలో \"[[$3#$2|$2]]\" వద్ద {{GENDER:$1|వ్యాఖ్యానించారు}}.",
+ "notification-mention": "[[User:$1|$1]] మిమ్మల్ని $5 చర్చా పేజీ పై \"[[:$3#$2|$4]]\"వద్ద {{GENDER:$1|పేర్కొన్నారు}}.",
+ "notification-mention-flyout": "$1 మిమ్మల్ని $5 చర్చా పేజీపై \"[[:$3#$2|$4]]\" వద్ద{{GENDER:$1|పేర్కొన్నారు}}.",
+ "notification-user-rights": "మీ [[Special:Log/rights/$1|వాడుకరి హక్కులు ]] [[User:$1|$1]].$2 ద్వారా {{GENDER:$1|మార్చబడ్డాయి}}. [[Special:ListGroupRights|మరింత తెలుసుకోండి]]",
+ "notification-user-rights-flyout": "మీ వాడుకరి హక్కులను $1($2) {{GENDER:$1|మార్చారు}}. [[Special:ListGroupRights|మరింత తెలుసుకోండి]]",
+ "notification-user-rights-add": "మీరిప్పుడు {{PLURAL:$2|ఈ సమూహం|ఈ సమూహాలలో}} సభ్యులు:$1",
+ "notification-user-rights-remove": "మీరికపై {{PLURAL:$2|ఈ సమూహం|ఈ సమూహాలలో}} సభ్యులు కారు:$1",
+ "notification-new-user": "{{SITENAME}}కు స్వాగతం, $1! మీ రాక మాకెంతో సంతోషం సుమండీ.",
+ "notification-reverted2": "{{PLURAL:$4|[[:$2]] పై మీరు చేసిన మార్పు|[[:$2]] పై మీరు చేసిన మార్పులు}} [[User:$1|$1]] ద్వారా {{GENDER:$1|రద్దు చేయబడ్డాయి}}.$3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|$2 పై మీ మార్పు|$2 పై మీ మార్పులు}} $1 ద్వారా {{GENDER:$1|రద్దు చేయబడ్డాయి}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{SITENAME}} వద్ద మీకొక సందేశం {{GENDER:$1|రాశారు}}.",
+ "notification-edit-talk-page-email-batch-body2": "$1 మీ చర్చా పేజీ పై ఒక సందేశాన్ని {{GENDER:$1|రాసారు}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 మీ చర్చా పేజీలోని \"$2\" పై ఒక సందేశం {{GENDER:$1|రాసారు}}.",
+ "notification-page-linked-email-subject": "మీ పేజీకి {{SITENAME}}లో లింకు ఇవ్వబడింది",
+ "notification-page-linked-email-batch-body": "$3 వద్ద నుండి $2 {{GENDER:$1|లింకు చేయబడ్డారు}}",
+ "notification-reverted-email-subject2": "{{SITENAME}} వద్ద మీ {{PLURAL:$3|మార్పు|మార్పులు}} {{GENDER:$1|వెనక్కి మళ్ళించ}} {{PLURAL:$3|బడింది|బడ్డాయి}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|$2 పై మీ మార్పు|$2 పై మీ మార్పులు}} $1 ద్వారా {{GENDER:$1|రద్దు చేయబడ్డాయి}}.",
+ "notification-mention-email-subject": "$1 మిమ్మల్ని {{SITENAME}} లో {{GENDER:$1|పేర్కొన్నారు}}.",
+ "notification-mention-email-batch-body": "$1 మిమ్మల్ని $4 చర్చా పేజీలో \"$3\" వద్ద {{GENDER:$1|పేర్కొన్నారు}}.",
+ "notification-user-rights-email-subject": "{{SITENAME}}లో మీ వాడుకరి హక్కులు మారినవి",
+ "notification-user-rights-email-batch-body": "మీ వాడుకరి హక్కులను $1.$2 {{GENDER:$1|మార్చారు}}.",
+ "echo-email-subject-default": "{{SITENAME}} వద్ద కొత్త సూచన",
+ "echo-email-body-default": "{{SITENAME}} వద్ద మీకొక కొత్త సూచన ఉన్నది : \n\n$1",
+ "echo-email-batch-body-default": "మీకొక కొత్త సూచన ఉంది.",
+ "echo-email-footer-default": "$2\n\nమీకు ఏ ఏ ఈ-మెయిళ్లు పంపించాలో నియంత్రించడానికి, మీ అభిరుచులను చూడండి:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "మీకు మేము ఏ ఏ ఈ-మెయిళ్లు పంపించాలో నియంత్రించడానికి, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">మీ అభిరుచులను చూడండి</a>.<br />\n$1",
+ "echo-overlay-link": "అన్ని సూచనలు",
+ "echo-overlay-title": "<b>సూచనలు</b>",
+ "echo-overlay-title-overflow": "<b> {{PLURAL:$1|సూచనలు}}</b> (చదవని $2 లో $1 వది)",
+ "echo-mark-all-as-read": "అన్నిటినీ చదివినవిగా గుర్తించు",
+ "echo-date-today": "ఈరోజు",
+ "echo-date-yesterday": "నిన్న",
+ "echo-load-more-error": "మరిన్ని ఫలితాలు తెచ్చి చూపడంలో దోషం జరిగింది.",
+ "notification-edit-talk-page-bundle": "$1 మరియు మరో $3 {{PLURAL:$4|వ్యక్తి|వ్యక్తులు}} మీ [[User talk:$2|వాడుకరి చర్చా పేజీ]]లో సందేశం {{GENDER:$1| చేర్చారు}}.",
+ "notification-page-linked-bundle": "$3 మరియు $4 ఇతర {{PLURAL:$5|పేజీ|పేజీల}} నుండి $2 {{GENDER:$1|లింకు చేయబడ్డారు}}. [[Special:WhatLinksHere/$2|ఈ పేజీకి చేర్చే అన్ని లింకులను చూడు]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 మరియు $2 {{PLURAL:$3|ఇతర వ్యక్తి|ఇతరులు}} మీ చర్చా పేజీలో ఒక సందేశం {{GENDER:$1|రాసారు}}.",
+ "notification-page-linked-email-batch-bundle-body": "$3 మరియు $4 ఇతర {{PLURAL:$5|పేజీ|పేజీల}} నుండి $2కు {{GENDER:$1|లింకు వేశారు}}",
+ "echo-email-batch-subject-daily": "మీకు {{SITENAME}} వద్ద {{PLURAL:$2|కొత్త సూచన ఉంది|కొత్త సందేశాలు ఉన్నాయి}}",
+ "echo-email-batch-subject-weekly": "మీకు ఈ వారం {{SITENAME}} లో {{PLURAL:$2|కొత్త సూచన ఉంది|కొత్త సూచనలుఉన్నాయి}}",
+ "echo-email-batch-body-intro-daily": "నమస్కారం $1 గారూ,\nమీ కోసం {{SITENAME}}లో ఈ రోజు జరిగిన సంగతుల యొక్క సారాంశం ఇక్కడ సమకూరుస్తున్నాం.",
+ "echo-email-batch-body-intro-weekly": "నమస్కారం $1 గారూ,\nమీ కోసం {{SITENAME}}లో ఈ వారం జరిగిన సంగతుల యొక్క సారాంశం ఇక్కడ సమకూరుస్తున్నాం.",
+ "echo-email-batch-link-text-view-all-notifications": "అన్ని సూచనలు చూడు",
+ "echo-rev-deleted-text-view": "ఈ పేజీ మార్పు అణచబడింది"
+}
diff --git a/Echo/i18n/th.json b/Echo/i18n/th.json
new file mode 100644
index 00000000..a8fff78c
--- /dev/null
+++ b/Echo/i18n/th.json
@@ -0,0 +1,103 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nullzero",
+ "Supasate",
+ "Horus"
+ ]
+ },
+ "echo-desc": "ระบบแจ้งเตือน",
+ "prefs-echo": "การแจ้งเตือน",
+ "prefs-emailsettings": "ตัวเลือกอีเมล",
+ "prefs-displaynotifications": "ตัวเลือกการแสดงผล",
+ "prefs-echosubscriptions": "แจ้งให้ฉันทราบเกี่ยวกับเหตุการณ์เหล่านี้",
+ "prefs-newmessageindicator": "ตัวบ่งชี้ข้อความใหม่",
+ "echo-pref-send-me": "ส่งหาฉัน:",
+ "echo-pref-send-to": "ส่งถึง:",
+ "echo-pref-email-format": "รูปแบบอีเมล:",
+ "echo-pref-web": "เว็บ",
+ "echo-pref-email": "อีเมล",
+ "echo-pref-email-frequency-never": "ไม่ส่งการแจ้งเตือนทางอีเมลหาฉัน",
+ "echo-pref-email-frequency-immediately": "การแจ้งเตือนแบบแยกสำหรับทุกเหตุการณ์ทันทีที่เกิดขึ้น",
+ "echo-pref-email-frequency-daily": "การแจ้งเตือนแบบสรุปรายวัน",
+ "echo-pref-email-frequency-weekly": "การแจ้งเตือนแบบสรุปรายสัปดาห์",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "ข้อความล้วน",
+ "echo-pref-notify-show-link": "แสดงการแจ้งเตือนในแถบเครื่องมือของฉัน",
+ "echo-pref-new-message-indicator": "แสดงตัวบ่งชี้ข้อความในหน้าพูดคุยในแถบเครื่องมือของฉัน",
+ "echo-learn-more": "เรียนรู้เพิ่มเติม",
+ "echo-new-messages": "คุณมีข้อความใหม่",
+ "echo-category-title-edit-user-talk": "ข้อความหน้าพูดคุย",
+ "echo-category-title-article-linked": "การโยงหน้า",
+ "echo-category-title-reverted": "การย้อนการแก้ไข",
+ "echo-category-title-mention": "การกล่าวถึง",
+ "echo-category-title-other": "อื่น ๆ",
+ "echo-category-title-system": "{{PLURAL:$1|ระบบ}}",
+ "echo-category-title-user-rights": "การเปลี่ยนแปลงสิทธิผู้ใช้",
+ "echo-pref-tooltip-edit-user-talk": "แจ้งเตือนเมื่อมีคนโพสต์ข้อความหรือตอบในหน้าพูดคุยของฉัน",
+ "echo-pref-tooltip-article-linked": "แจ้งเตือนฉันเมื่อมีคนโยงจากหน้าบทความถึงหน้าที่ฉันสร้าง",
+ "echo-pref-tooltip-reverted": "แจ้งเตือนฉันเมื่อมีคนย้อนการแก้ไขของฉัน โดยใช้เครื่องมือทำกลับหรือย้อนกลับการแก้ไข",
+ "echo-pref-tooltip-mention": "แจ้งเตือนฉันเมื่อมีผู้โยงหาหน้าผู้ใช้ของฉัน",
+ "echo-pref-tooltip-user-rights": "แจ้งเตือนฉันเมื่อมีผู้เปลี่ยนแปลงสิทธิผู้ใช้ของฉัน",
+ "echo-no-agent": "[ไม่มีผู้ใด]",
+ "echo-no-title": "[ไม่มีหน้าใด]",
+ "echo-error-no-formatter": "ไม่มีการกำหนดรูปแบบสำหรับการแจ้งเตือน",
+ "echo-error-preference": "ข้อผิดพลาด: ไม่สามารถตั้งค่าพึงใจผู้ใช้",
+ "echo-error-token": "ข้อผิดพลาด: ไม่สามารถเรียกโทเค็นผู้ใช้",
+ "notifications": "การแจ้งเตือน",
+ "tooltip-pt-notifications": "การแจ้งเตือนของคุณ",
+ "echo-specialpage": "การแจ้งเตือน",
+ "echo-anon": "เพื่อรับการแจ้งเตือน [$1 สร้างบัญชี] หรือ [$2 ล็อกอิน]",
+ "echo-none": "คุณไม่มีการแจ้งเตือน",
+ "echo-more-info": "ข้อมูลเพิ่มเติม",
+ "echo-feedback": "ผลป้อนกลับ",
+ "notification-link-text-view-message": "ดูข้อความ",
+ "notification-link-text-view-mention": "ดูการกล่าวถึง",
+ "notification-link-text-view-changes": "ดูความเปลี่ยนแปลง",
+ "notification-link-text-view-page": "ดูหน้า",
+ "notification-link-text-view-edit": "ดูการแก้ไข",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|ฝาก}}ข้อความไว้บน[[User talk:$2#$3|หน้าพูดคุย]]ของคุณ",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|ฝาก}}ข้อความบนหน้าพูดคุยของคุณที่ \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 ฝากข้อความไว้ใน[[User talk:$2#$3|หน้าพูดคุย]]ของคุณ",
+ "notification-edit-talk-page-flyout-with-section": "$1 ฝากข้อความไว้ในหน้าพูดคุยของคุณใน \"[[User talk:$2#$3|$4]]\"",
+ "notification-page-linked": "[[:$2]] ถูกโยงจาก [[:$3]] [[Special:WhatLinksHere/$2|ดูการโยงมายังหน้านี้ทั้งหมด]]",
+ "notification-page-linked-flyout": "[[:$2]] ถูกโยงจาก [[:$3]]",
+ "notification-add-comment2": "[[User:$1|$1]] ออกความเห็นใน \"[[$3|$2]]\" ในหน้าพูดคุย \"$4\"",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] โพสต์หัวข้อใหม่ \"$2\" ใน [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] ส่งข้อความหาคุณ: \"[[$3#$2|$2]]\"",
+ "notification-add-comment-yours2": "[[User:$1|$1]] ออกความเห็นบน \"[[$3#$2|$2]]\" ในหน้าพูดคุยของคุณ",
+ "notification-mention": "[[User:$1|$1]] กล่าวถึงคุณในหน้าพูดคุย $5 ใน \"[[:$3#$2|$4]]\"",
+ "notification-mention-flyout": "$1 กล่าวถึงคุณในหน้าพูดคุย $5 ใน \"[[:$3#$2|$4]]\"",
+ "notification-mention-nosection": "[[User:$1|$1]] กล่าวถึงคุณใน[[:$3|หน้าพูดคุย $2]]",
+ "notification-mention-nosection-flyout": "$1 กล่าวถึงคุณใน[[:$3|หน้าพูดคุย $2]]",
+ "notification-user-rights": "[[User:$1|$1]] [[Special:Log/rights/$1|เปลี่ยน]]สิทธิถูกใช้ของคุณ $2 [[Special:ListGroupRights|เรียนรู้เพิ่มเติม]]",
+ "notification-user-rights-flyout": "$1 เปลี่ยนสิทธิผู้ใช้ของคุณ $2 [[Special:ListGroupRights|เรียนรู้เพิ่มเติม]]",
+ "notification-user-rights-add": "ขณะนี้คุณเป็นสมาชิก{{PLURAL:$2|กลุ่มนี้|กลุ่มเหล่านี้}}: $1",
+ "notification-user-rights-remove": "คุณไม่ได้เป็นสมาชิก{{PLURAL:$2|กลุ่มนี้|กลุ่มเหล่านี้}}อีก: $1",
+ "notification-new-user": "ยินดีต้อนรับสู่ {{SITENAME}} $1! เรายินดีที่คุณอยู่ที่นี่",
+ "notification-reverted2": "การแก้ไขใน [[:$2]] ของคุณถูกย้อนโดย [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "การแก้ไขใน $2 ของคุณถูกย้อนโดย $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 ส่งข้อความถึงคุณบน {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 ส่งข้อความบนหน้าคุยกับผู้ใช้ของคุณ:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 ส่งข้อความบนหน้าคุยกับผู้ใช้ของคุณใน \"$2\":",
+ "notification-page-linked-email-subject": "หน้าของคุณถูกโยงบน {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 ถูกโยงจาก $3",
+ "notification-reverted-email-subject2": "การแก้ไขของคุณถูกย้อนใน {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "การแก้ไขของคุณใน $2 ถูกย้อนโดย $1",
+ "notification-mention-email-subject": "$1 กล่าวถึงคุณบน {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 กล่าวถึงคุณในหน้าอภิปราย $4 ใน \"$3\"",
+ "notification-mention-nosection-email-batch-body": "$1 กล่าวถึงคุณในหน้าอภิปราย $2",
+ "notification-user-rights-email-subject": "สิทธิผู้ใช้ของคุณถูกเปลี่ยนบน {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "สิทธิผู้ใช้ของคุณถูกเปลี่ยนโดย $1 $2",
+ "echo-email-subject-default": "การแจ้งเตือนใหม่ที่ {{SITENAME}}",
+ "echo-email-body-default": "คุณมีการแจ้งเตือนใหม่ที่ {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "คุณมีการแจ้งเตือนใหม่",
+ "echo-overlay-link": "การแจ้งเตือนทั้งหมด",
+ "echo-overlay-title": "<b>การแจ้งเตือน</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|การแจ้งเตือน}}</b> (กำลังแสดงที่ยังไม่ได้อ่าน $1 จาก $2 การแจ้งเตือน)",
+ "echo-mark-all-as-read": "ทำเครื่องหมายทั้งหมดว่าอ่านแล้ว",
+ "echo-date-today": "วันนี้",
+ "echo-date-yesterday": "เมื่อวานนี้",
+ "echo-email-batch-link-text-view-all-notifications": "ดูการแจ้งเตือนทั้งหมด",
+ "echo-rev-deleted-text-view": "รุ่นหน้านี้ถูกระงับ"
+}
diff --git a/Echo/i18n/tl.json b/Echo/i18n/tl.json
new file mode 100644
index 00000000..d884920f
--- /dev/null
+++ b/Echo/i18n/tl.json
@@ -0,0 +1,100 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw",
+ "Sky Harbor",
+ "TheSleepyhollow02",
+ "Jojit fb"
+ ]
+ },
+ "echo-desc": "Sistema ng pagpapabatid",
+ "prefs-echo": "Mga pagpapabatid",
+ "prefs-emailsettings": "Mga kagustuhan para sa e-liham",
+ "prefs-displaynotifications": "Mga kagustuhan sa pagpapakita",
+ "prefs-echosubscriptions": "Ipabatid ako tungkol sa mga pangyayaring ito",
+ "prefs-newmessageindicator": "Indikador ng mga bagong mensahe",
+ "echo-pref-send-me": "Ipadala sa akin:",
+ "echo-pref-send-to": "Ipadala kay:",
+ "echo-pref-email-format": "Kaanyuan ng e-liham:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-liham",
+ "echo-pref-email-frequency-never": "Huwag magpadala sa akin ng anumang pabatid sa e-liham",
+ "echo-pref-email-frequency-immediately": "Mga indibiduwal na pabatid nang papasok ito",
+ "echo-pref-email-frequency-daily": "Isang arawang buod ng mga pabatid",
+ "echo-pref-email-frequency-weekly": "Isang lingguhang buod ng mga pabatid",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Purong teksto",
+ "echo-pref-notify-show-link": "Ipakita ang mga pabatid sa aking toolbar",
+ "echo-pref-new-message-indicator": "Ipakita ang indikador ng mga mensaheng pampahinang usapan sa aking toolbar",
+ "echo-learn-more": "Matuto pa",
+ "echo-new-messages": "Mayroon kang mga bagong mensahe",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Mensahe|Mga mensahe}} sa pahinang usapan",
+ "echo-category-title-article-linked": "{{PLURAL:$1|Kawing|Mga kawing}} sa pahina",
+ "echo-category-title-mention": "{{PLURAL:$1|Banggit|Mga banggit}}",
+ "echo-category-title-other": "{{PLURAL:$1|Iba}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-pref-tooltip-edit-user-talk": "Ipabatid sa akin kung may nagpaskil ng mensahe o may tumugon sa aking pahinang usapan.",
+ "echo-pref-tooltip-article-linked": "Ipabatid sa akin kung may kumawing sa pahinang inilika ko mula sa isang pahina ng artikulo.",
+ "echo-pref-tooltip-mention": "Ipabatid sa aking kung may kumawing sa aking pahina ng tagagamit mula sa anumang pahinang usapan.",
+ "echo-no-agent": "[Wala sinuman]",
+ "echo-no-title": "[Walang pahina]",
+ "echo-error-no-formatter": "Walang itinakdang anyo para sa pabatid.",
+ "echo-error-preference": "Kamalian: Hindi maitakda ang kagustuhan ng tagagamit.",
+ "notifications": "Mga pagpapabatid",
+ "tooltip-pt-notifications": "Mga pabatid mo",
+ "echo-specialpage": "Mga pabatid",
+ "echo-anon": "Upang makatanggap ng mga pagpapabatid, [$1 lumikha ng isang account] o [$2 lumagdang papasok].",
+ "echo-none": "Wala kang mga pabatid.",
+ "echo-more-info": "Karagdagang impormasyon",
+ "echo-feedback": "Komentaryo",
+ "notification-link-text-view-message": "Ipakita ang mensahe",
+ "notification-link-text-view-mention": "Ipakita ang pagbanggit",
+ "notification-link-text-view-changes": "Ipakita ang pagbabago",
+ "notification-link-text-view-page": "Ipakita ang pahina",
+ "notification-link-text-view-edit": "Ipakita ang pagbabago",
+ "notification-edit-talk-page2": "{{GENDER:$1|Nag-iwan}} si [[User:$1|$1]] ng mensahe sa iyong [[User talk:$2#$3|pahinang usapan]].",
+ "notification-edit-talk-page-with-section": "{{GENDER:$1|Nag-iwan}} si [[User:$1|$1]] ng mensahe sa iyong pahinang usapan sa seksiyong \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "{{GENDER:$1|Nag-iwan}} si $1 ng mensahe sa iyong [[User talk:$2#$3|pahinang usapan]].",
+ "notification-edit-talk-page-flyout-with-section": "{{GENDER:$1|Nag-iwan}} si $1 ng mensahe sa iyong pahinang usapan sa seksiyong \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "{{GENDER:$1|Ikinawing}} ang [[:$2]] mula sa [[:$3]]. [[Special:WhatLinksHere/$2|Tingnan ang lahat ng kawing patungo sa pahinang ito.]]",
+ "notification-page-linked-flyout": "{{GENDER:$1|Ikinawing}} ang [[:$2]] mula sa [[:$3]].",
+ "notification-add-comment2": "{{GENDER:$1|Nagkomento}} si [[User:$1|$1]] sa seksiyong \"[[$3|$2]]\" ng pahinang usapan ng \"$4\".",
+ "notification-add-talkpage-topic-yours2": "{{GENDER:$1|Ipinadala}} ka ni [[User:$1|$1]] ng mensahe: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "{{GENDER:$1|Nagkomento}} si [[User:$1|$1]] sa seksiyong \"[[$3#$2|$2]]\" sa iyong pahinang usapan.",
+ "notification-mention": "{{GENDER:$1|Binanggit}} ka ni [[User:$1|$1]] sa pahinang usapan ng $5 sa seksiyong \"[[:$3#$2|$4]]\".",
+ "notification-mention-flyout": "{{GENDER:$1|Binanggit}} ka ni $1 sa pahinang usapan ng $5 sa seksiyong \"[[:$3#$2|$4]]\".",
+ "notification-user-rights": "[[Special:Log/rights/$1|{{GENDER:$1|Binago}}]] ni [[User:$1|$1]] ang iyong mga karapatang pantagagamit. $2. [[Special:ListGroupRights|Matuto pa]]",
+ "notification-user-rights-flyout": "{{GENDER:$1|Binago}} ni $1 ang iyong mga karapatang pantagagamit. $2. [[Special:ListGroupRights|Matuto pa]]",
+ "notification-user-rights-add": "Kasapi ka na ng {{PLURAL:$2|grupong ito|mga grupong ito}}: $1",
+ "notification-user-rights-remove": "Hindi ka na kasapi ng {{PLURAL:$2|grupong ito|mga grupong ito}}: $1",
+ "notification-new-user": "Maligayang pagdating sa {{SITENAME}}, $1! Masaya kami na nandito ka.",
+ "notification-edit-talk-page-email-subject2": "{{GENDER:$1|Nag-iwan}} si $1 ng mensahe para sa iyo sa {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "{{GENDER:$1|Nag-iwan}} si $1 ng mensahe sa iyong pahinang usapan:",
+ "notification-edit-talk-page-email-batch-body-with-section": "{{GENDER:$1|Nag-iwan}} si $1 ng mensahe sa iyong pahinang usapan sa \"$2\".",
+ "notification-page-linked-email-subject": "Ikinawing ang pahina mo sa {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "{{GENDER:$1|Ikinawing}} ang $2 mula sa $3.",
+ "notification-mention-email-subject": "{{GENDER:$1|Binanggit}} ka ni $1 sa {{SITENAME}}",
+ "notification-mention-email-batch-body": "{{GENDER:$1|Binanggit}} ka ni $1 sa pahinang usapan ng $4 sa seksiyong \"$3\".",
+ "notification-user-rights-email-subject": "Nagbago ang iyong mga karapatang pantagagamit sa {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "{{GENDER:$1|Binago}} ni $1 ang iyong karapatang pantagagamit. $2.",
+ "echo-email-subject-default": "Bagong pabatid sa {{SITENAME}}",
+ "echo-email-body-default": "Mayroon kang isang bagong pagpapabatid doon sa {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "May bago kang pabatid.",
+ "echo-email-footer-default": "$2\n\nUpang makontrol mo ang mga e-liham na ipinapadala namin sa iyo, tingnan ang iyong mga kagustuhan: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Upang makontrol mo ang mga e-liham na ipinapadala namin sa iyo, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">tingnan ang iyong mga kagustuhan</a>.<br />\n$1",
+ "echo-overlay-link": "Lahat ng mga pabatid",
+ "echo-overlay-title": "<b>Mga pabatid</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Mga pabatid}}</b> (ipinapakita ang $1 ng $2 hindi pa nababasa)",
+ "echo-mark-all-as-read": "Tatakan ang lahat bilang nabasa na",
+ "echo-date-today": "Ngayon",
+ "echo-date-yesterday": "Kahapon",
+ "notification-edit-talk-page-bundle": "{{GENDER:$1|Nag-iwan}} sina $1 at $3 {{PLURAL:$4|iba pa}} ng mensahe sa iyong [[User talk:$2|pahinang usapan]].",
+ "notification-page-linked-bundle": "{{GENDER:$1|Ikinawing}} ang $2 mula sa $3 at $4 ibang {{PLURAL:$5|pahina}}. [[Special:WhatLinksHere/$2|Tingnan ang lahat ng kawing patungo sa pahinang ito]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "{{GENDER:$1|Nag-iwan}} sina $1 at $2 {{PLURAL:$3|iba pa}} ng mensahe sa iyong pahinang usapan.",
+ "notification-page-linked-email-batch-bundle-body": "{{GENDER:$1|Ikinawing}} ang $2 mula sa $3 at $4 ibang {{PLURAL:$5|pahina}}.",
+ "echo-email-batch-subject-daily": "May {{PLURAL:$2|bago kang pabatid|mga bago kang pabatid}} sa {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "May {{PLURAL:$2|bago kang pabatid|mga bago kang pabatid}} sa {{SITENAME}} ngayong linggo",
+ "echo-email-batch-body-intro-daily": "Magandang araw $1,\nIto ang buod ng mga gawain ngayon sa {{SITENAME}} para sa iyo.",
+ "echo-email-batch-body-intro-weekly": "Magandang araw $1,\nIto ang buod ng mga gawain ngayong linggo sa {{SITENAME}} para sa iyo.",
+ "echo-email-batch-link-text-view-all-notifications": "Tingnan ang lahat ng pabatid"
+}
diff --git a/Echo/i18n/tr.json b/Echo/i18n/tr.json
new file mode 100644
index 00000000..d8e25c02
--- /dev/null
+++ b/Echo/i18n/tr.json
@@ -0,0 +1,119 @@
+{
+ "@metadata": {
+ "authors": [
+ "Emperyan",
+ "Incelemeelemani",
+ "Joseph",
+ "Meelo",
+ "Rapsar",
+ "Sayginer",
+ "Violetanka"
+ ]
+ },
+ "echo-desc": "Bildirim sistemi",
+ "prefs-echo": "Bildirimler",
+ "prefs-emailsettings": "E-posta seçenekleri",
+ "prefs-displaynotifications": "Görüntüleme seçenekleri",
+ "prefs-echosubscriptions": "Bu olaylar hakkında bildir",
+ "prefs-newmessageindicator": "Yeni ileti bildirimi",
+ "echo-pref-send-me": "Bana gönder:",
+ "echo-pref-send-to": "Şuna gönder:",
+ "echo-pref-email-format": "E-posta biçimi:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "E-posta",
+ "echo-pref-email-frequency-never": "Bana e-posta bildirimi gönderme",
+ "echo-pref-email-frequency-immediately": "Tüm iletiler",
+ "echo-pref-email-frequency-daily": "İletilerin günlük özeti",
+ "echo-pref-email-frequency-weekly": "İletilerin haftalık özeti",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Düz metin",
+ "echo-pref-notify-show-link": "Bildirimleri araç çubuğumda göster",
+ "echo-pref-new-message-indicator": "Mesaj sayfamın yerine mesaj göstergesi araç çubuğunu göster",
+ "echo-learn-more": "Daha fazla bilgi",
+ "echo-new-messages": "Yeni mesajınız var",
+ "echo-category-title-edit-user-talk": "Tartışma sayfası {{PLURAL:$1|mesajı|mesajları}}",
+ "echo-category-title-article-linked": "Sayfa {{PLURAL:$1|bağlantısı|bağlantıları}}",
+ "echo-category-title-reverted": "Değişiklik {{PLURAL:$1|iptali|iptalleri}}",
+ "echo-category-title-mention": "{{PLURAL:$1|Bahsetme|Bahsetmeler}}",
+ "echo-category-title-other": "{{PLURAL:$1|Diğer}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistem}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Kullanıcı hakları değişikliği|Kullanıcı hakları değişiklikleri}}",
+ "echo-pref-tooltip-edit-user-talk": "Bir kullanıcı mesaj sayfamı değiştirdiğinde bunu bana bildir.",
+ "echo-pref-tooltip-article-linked": "Oluşturduğum sayfalarda değişiklik yapıldığında bana bildir.",
+ "echo-pref-tooltip-reverted": "Düzenleme yapıldıktan sonra geri alındığı takdirde bu durumu bana bildir.",
+ "echo-pref-tooltip-mention": "Kullanıcı adıma bağlantı verildiğinde bunu bana bildir.",
+ "echo-pref-tooltip-user-rights": "Kullanıcı haklarım değiştirildiğinde bunu bana bildir.",
+ "echo-no-agent": "[Kimse]",
+ "echo-no-title": "[Sayfa yok]",
+ "echo-error-no-formatter": "Hiçbir bildirim için biçim tanımlanmamış.",
+ "echo-error-preference": "Hata: Kullanıcı tercihi ayarlanamadı.",
+ "echo-error-token": "Hata: Kullanıcı anahtarı alınamadı.",
+ "notifications": "Bildirimler",
+ "tooltip-pt-notifications": "Bildirimleriniz",
+ "echo-specialpage": "Bildirimler",
+ "echo-anon": "Bildirimlere ulaşabilmek için, [$1 hesap oluşturun] ya da [$2 giriş yapın].",
+ "echo-none": "Bildiriminiz bulunmuyor.",
+ "echo-more-info": "Daha fazla bilgi",
+ "echo-feedback": "Geri bildirim",
+ "notification-link-text-view-message": "Mesajı görüntüle",
+ "notification-link-text-view-mention": "Bahsi görüntüle",
+ "notification-link-text-view-changes": "Değişiklikleri görüntüle",
+ "notification-link-text-view-page": "Sayfayı görüntüle",
+ "notification-link-text-view-edit": "Değişikliği görüntüle",
+ "notification-edit-talk-page2": "[[User:$1|$1]], [[User talk:$2#$3|mesaj sayfanıza]] yeni bir mesaj {{GENDER:$1|bıraktı}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]], mesaj sayfanızın \"[[User talk:$2#$3|$4]]\" başlığına bir mesaj {{GENDER:$1|bıraktı}}.",
+ "notification-edit-talk-page-flyout2": "$1, [[User talk:$2#$3|mesaj sayfanıza]] bir mesaj {{GENDER:$1|bıraktı}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1, mesaj sayfanızdaki \"[[User talk:$2#$3|$4]]\" başlığına bir mesaj {{GENDER:$1|bıraktı}}.",
+ "notification-page-linked": "[[:$2]] sayfasına [[:$3]] sayfasından {{GENDER:$1|bağlantı verildi}}. [[Special:WhatLinksHere/$2|Bu sayfaya bağlantı veren tüm sayfaları görüntüleyin]].",
+ "notification-page-linked-flyout": "[[:$2]] sayfasına [[:$3]] sayfasından {{GENDER:$1|bağlantı verildi}}.",
+ "notification-add-comment2": "[[User:$1|$1]], \"$4\" mesaj sayfasındaki \"[[$3|$2]]\" bölümüne {{GENDER:$1|yorum yaptı}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] size bir mesaj {{GENDER:$1|gönderdi}}: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]], mesaj sayfanızdaki \"[[$3#$2|$2]]\" konusuna {{GENDER:$1|yorum yaptı}}.",
+ "notification-mention": "[[User:$1|$1]], $5 sayfasının tartışma sayfasının \"[[:$3#$2|$4]]\" başlığında sizden {{GENDER:$1|bahsetti}}.",
+ "notification-mention-flyout": "$1, $5 sayfasının tartışma sayfasının \"[[:$3#$2|$4]]\" başlığında sizden {{GENDER:$1|bahsetti}}.",
+ "notification-mention-nosection": "[[Kullanıcı:$1|$1]], [[:$3|$2 başlıklı tartışma sayfasında]] sizden {{GENDER:$1|bahsetti}}.",
+ "notification-mention-nosection-flyout": "$1, [[:$3|$2 başlıklı tartışma sayfasında]] sizden {{GENDER:$1|bahsetti}}.",
+ "notification-user-rights": "Kullanıcı haklarınız [[User:$1|$1]] tarafından [[Special:Log/rights/$1|{{GENDER:$1|değiştirildi}}]]. $2. [[Special:ListGroupRights|Daha fazla bilgi]]",
+ "notification-user-rights-flyout": "Kullanıcı haklarınız $1 tarafından {{GENDER:$1|değiştirildi}}. $2. [[Special:ListGroupRights|Daha fazla bilgi alın]]",
+ "notification-user-rights-add": "Artık {{PLURAL:$2|bu grubun|bu grupların}} üyesisiniz: $1",
+ "notification-user-rights-remove": "Artık {{PLURAL:$2|bu grubun|bu grupların}} üyesi değilsiniz: $1",
+ "notification-new-user": "Hoş geldin $1! Sizi burada görmekten memnun olduk.",
+ "notification-reverted2": "{{PLURAL:$4|[[:$2]] sayfasındaki değişikliğiniz|[[:$2]] sayfasındaki değişiklikleriniz}} [[User:$1|$1]] tarafından {{GENDER:$1|geri alındı}}. $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|$2 sayfasındaki değişikliğiniz|$2 sayfasındaki değişiklikleriniz}}, $1 tarafından {{GENDER:$1|geri alındı}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1, {{SITENAME}} sayfasında size bir mesaj {{GENDER:$1|bıraktı}}",
+ "notification-edit-talk-page-email-batch-body2": "$1, mesaj sayfanıza bir mesaj {{GENDER:$1|bıraktı}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1, mesaj sayfanızın \"$2\" başlığında bir mesaj {{GENDER:$1|bıraktı}}.",
+ "notification-page-linked-email-subject": "Sayfanıza {{SITENAME}} sitesinde bağlantı verildi",
+ "notification-page-linked-email-batch-body": "$2 sayfasına $3 sayfasından {{GENDER:$1|bağlantı verildi}}.",
+ "notification-mention-email-subject": "$1, {{SITENAME}} sitesinde sizden {{GENDER:$1|bahsetti}}",
+ "notification-mention-email-batch-body": "$1, $4 sayfasının tartışma sayfasının \"$3\" başlığında sizden {{GENDER:$1|bahsetti}}.",
+ "notification-user-rights-email-subject": "{{SITENAME}} için kullanıcı hakları değişmiştir",
+ "notification-user-rights-email-batch-body": "Kullanıcı haklarınız $1 tarafından {{GENDER:$1|değiştirildi}}. $2",
+ "echo-email-subject-default": "{{SITENAME}} için yeni bildirim",
+ "echo-email-body-default": "{{SITENAME}} için yeni bildiriminiz var:\n\n$1",
+ "echo-email-batch-body-default": "Yeni bir bildiriminiz var",
+ "echo-email-footer-default": "$2\n\nSize gönderdiğimiz e-postaları kontrol etmek için, tercihlerinizi kontrol edin:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Size gönderdiğimiz e-postaları kontrol etmek için, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">tercihlerinizi kontrol edin</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Uayrı ($1)|Uyarılar ($1)|100=Uyarılar (99+)}}",
+ "echo-notification-alert-text-only": "Uyarılar",
+ "echo-notification-message-text-only": "İletiler",
+ "echo-overlay-link": "Bütün bildirimler",
+ "echo-overlay-title": "<b>Bildirimler</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Bildirimler}}</b> ($2 okunmayandan $1 adeti gösteriliyor)",
+ "echo-mark-all-as-read": "Tümünü okundu olarak işaretle",
+ "echo-date-today": "Bugün",
+ "echo-date-yesterday": "Dün",
+ "echo-load-more-error": "Daha fazla sonuç oluşturma esnasında bir hata oluştu.",
+ "notification-edit-talk-page-bundle": "$1 ve diğer $3 {{PLURAL:$4|kullanıcı}}, [[User talk:$2|mesaj sayfanıza]] bir mesaj {{GENDER:$1|bıraktı}}.",
+ "notification-page-linked-bundle": "$2 sayfasına $3 sayfası ve diğer $4 {{PLURAL:$5|sayfadan|sayfadan}} {{GENDER:$1|bağlantı verildi}}. [[Special:WhatLinksHere/$2|Bu sayfaya bağlantı veren tüm sayfaları görüntüleyin]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 ve diğer $2 {{PLURAL:$3|kullanıcı}}, mesaj sayfanıza bir mesaj {{GENDER:$1|bıraktı}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2 sayfasına $3 sayfası ve diğer $4 {{PLURAL:$5|sayfadan|sayfadan}} {{GENDER:$1|bağlantı verildi}}.",
+ "echo-email-batch-subject-daily": "{{SITENAME}} sitesinde {{PLURAL:$2|yeni bir bildiriminiz|yeni bildirimleriniz}} var",
+ "echo-email-batch-subject-weekly": "Bu hafta {{SITENAME}} sitesinde {{PLURAL:$2|yeni bir bildiriminiz|yeni bildirimleriniz}} var",
+ "echo-email-batch-body-intro-daily": "Merhaba $1,\nBurada {{SITENAME}} için bu günün etkinlik özetini bulabilirsiniz.",
+ "echo-email-batch-body-intro-weekly": "Merhaba $1,\nBurada {{SITENAME}} için bu haftaki etkinlik özetini bulabilirsiniz.",
+ "echo-email-batch-link-text-view-all-notifications": "Tüm bildirimleri göster",
+ "echo-rev-deleted-text-view": "Bu sayfa sürümü kaldırıldı.",
+ "apihelp-echomarkread-example-2": "Tüm bildirimleri okunmuş olarak işaretle",
+ "apihelp-query+notifications-param-limit": "Gösterilebilecek azami bildirim sayısı."
+}
diff --git a/Echo/i18n/tt-cyrl.json b/Echo/i18n/tt-cyrl.json
new file mode 100644
index 00000000..294f1753
--- /dev/null
+++ b/Echo/i18n/tt-cyrl.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ilnur efende"
+ ]
+ },
+ "prefs-echo": "Яңалыклар",
+ "notifications": "Яңалыклар",
+ "tooltip-pt-notifications": "Сезнең хәбәрләр",
+ "echo-specialpage": "Яңалыклар",
+ "notification-link-text-view-changes": "Үзгәртүләрне карау",
+ "notification-link-text-view-edit": "Үзгәртүне карау",
+ "notification-mention": "[[User:$1|$1]] $5 бәхәс битенең \"[[:$3#$2|$4]]\" бүлегендә сезне искә алды.",
+ "notification-mention-flyout": "[[User:$1|$1]] $5 бәхәс битенең \"[[:$3#$2|$4]]\" бүлегендә сезне искә алды.",
+ "notification-mention-nosection": "[[User:$1|$1]] сезне [[:$3|$2 бәхәс битендә]] искә алды.",
+ "notification-mention-nosection-flyout": "$1 сезне [[:$3| $2 бәхәс битендә]] искә алды.",
+ "notification-mention-nosection-email-batch-body": "$1 сезне $2 бәхәс битендә искә алды.",
+ "echo-date-yesterday": "Кичә",
+ "notification-edit-talk-page-bundle": "$1 һәм тагын $3 кулланучы сезнең [[User talk:$2|бәхәс битендә]] хәбәр калдырганнар."
+}
diff --git a/Echo/i18n/ug-arab.json b/Echo/i18n/ug-arab.json
new file mode 100644
index 00000000..960fd0ba
--- /dev/null
+++ b/Echo/i18n/ug-arab.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sahran"
+ ]
+ },
+ "prefs-echo": "ئۇقتۇرۇشلار",
+ "prefs-displaynotifications": "كۆرسىتىش تاللانما",
+ "notifications": "ئۇقتۇرۇشلار",
+ "echo-date-today": "بۈگۈن",
+ "echo-date-yesterday": "تۈنۈگۈن"
+}
diff --git a/Echo/i18n/uk.json b/Echo/i18n/uk.json
new file mode 100644
index 00000000..ff20682b
--- /dev/null
+++ b/Echo/i18n/uk.json
@@ -0,0 +1,123 @@
+{
+ "@metadata": {
+ "authors": [
+ "AS",
+ "Ahonc",
+ "Andriykopanytsia",
+ "Base",
+ "Olvin",
+ "Steve.rusyn",
+ "SteveR",
+ "Ата"
+ ]
+ },
+ "echo-desc": "Система сповіщень",
+ "prefs-echo": "Сповіщення",
+ "prefs-emailsettings": "Параметри електронної пошти",
+ "prefs-displaynotifications": "Опції відображення",
+ "prefs-echosubscriptions": "Повідомляти мене про ці події",
+ "prefs-newmessageindicator": "Індикатор нових повідомлень",
+ "echo-pref-send-me": "Надіслати мені:",
+ "echo-pref-send-to": "Надіслати до:",
+ "echo-pref-email-format": "Формат листів:",
+ "echo-pref-web": "Веб",
+ "echo-pref-email": "Ел. пошта",
+ "echo-pref-email-frequency-never": "Не надсилати мені жодних сповіщень електронною поштою",
+ "echo-pref-email-frequency-immediately": "Сповіщати про кожну подію одразу",
+ "echo-pref-email-frequency-daily": "Щоденна збірка сповіщень",
+ "echo-pref-email-frequency-weekly": "Щомісячна збірка сповіщень",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Простий текст",
+ "echo-pref-notify-show-link": "Показувати сповіщення в моїй панелі інструментів",
+ "echo-pref-new-message-indicator": "Показувати індикатор повідомлень на сторінці обговорення у моїй панелі інструментів",
+ "echo-learn-more": "Дізнатися більше",
+ "echo-new-messages": "У Вас є нові повідомлення",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1|Повідомлення|Повідомлення|Повідомлень}} на сторінці обговорення",
+ "echo-category-title-article-linked": "{{PLURAL:$1|посилання}} на сторінку",
+ "echo-category-title-reverted": "{{PLURAL:$1|скасування|скасування|скасувань}} редагувань",
+ "echo-category-title-mention": "{{PLURAL:$1|згадування}}",
+ "echo-category-title-other": "{{PLURAL:$1|інше}}",
+ "echo-category-title-system": "{{PLURAL:$1|системне}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Зміна прав користувача|Зміни прав користувача}}",
+ "echo-pref-tooltip-edit-user-talk": "Повідомляти мене, коли хтось надіслав повідомлення або відповів на моїй сторінці обговорення.",
+ "echo-pref-tooltip-article-linked": "Повідомляти мене, коли хтось зробив посилання на створену мною сторінку.",
+ "echo-pref-tooltip-reverted": "Повідомляти мене, коли хтось відкинув моє редагування з допомогою скасування чи відкату.",
+ "echo-pref-tooltip-mention": "Повідомляти мене, коли хтось зробив посилання на мою сторінку користувача.",
+ "echo-pref-tooltip-user-rights": "Сповіщати мене, коли хтось змінює мої права користувача.",
+ "echo-no-agent": "[Ніхто]",
+ "echo-no-title": "[Нема сторінки]",
+ "echo-error-no-formatter": "Не визначено формату сповіщень",
+ "echo-error-preference": "Помилка: Не вдалося встановити уподобання користувача",
+ "echo-error-token": "Помилка: Не вдалося отримати маркер користувача",
+ "notifications": "Сповіщення",
+ "tooltip-pt-notifications": "Ваші сповіщення",
+ "echo-specialpage": "Сповіщення",
+ "echo-anon": "Для отримання сповіщень [$1 створіть обліковий запис] або [$2 увійдіть].",
+ "echo-none": "У Вас немає сповіщень.",
+ "echo-more-info": "Детальніше",
+ "echo-feedback": "Зворотний зв'язок",
+ "notification-link-text-view-message": "Переглянути повідомлення",
+ "notification-link-text-view-mention": "Переглянути згадку",
+ "notification-link-text-view-changes": "Переглянути зміни",
+ "notification-link-text-view-page": "Переглянути сторінку",
+ "notification-link-text-view-edit": "Переглянути редагування",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|залишив|залишила}} повідомлення на Вашій [[User talk:$2#$3|сторінці обговорення]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|залишив|залишила}} повідомлення на Вашій сторінці обговорення у «[[User talk:$2#$3|$4]]».",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|залишив|залишила}} повідомлення на Вашій [[User talk:$2#$3|сторінці обговорення]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|залишив|залишила}} повідомлення на Вашій сторінці обговорення у «[[User talk:$2#$3|$4]]».",
+ "notification-page-linked": "На [[:$3]] $1 {{GENDER:$1|додав|додала}} посилання на [[:$2]]. [[Special:WhatLinksHere/$2|Див. усі посилання на цю сторінку]]",
+ "notification-page-linked-flyout": "На [[:$3]] $1 {{GENDER:$1|додав|додала}} посилання на [[:$2]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|прокоментував|прокоментувала}} \"[[$3|$2]]\" на сторінці обговорення \"$4\".",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|створив|створила}} нову тему \"$2\" на [[$3]].",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|надіслав|надіслала}} Вам повідомлення: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|прокоментував|прокоментувала}} \"[[$3#$2|$2]]\" на Вашій сторінці обговорення.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|згадав|згадала}} Вас на сторінці обговорення $5 у «[[:$3#$2|$4]]».",
+ "notification-mention-flyout": "$1 {{GENDER:$1|згадав|згадала}} Вас на сторінці обговорення $5 у «[[:$3#$2|$4]]».",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|згадав|згадала}} вас на [[:$3|сторінці обговорення $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1|згадав|згадала}} вас на [[:$3|сторінці обговорення $2]].",
+ "notification-user-rights": "Ваші права користувача [[Special:Log/rights/$1|було змінено]] {{GENDER:$1|користувачем|користувачкою}} [[User:$1|$1]]. $2. [[Special:ListGroupRights|Дізнатися більше]]",
+ "notification-user-rights-flyout": "Ваші права користувача було змінено {{GENDER:$1|користувачем|користувачкою}} $1. $2. [[Special:ListGroupRights|Дізнатися більше]]",
+ "notification-user-rights-add": "Зараз Ви член {{PLURAL:$2|1=такої групи|таких груп}}: $1",
+ "notification-user-rights-remove": "Ви більше не є членом {{PLURAL:$2|1=цієї групи|таких груп}}: $1",
+ "notification-new-user": "Ласкаво просимо до {{GRAMMAR:Genitive|{{SITENAME}}}}, $1! Ми раді, що Ви тут.",
+ "notification-reverted2": "{{PLURAL:$4|1=Ваше редагування|Ваші редагування}} сторінки [[:$2]] було {{GENDER:$1|відкочено}} {{GENDER:$1|користувачем|користувачкою}} [[User:$1|$1]] $3",
+ "notification-reverted-flyout2": "{{PLURAL:$4|1=Ваше редагування|Ваші редагування}} сторінки $2 було {{GENDER:$1|відкочено}} {{GENDER:$1|користувачем|користувачкою}} $1 $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|залишив|залишила}} Вам повідомлення на сайті {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|залишив|залишила}} повідомлення на Вашій сторінці обговорення:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|залишив|залишила}} повідомлення на Вашій сторінці обговорення у «$2».",
+ "notification-page-linked-email-subject": "На сайті {{SITENAME}} з'явилось посилання на Вашу сторінку",
+ "notification-page-linked-email-batch-body": "На «$3» $1 {{GENDER:$1|зробив|зробила}} посилання на «$2»",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|1=Ваше редагування|Ваші редагування}} на сайті {{SITENAME}} було {{GENDER:$1|відкочено}}",
+ "notification-reverted-email-batch-body2": "{{PLURAL:$3|1=Ваше редагування|Ваші редагування}} сторінки $2 було {{GENDER:$1|відкочено}} {{GENDER:$1|користувачем|користувачкою}} $1",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|згадав|згадала}} Вас на {{GRAMMAR:locative|{{SITENAME}}}}.",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|згадав|згадала}} Вас на сторінці обговорення {{GENDER:$4|користувача|користувачки}} $4 у «$3».",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|згадав|згадала}} вас на сторінці обговорення $2.",
+ "notification-user-rights-email-subject": "Змінились Ваші права користувача на {{GRAMMAR:locative|{{SITENAME}}}}.",
+ "notification-user-rights-email-batch-body": "Ваші права користувача було змінено {{GENDER:$1|користувачем|користувачкою}} $1. $2.",
+ "echo-email-subject-default": "Нові сповіщення на {{GRAMMAR:locative|{{SITENAME}}}}",
+ "echo-email-body-default": "У Вас є нове сповіщення на {{GRAMMAR:locative|{{SITENAME}}}}:\n\n$1",
+ "echo-email-batch-body-default": "У Вас нове сповіщення.",
+ "echo-email-footer-default": "$2\n\nЩоб контролювати, які листи ми Вам надсилаємо, перевірте свої налаштування:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Щоб проконтролювати, які листи ми вам надсилаємо, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">перевірте свої налаштування</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Попередження ($1)|Попереджень ($1)|100=Попереджень (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Повідомлення ($1)|100=Повідомлення (99+)}}",
+ "echo-notification-alert-text-only": "Оповіщення",
+ "echo-notification-message-text-only": "Повідомлення",
+ "echo-overlay-link": "Усі сповіщення",
+ "echo-overlay-title": "<b>Сповіщення</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Сповіщення|Сповіщення|Сповіщень}}</b> (показано $1 з $2 непрочитаних)",
+ "echo-mark-all-as-read": "Позначити всі як прочитані",
+ "echo-date-today": "Сьогодні",
+ "echo-date-yesterday": "Вчора",
+ "echo-load-more-error": "Під час отримання додаткових результатів сталася помилка.",
+ "notification-edit-talk-page-bundle": "$1 та $3 {{PLURAL:$4|інший користувач|інші користувачі|інших користувачів}} {{GENDER:$1|залишили}} повідомлення на Вашій [[User talk:$2|сторінці обговорення]].",
+ "notification-page-linked-bundle": "На $3 та $4 {{PLURAL:$5|1=іншій сторінці|інших сторінках}} $1 {{GENDER:$1|додав|додала}} посилання на $2. [[Special:WhatLinksHere/$2|Див. усі посилання на цю сторінку]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 та $2 {{PLURAL:$3|інший користувач|інші користувачі|інших користувачів}} {{GENDER:$1|залишили}} повідомлення на Вашій сторінці обговорення",
+ "notification-page-linked-email-batch-bundle-body": "На $3 та $4 {{PLURAL:$5|1=іншій сторінці|інших сторінках}} $1 {{GENDER:$1|додав|додала}} посилання на $2.",
+ "echo-email-batch-subject-daily": "У Вас {{PLURAL:$2|нове сповіщення|нові сповіщення|нових сповіщень}} на сайті {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "У Вас {{PLURAL:$2|нове сповіщення|нові сповіщення|нових сповіщень}} на сайті {{SITENAME}} цього тижня",
+ "echo-email-batch-body-intro-daily": "Привіт $1!\nОсь підсумок денної активності на сайті {{SITENAME}} для вас.",
+ "echo-email-batch-body-intro-weekly": "Привіт $1!\nОсь підсумок тижневої активності на сайті {{SITENAME}} для вас.",
+ "echo-email-batch-link-text-view-all-notifications": "Переглянути усі сповіщення",
+ "echo-rev-deleted-text-view": "Цю версію сторінки було приховано."
+}
diff --git a/Echo/i18n/ur.json b/Echo/i18n/ur.json
new file mode 100644
index 00000000..f36cb44c
--- /dev/null
+++ b/Echo/i18n/ur.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Noor2020",
+ "පසිඳු කාවින්ද",
+ "Amire80",
+ "Fauzan",
+ "عثمان خان شاہ"
+ ]
+ },
+ "prefs-echo": "اطلاعات",
+ "echo-new-messages": "آپ کے لیے نئے پیغامات",
+ "echo-category-title-other": "دیگر",
+ "notifications": "اطلاعات",
+ "tooltip-pt-notifications": "آپ کے نوٹیفیکیشن",
+ "echo-specialpage": "میری اطلاعات",
+ "echo-feedback": "آپ کی رائے",
+ "notification-user-rights-flyout": "آپ کے صارفانہ حقوق ہوگئے {{GENDER:$1| تبدیل}} <b> $1 </b>کے ذریعے ۔ $2. [[Special:ListGroupRights|مزید دیکھیں]]",
+ "echo-notification-message-text-only": "پیغامات",
+ "echo-overlay-link": "سب اطلاعات...",
+ "echo-overlay-title": "<b>اطلاعات</b>",
+ "echo-overlay-title-overflow": "<b>اطلاعات</b> (دکھا رہا ہے $1 کے $2 غیر مطلع)",
+ "echo-mark-all-as-read": "جملہ اطلاعات کو خواندہ نشانزد کریں",
+ "echo-date-today": "آج",
+ "echo-date-yesterday": "گذشتہ کل"
+}
diff --git a/Echo/i18n/uz.json b/Echo/i18n/uz.json
new file mode 100644
index 00000000..23876020
--- /dev/null
+++ b/Echo/i18n/uz.json
@@ -0,0 +1,113 @@
+{
+ "@metadata": {
+ "authors": [
+ "CoderSI",
+ "Nataev",
+ "Sociologist"
+ ]
+ },
+ "echo-desc": "Xabarlar tizimi",
+ "prefs-echo": "Xabarlar",
+ "prefs-emailsettings": "Elektron pochta moslamalari",
+ "prefs-displaynotifications": "Tasvirlash moslamalari",
+ "prefs-echosubscriptions": "Quyidagi hodisalar haqida menga xabar berilsin",
+ "prefs-newmessageindicator": "Yangi xabar indikatori",
+ "echo-pref-send-me": "Menga joʻnatilsin:",
+ "echo-pref-send-to": "Joʻnatilsin:",
+ "echo-pref-email-format": "Elektron xat formati",
+ "echo-pref-web": "Veb",
+ "echo-pref-email": "Elektron pochta",
+ "echo-pref-email-frequency-never": "Menga elektron pochta orqali xabarlar joʻnatilmasin",
+ "echo-pref-email-frequency-immediately": "Alohida xabarlar kelgani sayin",
+ "echo-pref-email-frequency-daily": "Xabarlar haqida kundalik maʼlumot",
+ "echo-pref-email-frequency-weekly": "Xabarlar haqida haftalik maʼlumot",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Quruq matn",
+ "echo-pref-notify-show-link": "Asboblar panelimda xabarlar koʻrsatilsin",
+ "echo-pref-new-message-indicator": "Asboblar panelida munozara sahifasidagi xabarlar indikatori koʻrsatilsin",
+ "echo-learn-more": "Batafsil maʼlumot",
+ "echo-new-messages": "Sizda yangi xabarlar bor",
+ "echo-category-title-edit-user-talk": "Munozaramda {{PLURAL:$1|1=xabar|xabar}}",
+ "echo-category-title-article-linked": "Sahifalarimga {{PLURAL:$1|1=ishora|ishoralar}}",
+ "echo-category-title-reverted": "{{PLURAL:$1|Tahririm|Tahrirlarim}} qaytarildi",
+ "echo-category-title-mention": "{{PLURAL:$1|1=Tilga olish|Tilga olishlar}}",
+ "echo-category-title-other": "{{PLURAL:$1|1=boshqa|boshqalar}}",
+ "echo-category-title-system": "{{PLURAL:$1|Tuzum}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Foydalanuvchi huquqlarim oʻzgartirildi}}",
+ "echo-pref-tooltip-edit-user-talk": "Birorta xat yuborsa yoki munozara sahifamda javob yozsa xabar berilsin",
+ "echo-pref-tooltip-article-linked": "Maqolalarda men yaratgan biror-bir sahifaga link qoldirilsa xabar berilsin",
+ "echo-pref-tooltip-reverted": "Kimdir men qilgan tahrirni bekor qilsa, menga xabar berilsin.",
+ "echo-pref-tooltip-mention": "Biror foydalanuvchi har qanday munozarada sahifamga havola bergani haqida xabar qilinsin",
+ "echo-no-agent": "[Hech kim]",
+ "echo-no-title": "[Sahifa yoʻq]",
+ "echo-error-no-formatter": "Xabarlar uchun format belgilanmagan.",
+ "echo-error-preference": "Xato: Foydalanuvchi moslamalarini tayinlab boʻlmadi.",
+ "echo-error-token": "Xato: Foydalanuvchi markerini olib boʻlmadi (user token).",
+ "notifications": "Xabarlar",
+ "tooltip-pt-notifications": "Sizning xabarlaringiz",
+ "echo-specialpage": "Xabarlar",
+ "echo-anon": "Xabarlar olib turish uchun [$1 hisob yarating] yoki [$2 tizimga kiring].",
+ "echo-none": "Siz xabar olmadingiz.",
+ "echo-more-info": "Batafsil",
+ "echo-feedback": "Teskari aloqa",
+ "notification-link-text-view-message": "Xabarni koʻrib chiqish",
+ "notification-link-text-view-mention": "Eslatib oʻtishni koʻrib chiqish",
+ "notification-link-text-view-changes": "Oʻzgarishlarni koʻrish",
+ "notification-link-text-view-page": "Sahifani koʻrish",
+ "notification-link-text-view-edit": "Tahrirni koʻrish",
+ "notification-edit-talk-page2": "[[User:$1|$1]] sizning [[User talk:$2#$3|munozara sahifangizda]] xat {{GENDER:$1|qoldirdi}}.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] sizning munozara sahifangizda „[[User talk:$2#$3|$4]]“ mavzusida xat {{GENDER:$1|qoldirdi}}.",
+ "notification-edit-talk-page-flyout2": "$1 sizning [[User talk:$2#$3|munozara sahifangizda]] xat {{GENDER:$1|qoldirdi}}.",
+ "notification-edit-talk-page-flyout-with-section": "$1 sizning munozara sahifangizda „[[User talk:$2#$3|$4]]“ mavzusida xat {{GENDER:$1|qoldirdi}}.",
+ "notification-page-linked": "[[:$2]] [[:$3]]dan {{GENDER:$1|bogʻlandi}}. [[Special:WhatLinksHere/$2|Bu sahifaga ulangan barcha linklarni koʻring]].",
+ "notification-page-linked-flyout": "[[:$2]] sahifasi [[:$3]] sahifasi bilan {{GENDER:$1|bogʻlandi}}.",
+ "notification-add-comment2": "[[User:$1|$1]] „$4“ munozara sahifasida „[[$3|$2]]“ mavzusida {{GENDER:$1|sharh qoldirdi}}.",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] [[$3]] sahifasida yangi „$2“ mavzusini {{GENDER:$1|qoʻshdi}}.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] sizga xabar {{GENDER:$1|joʻnatdi}}: „[[$3#$2|$2]]“.",
+ "notification-add-comment-yours2": "[[User:$1|$1]] sizning munozara sahifangizda „[[$3#$2|$2]]“ mavzusida {{GENDER:$1|sharh qoldirdi}}.",
+ "notification-mention": "[[User:$1|$1]] $5 munozara sahifasidagi „[[:$3#$2|$4]]“ boʻlimida sizni {{GENDER:$1|tilga oldi}}.",
+ "notification-mention-flyout": "$5 sahifasi munozarasidagi „[[:$3#$2|$4]]“ boʻlimida $1 sizni {{GENDER:$1|tilga oldi}}.",
+ "notification-mention-nosection": "[[User:$1|$1]] [[:$3|$2 munozara sahifasida]] sizni {{GENDER:$1|tilga oldi}}.",
+ "notification-mention-nosection-flyout": "$1 [[:$3|$2 munozara sahifasida]] sizni {{GENDER:$1|tilga oldi}}.",
+ "notification-user-rights": "Sizning foydalanuvchi huquqlaringiz [[User:$1|$1]] tomonidan [[Special:Log/rights/$1|{{GENDER:$1|oʻzgartirildi}}]]. $2. [[Special:ListGroupRights|Batafsil]]",
+ "notification-user-rights-flyout": "Sizning foydalanuvchi huquqlaringiz $1 tomonidan [[Special:Log/rights/$1|{{GENDER:$1|oʻzgartirildi}}]]. $2. [[Special:ListGroupRights|Batafsil]]",
+ "notification-user-rights-add": "Siz endi {{PLURAL:$2|1=quyidagi guruh|quyidagi guruhlar}} aʼzosisiz: $1",
+ "notification-user-rights-remove": "Siz endi {{PLURAL:$2|1=quyidagi guruh|quyidagi guruhlar}} aʼzosi emassiz: $1",
+ "notification-new-user": "{{SITENAME}}ga xush kelibsiz!, $1! Siz bu yerdaligingizdan mamnunmiz.",
+ "notification-reverted2": "[[:$2]] sahifasidagi {{PLURAL:$4|1=tahriringizni|tahrirlaringizni}} [[User:$1|$1]] {{GENDER:$1|bekor qildi}}. $3",
+ "notification-reverted-flyout2": "$2 sahifasidagi {{PLURAL:$4|1=tahriringizni|tahrirlaringizni}} $1 {{GENDER:$1|bekor qildi}}. $3",
+ "notification-edit-talk-page-email-subject2": "$1 {{SITENAME}}da sizga xabar {{GENDER:$1|qoldirdi}}.",
+ "notification-edit-talk-page-email-batch-body2": "$1 munozara sahifangizda xabar {{GENDER:$1|qoldirdi}}:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 munozara sahifangizdagi „$2“ boʻlimida xabar {{GENDER:$1|qoldirdi}}:",
+ "notification-page-linked-email-subject": "{{SITENAME}} saytida siz yaratgan sahifaga havola paydo boʻldi.",
+ "notification-page-linked-email-batch-body": "$2 $3dan {{GENDER:$1|bogʻlandi}}.",
+ "notification-reverted-email-subject2": "{{GENDER:$1|Кimdir}} {{SITENAME}} saytida sizning {{PLURAL:$3|1=tahriringizni|tahrirlaringizni}} bekor qildi.",
+ "notification-reverted-email-batch-body2": "$2 sahifasidagi {{PLURAL:$4|1=tahriringizni|tahrirlaringizni}} $1 {{GENDER:$1|bekor qildi}}.",
+ "notification-mention-email-subject": "$1 sizni {{SITENAME}} saytida {{GENDER:$1|tilga oldi}}.",
+ "notification-mention-email-batch-body": "$4 sahifasining munozarasidagi „$3“ boʻlimida $1 sizni {{GENDER:$1|tilga oldi}}.",
+ "notification-mention-nosection-email-batch-body": "„$2 sahifasi munozarasida $1 sizni {{GENDER:$1|tilga oldi}}.",
+ "notification-user-rights-email-subject": "{{SITENAME}} saytidagi huquqlaringiz oʻzgartirildi.",
+ "notification-user-rights-email-batch-body": "Sizning huquqlaringiz $1 tomonidan {{GENDER:$1|oʻzgartirildi}}. $2.",
+ "echo-email-subject-default": "{{SITENAME}} saytida yangi xabarlar",
+ "echo-email-body-default": "{{SITENAME}} saytida sizda yangi xabar bor:\n\n$1",
+ "echo-email-batch-body-default": "Sizda yangi xabar bor.",
+ "echo-email-footer-default": "$2 \n\nSizga qanday elektron xabarlarni joʻnatishimizni boshqarish uchun shaxsiy moslamalaringizni koʻrib chiqing: {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Sizga qanday elektron xabarlarni joʻnatishimizni boshqarish uchun <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">shaxsiy moslamalaringizni koʻrib chiqing</a>.<br />",
+ "echo-overlay-link": "Barcha xabarlar",
+ "echo-overlay-title": "<b>Xabarlar</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Xabarlar}}</b> $2 ta oʻqilmagandan $1 tasi koʻrsatilyapti",
+ "echo-mark-all-as-read": "Barchasini oʻqilgan deb belgilash",
+ "echo-date-today": "Bugun",
+ "echo-date-yesterday": "Kecha",
+ "echo-load-more-error": "Qoʻshimcha natijalar olinayotganda xato roʻy berdi.",
+ "notification-edit-talk-page-bundle": "$1 va $3 {{PLURAL:$4|1=boshqa foydalanuvchi|boshqa foydalanuvchilar}} [[User talk:$2|munozara sahifangizda]] xabar {{GENDER:$1|qoldirdi}}.",
+ "notification-page-linked-bundle": "$2 ga $3 va $4 boshqa {{PLURAL:$5|sahifada|sahifalarda}} havola {{GENDER:$1|qoldirildi}}. [[Special:WhatLinksHere/$2|Bu sahifaga ulangan barcha linklarni koʻrib chiqing]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 va $2 {{PLURAL:$3|boshqa|boshqalar}} munozara sahigangizda xabar {{GENDER:$1|qoldirdi}}.",
+ "notification-page-linked-email-batch-bundle-body": "$2ga $3da va $4 boshqa {{PLURAL:$5|sahifada|sahifada}} havola {{GENDER:$1|qoldirildi}}.",
+ "echo-email-batch-subject-daily": "{{SITENAME}} saytida sizda {{PLURAL:$2|yangi xabar|yangi xabar}} bor.",
+ "echo-email-batch-subject-weekly": "Bu hafta {{SITENAME}} saytida sizda {{PLURAL:$2|yangi xabar|yangi xabar}} bor.",
+ "echo-email-batch-body-intro-daily": "Salom $1,\nMana siz uchun {{SITENAME}} saytidagi bugungi faoliyat haʻqida qisqa maʼlumot.",
+ "echo-email-batch-body-intro-weekly": "Salom $1,\nMana siz uchun {{SITENAME}} saytidagi bir haftalik faoliyat haʻqida qisqa maʼlumot.",
+ "echo-email-batch-link-text-view-all-notifications": "Barcha xabarlarni koʻrib chiqish",
+ "echo-rev-deleted-text-view": "Sahifaning mazkur versiyasi yashirilgan"
+}
diff --git a/Echo/i18n/vec.json b/Echo/i18n/vec.json
new file mode 100644
index 00000000..29d9d27f
--- /dev/null
+++ b/Echo/i18n/vec.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Candalua"
+ ]
+ },
+ "echo-pref-send-me": "Màndeme:",
+ "echo-pref-send-to": "Manda a:",
+ "echo-pref-email-format": "Formato email:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Email",
+ "echo-pref-email-frequency-never": "No sta mandarme nissuna notifica par email",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Testo normal",
+ "echo-new-messages": "Te ghè dei messagi novi",
+ "echo-category-title-other": "{{PLURAL:$1|Altro}}",
+ "echo-category-title-system": "{{PLURAL:$1|Sistema}}",
+ "echo-no-agent": "[Nissun]",
+ "echo-no-title": "[Nissuna pagina]",
+ "notification-link-text-view-message": "Varda messajo",
+ "echo-mark-all-as-read": "Segna tuto come zà lèto",
+ "echo-date-today": "Uncuò",
+ "echo-date-yesterday": "Jeri"
+}
diff --git a/Echo/i18n/vi.json b/Echo/i18n/vi.json
new file mode 100644
index 00000000..6f559e34
--- /dev/null
+++ b/Echo/i18n/vi.json
@@ -0,0 +1,124 @@
+{
+ "@metadata": {
+ "authors": [
+ "Baonguyen21022003",
+ "Minh Nguyen",
+ "Trần Nguyễn Minh Huy",
+ "Max20091"
+ ]
+ },
+ "echo-desc": "Hệ thống thông báo",
+ "prefs-echo": "Thông báo",
+ "prefs-emailsettings": "Tùy chọn thư điện tử",
+ "prefs-displaynotifications": "Tùy chọn hiển thị",
+ "prefs-echosubscriptions": "Báo cho tôi biết về những sự kiện này",
+ "prefs-newmessageindicator": "Đèn tin nhắn mới",
+ "echo-pref-send-me": "Gửi thư cho tôi:",
+ "echo-pref-send-to": "Gửi đến:",
+ "echo-pref-email-format": "Định dạng thư điện tử:",
+ "echo-pref-web": "Web",
+ "echo-pref-email": "Thư điện tử",
+ "echo-pref-email-frequency-never": "Không gửi cho tôi bất kỳ thông báo qua thư điện tử",
+ "echo-pref-email-frequency-immediately": "Gửi các thông báo từng cái một vào đúng lúc xảy ra",
+ "echo-pref-email-frequency-daily": "Tóm lược các thông báo hàng ngày",
+ "echo-pref-email-frequency-weekly": "Tóm lược các thông báo hàng tuần",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "Văn bản thuần",
+ "echo-pref-notify-show-link": "Hiển thị thông báo trên thanh công cụ",
+ "echo-pref-new-message-indicator": "Hiển thị đèn tin nhắn trên thanh công cụ của tôi",
+ "echo-learn-more": "Tìm hiểu thêm",
+ "echo-new-messages": "Bạn có tin nhắn mới",
+ "echo-category-title-edit-user-talk": "{{PLURAL:$1}}Lời tin nhắn",
+ "echo-category-title-article-linked": "{{PLURAL:$1}}Liên kết đến trang",
+ "echo-category-title-reverted": "{{PLURAL:$1}}Lùi sửa",
+ "echo-category-title-mention": "{{PLURAL:$1}}Lời nói đến",
+ "echo-category-title-other": "{{PLURAL:$1}}Khác",
+ "echo-category-title-system": "{{PLURAL:$1}}Hệ thống",
+ "echo-category-title-user-rights": "{{PLURAL:$1|Các thay đổi|Thay đổi}} về quyền người dùng",
+ "echo-pref-tooltip-edit-user-talk": "Báo cho tôi biết khi nào người ta nhắn tin hoặc trả lời trên trang thảo luận của tôi.",
+ "echo-pref-tooltip-article-linked": "Báo cho tôi biết khi nào người ta đặt liên kết từ một bài đến một trang do tôi tạo ra.",
+ "echo-pref-tooltip-reverted": "Báo cho tôi khi nào người ta lùi lại một sửa đổi của tôi dùng chức năng Lùi sửa hoặc Lùi tất cả.",
+ "echo-pref-tooltip-mention": "Báo cho tôi biết khi có người đặt liên kết đến trang thành viên của tôi.",
+ "echo-pref-tooltip-user-rights": "Thông báo cho tôi khi nào các quyền người dùng của tôi được thay đổi.",
+ "echo-no-agent": "[Không ai]",
+ "echo-no-title": "[Không có trang]",
+ "echo-error-no-formatter": "Thông báo không có định rõ định dạng",
+ "echo-error-preference": "Lỗi: Không thể đặt tùy chọn",
+ "echo-error-token": "Lỗi: Không thể lấy dấu hiệu người dùng.",
+ "notifications": "Thông báo",
+ "tooltip-pt-notifications": "Các thông báo cho bạn",
+ "echo-specialpage": "Thông báo",
+ "echo-anon": "Để nhận thông báo, hãy [$1 mở tài khoản] hoặc [$2 đăng nhập].",
+ "echo-none": "Bạn không có thông báo.",
+ "echo-more-info": "Thêm thông tin",
+ "echo-feedback": "Phản hồi",
+ "echo-quotation-marks": "“$1”",
+ "notification-link-text-view-message": "Xem thông điệp",
+ "notification-link-text-view-mention": "Xem lời nói đến bạn",
+ "notification-link-text-view-changes": "Xem các thay đổi",
+ "notification-link-text-view-page": "Xem trang",
+ "notification-link-text-view-edit": "Xem sửa đổi",
+ "notification-edit-talk-page2": "[[User:$1|$1]] đã nhắn tin vào [[User talk:$2#$3|trang thảo luận]] của bạn.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] đã {{GENDER:$1}}nhắn tin cho bạn trong “[[User talk:$2#$3|$4]]”.",
+ "notification-edit-talk-page-flyout2": "$1 đã nhắn tin vào [[User talk:$2#$3|trang thảo luận]] của bạn.",
+ "notification-edit-talk-page-flyout-with-section": "$1 đã {{GENDER:$1}}nhắn tin cho bạn trong “[[User talk:$2#$3|$4]]”.",
+ "notification-page-linked": "[[:$3]] mới {{GENDER:$1}}có liên kết đến [[:$2]]. [[Special:WhatLinksHere/$2|Xem tất cả các liên kết đến trang này]].",
+ "notification-page-linked-flyout": "[[:$3]] mới {{GENDER:$1}}có liên kết đến [[:$2]]",
+ "notification-add-comment2": "[[User:$1|$1]] đã bình luận về “[[$3|$2]]” tại trang thảo luận “$4”",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] đã bắt đầu cuộc thảo luận mới về “$2” tại [[$3]]",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] đã nhắn tin cho bạn: “[[$3#$2|$2]]”",
+ "notification-add-comment-yours2": "[[User:$1|$1]] đã bình luận về “[[$3#$2|$2]]” tại trang thảo luận của bạn",
+ "notification-mention": "[[User:$1|$1]] đã nói đến bạn trên trang tin nhắn của $5 trong “[[:$3#$2|$4]]”.",
+ "notification-mention-flyout": "$1 đã nói đến bạn trên trang tin nhắn của $5 trong “[[:$3#$2|$4]]”.",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1}}đã nói đến bạn trên [[:$3|trang thảo luận $2]].",
+ "notification-mention-nosection-flyout": "$1 {{GENDER:$1}}đã nói đến bạn trên [[:$3|trang thảo luận $2]].",
+ "notification-user-rights": "[[User:$1|$1]] {{GENDER:$1}}đã [[Special:Log/rights/$1|thay đổi]] các quyền người dùng của bạn. $2. [[Special:ListGroupRights|Tìm hiểu thêm]]",
+ "notification-user-rights-flyout": "$1 {{GENDER:$1}}đã thay đổi các quyền người dùng của bạn. $2. [[Special:ListGroupRights|Tìm hiểu thêm]]",
+ "notification-user-rights-add": "Bạn mới là thành viên của {{PLURAL:$2|nhóm|các nhóm}} này: $1",
+ "notification-user-rights-remove": "Bạn không còn là thành viên của {{PLURAL:$2|nhóm|các nhóm}} này: $1",
+ "notification-new-user": "Chào mừng $1 đã đến với {{SITENAME}}!",
+ "notification-reverted2": "[[User:$1|$1]] đã lùi lại {{PLURAL:$4|sửa đổi|các sửa đổi}} của bạn tại [[:$2]] $3",
+ "notification-reverted-flyout2": "$1 đã lùi lại {{PLURAL:$4|sửa đổi|các sửa đổi}} của bạn tại $2 $3",
+ "notification-edit-talk-page-email-subject2": "$1 đã {{GENDER:$1}}nhắn tin cho bạn trên {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 đã nhắn tin vào trang thảo luận của bạn:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 đã {{GENDER:$1}}nhắn tin cho bạn trong “$2”.",
+ "notification-page-linked-email-subject": "Có liên kết mới đến một trang do bạn tạo ra tại {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$3 mới {{GENDER:$1}}có liên kết đến $2",
+ "notification-reverted-email-subject2": "{{PLURAL:$3|Sửa đổi|Các sửa đổi}} của bạn đã bị {{GENDER:$1}}lùi lại trên {{SITENAME}}",
+ "notification-reverted-email-batch-body2": "$1 đã lùi lại {{PLURAL:$3|sửa đổi|các sửa đổi}} của bạn tại $2",
+ "notification-mention-email-subject": "$1 đã nói đến bạn tại {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 đã nói đến bạn trên trang tin nhắn của $4 trong “$3”",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1}}đã nói đến bạn trên trang thảo luận $2.",
+ "notification-user-rights-email-subject": "Các quyền người dùng của bạn đã thay đổi tại {{SITENAME}}",
+ "notification-user-rights-email-batch-body": "$1 {{GENDER:$1}}đã thay đổi các quyền người dùng của bạn. $2",
+ "echo-email-subject-default": "Thông báo mới tại {{SITENAME}}",
+ "echo-email-body-default": "Bạn có thông báo mới tại {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "Bạn có thông báo mới",
+ "echo-email-footer-default": "$2\n\nĐể cấu hình hoặc tắt các thông báo qua thư điện tử, hãy xem tùy chọn của bạn:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "Để kiểm soát các thư điện tử mà chúng tôi gửi cho bạn, hãy <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">kiểm tra tùy chọn của bạn</a>.<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|Tin nhắn ($1)|100=Tin nhắn (99+)}}",
+ "echo-notification-message": "{{PLURAL:$1|Thông điệp ($1)|100=Thông điệp (99+)}}",
+ "echo-notification-alert-text-only": "Tin nhắn",
+ "echo-notification-message-text-only": "Thông điệp",
+ "echo-overlay-link": "Tất cả các thông báo",
+ "echo-overlay-title": "<b>Thông báo</b>",
+ "echo-overlay-title-overflow": "<b>Tin nhắn</b> (đang xem $1 trên $2 chưa đọc)",
+ "echo-mark-all-as-read": "Đánh dấu tất cả là đã đọc",
+ "echo-date-today": "Hôm nay",
+ "echo-date-yesterday": "Hôm qua",
+ "echo-load-more-error": "Lỗi đã xảy ra khi lấy thêm kết quả.",
+ "notification-edit-talk-page-bundle": "$1 và $3 {{PLURAL:$4}}người khác đã {{GENDER:$1}}nhắn tin vào [[User talk:$2|trang thảo luận]] của bạn.",
+ "notification-page-linked-bundle": "$3 và $4 {{PLURAL:$5}}trang khác mới {{GENDER:$1}}có liên kết đến $2. [[Special:WhatLinksHere/$2|Xem tất cả các liên kết đến trang này]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 và $2 {{PLURAL:$3}}người khác {{GENDER:$1}}đã nhắn tin vào trang thảo luận của bạn",
+ "notification-page-linked-email-batch-bundle-body": "$3 và $4 {{PLURAL:$5}}trang khác {{GENDER:$1}}mới có liên kết đến $2",
+ "echo-email-batch-subject-daily": "Bạn có {{PLURAL:$2|một tin nhắn|các tin nhắn}} mới hôm nay trên {{SITENAME}}",
+ "echo-email-batch-subject-weekly": "Bạn có {{PLURAL:$2|thông báo|các thông báo}} mới trên {{SITENAME}} tuần này",
+ "echo-email-batch-body-intro-daily": "Chào $1,\nĐây là bản tóm tắt các chuyện xảy ra hôm nay trên {{SITENAME}}.",
+ "echo-email-batch-body-intro-weekly": "Chào $1,\nĐây là bản tóm tắt các chuyện xảy ra vào tuần này trên {{SITENAME}}.",
+ "echo-email-batch-link-text-view-all-notifications": "Xem tất cả thông báo",
+ "echo-rev-deleted-text-view": "Phiên bản trang này đã bị ẩn",
+ "apihelp-echomarkread-param-list": "Danh sách các ID thông báo để đánh dấu là đã đọc.",
+ "apihelp-echomarkread-example-2": "Đánh dấu tất cả thông báo là đã đọc",
+ "apihelp-query+notifications-param-prop": "Chi tiết để yêu cầu.",
+ "apihelp-query+notifications-example-1": "Danh sách thông báo"
+}
diff --git a/Echo/i18n/vo.json b/Echo/i18n/vo.json
new file mode 100644
index 00000000..d5fc5e67
--- /dev/null
+++ b/Echo/i18n/vo.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Malafaya"
+ ]
+ },
+ "prefs-echo": "Nunäds",
+ "echo-pref-send-me": "Sedön obe:",
+ "echo-new-messages": "Labol nunis nulik",
+ "notifications": "Nunäds",
+ "echo-specialpage": "Nunäds"
+}
diff --git a/Echo/i18n/yi.json b/Echo/i18n/yi.json
new file mode 100644
index 00000000..4f77cced
--- /dev/null
+++ b/Echo/i18n/yi.json
@@ -0,0 +1,84 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער"
+ ]
+ },
+ "echo-desc": "נאטיפֿיקאציע סיסטעם",
+ "prefs-echo": "אנזאגן",
+ "prefs-emailsettings": "ע־פאסט אפציעס",
+ "prefs-displaynotifications": "ווײַזן אפציעס",
+ "prefs-echosubscriptions": "זיי מיך מודיע וועגן די דאזיקע געשעענישן",
+ "prefs-newmessageindicator": "נייער אנזאג ווייזער",
+ "echo-pref-send-me": "שיקט מיר:",
+ "echo-pref-send-to": "שיקט צו:",
+ "echo-pref-email-format": "ע־פאסט פֿארמאט",
+ "echo-pref-web": "וועב",
+ "echo-pref-email": "ע-פאסט",
+ "echo-pref-email-frequency-never": "שיקט מיר נישט קיין ע־פאסט אנזאגן",
+ "echo-pref-email-frequency-immediately": "איינציקע אנזאגן ווען זיי קו מען אן",
+ "echo-pref-email-frequency-daily": "א טעגליכע רעזומע פון אנזאגן",
+ "echo-pref-email-frequency-weekly": "א וועכנטלעכע רעזומע פון אנזאגן",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "פשוטער טעקסט",
+ "echo-pref-notify-show-link": "ווײַזן אנזאגן אין מײַן געצייגפאס",
+ "echo-pref-new-message-indicator": "ווײַזן רעדן־בלאט מעלדונג סימן אין מײַן געצייג פאס",
+ "echo-learn-more": "לערנען נאך",
+ "echo-new-messages": "איר האט נייע מעלדונגען",
+ "echo-category-title-edit-user-talk": "שמועס בלאט {{PLURAL:$1|מעלדונג|מעלדונגען}}",
+ "echo-category-title-article-linked": "בלאט {{PLURAL:$1|לינק|לינקען}}",
+ "echo-category-title-reverted": "רעדאקטירן {{PLURAL:$1|צוריקמאכונג|צוריקמאכונגען}}",
+ "echo-category-title-mention": "{{PLURAL:$1|דערמאנונג|דערמאנונגען}}",
+ "echo-category-title-other": "{{PLURAL:$1|אנדערע}}",
+ "echo-category-title-system": "{{PLURAL:$1|סיסטעם}}",
+ "echo-pref-tooltip-edit-user-talk": "זיי מיך מודיע ווען עמעצער שיקט א מעלדונג אדער ענטפערט אויף מיין שמועס בלאט.",
+ "echo-pref-tooltip-article-linked": "מים מודיע זײַן ווען איינער פארבינדט זיך צו א בלאט וואס איך האב געשאפן פון אן ארטיקל בלאט.",
+ "echo-pref-tooltip-mention": "מיך מודיע זײַן ווען איינער פארבינדט זיך צו מײַן באניצער־בלאט.",
+ "echo-no-agent": "[קיינער]",
+ "echo-no-title": "[קיין בלאט]",
+ "echo-error-no-formatter": "קיין פארמאטירונג נישט דעפינירט פאר דער הודעה.",
+ "echo-error-preference": "פעלער: נישט געווען מעגלעך צו שטעלן באניצער פרעפערענץ.",
+ "notifications": "אנזאגן",
+ "tooltip-pt-notifications": "אײַערע אנזאגן",
+ "echo-specialpage": "אנזאגן",
+ "echo-anon": "כדי צו באקומען הודעות, [$1 שאפט א קאנטע] אדער [$2 לאגירט אריין].",
+ "echo-none": "איר האט נישט קיין אנזאגן.",
+ "echo-more-info": "נאך אינפארמאציע",
+ "echo-feedback": "פֿידבעק",
+ "notification-link-text-view-message": "באקוקן מעלדונג",
+ "notification-link-text-view-changes": "באקוקן ענדערונגען",
+ "notification-link-text-view-page": "באקוקן בלאט",
+ "notification-link-text-view-edit": "באקוקן רעדאקטירונג",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|האט געלאזט}} א מעלדונג אויף אײַער [[User talk:$2#$3|שמועס בלאט]].",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|האט געלאזט}} א מעלדונג אויף אייער שמועס בלאט ביי \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|האט געלאזט}} א מעלדונג אויף אײַער [[User talk:$2#$3|שמועס בלאט]].",
+ "notification-edit-talk-page-flyout-with-section": "$1 {{GENDER:$1|האט געלאזט}} א מעלדונג אויף אייער שמועס בלאט ביי \"[[User talk:$2#$3|$4]]\".",
+ "notification-page-linked": "[[:$2]] איז געווארן {{GENDER:$1|פארלינקט}} פון [[:$3]]. [[Special:WhatLinksHere/$2|זען אלע לינקען צו דעם בלאט]].",
+ "notification-page-linked-flyout": "[[:$2]] איז געווארן {{GENDER:$1|פֿאַרלינקט}} פֿון [[:$3]].",
+ "notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|האט געלאזט א הערה}} וועגן \"[[$3|$2]]\" אויפן \"$4\" רעדן בלאט.",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|האט}} אײַך געשיקט אן אנזאג: \"[[$3#$2|$2]]\".",
+ "notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|האט געלאזט א הערה}} וועגן \"[[$3#$2|$2]]\" אויף אײַער רעדן בלאט.",
+ "notification-mention": "[[User:$1|$1]] {{GENDER:$1|האט אײַך דערמאנט}} אויפן $5 רעדן בלאט אין \"[[:$3#$2|$4]]\".",
+ "notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|האט אײַך דערמאנט}} אויפן [[:$3|$2 רעדן בלאט]].",
+ "notification-user-rights-add": "איר זענט יעצט א מיטגליד פון {{PLURAL:$2|די גרופע |די גרופעס}}: $1",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|האט אייך געשריבן}} א נייע מעלדונג אינעם {{SITENAME}} וועבזייטל",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|האט געשריבן}} א מעלדונג אין אײַער רעדן בלאַט:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|האט געלאזט}} א מעלדונג אין אײַער רעדן בלאַט אין \"$2\".",
+ "notification-page-linked-email-subject": "אײַער בלאט איז געווארן פֿאַרלינקט אויף {{SITENAME}}",
+ "notification-page-linked-email-batch-body": "$2 איז געווארן {{GENDER:$1| פֿאַרלינקט}} פֿון $3.",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|האט אײַך דערמאנט}} אויף {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|האט אײַך דערמאנט}} אויפן $4 רעדן בלאט אין \"$3\".",
+ "echo-email-subject-default": "נײַער אנזאג בײַ {{SITENAME}}",
+ "echo-email-body-default": "איר האט א נײַעם אנזאג בײַ {{SITENAME}}:\n\n$1",
+ "echo-email-batch-body-default": "איר האט א נײַעם אנזאג.",
+ "echo-overlay-link": "אלע הודעות",
+ "echo-overlay-title": "<b>הודעות</b>",
+ "echo-mark-all-as-read": "מאַרקירן אַלע געליינט",
+ "echo-date-today": "הײַנט",
+ "echo-date-yesterday": "נעכטן",
+ "notification-edit-talk-page-bundle": "$1 און $3 {{PLURAL:$4|אנדערער|אנדערע}} {{GENDER:$1|האבן געלאזט}} אן אנזאג אויף אייער [[User talk:$2|רעדן בלאט]].",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 און $2 {{PLURAL:$3|אנדערער|אנדערע}} {{GENDER:$1|האבן געלאזט}} אן אנזאג אויף אייער רעדן בלאט.",
+ "notification-page-linked-email-batch-bundle-body": "$2 איז געווארן {{GENDER:$1|געלינקט}} פון $3 און $4 {{PLURAL:$5|אנדער בלאט|אנדערע בלעטער}}.",
+ "echo-email-batch-link-text-view-all-notifications": "ווײַזן אלע אנזאגן",
+ "echo-rev-deleted-text-view": "די בלאט־ווערסיע איז געווארן אונטערדרוקט."
+}
diff --git a/Echo/i18n/yo.json b/Echo/i18n/yo.json
new file mode 100644
index 00000000..2c3acb48
--- /dev/null
+++ b/Echo/i18n/yo.json
@@ -0,0 +1,34 @@
+{
+ "@metadata": {
+ "authors": [
+ "Demmy"
+ ]
+ },
+ "notifications": "Àwọn ìdálákìíyèsí",
+ "tooltip-pt-notifications": "Àwọn ìdálákìíyèsí yín",
+ "echo-specialpage": "Àwọn ìdálákìíyèsí",
+ "echo-none": "Ẹ kò ní ìdálákìíyèsí kankan.",
+ "notification-link-text-view-message": "Ìgbéwò ìránṣẹ́",
+ "notification-link-text-view-mention": "Ìgbéwò ìdárúkọ",
+ "notification-link-text-view-changes": "Ìgbéwò àwọn àtúnṣe tuntun",
+ "notification-link-text-view-page": "Ìgbéwò ojúewé",
+ "notification-link-text-view-edit": "Ìgbéwò àtúnṣe",
+ "notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|fi}} ìránṣẹ́ s'órí [[User talk:$2#$3|ojúewé ọ̀rọ̀]] yín.",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|fi}} ìránṣẹ́ s'órí ojúewé ọ̀rọ̀ yín ní \"[[User talk:$2#$3|$4]]\".",
+ "notification-edit-talk-page-flyout2": "$1 {{GENDER:$1|fi}} ìránṣẹ́ sí [[User talk:$2#$3|ojúewé ọ̀rọ̀]] yín.",
+ "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|fi}} ìránṣẹ́ fún yín lórí {{SITENAME}}",
+ "notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|fi}} ìránṣẹ́ s'órí ojúewé ọ̀rọ̀ yín:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|fi}} ìránṣẹ́ s'órí ojúewé ọ̀rọ̀ yín ní \"$2\".",
+ "notification-mention-email-subject": "$1 {{GENDER:$1|dárúkọ}} yín lórí {{SITENAME}}",
+ "notification-mention-email-batch-body": "$1 {{GENDER:$1|dárúkọ}} yín lórí ojúewé ọ̀rọ̀ $4 nínú \"$3\".",
+ "notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|dárúkọ}} yín lórí ojúewé ọ̀rọ̀ $2.",
+ "echo-email-subject-default": "Ìdálákìíyèsí tuntun wà ní {{SITENAME}}",
+ "echo-email-body-default": "Ẹ ní ìdálákìíyèsí tuntun ní {{SITENAME}}:\n\n\n$1",
+ "echo-email-batch-body-default": "Ẹ ní ìdálákìíyèsí tuntun.",
+ "echo-overlay-link": "Gbogbo ìdálákìíyèsí",
+ "echo-overlay-title": "<b>Àwọn ìdálákìíyèsí</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|Àwọn ìdálákìíyèsí}}</b> (ìhàn $1 nínú $2 àìtíìkà)",
+ "echo-date-today": "Òní",
+ "echo-date-yesterday": "Àná",
+ "echo-email-batch-link-text-view-all-notifications": "Ìgbéwò gbogbo ìdálákìíyèsí"
+}
diff --git a/Echo/i18n/yue.json b/Echo/i18n/yue.json
new file mode 100644
index 00000000..ef90224c
--- /dev/null
+++ b/Echo/i18n/yue.json
@@ -0,0 +1,67 @@
+{
+ "@metadata": {
+ "authors": [
+ "William915",
+ "Wong128hk"
+ ]
+ },
+ "echo-desc": "通知系統",
+ "prefs-echo": "通知",
+ "prefs-emailsettings": "電郵選項",
+ "prefs-displaynotifications": "顯示選項",
+ "prefs-echosubscriptions": "通知選項",
+ "prefs-newmessageindicator": "新留言提示",
+ "echo-pref-send-me": "幾耐電郵通知一次",
+ "echo-pref-send-to": "發畀:",
+ "echo-pref-email-format": "郵件格式︰",
+ "echo-pref-web": "網頁",
+ "echo-pref-email": "電郵",
+ "echo-pref-email-frequency-never": "唔使出電郵通知",
+ "echo-pref-email-frequency-immediately": "每樣都即時通知",
+ "echo-pref-email-frequency-daily": "一日出一次",
+ "echo-pref-email-frequency-weekly": "一個禮拜出一次",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "純文字",
+ "echo-pref-notify-show-link": "喺工具列道出通知",
+ "echo-pref-new-message-indicator": "喺工具列道出新留言提示",
+ "echo-learn-more": "了解多啲",
+ "echo-new-messages": "你有新信",
+ "echo-category-title-edit-user-talk": "傾偈版{{PLURAL:$1|新信}}",
+ "echo-category-title-article-linked": "{{PLURAL:$1|連}}到我開嘅版",
+ "echo-category-title-reverted": "將我嘅修改{{PLURAL:$1|打回頭}}",
+ "echo-category-title-mention": "{{PLURAL:$1|提到}}我",
+ "echo-category-title-other": "{{PLURAL:$1|其他}}",
+ "echo-category-title-system": "{{PLURAL:$1|系統}}",
+ "echo-pref-tooltip-edit-user-talk": "有人喺我傾偈版留信或者回覆,話我知。",
+ "echo-pref-tooltip-article-linked": "有人喺文章連過去我開嘅版,話我知",
+ "echo-pref-tooltip-reverted": "有人將我嘅修改打回頭,話我知。",
+ "echo-pref-tooltip-mention": "有人喺任何傾偈頁提及我嘅用戶頁,話我知。",
+ "echo-error-no-formatter": "無預定通知格式",
+ "echo-error-preference": "出錯︰設定唔到用戶喜好。",
+ "echo-error-token": "出錯︰攞唔到用戶保安編碼。",
+ "notifications": "通知",
+ "tooltip-pt-notifications": "你嘅通知",
+ "echo-specialpage": "通知",
+ "echo-anon": "要收到通知嘅話,就[$1 開戶]或者[$2 簽到]啦。",
+ "echo-none": "爾家無通知畀你",
+ "echo-more-info": "知多啲",
+ "echo-feedback": "反饋",
+ "notification-link-text-view-message": "去睇信息",
+ "notification-link-text-view-mention": "去睇下講啲咩",
+ "notification-link-text-view-changes": "去睇改咗啲乜",
+ "notification-link-text-view-page": "去睇嗰頁",
+ "notification-link-text-view-edit": "去睇改咗啲乜",
+ "notification-edit-talk-page2": "[[User:$1|$1]]喺你[[User talk:$2#$3|傾偈版]]道{{GENDER:$1|留}}咗個訊息。",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]]喺你傾偈版小節「[[User talk:$2#$3|$4]]」道{{GENDER:$1|留}}咗個訊息。",
+ "notification-edit-talk-page-flyout2": "$1喺你[[User talk:$2#$3|傾偈版]]道{{GENDER:$1|留}}咗個訊息。",
+ "notification-edit-talk-page-flyout-with-section": "$1喺你傾偈版小節「[[User talk:$2#$3|$4]]」道{{GENDER:$1|留}}咗個訊息。",
+ "notification-page-linked": "[[:$3]]道有連結{{GENDER:$1|連}}過去[[:$2]]。 [[Special:WhatLinksHere/$2|睇嗮有乜連過去]]",
+ "notification-page-linked-flyout": "[[:$3]]道有連結{{GENDER:$1|連}}過去[[:$2]]。",
+ "notification-add-comment2": "[[User:$1|$1]]喺「$4」傾偈頁小節「[[$3|$2]]」道{{GENDER:$1|發}}咗個意見。",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]]喺[[$3]]道{{GENDER:$1|開}}咗個小節「$2」。",
+ "echo-email-batch-body-default": "你有新通知",
+ "echo-mark-all-as-read": "全部標做讀過",
+ "echo-date-today": "今日",
+ "echo-date-yesterday": "尋日",
+ "echo-rev-deleted-text-view": "爾次修改收埋咗"
+}
diff --git a/Echo/i18n/zh-hans.json b/Echo/i18n/zh-hans.json
new file mode 100644
index 00000000..efb8be28
--- /dev/null
+++ b/Echo/i18n/zh-hans.json
@@ -0,0 +1,160 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia",
+ "Byfserag",
+ "Chiefwei",
+ "Cwek",
+ "Dimension",
+ "Fantasticfears",
+ "GeneralNFS",
+ "Hydra",
+ "Hzy980512",
+ "Kuailong",
+ "Li3939108",
+ "Liangent",
+ "Linforest",
+ "Liuxinyu970226",
+ "Qiyue2001",
+ "Shirayuki",
+ "Shizhao",
+ "StephDC",
+ "TianyinLee",
+ "Xiaomingyan",
+ "Xingzhe",
+ "Yfdyh000",
+ "乌拉跨氪",
+ "Mywood",
+ "Impersonator 1"
+ ]
+ },
+ "echo-desc": "通知系统",
+ "prefs-echo": "通知",
+ "prefs-emailsettings": "电子邮件选项",
+ "prefs-displaynotifications": "显示选项",
+ "prefs-echosubscriptions": "通知我这些事件",
+ "prefs-newmessageindicator": "新消息提示器",
+ "echo-pref-send-me": "给我发送:",
+ "echo-pref-send-to": "发送至:",
+ "echo-pref-email-format": "电子邮件格式:",
+ "echo-pref-web": "网页",
+ "echo-pref-email": "电子邮件",
+ "echo-pref-email-frequency-never": "不要给我发送任何电子邮件通知",
+ "echo-pref-email-frequency-immediately": "每一新事件都单独通知",
+ "echo-pref-email-frequency-daily": "每日一次通知摘要",
+ "echo-pref-email-frequency-weekly": "每周一次通知摘要",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "纯文本",
+ "echo-pref-notify-show-link": "在我的工具栏中显示通知",
+ "echo-pref-new-message-indicator": "在我的工具栏中显示讨论页留言提示器",
+ "echo-learn-more": "了解详情",
+ "echo-new-messages": "您有新留言",
+ "echo-category-title-edit-user-talk": "讨论页{{PLURAL:$1|留言}}",
+ "echo-category-title-article-linked": "页面{{PLURAL:$1|链接}}",
+ "echo-category-title-reverted": "编辑{{PLURAL:$1|还原}}",
+ "echo-category-title-mention": "{{PLURAL:$1|提及}}",
+ "echo-category-title-other": "{{PLURAL:$1|其他}}",
+ "echo-category-title-system": "{{PLURAL:$1|系统}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|用户权限更改}}",
+ "echo-pref-tooltip-edit-user-talk": "当有人在我的讨论页上留言或回复时通知我。",
+ "echo-pref-tooltip-article-linked": "当有人在条目中链接了我创建的页面时通知我。",
+ "echo-pref-tooltip-reverted": "当有人用撤销或回退工具还原了我的编辑时通知我。",
+ "echo-pref-tooltip-mention": "当有人链接我的用户页时通知我。",
+ "echo-pref-tooltip-user-rights": "当有人更新我的用户权限时通知我。",
+ "echo-no-agent": "[匿名]",
+ "echo-no-title": "[无页面]",
+ "echo-error-no-formatter": "未指定通知格式",
+ "echo-error-preference": "出错:无法设定用户设置。",
+ "echo-error-token": "出错:无法检索用户令牌。",
+ "notifications": "通知",
+ "tooltip-pt-notifications": "您的通知",
+ "echo-specialpage": "通知",
+ "echo-anon": "想要接收通知,请[$1 创建账户]或[$2 登录]。",
+ "echo-none": "您没有通知。",
+ "echo-more-info": "更多信息",
+ "echo-feedback": "反馈",
+ "echo-quotation-marks": "“$1”",
+ "notification-link-text-view-message": "查看留言",
+ "notification-link-text-view-mention": "查看提及",
+ "notification-link-text-view-changes": "查看更改",
+ "notification-link-text-view-page": "查看页面",
+ "notification-link-text-view-edit": "查看编辑",
+ "notification-edit-talk-page2": "[[User:$1|$1]]在您的[[User talk:$2#$3|讨论页]]留言了。",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]]在您的讨论页的“[[User talk:$2#$3|$4]]”段落{{GENDER:$1|留言}}了。",
+ "notification-edit-talk-page-flyout2": "$1在您的[[User talk:$2#$3|讨论页]]{{GENDER:$1|留言}}了。",
+ "notification-edit-talk-page-flyout-with-section": "$1在您的讨论页的“[[User talk:$2#$3|$4]]”段落{{GENDER:$1|留言}}了。",
+ "notification-page-linked": "[[:$3]]{{GENDER:$1|链接}}了[[:$2]]。[[Special:WhatLinksHere/$2|查看所有链至该页的页面]]。",
+ "notification-page-linked-flyout": "[[:$2]]被[[:$3]]{{GENDER:$1|链接}}。",
+ "notification-add-comment2": "[[User:$1|$1]]在“$4”的讨论页面的“[[$3|$2]]”段落{{GENDER:$1|发表意见}}。",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]]在[[$3]]上发起了新话题“$2”",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]]给您发来一则信息:“[[$3#$2|$2]]”。",
+ "notification-add-comment-yours2": "[[User:$1|$1]]在您的讨论页的“[[$3#$2|$2]]”段落{{GENDER:$1|发表意见}}。",
+ "notification-mention": "[[User:$1|$1]]在$5的讨论页的“[[:$3#$2|$4]]”段落{{GENDER:$1|提到}}了您。",
+ "notification-mention-flyout": "$1在$5的讨论页的“[[:$3#$2|$4]]”段落{{GENDER:$1|提到}}了您。",
+ "notification-mention-nosection": "[[User:$1|$1]]在[[:$3|$2的讨论页]]提到了您。",
+ "notification-mention-nosection-flyout": "$1在[[:$3|$2的讨论页]]提到了您。",
+ "notification-user-rights": "您的用户权限被[[User:$1|$1]][[Special:Log/rights/$1|更改了]]。$2。[[Special:ListGroupRights|了解更多]]",
+ "notification-user-rights-flyout": "您的用户权限被$1{{GENDER:$1|更改了}}。$2。[[Special:ListGroupRights|了解更多]]",
+ "notification-user-rights-add": "您被添加至该{{PLURAL:$2|用户组}}:$1",
+ "notification-user-rights-remove": "您被从该{{PLURAL:$2|用户组}}中移除:$1",
+ "notification-new-user": "欢迎来到{{SITENAME}},$1!",
+ "notification-reverted2": "您对[[:$2]]的{{PLURAL:$4|编辑}}被[[User:$1|$1]]{{GENDER:$1|还原了}}。$3",
+ "notification-reverted-flyout2": "您对$2的{{PLURAL:$4|编辑}}被$1{{GENDER:$1|还原了}}。$3",
+ "notification-edit-talk-page-email-subject2": "$1在{{SITENAME}}给您{{GENDER:$1|留言}}了",
+ "notification-edit-talk-page-email-batch-body2": "$1在您的讨论页{{GENDER:$1|留言}}了:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1在您的讨论页的“$2”段落{{GENDER:$1|留言}}了。",
+ "notification-page-linked-email-subject": "你在{{SITENAME}}创建的页面被链接",
+ "notification-page-linked-email-batch-body": "$2被$3{{GENDER:$1|链接}}。",
+ "notification-reverted-email-subject2": "你在{{SITENAME}}的{{PLURAL:$3|编辑}}被{{GENDER:$1|还原了}}",
+ "notification-reverted-email-batch-body2": "你{{PLURAL:$3|对$2的编辑}}被$1{{GENDER:$1|还原了}}。",
+ "notification-mention-email-subject": "$1在{{SITENAME}}{{GENDER:$1|提到}}了您",
+ "notification-mention-email-batch-body": "$1在$4的讨论页的“$3”段落{{GENDER:$1|提到}}了您。",
+ "notification-mention-nosection-email-batch-body": "$1在$2的讨论页提到了您。",
+ "notification-user-rights-email-subject": "您在{{SITENAME}}的用户权限已被更改",
+ "notification-user-rights-email-batch-body": "您的用户权限被$1{{GENDER:$1|更改}}。$2。",
+ "echo-email-subject-default": "{{SITENAME}}的新通知",
+ "echo-email-body-default": "你在{{SITENAME}}有新通知:\n\n$1",
+ "echo-email-batch-body-default": "您有新的通知。",
+ "echo-email-footer-default": "$2\n\n要管理我们给你发送的电子邮件,请更改您的设置:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "要管理我们给你发送的电子邮件,请<a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">更改您的设置</a>。<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|$1条提醒|100=超过99条提醒}}",
+ "echo-notification-message": "{{PLURAL:$1|$1条消息|100=超过99条消息}}",
+ "echo-notification-alert-text-only": "提醒",
+ "echo-notification-message-text-only": "消息",
+ "echo-overlay-link": "所有通知",
+ "echo-overlay-title": "<b>通知</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|通知}}</b>(显示$2条未读通知中的$1条)",
+ "echo-mark-all-as-read": "标记所有为已读",
+ "echo-date-today": "今天",
+ "echo-date-yesterday": "昨天",
+ "echo-load-more-error": "获取更多结果时出错。",
+ "notification-edit-talk-page-bundle": "$1及{{PLURAL:$4|另外}}$3位用户在您的[[User talk:$2|讨论页]]{{GENDER:$1|留言}}了。",
+ "notification-page-linked-bundle": "$2被$3和另外$4个{{PLURAL:$5|页面}}{{GENDER:$1|链接}}。[[Special:WhatLinksHere/$2|查看链至该页的所有页面]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1和{{PLURAL:$3|另外}}$2位用户在您的讨论页{{GENDER:$1|留言}}了。",
+ "notification-page-linked-email-batch-bundle-body": "$2被$3和另外$4个{{PLURAL:$5|页面}}{{GENDER:$1|链接}}。",
+ "echo-email-batch-subject-daily": "您在{{SITENAME}}有{{PLURAL:$2|新通知}}",
+ "echo-email-batch-subject-weekly": "您本周在{{SITENAME}}有{{PLURAL:$2|新通知}}",
+ "echo-email-batch-body-intro-daily": "嗨,$1,\n这是今天您在{{SITENAME}}的通知摘要。",
+ "echo-email-batch-body-intro-weekly": "$1,\n这是本周您在{{SITENAME}}的通知摘要。",
+ "echo-email-batch-link-text-view-all-notifications": "查看所有通知",
+ "echo-rev-deleted-text-view": "此页面版本已被隐藏。",
+ "apihelp-echomarkread-description": "对当前用户标记通知为已读。",
+ "apihelp-echomarkread-param-list": "要标记已读的通知ID列表。",
+ "apihelp-echomarkread-param-all": "如果设置,标记一位用户的所有通知为已读。",
+ "apihelp-echomarkread-param-sections": "要标记为已读的部分列表。",
+ "apihelp-echomarkread-example-1": "标记通知8为已读",
+ "apihelp-echomarkread-example-2": "标记所有通知为已读",
+ "apihelp-query+notifications-description": "获取当前用户等待的通知。",
+ "apihelp-query+notifications-param-prop": "请求的细节。",
+ "apihelp-query+notifications-param-sections": "要查询的通知部分。",
+ "apihelp-query+notifications-param-groupbysection": "是否按章节分组结果。如果设置,将分别获取每个章节。",
+ "apihelp-query+notifications-param-format": "如果指定,通知将以此格式返回。",
+ "apihelp-query+notifications-param-limit": "返回通知的最大数量。",
+ "apihelp-query+notifications-param-index": "如果指定,将返回一个按顺序的通知ID列表。",
+ "apihelp-query+notifications-param-alertcontinue": "当有更多警告结果可用时,使用这个继续。",
+ "apihelp-query+notifications-param-alertunreadfirst": "是否首先显示未读的消息通知。",
+ "apihelp-query+notifications-param-messagecontinue": "当有更多消息结果可用时,使用这个继续。",
+ "apihelp-query+notifications-param-messageunreadfirst": "是否首先显示未读的警告通知。",
+ "apihelp-query+notifications-example-1": "通知列表",
+ "apihelp-query+notifications-example-2": "列出通知,按节分组,带有数量"
+}
diff --git a/Echo/i18n/zh-hant.json b/Echo/i18n/zh-hant.json
new file mode 100644
index 00000000..8ae88786
--- /dev/null
+++ b/Echo/i18n/zh-hant.json
@@ -0,0 +1,129 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ch.Andrew",
+ "Chiefwei",
+ "Fantasticfears",
+ "Justincheng12345",
+ "Kevinhksouth",
+ "Liflon",
+ "Littletung",
+ "Liuxinyu970226",
+ "Shirayuki",
+ "Simon Shek",
+ "Waihorace",
+ "Wong128hk",
+ "LNDDYL",
+ "Cwlin0416"
+ ]
+ },
+ "echo-desc": "通知系統",
+ "prefs-echo": "通知",
+ "prefs-emailsettings": "電子郵件選項",
+ "prefs-displaynotifications": "顯示選項",
+ "prefs-echosubscriptions": "通知我這些事件",
+ "prefs-newmessageindicator": "新訊息指示器",
+ "echo-pref-send-me": "傳送給我:",
+ "echo-pref-send-to": "傳送至:",
+ "echo-pref-email-format": "電子郵件格式:",
+ "echo-pref-web": "網頁",
+ "echo-pref-email": "Email",
+ "echo-pref-email-frequency-never": "不要傳送任何信件通知",
+ "echo-pref-email-frequency-immediately": "個別通知發生事件時的訊息",
+ "echo-pref-email-frequency-daily": "每日通知摘要",
+ "echo-pref-email-frequency-weekly": "每週通知摘要",
+ "echo-pref-email-format-html": "HTML",
+ "echo-pref-email-format-plain-text": "純文字",
+ "echo-pref-notify-show-link": "在工具列中顯示通知",
+ "echo-pref-new-message-indicator": "在工具列中顯示對話頁面訊息提示工具",
+ "echo-learn-more": "瞭解更多",
+ "echo-new-messages": "您有新訊息",
+ "echo-category-title-edit-user-talk": "對話頁面{{PLURAL:$1|訊息}}",
+ "echo-category-title-article-linked": "頁面{{PLURAL:$1|連結}}",
+ "echo-category-title-reverted": "編輯{{PLURAL:$1|還原}}",
+ "echo-category-title-mention": "{{PLURAL:$1|提到}}",
+ "echo-category-title-other": "{{PLURAL:$1|其他}}",
+ "echo-category-title-system": "{{PLURAL:$1|系統}}",
+ "echo-category-title-user-rights": "{{PLURAL:$1|使用者權限更改}}",
+ "echo-pref-tooltip-edit-user-talk": "有人在我的對話頁面上留下訊息或是回覆留言時,請通知我。",
+ "echo-pref-tooltip-article-linked": "有人從文章頁面連結到我建立的頁面時,請通知我。",
+ "echo-pref-tooltip-reverted": "有人使用還原或取消功能來還原我的編輯時,請通知我。",
+ "echo-pref-tooltip-mention": "當有人連結我的使用者頁面時通知我。",
+ "echo-pref-tooltip-user-rights": "當有人更改我的使用者權限時通知我。",
+ "echo-no-agent": "[無使用者]",
+ "echo-no-title": "[無頁面]",
+ "echo-error-no-formatter": "沒有定義通知的格式。",
+ "echo-error-preference": "錯誤:無法設定使用者偏好設定。",
+ "echo-error-token": "錯誤:無法取回使用者密鑰。",
+ "notifications": "通知",
+ "tooltip-pt-notifications": "您的通知",
+ "echo-specialpage": "通知",
+ "echo-anon": "要接收通知,請先 [$1 註冊帳號] 或是 [$2 登入]。",
+ "echo-none": "您沒有任何通知。",
+ "echo-more-info": "更多資訊",
+ "echo-feedback": "意見回饋",
+ "notification-link-text-view-message": "檢視訊息",
+ "notification-link-text-view-mention": "檢視提到",
+ "notification-link-text-view-changes": "檢視變更",
+ "notification-link-text-view-page": "檢視頁面",
+ "notification-link-text-view-edit": "檢視編輯",
+ "notification-edit-talk-page2": "[[User:$1|$1]] 在您的[[User talk:$2#$3|對話頁面]]中{{GENDER:$1|留下了}}一則訊息。",
+ "notification-edit-talk-page-with-section": "[[User:$1|$1]] 在您的對話頁面段落 \"[[User talk:$2#$3|$4]]\" 中{{GENDER:$1|留下了}}一則訊息。",
+ "notification-edit-talk-page-flyout2": "$1 在您的[[User talk:$2#$3|對話頁面]]中{{GENDER:$1|留下了}}一則訊息。",
+ "notification-edit-talk-page-flyout-with-section": "$1 在您的對話頁面段落 \"[[User talk:$2#$3|$4]]\" 中{{GENDER:$1|留下了}}一則訊息。",
+ "notification-page-linked": "[[:$2]] 已從 [[:$3]] 頁面{{GENDER:$1|連入了}}。詳情請見[[Special:WhatLinksHere/$2|此頁面的所有連結]]。",
+ "notification-page-linked-flyout": "[[:$2]] 已從 [[:$3]] 頁面{{GENDER:$1|連入了}}。",
+ "notification-add-comment2": "[[User:$1|$1]] 在 \"$4\" 對話頁面段落 \"[[$3|$2]]\" 中{{GENDER:$1|發表了意見}}。",
+ "notification-add-talkpage-topic2": "[[User:$1|$1]] 在 [[$3]] 的頁面中{{GENDER:$1|張貼了}}新主題 \"$2\"。",
+ "notification-add-talkpage-topic-yours2": "[[User:$1|$1]] 傳送了一則訊息給您:\"[[$3#$2|$2]]\"。",
+ "notification-add-comment-yours2": "[[User:$1|$1]] 在您的對話頁面段落 \"[[$3#$2|$2]]\" 中{{GENDER:$1|發表了意見}}。",
+ "notification-mention": "[[User:$1|$1]] 在 $5 的對話頁面段落 \"[[:$3#$2|$4]]\" 中{{GENDER:$1|提到了}}您。",
+ "notification-mention-flyout": "$1 在 $5 對話頁面段落 \"[[:$3#$2|$4]]\" 中{{GENDER:$1|提到了}}您。",
+ "notification-mention-nosection": "[[User:$1|$1]] 於 [[:$3|$2 對話頁面]] 中提到了您。",
+ "notification-mention-nosection-flyout": "$1 於 [[:$3|$2 對話頁面]] 中提到了您。",
+ "notification-user-rights": "您的使用者權限已由 [[User:$1|$1]] [[Special:Log/rights/$1|變更]],$2。[[Special:ListGroupRights|瞭解更多]]",
+ "notification-user-rights-flyout": "您的使用者權限已由 $1 {{GENDER:$1|變更}},$2。[[Special:ListGroupRights|瞭解更多]]",
+ "notification-user-rights-add": "您現在已成為{{PLURAL:$2|這個群組|這些群組}}的成員:$1",
+ "notification-user-rights-remove": "你不再是{{PLURAL:$2|這個群組|這些群組}}的成員:$1",
+ "notification-new-user": "歡迎來到 {{SITENAME}},$1! 我們很歡迎您的蒞臨。",
+ "notification-reverted2": "您{{PLURAL:$4|在 [[:$2]] 頁面的編輯}}已由 [[User:$1|$1]] {{GENDER:$1|還原了}}。$3",
+ "notification-reverted-flyout2": "您{{PLURAL:$4|在 $2 頁面的編輯}}已由 $1 給還原了。 $3",
+ "notification-edit-talk-page-email-subject2": "$1 在 {{SITENAME}} {{GENDER:$1|留下了}}一則訊息給您。",
+ "notification-edit-talk-page-email-batch-body2": "$1 在您的對話頁面中{{GENDER:$1|留下了}}一則訊息:",
+ "notification-edit-talk-page-email-batch-body-with-section": "$1 在您的對話頁面 \"$2\" 中{{GENDER:$1|留下了}}一則訊息。",
+ "notification-page-linked-email-subject": "您在 {{SITENAME}} 的頁面已被連結",
+ "notification-page-linked-email-batch-body": "$2 頁面已被 $3 頁面{{GENDER:$1|連結}}。",
+ "notification-reverted-email-subject2": "您在 {{SITENAME}} 的{{PLURAL:$3|編輯}}已{{GENDER:$1|還原了}}",
+ "notification-reverted-email-batch-body2": "您在 {{PLURAL:$3|$2 頁面的編輯}}已由 $1 {{GENDER:$1|還原了}}。",
+ "notification-mention-email-subject": "$1 在 {{SITENAME}} {{GENDER:$1|提到了}}您",
+ "notification-mention-email-batch-body": "$1 在 $4 的對話頁面段落 \"$3\" 中{{GENDER:$1|提到了}}您。",
+ "notification-mention-nosection-email-batch-body": "$1 於 $2 對話頁面提到了您。",
+ "notification-user-rights-email-subject": "您在 {{SITENAME}} 的使用者權限已變更",
+ "notification-user-rights-email-batch-body": "$1 已修改你的使用者權限。$2",
+ "echo-email-subject-default": "{{SITENAME}} 的新通知",
+ "echo-email-body-default": "你在 {{SITENAME}} 有一則新訊息:\n\n\n$1",
+ "echo-email-batch-body-default": "你有一則新通知訊息。",
+ "echo-email-footer-default": "$2\n\n如要調整我們寄給您的電子郵件,請檢查您的偏好設定:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
+ "echo-email-footer-default-html": "如要調整我們寄給您的電子郵件,<a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">請檢查您的偏好設定</a>。<br />\n$1",
+ "echo-notification-alert": "{{PLURAL:$1|警報 ($1 條)|100=警報 (超過 99 條)}}",
+ "echo-notification-message": "{{PLURAL:$1|訊息 ($1)|訊息 ($1)|100=訊息 (99+)}}",
+ "echo-notification-alert-text-only": "警告",
+ "echo-notification-message-text-only": "訊息",
+ "echo-overlay-link": "所有通知",
+ "echo-overlay-title": "<b>通知</b>",
+ "echo-overlay-title-overflow": "<b>{{PLURAL:$1|通知}}</b> (顯示 $2 則未讀訊息中的 $1 則)",
+ "echo-mark-all-as-read": "標記所有為已讀",
+ "echo-date-today": "今日",
+ "echo-date-yesterday": "昨日",
+ "echo-load-more-error": "擷取更多結果的時候發生錯誤。",
+ "notification-edit-talk-page-bundle": "$1 與{{PLURAL:$4|另外}} $3 位使用者在您的[[User talk:$2|對話頁面]]裡面{{GENDER:$1|留下了}}一則訊息。",
+ "notification-page-linked-bundle": "$2 已由 $3 及另外 $4 個{{PLURAL:$5|頁面}}{{GENDER:$1|連入}}了。詳情請見[[Special:WhatLinksHere/$2|所有的連入頁面]]",
+ "notification-edit-user-talk-email-batch-bundle-body": "$1 與{{PLURAL:$3|另外}} $2 位使用者在您的對話頁面裡面{{GENDER:$1|留下了}}訊息。",
+ "notification-page-linked-email-batch-bundle-body": "$2 已由 $3 頁面及另外 $4 個{{PLURAL:$5|頁面}}{{GENDER:$1|連入了}}。",
+ "echo-email-batch-subject-daily": "您在 {{SITENAME}} 有{{PLURAL:$2|一則新通知}}",
+ "echo-email-batch-subject-weekly": "本週您在 {{SITENAME}} 有{{PLURAL:$2|一則新通知}}",
+ "echo-email-batch-body-intro-daily": "$1 您好,\n這是您在 {{SITENAME}} 的今日活動記錄摘要。",
+ "echo-email-batch-body-intro-weekly": "$1 您好,\n這是您在 {{SITENAME}} 的本週活動記錄摘要。",
+ "echo-email-batch-link-text-view-all-notifications": "檢視所有通知",
+ "echo-rev-deleted-text-view": "該頁面修訂已禁止使用。"
+}
diff --git a/Echo/includes/AttributeManager.php b/Echo/includes/AttributeManager.php
new file mode 100644
index 00000000..5ffb68d2
--- /dev/null
+++ b/Echo/includes/AttributeManager.php
@@ -0,0 +1,247 @@
+<?php
+
+/**
+ * An object that manages attributes of echo notifications: category, elegibility,
+ * group, section etc.
+ */
+class EchoAttributeManager {
+
+ /**
+ * @var array
+ */
+ protected $notifications;
+
+ /**
+ * @var array
+ */
+ protected $categories;
+
+ /**
+ * Notification section constant
+ */
+ const ALERT = 'alert';
+ const MESSAGE = 'message';
+ const ALL = 'all';
+
+ /**
+ * Notifications are broken down to two sections, default is alert
+ * @var array
+ */
+ public static $sections = array (
+ self::ALERT,
+ self::MESSAGE
+ );
+
+ /**
+ * An array of EchoAttributeManager instance created from global variables
+ * @param EchoAttributeManager[]
+ */
+ protected static $globalVarInstance = array();
+
+ /**
+ * @param array notification attributes
+ * @param array notification categories
+ */
+ public function __construct( array $notifications, array $categories ) {
+ // Extensions can define their own notifications and categories
+ $this->notifications = $notifications;
+ $this->categories = $categories;
+ }
+
+ /**
+ * Create an instance from global variables
+ * @return EchoAttributeManager
+ */
+ public static function newFromGlobalVars() {
+ global $wgEchoNotifications, $wgEchoNotificationCategories;
+
+ // Unit test may alter the global data for test purpose
+ if ( defined( 'MW_PHPUNIT_TEST' ) && MW_PHPUNIT_TEST ) {
+ return new self( $wgEchoNotifications, $wgEchoNotificationCategories );
+ }
+ // A job queue job may run against different wikis, the singleton
+ // instance should be a per wiki singleton
+ $wikiId = wfWikiId();
+ if ( !isset( self::$globalVarInstance[$wikiId] ) ) {
+ self::$globalVarInstance[$wikiId] = new self(
+ $wgEchoNotifications,
+ $wgEchoNotificationCategories
+ );
+ }
+ return self::$globalVarInstance[$wikiId];
+ }
+
+ /**
+ * Get the user-locators related to the provided event type
+ *
+ * @param string $type
+ * @return array
+ */
+ public function getUserLocators( $type ) {
+ if ( isset( $this->notifications[$type]['user-locators'] ) ) {
+ return (array)$this->notifications[$type]['user-locators'];
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Get the enabled events for a user, which excludes user-dismissed events
+ * from the general enabled events
+ * @param User
+ * @param string web/email
+ * @return string[]
+ */
+ public function getUserEnabledEvents( User $user, $outputFormat ) {
+ $eventTypesToLoad = $this->notifications;
+ foreach ( $eventTypesToLoad as $eventType => $eventData ) {
+ $category = $this->getNotificationCategory( $eventType );
+ // Make sure the user is eligible to recieve this type of notification
+ if ( !$this->getCategoryEligibility( $user, $category ) ) {
+ unset( $eventTypesToLoad[$eventType] );
+ }
+ if ( !$user->getOption( 'echo-subscriptions-' . $outputFormat . '-' . $category ) ) {
+ unset( $eventTypesToLoad[$eventType] );
+ }
+ }
+ $eventTypes = array_keys( $eventTypesToLoad );
+
+ return $eventTypes;
+ }
+
+ /**
+ * Get the uesr enabled events for the specified sections
+ * @param User
+ * @param string
+ * @param string[]
+ * @return string[]
+ */
+ public function getUserEnabledEventsbySections( User $user, $outputFormat, array $sections ) {
+ $events = array();
+ foreach ( $sections as $section ) {
+ $events = array_merge(
+ $events,
+ call_user_func(
+ array( $this, 'get' . ucfirst( $section ) . 'Events' )
+ )
+ );
+ }
+ return array_intersect(
+ $this->getUserEnabledEvents( $user, $outputFormat ),
+ $events
+ );
+ }
+
+ /**
+ * Get alert notification event. Notifications without a section attributes
+ * default to section alert
+ * @return array
+ */
+ public function getAlertEvents() {
+ $events = array();
+ foreach ( $this->notifications as $event => $attribs ) {
+ if (
+ !isset( $attribs['section'] )
+ || !in_array( $attribs['section'], self::$sections )
+ || $attribs['section'] === 'alert'
+ ) {
+ $events[] = $event;
+ }
+ }
+ return $events;
+ }
+
+ /**
+ * Get message notification event
+ * @return array
+ */
+ public function getMessageEvents() {
+ $events = array();
+ foreach ( $this->notifications as $event => $attribs ) {
+ if (
+ isset( $attribs['section'] )
+ && $attribs['section'] === 'message'
+ ) {
+ $events[] = $event;
+ }
+ }
+ return $events;
+ }
+
+ /**
+ * See if a user is eligible to recieve a certain type of notification
+ * (based on user groups, not user preferences)
+ *
+ * @param User
+ * @param string A notification category defined in $wgEchoNotificationCategories
+ * @return boolean
+ */
+ public function getCategoryEligibility( $user, $category ) {
+ $usersGroups = $user->getGroups();
+ if ( isset( $this->categories[$category]['usergroups'] ) ) {
+ $allowedGroups = $this->categories[$category]['usergroups'];
+ if ( !array_intersect( $usersGroups, $allowedGroups ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get the priority for a specific notification type
+ *
+ * @param string A notification type defined in $wgEchoNotifications
+ * @return integer From 1 to 10 (10 is default)
+ */
+ public function getNotificationPriority( $notificationType ) {
+ $category = $this->getNotificationCategory( $notificationType );
+ return $this->getCategoryPriority( $category );
+ }
+
+ /**
+ * Get the priority for a notification category
+ *
+ * @param string A notification category defined in $wgEchoNotificationCategories
+ * @return integer From 1 to 10 (10 is default)
+ */
+ public function getCategoryPriority( $category ) {
+ if ( isset( $this->categories[$category]['priority'] ) ) {
+ $priority = $this->categories[$category]['priority'];
+ if ( $priority >= 1 && $priority <= 10 ) {
+ return $priority;
+ }
+ }
+ return 10;
+ }
+
+ /**
+ * Get the notification category for a notification type
+ *
+ * @param string A notification type defined in $wgEchoNotifications
+ * @return string The name of the notification category or 'other' if no
+ * category is explicitly assigned.
+ */
+ public function getNotificationCategory( $notificationType ) {
+ if ( isset( $this->notifications[$notificationType]['category'] ) ) {
+ $category = $this->notifications[$notificationType]['category'];
+ if ( isset( $this->categories[$category] ) ) {
+ return $category;
+ }
+ }
+ return 'other';
+ }
+
+ /**
+ * Get notification section for a notification type
+ * @todo add a unit test case
+ * @parm string
+ * @return string
+ */
+ public function getNotificationSection( $notificationType ) {
+ if ( isset( $this->notifications[$notificationType]['section'] ) ) {
+ return $this->notifications[$notificationType]['section'];
+ }
+ return 'alert';
+ }
+
+}
diff --git a/Echo/includes/BatchRowUpdate.php b/Echo/includes/BatchRowUpdate.php
new file mode 100644
index 00000000..8838fca8
--- /dev/null
+++ b/Echo/includes/BatchRowUpdate.php
@@ -0,0 +1,454 @@
+<?php
+/**
+ * Provides components to update a tables rows via a batching process
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+/**
+ * Ties together the batch update components to provide a composable method
+ * of batch updating rows in a database. To use create a class implementing
+ * the EchoRowUpdateGenerator interface and configure the EchoBatchRowIterator and
+ * EchoBatchRowWriter for access to the correct table. The components will
+ * handle reading, writing, and waiting for slaves while the generator implementation
+ * handles generating update arrays for singular rows.
+ *
+ * Instantiate:
+ * $updater = new EchoBatchRowUpdate(
+ * new EchoBatchRowIterator( $dbr, 'some_table', 'primary_key_column', 500 ),
+ * new EchoBatchRowWriter( $dbw, 'some_table', 'clusterName' ),
+ * new MyImplementationOfEchoRowUpdateGenerator
+ * );
+ *
+ * Run:
+ * $updater->execute();
+ *
+ * An example maintenance script utilizing the EchoBatchRowUpdate can be located in the Echo
+ * extension file maintenance/updateSchema.php
+ *
+ * @ingroup Maintenance
+ */
+class EchoBatchRowUpdate {
+ /**
+ * @var EchoBatchRowIterator $reader Iterator that returns an array of database rows
+ */
+ protected $reader;
+
+ /**
+ * @var EchoBatchRowWriter $writer Writer capable of pushing row updates to the database
+ */
+ protected $writer;
+
+ /**
+ * @var EchoRowUpdateGenerator $generator Generates single row updates based on the rows content
+ */
+ protected $generator;
+
+ /**
+ * @var callable $output Output callback
+ */
+ protected $output;
+
+ /**
+ * @param EchoBatchRowIterator $reader Iterator that returns an array of database rows
+ * @param EchoBatchRowWriter $writer Writer capable of pushing row updates to the database
+ * @param EchoRowUpdateGenerator $generator Generates single row updates based on the rows content
+ */
+ public function __construct( EchoBatchRowIterator $reader, EchoBatchRowWriter $writer, EchoRowUpdateGenerator $generator ) {
+ $this->reader = $reader;
+ $this->writer = $writer;
+ $this->generator = $generator;
+ $this->output = function() {
+ }; // nop
+ }
+
+ /**
+ * Runs the batch update process
+ */
+ public function execute() {
+ foreach ( $this->reader as $rows ) {
+ $updates = array();
+ foreach ( $rows as $row ) {
+ $update = $this->generator->update( $row );
+ if ( $update ) {
+ $updates[] = array(
+ 'primaryKey' => $this->reader->extractPrimaryKeys( $row ),
+ 'changes' => $update,
+ );
+ }
+ }
+
+ if ( $updates ) {
+ $this->output( "Processing " . count( $updates ) . " rows\n" );
+ $this->writer->write( $updates );
+ }
+ }
+
+ $this->output( "Completed\n" );
+ }
+
+ /**
+ * Accepts a callable which will receive a single parameter containing
+ * string status updates
+ *
+ * @param callable $output A callback taking a single string parameter to output
+ *
+ * @throws MWException
+ */
+ public function setOutput( $output ) {
+ if ( !is_callable( $output ) ) {
+ throw new MWException( 'Provided $output param is required to be callable.' );
+ }
+ $this->output = $output;
+ }
+
+ /**
+ * Write out a status update
+ *
+ * @param string $text The value to print
+ */
+ protected function output( $text ) {
+ call_user_func( $this->output, $text );
+ }
+}
+
+/**
+ * Interface for generating updates to single rows in the database.
+ *
+ * @ingroup Maintenance
+ */
+interface EchoRowUpdateGenerator {
+
+ /**
+ * Given a database row, generates an array mapping column names to updated value within the database row
+ *
+ * Sample Response:
+ * return array(
+ * 'some_col' => 'new value',
+ * 'other_col' => 99,
+ * );
+ *
+ * @param stdClass $row A row from the database
+ * @return array Map of column names to updated value within the database row. When no update is required
+ * returns an empty array.
+ */
+ public function update( $row );
+}
+
+/**
+ * Updates database rows by primary key in batches. There are two options for writing to tables
+ * with a composite primary key.
+ *
+ * @ingroup Maintenance
+ */
+class EchoBatchRowWriter {
+ /**
+ * @var DatabaseBase $db The database to write to
+ */
+ protected $db;
+
+ /**
+ * @var string $table The name of the table to update
+ */
+ protected $table;
+
+ /**
+ * @var string $clusterName A cluster name valid for use with LBFactory
+ */
+ protected $clusterName;
+
+ /**
+ * @param DatabaseBase $db The database to write to
+ * @param string $table The name of the table to update
+ * @param string|bool $clusterName A cluster name valid for use with LBFactory
+ */
+ public function __construct( DatabaseBase $db, $table, $clusterName = false ) {
+ $this->db = $db;
+ $this->table = $table;
+ $this->clusterName = $clusterName;
+ }
+
+ /**
+ * @param array $updates Array of arrays each containing two keys, 'primaryKey' and 'changes'.
+ * primaryKey must contain a map of column names to values sufficient to uniquely identify the row
+ * changes must contain a map of column names to update values to apply to the row
+ */
+ public function write( array $updates ) {
+ $this->db->begin();
+
+ foreach ( $updates as $update ) {
+ //echo "Updating: ";var_dump( $update['primaryKey'] );
+ //echo "With values: ";var_dump( $update['changes'] );
+ $this->db->update(
+ $this->table,
+ $update['changes'],
+ $update['primaryKey'],
+ __METHOD__
+ );
+ }
+
+ $this->db->commit();
+ wfWaitForSlaves( false, false, $this->clusterName );
+ }
+}
+
+/**
+ * Fetches rows batched into groups from the database in ascending order of the primary key(s).
+ *
+ * @ingroup Maintenance
+ */
+class EchoBatchRowIterator implements RecursiveIterator {
+
+ /**
+ * @var DatabaseBase $db The database to read from
+ */
+ protected $db;
+
+ /**
+ * @var string $table The name of the table to read from
+ */
+ protected $table;
+
+ /**
+ * @var array $primaryKey The name of the primary key(s)
+ */
+ protected $primaryKey;
+
+ /**
+ * @var integer $batchSize The number of rows to fetch per iteration
+ */
+ protected $batchSize;
+
+ /**
+ * @var array $conditions Array of strings containing SQL conditions to add to the query
+ */
+ protected $conditions = array();
+
+ /**
+ * @var array $joinConditions
+ */
+ protected $joinConditions = array();
+
+ /**
+ * @var array $fetchColumns List of column names to select from the table suitable for use with DatabaseBase::select()
+ */
+ protected $fetchColumns = array( '*' );
+
+ /**
+ * @var string $orderBy SQL Order by condition generated from $this->primaryKey
+ */
+ protected $orderBy;
+
+ /**
+ * @var array $current The current iterator value
+ */
+ private $current = array();
+
+ /**
+ * @var integer key 0-indexed number of pages fetched since self::reset()
+ */
+ private $key;
+
+ /**
+ * @param DatabaseBase $db The database to read from
+ * @param string $table The name of the table to read from
+ * @param string|array $primaryKey The name or names of the primary key columns
+ * @param integer $batchSize The number of rows to fetch per iteration
+ *
+ * @throws MWException
+ */
+ public function __construct( DatabaseBase $db, $table, $primaryKey, $batchSize ) {
+ if ( $batchSize < 1 ) {
+ throw new MWException( 'Batch size must be at least 1 row.' );
+ }
+ $this->db = $db;
+ $this->table = $table;
+ $this->primaryKey = (array) $primaryKey;
+ $this->fetchColumns = $this->primaryKey;
+ $this->orderBy = implode( ' ASC,', $this->primaryKey ) . ' ASC';
+ $this->batchSize = $batchSize;
+ }
+
+ /**
+ * @param string $condition Query conditions suitable for use with DatabaseBase::select
+ */
+ public function addConditions( array $conditions ) {
+ $this->conditions = array_merge( $this->conditions, $conditions );
+ }
+
+ public function addJoinConditions( array $conditions ) {
+ $this->joinConditions = array_merge( $this->joinConditions, $conditions );
+ }
+
+ /**
+ * @param array $columns List of column names to select from the table suitable for use with DatabaseBase::select()
+ */
+ public function setFetchColumns( array $columns ) {
+ // If it's not the all column selector merge in the primary keys we need
+ if ( count( $columns ) === 1 && reset( $columns ) === '*' ) {
+ $this->fetchColumns = $columns;
+ } else {
+ $this->fetchColumns = array_unique( array_merge( $this->primaryKey, $columns ) );
+ }
+ }
+
+ /**
+ * Extracts the primary key(s) from a database row.
+ *
+ * @param stdClass $row An individual database row from this iterator
+ * @return array Map of primary key column to value within the row
+ */
+ public function extractPrimaryKeys( $row ) {
+ $pk = array();
+ foreach ( $this->primaryKey as $column ) {
+ $pk[$column] = $row->$column;
+ }
+ return $pk;
+ }
+
+ /**
+ * @return array The most recently fetched set of rows from the database
+ */
+ public function current() {
+ return $this->current;
+ }
+
+ /**
+ * @return integer 0-indexed count of the page number fetched
+ */
+ public function key() {
+ return $this->key;
+ }
+
+ /**
+ * Reset the iterator to the begining of the table.
+ */
+ public function rewind() {
+ $this->key = -1; // self::next() will turn this into 0
+ $this->current = array();
+ $this->next();
+ }
+
+ /**
+ * @return boolean True when the iterator is in a valid state
+ */
+ public function valid() {
+ return (bool) $this->current;
+ }
+
+ /**
+ * @return boolean True when this result set has rows
+ */
+ public function hasChildren() {
+ return $this->current && count( $this->current );
+ }
+
+ /**
+ * @return RecursiveIterator
+ */
+ public function getChildren() {
+ return new EchoNotRecursiveIterator( new ArrayIterator( $this->current ) );
+ }
+
+ /**
+ * Fetch the next set of rows from the database.
+ */
+ public function next() {
+ $res = $this->db->select(
+ $this->table,
+ $this->fetchColumns,
+ $this->buildConditions(),
+ __METHOD__,
+ array(
+ 'LIMIT' => $this->batchSize,
+ 'ORDER BY' => $this->orderBy,
+ ),
+ $this->joinConditions
+ );
+
+ // The iterator is converted to an array because in addition to returning it
+ // in self::current() we need to use the end value in self::buildConditions()
+ $this->current = iterator_to_array( $res );
+ $this->key++;
+ }
+
+ /**
+ * Uses the primary key list and the maximal result row from the previous iteration to build
+ * an SQL condition sufficient for selecting the next page of results. All except the final
+ * key use `=` conditions while the final key uses a `>` condition
+ *
+ * Example output:
+ * array( '( foo = 42 AND bar > 7 ) OR ( foo > 42 )' )
+ *
+ * @return array The SQL conditions necessary to select the next set of rows in the batched query
+ */
+ protected function buildConditions() {
+ if ( !$this->current ) {
+ return $this->conditions;
+ }
+
+ $maxRow = end( $this->current );
+ $maximumValues = array();
+ foreach ( $this->primaryKey as $column ) {
+ $maximumValues[$column] = $this->db->addQuotes( $maxRow->$column );
+ }
+
+ $pkConditions = array();
+ // For example: If we have 3 primary keys
+ // first run through will generate
+ // col1 = 4 AND col2 = 7 AND col3 > 1
+ // second run through will generate
+ // col1 = 4 AND col2 > 7
+ // and the final run through will generate
+ // col1 > 4
+ while ( $maximumValues ) {
+ $pkConditions[] = $this->buildGreaterThanCondition( $maximumValues );
+ array_pop( $maximumValues );
+ }
+
+ $conditions = $this->conditions;
+ $conditions[] = sprintf( '( %s )', implode( ' ) OR ( ', $pkConditions ) );
+
+ return $conditions;
+ }
+
+ /**
+ * Given an array of column names and their maximum value generate an SQL
+ * condition where all keys except the last match $quotedMaximumValues
+ * exactly and the last column is greater than the matching value in $quotedMaximumValues
+ *
+ * @param array $quotedMaximumValues The maximum values quoted with $this->db->addQuotes()
+ * @return string An SQL condition that will select rows where all columns match the
+ * maximum value exactly except the last column which must be greater than the provided
+ * maximum value
+ */
+ protected function buildGreaterThanCondition( array $quotedMaximumValues ) {
+ $keys = array_keys( $quotedMaximumValues );
+ $lastColumn = end( $keys );
+ $lastValue = array_pop( $quotedMaximumValues );
+ $conditions = array();
+ foreach ( $quotedMaximumValues as $column => $value ) {
+ $conditions[] = "$column = $value";
+ }
+ $conditions[] = "$lastColumn > $lastValue";
+
+ return implode( ' AND ', $conditions );
+ }
+}
+
diff --git a/Echo/includes/ContainmentSet.php b/Echo/includes/ContainmentSet.php
new file mode 100644
index 00000000..95c1c8af
--- /dev/null
+++ b/Echo/includes/ContainmentSet.php
@@ -0,0 +1,242 @@
+<?php
+
+/**
+ * Interface providing list of contained values and an optional cache key to go along with it.
+ */
+interface EchoContainmentList {
+ /**
+ * @return array The values contained within this list.
+ */
+ public function getValues();
+
+ /**
+ * @return string A string suitable for appending to the cache key prefix to facilitate
+ * cache busting when the underlying data changes, or a blank string if
+ * not relevant.
+ */
+ public function getCacheKey();
+}
+
+/**
+ * Utilizes EchoContainmentList interface to provide a fluent interface to whitelist/blacklist
+ * from multiple sources like global variables, wiki pages, etc.
+ *
+ * Initialize:
+ * $set = new EchoContainmentSet;
+ * $set->addArray( $wgSomeGlobalParameter );
+ * $set->addOnWiki( NS_USER, 'Foo/bar-baz', $wgMemc, 'some_user_specific_cache_key' );
+ *
+ * Usage:
+ * if ( $set->contains( 'SomeUser' ) ) {
+ * ...
+ * }
+ */
+class EchoContainmentSet {
+ /**
+ * @var $lists array of EchoContainmentList objects
+ */
+ protected $lists = array();
+
+ /**
+ * Add an EchoContainmentList to the set of lists checked by self::contains()
+ *
+ * @param $list EchoContainmentList
+ */
+ public function add( EchoContainmentList $list ) {
+ $this->lists[] = $list;
+ }
+
+ /**
+ * Add a php array to the set of lists checked by self::contains()
+ *
+ * @param $list array
+ */
+ public function addArray( array $list ) {
+ $this->add( new EchoArrayList( $list ) );
+ }
+
+ /**
+ * Add a list from a wiki page to the set of lists checked by self::contains(). Data
+ * from wiki pages is cached via the BagOStuff. Caching is disabled when passing a null
+ * $cache object.
+ *
+ * @param $namespace integer An NS_* constant representing the mediawiki namespace of the page containing the list.
+ * @param $title string The title of the page containing the list.
+ * @param $cache BagOStuff An object to cache the page with or null for no cache.
+ * @param $cacheKeyPrefix string A prefix to be combined with the pages latest revision id and used as a cache key.
+ *
+ * @throws MWException
+ */
+ public function addOnWiki( $namespace, $title, BagOStuff $cache = null, $cacheKeyPrefix = '' ) {
+ $list = new EchoOnWikiList( $namespace, $title );
+ if ( $cache ) {
+ if ( $cacheKeyPrefix === '' ) {
+ throw new MWException( 'Cache requires providing a cache key prefix.' );
+ }
+ $list = new EchoCachedList( $cache, $cacheKeyPrefix, $list );
+ }
+ $this->add( $list );
+ }
+
+ /**
+ * Test the wrapped lists for existence of $value
+ *
+ * @param $value mixed The value to look for
+ * @return boolean True when the set contains the provided value
+ */
+ public function contains( $value ) {
+ foreach ( $this->lists as $list ) {
+ if ( array_search( $value, $list->getValues() ) !== false ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
+
+/**
+ * Implements the EchoContainmentList interface for php arrays. Possible source
+ * of arrays includes $wg* global variables initialized from extensions or global
+ * wiki config.
+ */
+class EchoArrayList implements EchoContainmentList {
+ /**
+ * @param $list array
+ */
+ protected $list;
+
+ /**
+ * @param $list array
+ */
+ public function __construct( array $list ) {
+ $this->list = $list;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getValues() {
+ return $this->list;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getCacheKey() {
+ return '';
+ }
+}
+
+/**
+ * Implements EchoContainmentList interface for sourcing a list of items from a wiki
+ * page. Uses the pages latest revision ID as cache key.
+ */
+class EchoOnWikiList implements EchoContainmentList {
+ /**
+ * @var $title Title|null A title object representing the page to source the list from,
+ * or null if the page does not exist.
+ */
+ protected $title;
+
+ /**
+ * @param $titleNs integer An NS_* constant representing the mediawiki namespace of the page
+ * @param $titleString string String portion of the wiki page title
+ */
+ public function __construct( $titleNs, $titleString ) {
+ $title = Title::newFromText( $titleString, $titleNs );
+ if ( $title !== null && $title->getArticleId() ) {
+ $this->title = $title;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getValues() {
+ if ( !$this->title ) {
+ return array();
+ }
+
+ $article = WikiPage::newFromID( $this->title->getArticleId() );
+ if ( $article === null || !$article->exists() ) {
+ return array();
+ }
+
+ return array_filter( array_map( 'trim', explode( "\n", $article->getText() ) ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getCacheKey() {
+ if ( !$this->title ) {
+ return '';
+ }
+
+ return $this->title->getLatestRevID();
+ }
+}
+
+/**
+ * Caches an EchoContainmentList within a BagOStuff(memcache, etc) to prevent needing
+ * to load the nested list from a potentially slow source (mysql, etc).
+ */
+class EchoCachedList implements EchoContainmentList {
+ const ONE_WEEK = 4233600;
+ const ONE_DAY = 86400;
+
+ protected $cache;
+ protected $partialCacheKey;
+ protected $nestedList;
+ protected $timeout;
+ private $result;
+
+ /**
+ * @param $cache BagOStuff Bag to stored cached data in.
+ * @param $partialCacheKey string Partial cache key, $nestedList->getCacheKey() will be appended to this
+ * to construct the cache key used.
+ * @param $nestedList EchoContainmentList The nested EchoContainmentList to cache the result of.
+ * @param $timeout integer How long in seconds to cache the nested list, defaults to 1 week.
+ */
+ public function __construct( BagOStuff $cache, $partialCacheKey, EchoContainmentList $nestedList, $timeout = self::ONE_WEEK ) {
+ $this->cache = $cache;
+ $this->partialCacheKey = $partialCacheKey;
+ $this->nestedList = $nestedList;
+ $this->timeout = $timeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getValues() {
+ if ( $this->result ) {
+ return $this->result;
+ }
+
+ $cacheKey = $this->getCacheKey();
+ $fetched = $this->cache->get( $cacheKey );
+ if ( is_array( $fetched ) ) {
+ return $this->result = $fetched;
+ }
+
+ $result = $this->nestedList->getValues();
+ if ( !is_array( $result ) ) {
+ throw new MWException( sprintf(
+ "Expected array but received '%s' from '%s::getValues'",
+ is_object( $result ) ? get_class( $result ) : gettype( $result ),
+ get_class( $this->nestedList )
+ ) );
+ }
+ $this->cache->set( $cacheKey, $result, $this->timeout );
+
+ return $this->result = $result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getCacheKey() {
+ return $this->partialCacheKey . '_' . $this->nestedList->getCacheKey();
+ }
+}
diff --git a/Echo/includes/DataOutputFormatter.php b/Echo/includes/DataOutputFormatter.php
new file mode 100644
index 00000000..06ce147f
--- /dev/null
+++ b/Echo/includes/DataOutputFormatter.php
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * Utility class that formats a notification in the format specified
+ */
+class EchoDataOutputFormatter {
+
+ /**
+ * Format a notification for a user in the format specified
+ *
+ * @param string|bool specifify output format, false to not format any notifications
+ * @param User|null the target user viewing the notification
+ * @return array
+ */
+ public static function formatOutput( EchoNotification $notification, $format = false, User $user = null ) {
+ $event = $notification->getEvent();
+ $timestamp = $notification->getTimestamp();
+ $utcTimestampUnix = wfTimestamp( TS_UNIX, $timestamp );
+
+ // Default to notification user if user is not specified
+ if ( !$user ) {
+ $user = $notification->getUser();
+ }
+
+ if ( $notification->getBundleBase() && $notification->getBundleDisplayHash() ) {
+ $event->setBundleHash( $notification->getBundleDisplayHash() );
+ }
+
+ $timestampMw = self::getUserLocalTime( $user, $timestamp );
+
+ // Start creating date section header
+ $now = wfTimestamp();
+ $dateFormat = substr( $timestampMw, 0, 8 );
+ $timeDiff = $now - $utcTimestampUnix;
+ // Most notifications would be more than two days ago, check this
+ // first instead of checking 'today' then 'yesterday'
+ if ( $timeDiff > 172800 ) {
+ $date = self::getDateHeader( $user, $timestampMw );
+ // 'Today'
+ } elseif ( substr( self::getUserLocalTime( $user, $now ), 0, 8 ) === $dateFormat ) {
+ $date = wfMessage( 'echo-date-today' )->escaped();
+ // 'Yesterday'
+ } elseif ( substr( self::getUserLocalTime( $user, $now - 86400 ), 0, 8 ) === $dateFormat ) {
+ $date = wfMessage( 'echo-date-yesterday' )->escaped();
+ } else {
+ $date = self::getDateHeader( $user, $timestampMw );
+ }
+ // End creating date section header
+
+ $output = array(
+ 'id' => $event->getId(),
+ 'type' => $event->getType(),
+ 'category' => $event->getCategory(),
+ 'timestamp' => array(
+ // UTC timestamp in UNIX format used for loading more notification
+ 'utcunix' => $utcTimestampUnix,
+ 'unix' => self::getUserLocalTime( $user, $timestamp, TS_UNIX ),
+ 'mw' => $timestampMw,
+ 'date' => $date
+ ),
+ );
+
+ if ( $event->getVariant() ) {
+ $output['variant'] = $event->getVariant();
+ }
+
+ $title = $event->getTitle();
+ if ( $title ) {
+ $output['title'] = array(
+ 'full' => $title->getPrefixedText(),
+ 'namespace' => $title->getNSText(),
+ 'namespace-key' =>$title->getNamespace(),
+ 'text' => $title->getText(),
+ );
+ }
+
+ $agent = $event->getAgent();
+ if ( $agent ) {
+ if ( $event->userCan( Revision::DELETED_USER, $user ) ) {
+ $output['agent'] = array(
+ 'id' => $agent->getId(),
+ 'name' => $agent->getName(),
+ );
+ } else {
+ $output['agent'] = array( 'userhidden' => '' );
+ }
+ }
+
+ if ( $notification->getReadTimestamp() ) {
+ $output['read'] = $notification->getReadTimestamp();
+ }
+
+ // This is only meant for unread notifications, if a notification has a target
+ // page, then it shouldn't be auto marked as read unless the user visits
+ // the target page or a user marks it as read manully ( coming soon )
+ $output['targetpages'] = array();
+ if ( $notification->getTargetPages() ) {
+ foreach ( $notification->getTargetPages() as $targetPage ) {
+ $output['targetpages'][] = $targetPage->getPageId();
+ }
+ }
+
+ if ( $format ) {
+ $output['*'] = EchoNotificationController::formatNotification( $event, $user, $format );
+ }
+
+ return $output;
+ }
+
+ /**
+ * Get the date header in user's format, 'May 10' or '10 May', depending
+ * on user's date format preference
+ * @param User $user
+ * @param string $timestampMw
+ * @return string
+ */
+ protected static function getDateHeader( User $user, $timestampMw ) {
+ $lang = RequestContext::getMain()->getLanguage();
+ $dateFormat = $lang->getDateFormatString( 'pretty', $user->getDatePreference() ?: 'default' );
+ return $lang->sprintfDate( $dateFormat, $timestampMw );
+ }
+
+ /**
+ * Helper function for converting UTC timezone to a user's timezone
+ *
+ * @param User
+ * @param string
+ * @param int output format
+ *
+ * @return string
+ */
+ public static function getUserLocalTime( User $user, $ts, $format = TS_MW ) {
+ $timestamp = new MWTimestamp( $ts );
+ $timestamp->offsetForUser( $user );
+ return $timestamp->getTimestamp( $format );
+ }
+
+}
diff --git a/Echo/includes/DbEmailBatch.php b/Echo/includes/DbEmailBatch.php
new file mode 100644
index 00000000..878974ba
--- /dev/null
+++ b/Echo/includes/DbEmailBatch.php
@@ -0,0 +1,160 @@
+<?php
+
+/**
+ * Handle user email batch ( daily/weekly ) for database storage
+ */
+class MWDbEchoEmailBatch extends MWEchoEmailBatch {
+
+ /**
+ * Set the last event of this batch, this is a cutoff point for clearing
+ * processed/invalid events
+ *
+ * @return bool true if event exists false otherwise
+ */
+ protected function setLastEvent() {
+ $dbr = MWEchoDbFactory::getDB( DB_SLAVE );
+ $res = $dbr->selectField(
+ array( 'echo_email_batch' ),
+ array( 'MAX( eeb_event_id )' ),
+ array( 'eeb_user_id' => $this->mUser->getId() ),
+ __METHOD__
+ );
+
+ if ( $res ) {
+ $this->lastEvent = $res;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the events queued for the current user
+ * @return array
+ */
+ protected function getEvents() {
+ global $wgEchoNotifications;
+
+ $events = array();
+
+ $validEvents = array_keys( $wgEchoNotifications );
+
+ // Per the tech discussion in the design meeting (03/22/2013), since this is
+ // processed by a cron job, it's okay to use GROUP BY over more complex
+ // composite index, favor insert performance, storage space over read
+ // performance in this case
+ if ( $validEvents ) {
+ $dbr = MWEchoDbFactory::getDB( DB_SLAVE );
+
+ $conds = array(
+ 'eeb_user_id' => $this->mUser->getId(),
+ 'event_id = eeb_event_id',
+ 'event_type' => $validEvents
+ );
+
+ // See setLastEvent() for more detail for this variable
+ if ( $this->lastEvent ) {
+ $conds[] = 'eeb_event_id <= ' . intval( $this->lastEvent );
+ }
+
+ $res = $dbr->select(
+ array( 'echo_email_batch', 'echo_event' ),
+ array( '*' ),
+ $conds,
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'eeb_event_priority',
+ 'LIMIT' => self::$displaySize + 1,
+ 'GROUP BY' => 'eeb_event_hash'
+ )
+ );
+
+ foreach ( $res as $row ) {
+ // records in the queue inserted before email bundling code
+ // have no hash, in this case, we just ignore them
+ if ( $row->eeb_event_hash ) {
+ $events[$row->eeb_id] = $row;
+ }
+ }
+ }
+
+ return $events;
+ }
+
+ /**
+ * Clear "processed" events in the queue, processed could be: email sent, invalid, users do not want to receive emails
+ */
+ public function clearProcessedEvent() {
+ $conds = array( 'eeb_user_id' => $this->mUser->getId() );
+
+ // there is a processed cutoff point
+ if ( $this->lastEvent ) {
+ $conds[] = 'eeb_event_id <= ' . intval( $this->lastEvent );
+ }
+
+ $dbw = MWEchoDbFactory::getDB( DB_MASTER );
+ $dbw->delete(
+ 'echo_email_batch',
+ $conds,
+ __METHOD__,
+ array()
+ );
+ }
+
+ /**
+ * Insert notification event into email queue
+ * @param $userId int
+ * @param $eventId int
+ * @param $priority int
+ * @param $hash string
+ */
+ public static function actuallyAddToQueue( $userId, $eventId, $priority, $hash ) {
+ if ( !$userId || !$eventId ) {
+ return;
+ }
+
+ $dbw = MWEchoDbFactory::getDB( DB_MASTER );
+
+ $row = array(
+ 'eeb_user_id' => $userId,
+ 'eeb_event_id' => $eventId,
+ 'eeb_event_priority' => $priority,
+ 'eeb_event_hash' => $hash
+ );
+
+ $id = $dbw->nextSequenceValue( 'echo_email_batch_eeb_id' );
+
+ if ( $id ) {
+ $row['eeb_id'] = $id;
+ }
+
+ $dbw->insert(
+ 'echo_email_batch',
+ $row,
+ __METHOD__,
+ array( 'IGNORE' )
+ );
+ }
+
+ /**
+ * Get a list of users to be notified for the batch
+ *
+ * @param $startUserId int
+ * @param $batchSize int
+ *
+ * @return ResultWrapper|bool
+ */
+ public static function actuallyGetUsersToNotify( $startUserId, $batchSize ) {
+ $dbr = MWEchoDbFactory::getDB( DB_SLAVE );
+ $res = $dbr->select(
+ array( 'echo_email_batch' ),
+ array( 'eeb_user_id' ),
+ array( 'eeb_user_id > ' . $startUserId ),
+ __METHOD__,
+ array( 'ORDER BY' => 'eeb_user_id', 'LIMIT' => $batchSize )
+ );
+
+ return $res;
+ }
+
+}
diff --git a/Echo/includes/DbEmailBundler.php b/Echo/includes/DbEmailBundler.php
new file mode 100644
index 00000000..b3dbb8b7
--- /dev/null
+++ b/Echo/includes/DbEmailBundler.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Email Bundling for database storage
+ */
+class MWDbEchoEmailBundler extends MWEchoEmailBundler {
+
+ /**
+ * Retrieve the base event for email bundling, the one with the largest eeb_id
+ * @return bool
+ */
+ protected function retrieveBaseEvent() {
+ $dbr = MWEchoDbFactory::getDB( DB_SLAVE );
+ $res = $dbr->selectRow(
+ array( 'echo_email_batch' ),
+ array( 'eeb_event_id' ),
+ array(
+ 'eeb_user_id' => $this->mUser->getId(),
+ 'eeb_event_hash' => $this->bundleHash
+ ),
+ __METHOD__,
+ array( 'ORDER BY' => 'eeb_event_priority DESC, eeb_id DESC', 'LIMIT' => 1 )
+ );
+ if ( !$res ) {
+ return false;
+ }
+ $this->baseEvent = EchoEvent::newFromId( $res->eeb_event_id );
+ return true;
+ }
+
+ /**
+ * Clear processed events from the queue
+ */
+ protected function clearProcessedEvent() {
+ if ( !$this->baseEvent ) {
+ return;
+ }
+ $conds = array( 'eeb_user_id' => $this->mUser->getId(), 'eeb_event_hash' => $this->bundleHash );
+
+ $conds[] = 'eeb_event_id <= ' . intval( $this->baseEvent->getId() );
+
+ $dbw = MWEchoDbFactory::getDB( DB_MASTER );
+ $dbw->delete(
+ 'echo_email_batch',
+ $conds,
+ __METHOD__,
+ array()
+ );
+ }
+
+}
diff --git a/Echo/includes/DeferredMarkAsReadUpdate.php b/Echo/includes/DeferredMarkAsReadUpdate.php
new file mode 100644
index 00000000..9b02e8cc
--- /dev/null
+++ b/Echo/includes/DeferredMarkAsReadUpdate.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * Mark event notifications as read at the end of a request. Used to queue up
+ * individual events to mark due to formatting failures or other uses.
+ */
+class EchoDeferredMarkAsReadUpdate implements DeferrableUpdate {
+ /**
+ * @var array
+ */
+ protected $events = array();
+
+ /**
+ * @param EchoEvent $event
+ * @param User $user
+ */
+ public function add( EchoEvent $event, User $user ) {
+ $uid = $user->getId();
+ if ( isset( $this->events[$uid] ) ) {
+ $this->events[$uid]['eventIds'][] = $event->getId();
+ } else {
+ $this->events[$uid] = array(
+ 'user' => $user,
+ 'eventIds' => array( $event->getId() ),
+ );
+ }
+ }
+
+ /**
+ * Mark's all queue'd notifications as read.
+ * Satisfies DeferrableUpdate interface
+ */
+ public function doUpdate() {
+ foreach ( $this->events as $data ) {
+ MWEchoNotifUser::newFromUser( $data['user'] )->markRead( $data['eventIds'] );
+ }
+ $this->events = array();
+ }
+}
diff --git a/Echo/includes/DiffParser.php b/Echo/includes/DiffParser.php
new file mode 100644
index 00000000..9f60c366
--- /dev/null
+++ b/Echo/includes/DiffParser.php
@@ -0,0 +1,315 @@
+<?php
+/**
+ * MediaWiki Extension: Echo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY.
+ */
+
+/**
+ *
+ * @file
+ * @ingroup Extensions
+ * @author Erik Bernhardson
+ */
+
+/**
+ * Calculates the individual sets of differences between two pieces of text
+ * as individual groupings of add, subtract, and change actions. Internally
+ * uses 0-indexing for positions. All results from the class are 1 indexed
+ * to stay consistent with the origional diff output and the previous diff
+ * parsing code.
+ */
+class EchoDiffParser {
+
+ /**
+ * @var integer $prefixLength The number of characters the diff prefixes a line with
+ */
+ protected $prefixLength = 1;
+
+ /**
+ * @var array $left The text of the left side of the diff operation
+ */
+ protected $left;
+
+ /**
+ * @var integer $leftPos The current position within the left text
+ */
+ protected $leftPos;
+
+ /**
+ * @var array $right The text of the right side of the diff operation
+ */
+ protected $right;
+
+ /**
+ * @var integer $rightPos The current position within the right text
+ */
+ protected $rightPos;
+
+ /**
+ * @var array[] $changeSet Set of add, subtract, or change operations within the diff
+ */
+ protected $changeSet;
+
+ /**
+ * Get the set of add, subtract, and change operations required to transform leftText into rightText
+ *
+ * @param string $leftText The left, or old, revision of the text
+ * @param string $rightText The right, or new, revision of the text
+ * @return array[] Array of arrays containing changes to individual groups of lines within the text
+ * Each change consists of:
+ * An 'action', one of:
+ * - add
+ * - subtract
+ * - change
+ * 'content' that was added or removed, or in the case
+ * of a change, 'old_content' and 'new_content'
+ * 'left_pos' and 'right_pos' (in 1-indexed lines) of the change.
+ */
+ public function getChangeSet( $leftText, $rightText ) {
+ /**
+ * The internal diff utility, which is used when GNU diff is not available
+ * prefixes lines with 2 characters instead of 1.
+ * For more info see bug 41689.
+ */
+ if ( self::usingInternalDiff() ) {
+ $this->prefixLength = 2;
+ } else {
+ $this->prefixLength = 1;
+ }
+
+ $left = trim( $leftText ) . "\n";
+ $right = trim( $rightText ) . "\n";
+ $diff = wfDiff( $left, $right, '-u -w' );
+
+ return $this->parse( $diff, $left, $right );
+ }
+
+ /**
+ * Duplicates the check from the global wfDiff function to determine
+ * if we are using internal or external diff utilities
+ */
+ static protected function usingInternalDiff() {
+ global $wgDiff;
+
+ wfSuppressWarnings();
+ $haveDiff = $wgDiff && file_exists( $wgDiff );
+ wfRestoreWarnings();
+
+ return !$haveDiff;
+ }
+
+ /**
+ * Parse the unified diff output into an array of changes to individual groups of the text
+ *
+ * @param string $diff The unified diff output
+ * @param string $left The left side of the diff used for sanity checks
+ * @param string $right The right side of the diff used for sanity checks
+ *
+ * @return array[]
+ */
+ protected function parse( $diff, $left, $right ) {
+ $this->left = explode( "\n", $left );
+ $this->right = explode( "\n", $right );
+ $diff = explode( "\n", $diff );
+
+ $this->leftPos = 0;
+ $this->rightPos = 0;
+ $this->changeSet = array(
+ '_info' => array(
+ 'lhs-length' => count( $this->left ),
+ 'rhs-length' => count( $this->right ),
+ 'lhs' => $this->left,
+ 'rhs' => $this->right,
+ ),
+ );
+
+ $change = null;
+ foreach ( $diff as $line ) {
+ $change = $this->parseLine( $line, $change );
+ }
+ if ( $change === null ) {
+ return $this->changeSet;
+ } else {
+ return array_merge( $this->changeSet, $change->getChangeSet() );
+ }
+ }
+
+ /**
+ * Parse the next line of the unified diff output
+ *
+ * @param string $line The next line of the unified diff
+ * @param EchoDiffGroup $change Changes the the immediately previous lines
+ *
+ * @throws MWException
+ * @return EchoDiffGroup Changes to this line and any changed lines immediately previous
+ */
+ protected function parseLine( $line, EchoDiffGroup $change = null ) {
+ if ( $line ) {
+ $op = $line[0];
+ if ( strlen( $line ) > $this->prefixLength ) {
+ $line = substr( $line, $this->prefixLength );
+ } else {
+ $line = '';
+ }
+ } else {
+ $op = ' ';
+ }
+
+ switch( $op ) {
+ case '@': // metadata
+ if ( $change !== null ) {
+ $this->changeSet = array_merge( $this->changeSet, $change->getChangeSet() );
+ $change = null;
+ }
+ // @@ -start,numLines +start,numLines @@
+ list( , $left, $right ) = explode( ' ', $line );
+ list( $this->leftPos ) = explode( ',', substr( $left, 1 ) );
+ list( $this->rightPos ) = explode( ',', substr( $right, 1 ) );
+
+ // -1 because diff is 1 indexed and we are 0 indexed
+ $this->leftPos--;
+ $this->rightPos--;
+ break;
+
+ case ' ': // No changes
+ if ( $change !== null ) {
+ $this->changeSet = array_merge( $this->changeSet, $change->getChangeSet() );
+ $change = null;
+ }
+ $this->leftPos++;
+ $this->rightPos++;
+ break;
+
+ case '-': // subtract
+ if ( $this->left[$this->leftPos] !== $line ) {
+ throw new MWException( 'Positional error: left' );
+ }
+ if ( $change === null ) {
+ $change = new EchoDiffGroup( $this->leftPos, $this->rightPos );
+ }
+ $change->subtract( $line );
+ $this->leftPos++;
+ break;
+
+ case '+': // add
+ if ( $this->right[$this->rightPos] !== $line ) {
+ throw new MWException( 'Positional error: right' );
+ }
+ if ( $change === null ) {
+ $change = new EchoDiffGroup( $this->leftPos, $this->rightPos );
+ }
+ $change->add( $line );
+ $this->rightPos++;
+ break;
+
+ default:
+ throw new MWException( 'Unknown Diff Operation: ' . $op );
+ }
+
+ return $change;
+ }
+}
+
+/**
+ * Represents a single set of changes all effecting neighboring lines
+ */
+class EchoDiffGroup {
+ /**
+ * @var array The left and right position this change starts at
+ */
+ protected $position;
+
+ /**
+ * @var array The lines that have been added
+ */
+ protected $new = array();
+
+ /**
+ * @var array The lines that have been removed
+ */
+ protected $old = array();
+
+ /**
+ * @param integer $leftPos The starting line number in the left text
+ * @param integer $rightPos The starting line number in the right text
+ */
+ public function __construct( $leftPos, $rightPos ) {
+ // +1 due to the origional code use 1 indexing for this result
+ $this->position = array(
+ 'right-pos' => $rightPos + 1,
+ 'left-pos' => $leftPos + 1,
+ );
+ }
+
+ /**
+ * @param string $line Line in the right text but not in the left
+ */
+ public function add( $line ) {
+ $this->new[] = $line;
+ }
+
+ /**
+ * @param string $line Line in the left text but not in the right
+ */
+ public function subtract( $line ) {
+ $this->old[] = $line;
+ }
+
+ /**
+ * @return array[] set of changes
+ * Each change consists of:
+ * An 'action', one of:
+ * - add
+ * - subtract
+ * - change
+ * 'content' that was added or removed, or in the case
+ * of a change, 'old_content' and 'new_content'
+ * 'left_pos' and 'right_pos' (in 1-indexed lines) of the change.
+ */
+ public function getChangeSet() {
+ $old = implode( "\n", $this->old );
+ $new = implode( "\n", $this->new );
+ $position = $this->position;
+ $changeSet = array();
+
+ // The implodes must come first because we consider array( '' ) to also be false
+ // meaning a blank link replaced with content is an addition
+ if ( $old && $new ) {
+ $min = min( count( $this->old ), count( $this->new ) );
+ $changeSet[] = $position + array(
+ 'action' => 'change',
+ 'old_content' => implode( "\n", array_slice( $this->old, 0, $min ) ),
+ 'new_content' => implode( "\n", array_slice( $this->new, 0, $min ) ),
+ );
+ $position['left-pos'] += $min;
+ $position['right-pos'] += $min;
+ $old = implode( "\n", array_slice( $this->old, $min ) );
+ $new = implode( "\n", array_slice( $this->new, $min ) );
+ }
+
+ if ( $new ) {
+ $changeSet[] = $position + array(
+ 'action' => 'add',
+ 'content' => $new,
+ );
+ } elseif ( $old ) {
+ $changeSet[] = $position + array(
+ 'action' => 'subtract',
+ 'content' => $old,
+ );
+ }
+
+ return $changeSet;
+ }
+}
diff --git a/Echo/includes/DiscussionParser.php b/Echo/includes/DiscussionParser.php
new file mode 100644
index 00000000..bfb648b6
--- /dev/null
+++ b/Echo/includes/DiscussionParser.php
@@ -0,0 +1,875 @@
+<?php
+
+abstract class EchoDiscussionParser {
+ const HEADER_REGEX = '^(==+)\s*([^=].*)\s*\1$';
+
+ static protected $timestampRegex;
+ static protected $revisionInterpretationCache = array();
+ static protected $diffParser;
+
+ /**
+ * Given a Revision object, generates EchoEvent objects for
+ * the discussion-related actions that occurred in that Revision.
+ *
+ * @param $revision Revision object
+ * @return null
+ */
+ static function generateEventsForRevision( $revision ) {
+ $interpretation = self::getChangeInterpretationForRevision( $revision );
+
+ // use slave database if there is a previous revision
+ if ( $revision->getPrevious() ) {
+ $title = Title::newFromID( $revision->getPage() );
+ // use master database for new page
+ } else {
+ $title = Title::newFromID( $revision->getPage(), Title::GAID_FOR_UPDATE );
+ }
+
+ // not a valid title
+ if ( !$title ) {
+ return;
+ }
+
+ $userID = $revision->getUser();
+ $userName = $revision->getUserText();
+ $user = $userID != 0 ? User::newFromId( $userID ) : User::newFromName( $userName, false );
+
+ foreach ( $interpretation as $action ) {
+ // These two event types are disabled temporarily, there is no need to process them
+ if ( $action['type'] == 'add-comment' ) {
+ $fullSection = $action['full-section'];
+ $header = self::extractHeader( $fullSection );
+ self::generateMentionEvents( $header, $action['content'], $revision, $user );
+ } elseif ( $action['type'] == 'new-section-with-comment' ) {
+ $content = $action['content'];
+ $header = self::extractHeader( $content );
+ self::generateMentionEvents( $header, $content, $revision, $user );
+ }
+ }
+
+ if ( $title->getNamespace() == NS_USER_TALK ) {
+ $notifyUser = User::newFromName( $title->getText() );
+ // If the recipient is a valid non-anonymous user and hasn't turned
+ // off their notifications, generate a talk page post Echo notification.
+ if ( $notifyUser && $notifyUser->getID() && $notifyUser->getOption( 'echo-notify-show-link' ) ) {
+ // if this is a minor edit, only notify if the agent doesn't have talk page minor edit notification blocked
+ if ( !$revision->isMinor() || !$user->isAllowed( 'nominornewtalk' ) ) {
+ $section = self::detectSectionTitleAndText( $interpretation, $title );
+ EchoEvent::create( array(
+ 'type' => 'edit-user-talk',
+ 'title' => $title,
+ 'extra' => array(
+ 'revid' => $revision->getID(),
+ 'minoredit' => $revision->isMinor(),
+ 'section-title' => $section['section-title'],
+ 'section-text' => $section['section-text']
+ ),
+ 'agent' => $user,
+ ) );
+ }
+ }
+ }
+ }
+
+ /**
+ * Attempts to determine what section title the edit was performed under (if any)
+ *
+ * @param $interpretation array Results of self::getChangeInterpretationForRevision
+ * @return array Array containing section title and text
+ * @param Title $title
+ */
+ public static function detectSectionTitleAndText( array $interpretation, Title $title = null ) {
+ $header = $snippet = '';
+ $found = false;
+
+ foreach ( $interpretation as $action ) {
+ switch( $action['type'] ) {
+ case 'add-comment':
+ $header = self::extractHeader( $action['full-section'] );
+ $snippet = self::getTextSnippet( self::stripSignature( self::stripHeader( $action['content'] ), $title ), 150 );
+ break;
+ case 'new-section-with-comment':
+ $header = self::extractHeader( $action['content'] );
+ $snippet = self::getTextSnippet( self::stripSignature( self::stripHeader( $action['content'] ), $title ), 150 );
+ break;
+ }
+ if ( $header ) {
+ // If we find multiple headers within the same change interpretation then
+ // we cannot choose just 1 to link to
+ if ( $found ) {
+ return array( 'section-title' => '', 'section-text' => '' );
+ }
+ $found = $header;
+ }
+ }
+ if ( $found ) {
+ return array( 'section-title' => $header, 'section-text' => $snippet );
+ }
+ return array( 'section-title' => '', 'section-text' => '' );
+ }
+
+ /**
+ * For an action taken on a talk page, notify users whose user pages
+ * are linked.
+ * @param $header string The subject line for the discussion.
+ * @param $content string The content of the post, as a wikitext string.
+ * @param $revision Revision object.
+ * @param $agent User The user who made the comment.
+ */
+ public static function generateMentionEvents( $header, $content, $revision, $agent ) {
+ $title = $revision->getTitle();
+ if ( !$title ) {
+ return;
+ }
+
+ $output = self::parseNonEditWikitext( $content, new Article( $title ) );
+ $links = $output->getLinks();
+
+ if ( !isset( $links[NS_USER] ) || !is_array( $links[NS_USER] ) ) {
+ return;
+ }
+ $mentionedUsers = array();
+ $count = 0;
+
+ foreach ( $links[NS_USER] as $dbk => $page_id ) {
+ $user = User::newFromName( $dbk );
+
+ // we should not add user to 'mention' notification list if
+ // 1. the user name is not valid
+ // 2. the user mentions themselves
+ // 3. the user is the owner of the talk page
+ // 4. user is anonymous
+ if (
+ !$user || $user->isAnon() || $user->getId() == $revision->getUser() ||
+ ( $title->getNamespace() === NS_USER_TALK && $title->getDBkey() === $dbk )
+ ) {
+ continue;
+ }
+ $mentionedUsers[$user->getId()] = $user->getId();
+ $count++;
+ // If more than 20 users are being pinged this is likely a spam/attack vector
+ // Don't send any mention notifications.
+ if ( $count > 20 ) {
+ return;
+ }
+ }
+
+ if ( !$mentionedUsers ) {
+ return;
+ }
+
+ EchoEvent::create( array(
+ 'type' => 'mention',
+ 'title' => $title,
+ 'extra' => array(
+ 'content' => $content,
+ 'section-title' => $header,
+ 'revid' => $revision->getId(),
+ 'mentioned-users' => $mentionedUsers,
+ ),
+ 'agent' => $agent,
+ ) );
+ }
+
+ /**
+ * It's like Article::prepareTextForEdit,
+ * but not for editing (old wikitext usually)
+ * Stolen from AbuseFilterVariableHolder
+ *
+ * @param $wikitext String
+ * @param $article Article
+ *
+ * @return ParserOutput
+ */
+ static function parseNonEditWikitext( $wikitext, $article ) {
+ static $cache = array();
+
+ $cacheKey = md5( $wikitext ) . ':' . $article->getTitle()->getPrefixedText();
+
+ if ( isset( $cache[$cacheKey] ) ) {
+ return $cache[$cacheKey];
+ }
+
+ global $wgParser;
+ $options = new ParserOptions;
+ $options->setTidy( true );
+ $output = $wgParser->parse( $wikitext, $article->getTitle(), $options );
+ $cache[$cacheKey] = $output;
+
+ return $output;
+ }
+
+ /**
+ * Given a Revision object, determines which users are interested
+ * in related EchoEvents.
+ *
+ * @param $revision Revision object.
+ * @return Array of User objects
+ */
+ static function getNotifiedUsersForComment( $revision ) {
+ $interpretation = self::getChangeInterpretationForRevision( $revision );
+ $users = array();
+
+ foreach ( $interpretation as $action ) {
+ if ( $action['type'] == 'add-comment' ) {
+ $fullSection = $action['full-section'];
+ $interestedUsers = array_keys( self::extractSignatures( $fullSection, $revision->getTitle() ) );
+
+ foreach ( $interestedUsers as $userName ) {
+ $user = User::newFromName( $userName );
+
+ // Deliberately ignoring anonymous users
+ if ( $user && $user->getID() ) {
+ $users[$user->getID()] = $user;
+ }
+ }
+ }
+ }
+
+ if ( $revision->getTitle()->getNamespace() == NS_USER_TALK ) {
+ $userName = $revision->getTitle()->getText();
+ $user = User::newFromName( $userName );
+
+ if ( $user ) {
+ $users[$user->getID()] = $user;
+ }
+ }
+
+ return $users;
+ }
+
+ /**
+ * Given a Revision object, returns a talk-page-centric interpretation
+ * of the changes made in it.
+ *
+ * @param $revision Revision object
+ * @see EchoDiscussionParser::interpretDiff
+ * @return Array, see interpretDiff for details.
+ */
+ static function getChangeInterpretationForRevision( $revision ) {
+ if ( $revision->getID() && isset( self::$revisionInterpretationCache[$revision->getID()] ) ) {
+ return self::$revisionInterpretationCache[$revision->getID()];
+ }
+
+ $userID = $revision->getUser();
+ $userName = $revision->getUserText();
+ $user = $userID != 0 ? User::newFromId( $userID ) : User::newFromName( $userName, false );
+ $prevText = '';
+ if ( $revision->getParentId() ) {
+ $prevRevision = Revision::newFromId( $revision->getParentId() );
+ if ( $prevRevision ) {
+ $prevText = $prevRevision->getText();
+ }
+ }
+
+ $changes = self::getMachineReadableDiff( $prevText, $revision->getText() );
+ $output = self::interpretDiff( $changes, $user->getName(), $revision->getTitle() );
+
+ self::$revisionInterpretationCache[$revision->getID()] = $output;
+ return $output;
+ }
+
+ /**
+ * Given a machine-readable diff, interprets the changes
+ * in terms of discussion page actions
+ *
+ * @todo Expand recognisable actions.
+ * @param array $changes Output of EchoEvent::getMachineReadableDiff
+ * @param string $user Username
+ * @param Title $title
+ * @return Array of associative arrays.
+ * Each entry represents an action, which is classified in the 'action' field.
+ * All types contain a 'content' field except 'unknown'
+ * (which instead passes through the machine-readable diff in 'details')
+ * and 'unknown-change' (which provides 'new_content' and 'old_content')
+ * action may be:
+ * - add-comment: A comment signed by the user is added to an
+ * existing section.
+ * - new-section-with-comment: A new section is added, containing
+ * a single comment signed by the user in question.
+ * - unknown-signed-addition: Some signed content is added, but it
+ * includes section headers, is signed by another user or
+ * otherwise confuses the interpretation engine.
+ * - unknown-multi-signed-addition: Some signed content is added,
+ * but it contains multiple signatures.
+ * - unknown-unsigned-addition: Some content is added, but it is
+ * unsigned.
+ * - unknown-subtraction: Some content was removed. These actions are
+ * not currently analysed.
+ * - unknown-change: Some content was replaced with other content.
+ * These actions are not currently analysed.
+ * - unknown: Unrecognised change type.
+ */
+ static function interpretDiff( $changes, $user, Title $title = null ) {
+ // One extra item in $changes for _info
+ $actions = array();
+
+ foreach ( $changes as $index => $change ) {
+ if ( !is_numeric( $index ) ) {
+ continue;
+ }
+
+ if ( !$change['action'] ) {
+ // Unknown action; skip
+ continue;
+ }
+
+ if ( $change['action'] == 'add' ) {
+ $content = trim( $change['content'] );
+ // The \A means the regex must match at the begining of the string.
+ // This is slightly different than ^ which matches begining of each
+ // line in multiline mode.
+ $startSection = preg_match( "/\A" . self::HEADER_REGEX . '/um', $content );
+ $sectionCount = self::getSectionCount( $content );
+ $signedUsers = array_keys( self::extractSignatures( $content, $title ) );
+
+ if (
+ count( $signedUsers ) == 1 &&
+ in_array( $user, $signedUsers )
+ ) {
+ if ( $sectionCount === 0 ) {
+ $fullSection = self::getFullSection( $changes['_info']['rhs'], $change['right-pos'] );
+ $actions[] = array(
+ 'type' => 'add-comment',
+ 'content' => $content,
+ 'full-section' => $fullSection,
+ );
+ } elseif ( $startSection && $sectionCount === 1 ) {
+ $actions[] = array(
+ 'type' => 'new-section-with-comment',
+ 'content' => $content,
+ );
+ } else {
+ $actions[] = array(
+ 'type' => 'unknown-signed-addition',
+ 'content' => $content,
+ );
+ }
+ } elseif ( count( $signedUsers ) >= 1 ) {
+ $actions[] = array(
+ 'type' => 'unknown-multi-signed-addition',
+ 'content' => $content,
+ );
+ } else {
+ $actions[] = array(
+ 'type' => 'unknown-unsigned-addition',
+ 'content' => $content,
+ );
+ }
+ } elseif ( $change['action'] == 'subtract' ) {
+ $actions[] = array(
+ 'type' => 'unknown-subtraction',
+ 'content' => $change['content'],
+ );
+ } elseif ( $change['action'] == 'change' ) {
+ $actions[] = array(
+ 'type' => 'unknown-change',
+ 'old_content' => $change['old_content'],
+ 'new_content' => $change['new_content'],
+ );
+ } else {
+ $actions[] = array(
+ 'type' => 'unknown',
+ 'details' => $change,
+ );
+ }
+ }
+
+ // $actions['_diff'] = $changes;
+ // unset( $actions['_diff']['_info'] );
+
+ return $actions;
+ }
+
+ /**
+ * Finds the section that a given line is in.
+ *
+ * @param $lines Array of lines in the page.
+ * @param $offset int The line to find the full section for.
+ * @return string Content of the section.
+ */
+ static function getFullSection( $lines, $offset ) {
+ $content = $lines[$offset - 1];
+ $headerRegex = '/' . self::HEADER_REGEX . '/um';
+
+ // Expand backwards...
+ $continue = !preg_match( $headerRegex, $lines[$offset - 1] );
+ $i = $offset - 1;
+ while ( $continue && $i > 0 ) {
+ --$i;
+ $line = $lines[$i];
+ $content = "$line\n$content";
+ if ( preg_match( $headerRegex, $line ) ) {
+ $continue = false;
+ }
+ }
+
+ // And then forwards...
+
+ $continue = true;
+ $i = $offset - 1;
+ while ( $continue && $i < count( $lines ) - 1 ) {
+ ++$i;
+ $line = $lines[$i];
+ if ( preg_match( $headerRegex, $line ) ) {
+ $continue = false;
+ } else {
+ $content .= "\n$line";
+ }
+ }
+
+ return trim( $content, "\n" );
+ }
+
+ /**
+ * Gets the number of section headers in a string.
+ *
+ * @param $text string The text.
+ * @return int Number of section headers found.
+ */
+ static function getSectionCount( $text ) {
+ $text = trim( $text );
+
+ $matches = array();
+ preg_match_all( '/' . self::HEADER_REGEX . '/um', $text, $matches );
+
+ return count( $matches[0] );
+ }
+
+ /**
+ * Gets the title of a section or sub section
+ *
+ * @param $text string The text of the section.
+ * @return string The title of the section.
+ */
+ static function extractHeader( $text ) {
+ $text = trim( $text );
+
+ $matches = array();
+
+ if ( !preg_match_all( '/' . self::HEADER_REGEX . '/um', $text, $matches ) ) {
+ return false;
+ }
+
+ return trim( end( $matches[2] ) );
+ }
+
+ /**
+ * Strips out a signature if possible.
+ *
+ * @param $text string The wikitext to strip
+ * @param Title $title
+ * @return string
+ */
+ static function stripSignature( $text, Title $title = null ) {
+ $output = self::getUserFromLine( $text, $title );
+ if ( $output === false ) {
+ $timestampPos = self::getTimestampPosition( $text );
+ return substr( $text, 0, $timestampPos );
+ }
+
+ // Use truncate() instead of truncateHTML() because truncateHTML()
+ // would not strip signature if the text contains < or &
+ global $wgContLang;
+ return $wgContLang->truncate( $text, $output[0], '' );
+ }
+
+ /**
+ * Strips unnecessary indentation and so on from comments
+ *
+ * @param $text string The text to strip from
+ * @return string Stripped wikitext
+ */
+ static function stripIndents( $text ) {
+ // First strip all indentation from the beginning of lines
+ $text = preg_replace( '/^\s*\:+/m', '', $text );
+
+ // Now if there is only one list item, strip that too
+ $listRegex = '/^\s*(?:[\:#*]\s*)*[#*]/m';
+ $matches = array();
+ if ( preg_match_all( $listRegex, $text, $matches ) ) {
+ if ( count( $matches ) == 1 ) {
+ $text = preg_replace( $listRegex, '', $text );
+ }
+ }
+
+ return $text;
+ }
+
+ /**
+ * Strips out a section header
+ * @param $text string The text to strip out the section header from.
+ * @return string: The same text, with the section header stripped out.
+ */
+ static function stripHeader( $text ) {
+ $text = preg_replace( '/' . self::HEADER_REGEX . '/um', '', $text );
+
+ return $text;
+ }
+
+ /**
+ * Determines whether the input is a signed comment.
+ *
+ * @param $text string The text to check.
+ * @param $user User|bool If set, will only return true if the comment is
+ * signed by this user.
+ * @param Title $title
+ * @return bool: true or false.
+ */
+ static function isSignedComment( $text, $user = false, Title $title = null ) {
+ $userData = self::getUserFromLine( $text, $title );
+
+ if ( $userData === false ) {
+ return false;
+ } elseif ( $user === false ) {
+ return true;
+ }
+
+ list( , $foundUser ) = $userData;
+
+ return User::getCanonicalName( $foundUser, false ) === User::getCanonicalName( $user, false );
+ }
+
+ /**
+ * Finds the start position, if any, of the timestamp on a line
+ *
+ * @param $line string The line to search for a signature on
+ * @return int|bool Integer position
+ */
+ static function getTimestampPosition( $line ) {
+ $timestampRegex = self::getTimestampRegex();
+ $endOfLine = self::getLineEndingRegex();
+ $tsMatches = array();
+ if ( !preg_match(
+ "/$timestampRegex$endOfLine/mu",
+ $line,
+ $tsMatches,
+ PREG_OFFSET_CAPTURE
+ ) ) {
+ return false;
+ }
+
+ return $tsMatches[0][1];
+ }
+
+ /**
+ * Finds differences between $oldText and $newText
+ * and returns the result in a machine-readable format.
+ *
+ * @param $oldText string The "left hand side" of the diff.
+ * @param $newText string The "right hand side" of the diff.
+ * @throws MWException
+ * @return Array of changes.
+ * Each change consists of:
+ * * An 'action', one of:
+ * - add
+ * - subtract
+ * - change
+ * * 'content' that was added or removed, or in the case
+ * of a change, 'old_content' and 'new_content'
+ * * 'left_pos' and 'right_pos' (in lines) of the change.
+ */
+ static function getMachineReadableDiff( $oldText, $newText ) {
+ if ( !isset( self::$diffParser ) ) {
+ self::$diffParser = new EchoDiffParser;
+ }
+ return self::$diffParser->getChangeSet( $oldText, $newText );
+ }
+
+ /**
+ * Finds and extracts signatures in $text
+ *
+ * @param $text string The text in which to look for signed comments.
+ * @param Title $title
+ * @return array. Associative array, the key is the username, the value
+ * is the last signature that was found.
+ */
+ static function extractSignatures( $text, Title $title = null ) {
+ $lines = explode( "\n", $text );
+
+ $output = array();
+
+ $lineNumber = 0;
+
+ foreach ( $lines as $line ) {
+ ++$lineNumber;
+
+ // Look for the last user link on the line.
+ $userData = self::getUserFromLine( $line, $title );
+ if ( $userData === false ) {
+ // print "F\t$lineNumber\t$line\n";
+ continue;
+ } else {
+ // print "S\t$lineNumber\n";
+ }
+
+ list( $signaturePos, $user ) = $userData;
+
+ $signature = substr( $line, $signaturePos );
+ $output[$user] = $signature;
+ }
+
+ return $output;
+ }
+
+ /**
+ * From a line in a wiki page, determine which user, if any,
+ * has signed it.
+ *
+ * @param $line string The line.
+ * @param Title $title
+ * @return bool|array false for none, Array for success.
+ * - First element is the position of the signature.
+ * - Second element is the normalised user name.
+ */
+ static public function getUserFromLine( $line, Title $title = null ) {
+ global $wgParser;
+
+ // match all title-like excerpts in this line
+ if ( !preg_match_all( '/\[\[([^\[]+)\]\]/', $line, $matches ) ) {
+ return false;
+ }
+
+ /*
+ * Signatures can look like anything (as defined by i18n messages
+ * "signature" & "signature-anon").
+ * A signature can, e.g., be both a link to user & user-talk page.
+ * I'll be looping backwards through all founds links, figure out what
+ * matches to a user, regenerate the signature based on that user, and
+ * see if it matches!
+ */
+ $matches = array_reverse( $matches[1] );
+ foreach ( $matches as $match ) {
+ /*
+ * Create an object out of the link title.
+ * In theory, links can be [[text]], [[text|text]] or pipe tricks
+ * [[text|]] or [[|text]].
+ * In the case of reverse pipe trick, the value we use *could* be
+ * empty, but Parser::pstPass2 should have normalized that for us
+ * already.
+ */
+ $match = explode( '|', $match );
+ $title = Title::newFromText( $match[0] );
+
+ // figure out if we the link is related to a user
+ if ( $title && ( $title->getNamespace() === NS_USER || $title->getNamespace() === NS_USER_TALK ) ) {
+ $username = $title->getText();
+ } elseif ( $title && $title->isSpecial( 'Contributions' ) ) {
+ $parts = explode( '/', $title->getText(), 2 );
+ $username = end( $parts );
+ } else {
+ // move on to next matched title-like excerpt
+ continue;
+ }
+
+ // generate (dateless) signature from the user we think we've
+ // discovered the signature from
+ // don't validate the username - anon (IP) is fine!
+ $user = User::newFromName( $username, false );
+ $sig = $wgParser->preSaveTransform( '~~~', $title ?: Title::newMainPage(), $user, new ParserOptions() );
+
+ // see if we can find this user's generated signature in the content
+ $pos = strrpos( $line, $sig );
+ if ( $pos !== false ) {
+ return array( $pos, $username );
+ }
+
+ // couldn't find sig, move on to next link excerpt and try there
+ }
+
+ // couldn't find any matching signature
+ return false;
+ }
+
+ /**
+ * Find the last link beginning with a given prefix on a line.
+ *
+ * @param $line string The line to search.
+ * @param $linkPrefix string The prefix to search for.
+ * @param $failureOffset bool
+ * @return bool false for failure, array for success.
+ * - First element is the string offset of the link.
+ * - Second element is the user the link refers to.
+ */
+ static function getLinkFromLine( $line, $linkPrefix, $failureOffset = false ) {
+ $offset = 0;
+
+ // If extraction failed at another offset, try again.
+ if ( $failureOffset !== false ) {
+ $offset = $failureOffset - strlen( $line ) - 1;
+ }
+
+ // Avoid PHP warning: Offset is greater than the length of haystack string
+ if ( abs( $offset ) > strlen( $line ) ) {
+ return false;
+ }
+
+ $linkPos = strripos( $line, $linkPrefix, $offset );
+
+ if ( $linkPos === false ) {
+ // print "I\tNo match for $linkPrefix\n";
+ return false;
+ }
+
+ $linkUser = self::extractUserFromLink( $line, $linkPrefix, $linkPos );
+
+ if ( $linkUser === false ) {
+ // print "E\tExtraction failed\t$linkPrefix\n";
+ // Look for another place.
+ return self::getLinkFromLine( $line, $linkPrefix, $linkPos );
+ } else {
+ return array( $linkPos, $linkUser );
+ }
+ }
+
+ /**
+ * Given text including a link, gives the user that that link refers to
+ *
+ * @param $text string The text to extract from.
+ * @param $prefix string The link prefix that was used to find the link.
+ * @param $offset int Optionally, the offset of the start of the link.
+ * @return bool|string Type description
+ */
+ static function extractUserFromLink( $text, $prefix, $offset = 0 ) {
+ $userPart = substr( $text, strlen( $prefix ) + $offset );
+
+ $userMatches = array();
+ if ( !preg_match(
+ '/^[^\|\]\#]+/u',
+ $userPart,
+ $userMatches
+ ) ) {
+ // user link is invalid
+ // print "I\tUser link invalid\t$userPart\n";
+ // print "E\tCannot find user info to extract\n";
+ return false;
+ }
+
+ $user = $userMatches[0];
+
+ if (
+ !User::isIP( $user ) &&
+ User::getCanonicalName( $user ) === false
+ ) {
+ // Not a real username
+ // print "E\tInvalid username\n";
+ return false;
+ }
+
+ return User::getCanonicalName( $userMatches[0], false );
+ }
+
+ /**
+ * Gets a regular expression fragmentmatching characters that
+ * can appear in a line after the signature.
+ *
+ * @return String regular expression fragment.
+ */
+ static function getLineEndingRegex() {
+ $ignoredEndings = array(
+ '\s*',
+ preg_quote( '}' ),
+ preg_quote( '{' ),
+ '\<[^\>]+\>',
+ preg_quote( '{{' ) . '[^}]+' . preg_quote( '}}' ),
+ );
+
+ $regex = '(?:' . implode( '|', $ignoredEndings ) . ')*';
+
+ return $regex;
+ }
+
+ /**
+ * Gets a regular expression that will match this wiki's
+ * timestamps as given by ~~~~.
+ *
+ * @throws MWException
+ * @return String regular expression fragment.
+ */
+ static function getTimestampRegex() {
+ if ( self::$timestampRegex !== null ) {
+ return self::$timestampRegex;
+ }
+
+ // Step 1: Get an exemplar timestamp
+ $title = Title::newMainPage();
+ $user = User::newFromName( 'Test' );
+ $options = new ParserOptions;
+
+ global $wgParser;
+ $exemplarTimestamp =
+ $wgParser->preSaveTransform( '~~~~~', $title, $user, $options );
+
+ // Step 2: Generalise it
+ // Trim off the timezone to replace at the end
+ $output = $exemplarTimestamp;
+ $tzRegex = '/\s*\(\w+\)\s*$/';
+ $tzMatches = array();
+ if ( preg_match( $tzRegex, $output, $tzMatches ) ) {
+ $output = preg_replace( $tzRegex, '', $output );
+ }
+ $output = preg_quote( $output, '/' );
+ $output = preg_replace( '/[^\d\W]+/u', '[^\d\W]+', $output );
+ $output = preg_replace( '/\d+/u', '\d+', $output );
+
+ if ( $tzMatches ) {
+ $output .= preg_quote( $tzMatches[0] );
+ }
+
+ if ( !preg_match( "/$output/u", $exemplarTimestamp ) ) {
+ throw new MWException( "Timestamp regex does not match exemplar" );
+ }
+
+ self::$timestampRegex = $output;
+
+ return $output;
+ }
+
+ /**
+ * This function returns plain text snippet, it also removes html tag,
+ * template from text content
+ * @param $text string
+ * @param $length int default 150
+ * @return string
+ */
+ static function getTextSnippet( $text, $length = 150 ) {
+ global $wgLang;
+
+ $text = strip_tags( $text );
+ $attempt = 0;
+
+ // 10 attempts at most, the logic here is to find the first }} and
+ // find the matching {{ for that }}
+ while ( $attempt < 10 ) {
+ $closeCurPos = strpos( $text, '}}' );
+
+ if ( $closeCurPos === false ) {
+ break;
+ }
+ $tempStr = substr( $text, 0, $closeCurPos + 2 );
+
+ $openCurPos = strrpos( $tempStr, '{{' );
+ if ( $openCurPos === false ) {
+ $text = substr_replace( $text, '', $closeCurPos, 2 );
+ } else {
+ $text = substr_replace( $text, '', $openCurPos, $closeCurPos - $openCurPos + 2 );
+ }
+ $attempt++;
+ }
+
+ // See Parser::parse() function, &#160; is replaced specifically, replace it back here
+ // with a space as this html entity won't be handled by htmlspecialchars_decode()
+ $text = str_replace( '&#160;', ' ', MessageCache::singleton()->parse( $text )->getText() );
+ $text = trim( strip_tags( htmlspecialchars_decode( $text ) ) );
+ // strip out non-useful data for snippet
+ $text = str_replace( array( '{', '}' ), '', $text );
+ $text = $wgLang->truncate( $text, $length );
+
+ // Return empty string if there is undecoded char left
+ if ( strpos( $text, '&#' ) !== false ) {
+ $text = '';
+ }
+
+ return $text;
+ }
+}
diff --git a/Echo/includes/EchoDbFactory.php b/Echo/includes/EchoDbFactory.php
new file mode 100644
index 00000000..9934d91d
--- /dev/null
+++ b/Echo/includes/EchoDbFactory.php
@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * Database factory class, this will determine whether to use the main database
+ * or an external database defined in configuration file
+ */
+class MWEchoDbFactory {
+
+ /**
+ * The wiki to access the database for
+ * @var string|bool
+ */
+ protected $wiki;
+
+ /**
+ * The cluster for the database
+ * @var string|bool
+ */
+ protected $cluster;
+
+ /**
+ * @param string|bool
+ * @param string|bool
+ */
+ public function __construct( $cluster = false, $wiki = false ) {
+ $this->cluster = $cluster;
+ $this->wiki = $wiki;
+ }
+
+ /**
+ * Create a db factory instance from default Echo configuration
+ * DO NOT use singleton in here because job queue may run
+ * against multiple wikis, having a singleton would result in
+ * wrong db configuration. In addition, singleton is not necessary
+ * because it's actually handled inside core database object
+ *
+ * @return MWEchoDbFactory
+ */
+ public static function newFromDefault() {
+ global $wgEchoCluster;
+ return new self( $wgEchoCluster );
+ }
+
+ /**
+ * Get the database load balancer
+ * @param $wiki string|bool The wiki ID, or false for the current wiki
+ * @return LoadBalancer
+ */
+ protected function getLB() {
+ // Use the external db defined for Echo
+ if ( $this->cluster ) {
+ $lb = wfGetLBFactory()->getExternalLB( $this->cluster, $this->wiki );
+ } else {
+ $lb = wfGetLB( $this->wiki );
+ }
+
+ return $lb;
+ }
+
+ /**
+ * Get the database connection for Echo
+ * @param $db int Index of the connection to get
+ * @param $groups mixed Query groups.
+ * @return DatabaseBase
+ */
+ public function getEchoDb( $db, $groups = array() ) {
+ return $this->getLB()->getConnection( $db, $groups, $this->wiki );
+ }
+
+ /**
+ * Wrapper function for wfGetDB, some extensions like MobileFrontend is
+ * using this to issue sql queries against Echo database directly. This
+ * is totally not accepted and should be updated to use Echo database access
+ * objects
+ *
+ * @deprecated Use newFromDefault() instead to create a db factory
+ * @param $db int Index of the connection to get
+ * @param $groups mixed Query groups.
+ * @param $wiki string|bool The wiki ID, or false for the current wiki
+ * @return DatabaseBase
+ */
+ public static function getDB( $db, $groups = array(), $wiki = false ) {
+ global $wgEchoCluster;
+
+ // Use the external db defined for Echo
+ if ( $wgEchoCluster ) {
+ $lb = wfGetLBFactory()->getExternalLB( $wgEchoCluster, $wiki );
+ } else {
+ $lb = wfGetLB( $wiki );
+ }
+
+ return $lb->getConnection( $db, $groups, $wiki );
+
+ }
+
+ /**
+ * Wait for the slaves of the database
+ */
+ public function waitForSlaves() {
+ $this->waitFor( $this->getMasterPosition() );
+ }
+
+ /**
+ * Get the current master position for the wiki and echo
+ * db when they have at least one slave in their cluster.
+ *
+ * @return array
+ */
+ public function getMasterPosition() {
+ $position = array(
+ 'wikiDb' => false,
+ 'echoDb' => false,
+ );
+ $lb = wfGetLB();
+ if ( $lb->getServerCount() > 1 ) {
+ $position['wikiDb'] = $lb->getMasterPos();
+ };
+
+ if ( $this->cluster ) {
+ $lb = $this->getLB();
+ if ( $lb->getServerCount() > 1 ) {
+ $position['echoDb'] = $lb->getMasterPos();
+ }
+ }
+
+ return $position;
+ }
+
+ /**
+ * Recieves the output of self::getMasterPosition. Waits
+ * for slaves to catch up to the master position at that
+ * point.
+ *
+ * @param array $position
+ */
+ public function waitFor( array $position ) {
+ if ( $position['wikiDb'] ) {
+ wfGetLB()->waitFor( $position['wikiDb'] );
+ }
+ if ( $position['echoDb'] ) {
+ $this->getLB()->waitFor( $position['echoDb'] );
+ }
+ }
+}
diff --git a/Echo/includes/EmailBatch.php b/Echo/includes/EmailBatch.php
new file mode 100644
index 00000000..8e847982
--- /dev/null
+++ b/Echo/includes/EmailBatch.php
@@ -0,0 +1,263 @@
+<?php
+
+/**
+ * Handle user email batch ( daily/ weekly )
+ */
+abstract class MWEchoEmailBatch {
+
+ // the user to be notified
+ protected $mUser;
+
+ // list of email content
+ protected $content = array();
+ // the last notification event of this batch
+ protected $lastEvent;
+ // the event count, this count is supported up to self::$displaySize + 1
+ protected $count = 0;
+
+ // number of bundle events to include in an email, we couldn't include
+ // all events in a batch email
+ protected static $displaySize = 20;
+
+ /**
+ * @param $user User
+ */
+ public function __construct( User $user ) {
+ $this->mUser = $user;
+ }
+
+ /**
+ * Factory method to determine whether to create a batch instance for this
+ * user based on the user setting, this assumes the following value for
+ * member setting for echo-email-frequency
+ * -1 - no email
+ * 0 - instant
+ * 1 - once everyday
+ * 7 - once every 7 days
+ * @param $userId int
+ * @return MWEchoEmailBatch/false
+ */
+ public static function newFromUserId( $userId ) {
+ $batchClassName = self::getEmailBatchClass();
+
+ $user = User::newFromId( intval( $userId ) );
+
+ $userEmailSetting = intval( $user->getOption( 'echo-email-frequency' ) );
+
+ // clear all existing events if user decides not to receive emails
+ if ( $userEmailSetting == -1 ) {
+ $emailBatch = new $batchClassName( $user );
+ $emailBatch->clearProcessedEvent();
+ return false;
+ }
+
+ // @Todo - There may be some items idling in the queue, eg, a bundle job is lost
+ // and there is not never another message with the same hash or a user switches from
+ // digest to instant. We should check the first item in the queue, if it doesn't
+ // have either web or email bundling or created long ago, then clear it, this will
+ // prevent idling item queuing up.
+
+ // user has instant email delivery
+ if ( $userEmailSetting == 0 ) {
+ return false;
+ }
+
+ $userLastBatch = $user->getOption( 'echo-email-last-batch' );
+
+ // send email batch, if
+ // 1. it has been long enough since last email batch based on frequency
+ // 2. there is no last batch timestamp recorded for the user
+ // 3. user has switched from batch to instant email, send events left in the queue
+ if ( $userLastBatch ) {
+ // use 20 as hours per day to get estimate
+ $nextBatch = wfTimestamp( TS_UNIX, $userLastBatch ) + $userEmailSetting * 20 * 60 * 60;
+ if ( wfTimestamp( TS_MW, $nextBatch ) > wfTimestampNow() ) {
+ return false;
+ }
+ }
+
+ return new $batchClassName( $user );
+ }
+
+ /**
+ * Get the name of the email batch class
+ * @return string
+ * @throws MWException
+ */
+ private static function getEmailBatchClass() {
+ global $wgEchoBackendName;
+
+ $className = 'MW' . $wgEchoBackendName . 'EchoEmailBatch';
+
+ if ( !class_exists( $className ) ) {
+ throw new MWException( "$wgEchoBackendName email batch is not supported!" );
+ }
+
+ return $className;
+ }
+
+ /**
+ * Wrapper function that calls other functions required to process email batch
+ */
+ public function process() {
+ // if there is no event for this user, exist the process
+ if ( !$this->setLastEvent() ) {
+ return;
+ }
+
+ // get valid events
+ $events = $this->getEvents();
+
+ if ( $events ) {
+ foreach( $events as $row ) {
+ $this->count++;
+ if ( $this->count > self::$displaySize ) {
+ break;
+ }
+ $event = EchoEvent::newFromRow( $row );
+ $this->appendContent( $event, $row->eeb_event_hash );
+ }
+
+ $this->sendEmail();
+ }
+
+ $this->clearProcessedEvent();
+ $this->updateUserLastBatchTimestamp();
+ }
+
+ /**
+ * Set the last event of this batch, this is a cutoff point for clearing
+ * processed/invalid events
+ *
+ * @return bool true if event exists false otherwise
+ */
+ abstract protected function setLastEvent();
+
+ /**
+ * Update the user's last batch timestamp after a successful batch
+ */
+ protected function updateUserLastBatchTimestamp() {
+ $this->mUser->setOption( 'echo-email-last-batch', wfTimestampNow() );
+ $this->mUser->saveSettings();
+ $this->mUser->invalidateCache();
+ }
+
+ /**
+ * Get the events queued for the current user
+ * @return array
+ */
+ abstract protected function getEvents();
+
+ /**
+ * Add individual event template to the big email content
+ */
+ protected function appendContent( $event, $hash ) {
+ // get the category for this event
+ $category = $event->getCategory();
+ $event->setBundleHash( $hash );
+ $email = EchoNotificationController::formatNotification( $event, $this->mUser, 'email', 'emaildigest' );
+
+ if ( !isset( $this->content[$category] ) ) {
+ $this->content[$category] = array();
+ }
+ $this->content[$category][] = $email;
+ }
+
+ /**
+ * Clear "processed" events in the queue, processed could be: email sent, invalid, users do not want to receive emails
+ */
+ abstract public function clearProcessedEvent();
+
+ /**
+ * Send the batch email
+ */
+ public function sendEmail() {
+ global $wgNotificationSender, $wgNotificationReplyName;
+
+ // @Todo - replace them with the CONSTANT in 33810 once it is merged
+ if ( $this->mUser->getOption( 'echo-email-frequency' ) == 7 ) {
+ $frequency = 'weekly';
+ $emailDeliveryMode = 'weekly_digest';
+ } else {
+ $frequency = 'daily';
+ $emailDeliveryMode = 'daily_digest';
+ }
+
+ // Echo digest email mode
+ $emailDigest = new EchoEmailDigest( $this->mUser, $this->content, $frequency );
+
+ $textEmailFormatter = new EchoTextEmailFormatter( $emailDigest );
+
+ $body = $textEmailFormatter->formatEmail();
+
+ $format = MWEchoNotifUser::newFromUser( $this->mUser )->getEmailFormat();
+ if ( $format == EchoHooks::EMAIL_FORMAT_HTML ) {
+ $htmlEmailFormatter = new EchoHTMLEmailFormatter( $emailDigest );
+ $body = array(
+ 'text' => $body,
+ 'html' => $htmlEmailFormatter->formatEmail()
+ );
+ }
+
+ // email subject
+ if ( $this->count > self::$displaySize ) {
+ $count = wfMessage( 'echo-notification-count' )
+ ->inLanguage( $this->mUser->getOption( 'language' ) )
+ ->params( self::$displaySize )->text();
+ } else {
+ $count = $this->count;
+ }
+ // Give grep a chance to find the usages:
+ // echo-email-batch-subject-daily, echo-email-batch-subject-weekly
+ $subject = wfMessage( 'echo-email-batch-subject-' . $frequency )
+ ->inLanguage( $this->mUser->getOption( 'language' ) )
+ ->params( $count, $this->count )->text();
+
+ $toAddress = MailAddress::newFromUser( $this->mUser );
+ $fromAddress = new MailAddress( $wgNotificationSender, EchoHooks::getNotificationSenderName() );
+ $replyAddress = new MailAddress( $wgNotificationSender, $wgNotificationReplyName );
+
+ // @Todo Push the email to job queue or just send it out directly?
+ UserMailer::send( $toAddress, $fromAddress, $subject, $body, $replyAddress );
+ MWEchoEventLogging::logSchemaEchoMail( $this->mUser, $emailDeliveryMode );
+ }
+
+ /**
+ * Insert notification event into email queue
+ *
+ * @param $userId int
+ * @param $eventId int
+ * @param $priority int
+ * @param $hash string
+ *
+ * @throws MWException
+ */
+ public static function addToQueue( $userId, $eventId, $priority, $hash ) {
+ $batchClassName = self::getEmailBatchClass();
+
+ if ( !method_exists( $batchClassName, 'actuallyAddToQueue' ) ) {
+ throw new MWException( "$batchClassName must implement method actuallyAddToQueue()" );
+ }
+
+ $batchClassName::actuallyAddToQueue( $userId, $eventId, $priority, $hash );
+ }
+
+ /**
+ * Get a list of users to be notified for the batch
+ *
+ * @param $startUserId int
+ * @param $batchSize int
+ *
+ * @throws MWException
+ * @return ResultWrapper|bool
+ */
+ public static function getUsersToNotify( $startUserId, $batchSize ) {
+ $batchClassName = self::getEmailBatchClass();
+
+ if ( !method_exists( $batchClassName, 'actuallyGetUsersToNotify' ) ) {
+ throw new MWException( "$batchClassName must implement method actuallyGetUsersToNotify()" );
+ }
+
+ return $batchClassName::actuallyGetUsersToNotify( $startUserId, $batchSize );
+ }
+}
diff --git a/Echo/includes/EmailBundler.php b/Echo/includes/EmailBundler.php
new file mode 100644
index 00000000..ba01ad11
--- /dev/null
+++ b/Echo/includes/EmailBundler.php
@@ -0,0 +1,292 @@
+<?php
+
+/**
+ * This class handles email bundling, it has only two public interfacing entries:
+ *
+ * 1. a single notification is triggered which calls self::addToEmailBatch()
+ * (a) cycle is null/reset, send single notification, schedule a bundle job for next notification
+ * (b) cycle is in bundle mode, add the notification to the queue
+ *
+ * 2. a job is popped off the queue which calls self::processBundleEmail()
+ *
+ */
+abstract class MWEchoEmailBundler {
+
+ /**
+ * @var User
+ */
+ protected $mUser;
+
+ /**
+ * @var string
+ */
+ protected $bundleHash;
+
+ /**
+ * @var string
+ *
+ * The timestamp of email being sent
+ */
+ protected $timestamp;
+
+ /**
+ * @var EchoEvent
+ */
+ protected $baseEvent;
+
+ /**
+ * @var int
+ *
+ * seconds between sending batch email for a bundle notification
+ * this only applies to a bundle type
+ */
+ protected $emailInterval;
+
+ /**
+ * Private constructor
+ */
+ private function __construct( $user, $hash ) {
+ global $wgEchoBundleEmailInterval;
+
+ $this->mUser = $user;
+ $this->bundleHash = $hash;
+ $this->emailInterval = $wgEchoBundleEmailInterval;
+
+ if ( $this->emailInterval < 0 ) {
+ $this->emailInterval = 0;
+ }
+ }
+
+ /**
+ * Get the name of the email batch class
+ * @return string
+ * @throws MWException
+ */
+ private static function getEmailBundlerClass() {
+ global $wgEchoBackendName;
+
+ $className = 'MW' . $wgEchoBackendName . 'EchoEmailBundler';
+
+ if ( !class_exists( $className ) ) {
+ throw new MWException( "$wgEchoBackendName email bundler is not supported!" );
+ }
+
+ return $className;
+ }
+
+ /**
+ * Factory method
+ */
+ public static function newFromUserHash( User $user, $hash ) {
+ if ( !$user->getId() ) {
+ return false;
+ }
+ if ( !$hash || !preg_match( '/^[a-f0-9]{32}$/', $hash ) ) {
+ return false;
+ }
+ $className = self::getEmailBundlerClass();
+ return new $className( $user, $hash );
+ }
+
+ /**
+ * Check if a new notification should be added to the batch queue
+ * true - added to the queue for bundling email
+ * false - not added, the client should send single email
+ *
+ * @param int $eventId
+ * @param int $eventPriority
+ *
+ * @return bool
+ */
+ public function addToEmailBatch( $eventId, $eventPriority ) {
+ $this->retrieveLastEmailTimestamp();
+ $this->retrieveBaseEvent();
+
+ // send instant single notification email if there is no base event in the batch queue
+ // and the email is ready to send, otherwiase, add the email to batch and schedule
+ // a delayed job
+ if ( !$this->baseEvent && $this->shouldSendEmailNow() ) {
+ $this->timestamp = wfTimestampNow();
+ $this->updateEmailMetadata();
+ return false;
+ } else {
+ // add to email batch queue
+ MWEchoEmailBatch::addToQueue(
+ $this->mUser->getId(),
+ $eventId,
+ $eventPriority,
+ $this->bundleHash
+ );
+
+ // always push the job to job queue in case the previous job
+ // was lost, job queue will ignore duplicate
+ $this->pushToJobQueue( $this->getDelayTime() );
+ return true;
+ }
+ }
+
+ /**
+ * Get the time diff since last email
+ */
+ protected function timeSinceLastEmail() {
+ // if there is no timestamp, next email should be sent right away
+ // set the time diff longer than the email interval
+ if ( !$this->timestamp ) {
+ return $this->emailInterval + 600;
+ }
+
+ $now = wfTimestamp( TS_UNIX );
+
+ return $now - wfTimestamp( TS_UNIX, $this->timestamp );
+ }
+
+ /**
+ * Check if an email should be sent right away
+ * @return bool
+ */
+ protected function shouldSendEmailNow() {
+ if ( $this->timeSinceLastEmail() > $this->emailInterval ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the delay time
+ * @return int
+ */
+ protected function getDelayTime() {
+ $delay = $this->emailInterval - $this->timeSinceLastEmail();
+ if ( $delay <= 0 ) {
+ $delay = 0;
+ }
+ return $delay;
+ }
+
+ /**
+ * Get the timestamp of last email
+ */
+ protected function retrieveLastEmailTimestamp() {
+ global $wgMemc;
+
+ $data = $wgMemc->get( $this->getMemcacheKey() );
+ if ( $data !== false ) {
+ $this->timestamp = $data['timestamp'];
+ }
+ }
+
+ /**
+ * Get the memcache key
+ * @return string
+ */
+ protected function getMemcacheKey() {
+ return wfMemcKey( 'echo', 'email_bundle_status', $this->mUser->getId(), $this->bundleHash );
+ }
+
+ /**
+ * Retrieve the base event for email bundling
+ * @return bool
+ */
+ abstract protected function retrieveBaseEvent();
+
+ /**
+ * Push the latest bundle data to the queue
+ * @param $delay int To delay the job in $delay seconds
+ */
+ public function pushToJobQueue( $delay = 0 ) {
+ $title = Title::newMainPage();
+ $job = new MWEchoNotificationEmailBundleJob(
+ $title,
+ array(
+ 'user_id' => $this->mUser->getId(),
+ 'bundle_hash' => $this->bundleHash,
+ 'jobReleaseTimestamp' => wfTimestamp( TS_MW, wfTimestamp( TS_UNIX ) + $delay )
+ )
+ );
+ JobQueueGroup::singleton()->push( $job );
+ }
+
+ /**
+ * Main function for processinig bundle email
+ */
+ public function processBundleEmail() {
+ $emailSetting = intval( $this->mUser->getOption( 'echo-email-frequency' ) );
+
+ // User has switched to email digest or decided not to receive email,
+ // the daily cron will handle events left in the queue
+ if ( $emailSetting != 0 ) {
+ throw new MWException( "User has switched to email digest/no email option!" );
+ }
+
+ // If there is nothing in the queue, do not update timestamp so next
+ // email would be just an instant email
+ if ( $this->retrieveBaseEvent() ) {
+ $this->timestamp = wfTimestampNow();
+ $this->updateEmailMetadata();
+ $this->sendEmail();
+ $this->clearProcessedEvent();
+ } else {
+ throw new MWException( "There is no bundle notification to process!" );
+ }
+ }
+
+ /**
+ * Send the bundle email
+ */
+ protected function sendEmail() {
+ $content = $this->generateEmailContent();
+
+ if ( !isset( $content['subject'] ) || !isset( $content['body'] ) ) {
+ throw new MWException( "Fail to create bundle email content!" );
+ }
+
+ global $wgNotificationSender, $wgNotificationReplyName;
+
+ $toAddress = MailAddress::newFromUser( $this->mUser );
+ $fromAddress = new MailAddress( $wgNotificationSender, EchoHooks::getNotificationSenderName() );
+ $replyAddress = new MailAddress( $wgNotificationSender, $wgNotificationReplyName );
+
+ // Schedule a email job or just send the email directly?
+ UserMailer::send( $toAddress, $fromAddress, $content['subject'], $content['body'], $replyAddress );
+ MWEchoEventLogging::logSchemaEchoMail( $this->mUser, 'bundle' );
+ }
+
+ /**
+ * Generate the content for bundle email
+ * @return string
+ */
+ protected function generateEmailContent() {
+ if ( !$this->baseEvent ) {
+ return '';
+ }
+ $this->baseEvent->setBundleHash( $this->bundleHash );
+ return EchoNotificationController::formatNotification( $this->baseEvent, $this->mUser, 'email', 'email' );
+ }
+
+ /**
+ * Update bundle email metadata for user/hash pair
+ */
+ protected function updateEmailMetadata() {
+ global $wgMemc;
+
+ $key = $this->getMemcacheKey();
+
+ // Delete existing data
+ $wgMemc->delete( $key );
+ // Store new data and make it expire in 7 days
+ $wgMemc->set(
+ $key,
+ array(
+ 'timestamp' => $this->timestamp
+ ),
+ 3600 * 24 * 7
+ );
+ }
+
+ /**
+ * clear processed event in the queue
+ */
+ abstract protected function clearProcessedEvent();
+
+}
diff --git a/Echo/includes/EmailFormatter.php b/Echo/includes/EmailFormatter.php
new file mode 100644
index 00000000..aa0da68f
--- /dev/null
+++ b/Echo/includes/EmailFormatter.php
@@ -0,0 +1,866 @@
+<?php
+
+/**
+ * Abstract class for formatting email notifications
+ */
+abstract class EchoEmailFormatter {
+
+ /**
+ * @var EchoEmailMode
+ */
+ protected $emailMode;
+
+ /**
+ * @param $emailMode EchoEmailMode
+ */
+ public function __construct( EchoEmailMode $emailMode ) {
+ $this->emailMode = $emailMode;
+ }
+
+ /**
+ * Abstract method for formatting email
+ * @return string
+ */
+ abstract public function formatEmail();
+}
+
+/**
+ * Formatter class for formatting text email notification
+ */
+class EchoTextEmailFormatter extends EchoEmailFormatter {
+
+ /**
+ * @param $emailMode EchoEmailMode
+ */
+ public function __construct( EchoEmailMode $emailMode ) {
+ parent::__construct( $emailMode );
+ $this->emailMode->attachDecorator( new EchoTextEmailDecorator() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function formatEmail() {
+ $template = $this->emailMode->getTextTemplate();
+
+ foreach ( $this->emailMode->getComponent() as $val ) {
+ $func = 'build' . ucfirst( $val );
+ $template = str_replace( "%%$val%%", $this->emailMode->$func(), $template );
+ }
+
+ // Remove redundant newline characters
+ return $this->removeExtraNewLine( $template );
+ }
+
+ /**
+ * Remove extra newline from a text content
+ * @param $text string
+ * @return string
+ */
+ protected function removeExtraNewLine( $text ) {
+ return preg_replace( "/\n{3,}/", "\n\n", $text );
+ }
+
+}
+
+/**
+ * Formatter class for formatting HTML email notification
+ */
+class EchoHTMLEmailFormatter extends EchoEmailFormatter {
+
+ /**
+ * @param $emailMode EchoEmailMode
+ */
+ public function __construct( EchoEmailMode $emailMode ) {
+ parent::__construct( $emailMode );
+ $this->emailMode->attachDecorator( new EchoHTMLEmailDecorator() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function formatEmail() {
+ $template = $this->emailMode->getHTMLTemplate();
+
+ foreach ( $this->emailMode->getComponent() as $val ) {
+ $func = 'build' . ucfirst( $val );
+ $template = str_replace( "%%$val%%", $this->emailMode->$func(), $template );
+ }
+
+ return $template;
+ }
+}
+
+/**
+ * Abstract entity that represents an email delivery mode
+ */
+abstract class EchoEmailMode {
+
+ /**
+ * @var array
+ * Email components
+ */
+ protected $component;
+
+ /**
+ * @var User
+ * The user who receives email notifications
+ */
+ protected $user;
+
+ /**
+ * @var EchoEmailDecorator
+ * Email decorator
+ */
+ protected $decorator;
+
+ /**
+ * @var Language
+ * The language object for the user language
+ */
+ protected $lang;
+
+ /**
+ * @param $user User
+ * @param $component array
+ */
+ public function __construct( User $user, array $component ) {
+ $this->user = $user;
+ // All email delivery mode share the same footer
+ $this->component = array_merge( $component, array( 'footer' ) );
+ // Initialize with a text decorator, the decorator can be altered
+ // via attacheDecorator() based on text/html emails
+ $this->decorator = new EchoTextEmailDecorator();
+ $this->lang = Language::factory( $user->getOption( 'language' ) );
+ }
+
+ /**
+ * Get text email template
+ * @return string
+ */
+ abstract public function getTextTemplate();
+
+ /**
+ * Get html email template
+ * @return string
+ */
+ abstract public function getHTMLTemplate();
+
+ /**
+ * Get the footer component
+ * @return string
+ */
+ public function buildFooter() {
+ global $wgEchoEmailFooterAddress;
+ return $this->decorator->decorateFooter( $wgEchoEmailFooterAddress, $this->user );
+ }
+
+ /**
+ * Getter method for email template component
+ * @return array
+ */
+ public function getComponent() {
+ return $this->component;
+ }
+
+ /**
+ * Get the notification icon path
+ * @param $icon string
+ * @return string
+ */
+ public static function getNotifIcon( $icon ) {
+ global $wgEchoNotificationIcons, $wgExtensionAssetsPath, $wgLang;
+
+ $iconInfo = $wgEchoNotificationIcons[$icon];
+ if ( isset( $iconInfo['url'] ) && $iconInfo['url'] ) {
+ $iconUrl = $iconInfo['url'];
+ } else {
+ if ( !isset( $iconInfo['path'] ) || !$iconInfo['path'] ) {
+ $iconInfo = $wgEchoNotificationIcons['placeholder'];
+ }
+ if ( is_array( $iconInfo['path'] ) ) {
+ $dir = $wgLang->getDir();
+ if ( isset( $iconInfo['path'][$dir] ) ) {
+ $path = $iconInfo['path'][$dir];
+ } else {
+ wfDebugLog( 'Echo', "The \"$icon\" icon does not have anything set for $dir direction." );
+ $path = $wgEchoNotificationIcons['placeholder']['path']; // Fallback
+ }
+ } else {
+ $path = $iconInfo['path'];
+ }
+ $iconUrl = "$wgExtensionAssetsPath/$path";
+ }
+
+ // Use http for image path, there is no need for https
+ return wfExpandUrl( $iconUrl, PROTO_HTTP );
+ }
+
+ /**
+ * Attach an email decorator to the email mode object
+ * @param $decorator EchoEmailDecorator
+ */
+ public function attachDecorator( EchoEmailDecorator $decorator ) {
+ $this->decorator = $decorator;
+ }
+
+ /**
+ * Format the message in the user's language
+ * @param $message string
+ * @param $user User
+ * @return Message
+ */
+ public static function message( $message, $user ) {
+ return wfMessage( $message )->inLanguage( $user->getOption( 'language' ) );
+ }
+
+}
+
+/**
+ * Entity that represents a single email delivery mode
+ */
+class EchoEmailSingle extends EchoEmailMode {
+
+ /**
+ * @var EchoBasicFormatter
+ */
+ protected $notifFormatter;
+
+ /**
+ * @var EchoEvent
+ */
+ protected $event;
+
+ /**
+ * @param $notifFormatter EchoBasicFormatter
+ * @param $event EchoEvent
+ * @param $user User
+ */
+ public function __construct( EchoBasicFormatter $notifFormatter, EchoEvent $event, User $user ) {
+ parent::__construct( $user, array ( 'emailIcon', 'intro', 'summary', 'action' ) );
+ $this->notifFormatter = $notifFormatter;
+ $this->event = $event;
+ }
+
+ /**
+ * Build the intro component
+ * @return string
+ */
+ public function buildIntro() {
+ $bundle = $this->notifFormatter->getValue( 'bundleData' );
+ $email = $this->notifFormatter->getValue( 'email' );
+
+ if ( $bundle['use-bundle'] && $email['batch-bundle-body']['message'] ) {
+ $detail = $email['batch-bundle-body'];
+ } else {
+ $detail = $email['batch-body'];
+ }
+
+ $message = $this->notifFormatter->formatFragment(
+ $detail,
+ $this->event,
+ $this->user
+ );
+
+ return $this->decorator->decorateIntro( $message );
+ }
+
+ /**
+ * Build the summary component
+ * @return string
+ */
+ public function buildSummary() {
+ return $this->decorator->decorateRevisionSnippet(
+ $this->notifFormatter->getRevisionSnippet(
+ $this->event,
+ $this->user
+ )
+ );
+ }
+
+ /**
+ * Build the action component
+ * @return string
+ */
+ public function buildAction() {
+ $link = array();
+ $ranks = array( 'primary', 'secondary' );
+
+ foreach ( $ranks as $rank ) {
+ $message = $this->event->getLinkMessage( $rank );
+
+ // Valid call to action should have link text
+ if ( !$message ) {
+ continue;
+ }
+
+ $link[] = $this->decorator->decorateSingleAction(
+ $this->notifFormatter,
+ $this->event,
+ $this->user,
+ $rank,
+ $message
+ );
+ }
+
+ // Add some spacing between the two action links
+ $spacing = $this->decorator->getActionLinkSeparator();
+ return implode( $spacing . $spacing, $link );
+ }
+
+ /**
+ * Build the email icon component
+ * @return string
+ */
+ public function buildEmailIcon() {
+ return EchoEmailMode::getNotifIcon( $this->notifFormatter->getValue( 'icon' ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getTextTemplate() {
+ return <<< EOF
+%%intro%%
+
+%%summary%%
+
+%%action%%
+
+%%footer%%
+EOF;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getHTMLTemplate() {
+ $alignStart = $this->lang->alignStart();
+ return <<< EOF
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <style>
+ @media only screen and (max-width: 480px){
+ table[id="email-container"]{max-width:600px !important; width:100% !important;}
+ }
+ </style>
+</head><body>
+<table cellspacing="0" cellpadding="0" border="0" width="100%" align="center" lang="{$this->lang->getCode()}" dir="{$this->lang->getDir()}">
+<tr>
+ <td bgcolor="#E6E7E8"><center>
+ <br /><br />
+ <table cellspacing="0" cellpadding="0" border="0" width="600" id="email-container">
+ <tr>
+ <td bgcolor="#FFFFFF" width="5%">&nbsp;</td>
+ <td bgcolor="#FFFFFF" width="10%">&nbsp;</td>
+ <td bgcolor="#FFFFFF" width="80%" style="line-height:40px;">&nbsp;</td>
+ <td bgcolor="#FFFFFF" width="5%">&nbsp;</td>
+ </tr><tr>
+ <td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
+ <td bgcolor="#FFFFFF" align="center" valign="top" rowspan="2"><img src="%%emailIcon%%" alt="" height="30" width="30"></td>
+ <td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:13px; line-height:20px; color:#6D6E70;">%%intro%%</td>
+ <td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
+ </tr><tr>
+ <td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; line-height: 20px; font-weight: 600;">
+ <table cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; padding-top: 8px; font-size:13px; font-weight: bold; color: #58585B;">
+ %%summary%%
+ </td>
+ </tr>
+ </table>
+ <table cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:14px; padding-top: 25px;">
+ %%action%%
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr><tr>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ <td bgcolor="#FFFFFF" style="line-height:40px;">&nbsp;</td>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ </tr><tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:10px; line-height:13px; color:#6D6E70; padding:10px 20px;"><br />
+ %%footer%%
+ <br /><br />
+ </td>
+ <td>&nbsp;</td>
+ </tr><tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+ </table>
+ <br><br></center>
+ </td>
+</tr>
+</table>
+</body></html>
+EOF;
+ }
+
+}
+
+/**
+ * Class that represents email digest delivery mode
+ */
+class EchoEmailDigest extends EchoEmailMode {
+
+ /**
+ * @var string
+ * The mode of email digest, 'weekly' or 'daily'
+ */
+ protected $digestMode;
+
+ /**
+ * @var array
+ * Raw email digest list
+ */
+ protected $rawDigestList;
+
+ /**
+ * @param $user User
+ * @param $rawDigestList array the raw notification event list
+ * @param $digestMode string 'daily'/'weekly'
+ */
+ public function __construct( User $user, array $rawDigestList, $digestMode = 'daily' ) {
+ parent::__construct( $user, array( 'intro', 'digestList', 'action' ) );
+ // Some data validation
+ if ( !in_array( $digestMode, array( 'daily', 'weekly' ) ) ) {
+ $digestMode = 'daily';
+ }
+ $this->digestMode = $digestMode;
+ $this->rawDigestList = $rawDigestList;
+ }
+
+ /**
+ * Build the intro component
+ * @return string
+ */
+ public function buildIntro() {
+ // Give grep a chance to find the usages:
+ // echo-email-batch-body-intro-daily, echo-email-batch-body-intro-weekly
+ $message = EchoEmailMode::message(
+ 'echo-email-batch-body-intro-' . $this->digestMode, $this->user
+ )->params( $this->user->getName() );
+
+ return $this->decorator->decorateIntro( $message );
+ }
+
+ /**
+ * Build the digestList component
+ * @return string
+ */
+ public function buildDigestList() {
+ if ( !$this->rawDigestList ) {
+ return '';
+ }
+
+ return $this->decorator->decorateDigestList( $this->rawDigestList, $this->user );
+ }
+
+ /**
+ * Build the action component
+ * @return string
+ */
+ public function buildAction() {
+ $title = SpecialPage::getTitleFor( 'Notifications' );
+
+ return $this->decorator->decorateDigestAction( $title, $this->user );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getTextTemplate() {
+ return <<< EOF
+%%intro%%
+
+%%digestList%%
+
+%%action%%
+
+%%footer%%
+
+EOF;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getHTMLTemplate() {
+ $alignStart = $this->lang->alignStart();
+ return <<< EOF
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <style>
+ @media only screen and (max-width: 480px){
+ table[id="email-container"]{max-width:600px !important; width:100% !important;}
+ }
+ </style>
+</head><body>
+<table cellspacing="0" cellpadding="0" border="0" width="100%" align="center" lang="{$this->lang->getCode()}" dir="{$this->lang->getDir()}">
+<tr>
+ <td bgcolor="#E6E7E8"><center>
+ <br /><br />
+ <table cellspacing="0" cellpadding="0" border="0" width="600" id="email-container">
+ <tr>
+ <td bgcolor="#FFFFFF" width="5%">&nbsp;</td>
+ <td bgcolor="#FFFFFF" width="6%">&nbsp;</td>
+ <td bgcolor="#FFFFFF" width="79%" style="line-height:40px;">&nbsp;</td>
+ <td bgcolor="#FFFFFF" width="10%">&nbsp;</td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
+ <td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
+ <td bgcolor="#FFFFFF" align="center" style="font-family: Arial, Helvetica, sans-serif; font-size:13px; line-height:20px; color:#6D6E70; text-align: center;">%%intro%%</td>
+ <td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; line-height: 20px; font-weight: 600;">
+ <table cellspacing="0" cellpadding="0" border="0" width="100%">
+ <tr>
+ <td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:13px; color: #58585B; padding-top: 25px;">
+ %%digestList%%
+ </td>
+ </tr>
+ </table>
+ <br /><br />
+ </td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ <td bgcolor="#FFFFFF" style="line-height:60px;" align="center">%%action%%</td>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ <td bgcolor="#FFFFFF" style="line-height:40px;">&nbsp;</td>
+ <td bgcolor="#FFFFFF">&nbsp;</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:10px; line-height:13px; color:#6D6E70; padding: 10px 20px;"><br />
+ %%footer%%
+ <br /><br />
+ </td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+ </table>
+ <br><br></center>
+ </td>
+</tr>
+</table>
+</body></html>
+EOF;
+ }
+
+}
+
+/**
+ * Email decorator interface
+ */
+interface EchoEmailDecorator {
+ /**
+ * Decorate the intro for all modes
+ * @param $message Message the intro message object
+ * @return string
+ */
+ public function decorateIntro( $message );
+
+ /**
+ * Decorate the digest list for digest mode
+ * @param $digestList array
+ * @param $user User
+ * @return string
+ */
+ public function decorateDigestList( $digestList, $user );
+
+ /**
+ * Decorate the primary action for digest mode
+ * @param $title Title
+ * @param $user User
+ * @return string
+ */
+ public function decorateDigestAction( $title, $user );
+
+ /**
+ * Decorate the footer for all mode
+ * @param $address string
+ * @param $user User
+ * @return string
+ */
+ public function decorateFooter( $address, $user );
+
+ /**
+ * Decorate the actions for single mode
+ * @param $notifFormatter EchoBasicFormatter
+ * @param $event EchoEvent
+ * @param $user User
+ * @param $rank string
+ * @param $message string
+ * @return string
+ */
+ public function decorateSingleAction( $notifFormatter, $event, $user, $rank, $message );
+
+ /**
+ * Decorate a revision snippet
+ * @param string $snippet the raw revision snippet
+ * @return string
+ */
+ public function decorateRevisionSnippet( $snippet );
+
+ /**
+ * Get the spacing for between action links
+ * @return string
+ */
+ public function getActionLinkSeparator();
+}
+
+/**
+ * Text email decorator
+ */
+class EchoTextEmailDecorator implements EchoEmailDecorator {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateIntro( $message ) {
+ return $message->text();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestList( $digestList, $user ) {
+ $result = array();
+
+ // build the text section for each category
+ foreach( $digestList as $category => $notifs ) {
+ $output = EchoEmailMode::message( 'echo-category-title-' . $category, $user )->numParams( count( $notifs ) )->text()
+ . EchoEmailMode::message( 'colon-separator', $user )->text() . "\n";
+
+ foreach( $notifs as $notif ) {
+ $output .= "\n " . EchoEmailMode::message( 'echo-email-batch-bullet', $user )->text() . ' ' . $notif['batch-body'];
+ }
+ $result[] = $output;
+ }
+
+ // for prepending and appending 'echo-email-batch-separator'
+ $result = array_merge( array( '' ), $result, array( '' ) );
+
+ return trim(
+ implode(
+ "\n\n" . EchoEmailMode::message( 'echo-email-batch-separator', $user )->text() . "\n\n",
+ $result
+ )
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestAction( $title, $user ) {
+ return EchoEmailMode::message( 'echo-email-batch-link-text-view-all-notifications', $user )->text()
+ . EchoEmailMode::message( 'colon-separator', $user )->text()
+ . '<'
+ . $title->getFullURL( '', false, PROTO_HTTPS )
+ . '>';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateFooter( $address, $user ) {
+ return EchoEmailMode::message( 'echo-email-footer-default', $user )
+ ->params(
+ $address,
+ EchoEmailMode::message( 'echo-email-batch-separator', $user )->text()
+ )
+ ->text();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateSingleAction( $notifFormatter, $event, $user, $rank, $message ) {
+ $url = $notifFormatter->getLink( $event, $user, $rank, false, true );
+
+ return EchoEmailMode::message( $message, $user )->text()
+ . EchoEmailMode::message( 'colon-separator', $user )->text()
+ . '<'
+ . $notifFormatter->sanitizeEmailLink( $url )
+ . '>';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateRevisionSnippet( $snippet ) {
+ // Doing nothing now, but there is a potential to wrap the text
+ // around snippet with quote in plain text email
+ return $snippet;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getActionLinkSeparator() {
+ return "\n";
+ }
+}
+
+/**
+ * HTML email decorator
+ */
+class EchoHTMLEmailDecorator implements EchoEmailDecorator {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateIntro( $message ) {
+ return nl2br( $message->parse() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestList( $digestList, $user ) {
+ $result = array();
+ // build the html section for each category
+ foreach( $digestList as $category => $notifs ) {
+ $output = $this->applyStyleToCategory(
+ EchoEmailMode::message( 'echo-category-title-' . $category, $user )
+ ->numParams( count( $notifs ) )
+ ->escaped()
+ );
+ foreach( $notifs as $notif ) {
+ $output .= "\n" . $this->applyStyleToEvent( $notif );
+ }
+ $result[] = '<table border="0" width="100%">' . $output . '</table>';
+ }
+
+ return trim( implode( "\n", $result ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestAction( $title, $user ) {
+ return Linker::link(
+ $title,
+ EchoEmailMode::message( 'echo-email-batch-link-text-view-all-notifications', $user )->escaped(),
+ array( 'style' => $this->getPrimaryLinkCSS() ),
+ array(),
+ array( 'https' )
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateFooter( $address, $user ) {
+ $title = SpecialPage::getTitleFor( 'Preferences' );
+ $title->setFragment( "#mw-prefsection-echo" );
+ return EchoEmailMode::message( 'echo-email-footer-default-html', $user )
+ ->params( $address )
+ ->rawParams( $title->getFullURL( '', false, PROTO_HTTPS ) )
+ ->text();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateSingleAction( $notifFormatter, $event, $user, $rank, $message ) {
+ if ( $rank === 'primary' ) {
+ $style = $this->getPrimaryLinkCSS();
+ } else {
+ $style = $this->getSecondaryLinkCSS();
+ }
+
+ return $notifFormatter->getLink( $event, $user, $rank, false, false, $style );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateRevisionSnippet( $snippet ) {
+ return htmlspecialchars( $snippet );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getActionLinkSeparator() {
+ return "&nbsp;";
+ }
+
+ /**
+ * The style for primary link
+ * @return string
+ */
+ protected function getPrimaryLinkCSS() {
+ return 'cursor:pointer; text-align:center; text-decoration:none; padding:.45em 1.2em .45em;
+ color:#D9EEF7; background:#3366BB; font-family: Arial, Helvetica, sans-serif;font-size: 13px;';
+ }
+
+ /**
+ * The style for secondary link
+ * @return string
+ */
+ protected function getSecondaryLinkCSS() {
+ return 'text-decoration: none;font-size: 10px;font-family: Arial, Helvetica, sans-serif; color: #808184';
+ }
+
+ /**
+ * Apply style to notification category header
+ * @param $category string
+ * @return string
+ */
+ protected function applyStyleToCategory( $category ) {
+ return <<< EOF
+<tr>
+ <td colspan="2" style="color: #A87B4F; font-weight: normal; font-size: 13px; padding-top: 15px;">
+ $category <br />
+ <hr style="background-color:#FFFFFF; color:#FFFFFF; border: 1px solid #F2F2F2;" />
+ </td>
+</tr>
+EOF;
+ }
+
+ /**
+ * Apply style to individual notification event
+ * @param $notif array an array containts keys: icon, batch-body, batch-body-html
+ * @return string
+ */
+ protected function applyStyletoEvent( $notif ) {
+ // notification icon
+ $icon = EchoEmailMode::getNotifIcon( $notif['icon'] );
+ // notification text
+ $text = $notif['batch-body-html'];
+
+ return <<< EOF
+<tr>
+ <td width="30">
+ <img src="$icon" width="30" height="30" style="vertical-align:middle;">
+ </td>
+ <td style="font-family: Arial, Helvetica, sans-serif; font-size:13px; color: #58585B;">
+ $text
+ </td>
+</tr>
+EOF;
+ }
+
+}
+
diff --git a/Echo/includes/EventLogging.php b/Echo/includes/EventLogging.php
new file mode 100644
index 00000000..753b9a92
--- /dev/null
+++ b/Echo/includes/EventLogging.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Static class for handling all kinds of event logging
+ */
+class MWEchoEventLogging {
+
+ /**
+ * This is the only function that interacts with EventLogging
+ * @param $schema string
+ * @param $data array
+ */
+ public static function actuallyLogTheEvent( $schema, $data ) {
+ global $wgEchoConfig;
+
+ EventLogging::logEvent( $schema, $wgEchoConfig['eventlogging'][$schema]['revision'], $data );
+ }
+
+ /**
+ * Function for logging the event for Schema:Echo
+ * @param $user User being notified.
+ * @param $event EchoEvent to log detail about.
+ * @param $deliveryMethod string containing either 'web' or 'email'
+ */
+ public static function logSchemaEcho( User $user, EchoEvent $event, $deliveryMethod ) {
+ global $wgEchoConfig, $wgEchoNotifications;
+ if ( !$wgEchoConfig['eventlogging']['Echo']['enabled'] ) {
+ // Only attempt event logging if Echo schema is enabled
+ return;
+ }
+
+ // Notifications under system category should have -1 as sender id
+ if ( $event->getCategory() === 'system' ) {
+ $sender = -1;
+ } else {
+ $agent = $event->getAgent();
+ if ( $agent ) {
+ $sender = $agent->isAnon() ? $agent->getName() : $agent->getId();
+ } else {
+ $sender = -1;
+ }
+ }
+
+ if ( isset( $wgEchoNotifications[$event->getType()]['group'] ) ) {
+ $group = $wgEchoNotifications[$event->getType()]['group'];
+ } else {
+ $group = 'neutral';
+ }
+ $data = array (
+ 'version' => $wgEchoConfig['version'],
+ 'eventId' => $event->getId(),
+ 'notificationType' => $event->getType(),
+ 'notificationGroup' => $group,
+ 'sender' => (string)$sender,
+ 'recipientUserId' => $user->getId(),
+ 'recipientEditCount' => (int)$user->getEditCount()
+ );
+ // Add the source if it exists. (This is mostly for the Thanks extension.)
+ $extra = $event->getExtra();
+ if ( isset( $extra['source'] ) ) {
+ $data['eventSource'] = (string)$extra['source'];
+ }
+ if( $deliveryMethod == 'email' ) {
+ $data['deliveryMethod'] = 'email';
+ } else {
+ // whitelist valid delivery methods so it is always valid
+ $data['deliveryMethod'] = 'web';
+ }
+ // Add revision ID if it exists
+ $rev = $event->getRevision();
+ if ( $rev ) {
+ $data['revisionId'] = $rev->getId();
+ }
+
+ self::actuallyLogTheEvent( 'Echo', $data );
+ }
+
+ /**
+ * Function for logging the event for Schema:EchoEmail
+ * @param $user User
+ * @param $emailDeliveryMode string
+ */
+ public static function logSchemaEchoMail( User $user, $emailDeliveryMode = 'single' ) {
+ global $wgEchoConfig;
+
+ if ( !$wgEchoConfig['eventlogging']['EchoMail']['enabled'] ) {
+ // Only attempt event logging if EchoMail schema is enabled
+ return;
+ }
+
+ $data = array (
+ 'version' => $wgEchoConfig['version'],
+ 'recipientUserId' => $user->getId(),
+ 'emailDeliveryMode' => $emailDeliveryMode
+ );
+
+ self::actuallyLogTheEvent( 'EchoMail', $data );
+ }
+
+}
diff --git a/Echo/includes/NotifUser.php b/Echo/includes/NotifUser.php
new file mode 100644
index 00000000..30ca94da
--- /dev/null
+++ b/Echo/includes/NotifUser.php
@@ -0,0 +1,376 @@
+<?php
+
+/**
+ * Entity that represents a notification target user
+ */
+class MWEchoNotifUser {
+
+ /**
+ * Notification target user
+ * @var User
+ */
+ private $mUser;
+
+ /**
+ * Object cache
+ * @var BagOStuff
+ */
+ private $cache;
+
+ /**
+ * Database access gateway
+ * @var EchoUserNotificationGateway
+ */
+ private $userNotifGateway;
+
+ /**
+ * Notification mapper
+ * @var EchoNotificationMapper
+ */
+ private $notifMapper;
+
+ /**
+ * Target page mapper
+ * @var EchoTargetPageMapper
+ */
+ private $targetPageMapper;
+
+ /**
+ * Whether to check cache for section status
+ */
+ static $sectionStatusCheckCache = array (
+ EchoAttributeManager::ALERT => false,
+ EchoAttributeManager::MESSAGE => true
+ );
+
+ /**
+ * Usually client code doesn't need to initialize the object directly
+ * because it could be obtained from factory method newFromUser()
+ * @param User $user
+ * @param BagOStuff $cache
+ * @param EchoUserNotificationGateway $userNotifGateway
+ * @param EchoNotificationMapper $notifMapper
+ * @param EchoTargetPageMapper $targetPageMapper
+ */
+ public function __construct(
+ User $user,
+ BagOStuff $cache,
+ EchoUserNotificationGateway $userNotifGateway,
+ EchoNotificationMapper $notifMapper,
+ EchoTargetPageMapper $targetPageMapper
+ ) {
+ $this->mUser = $user;
+ $this->userNotifGateway = $userNotifGateway;
+ $this->cache = $cache;
+ $this->notifMapper = $notifMapper;
+ $this->targetPageMapper = $targetPageMapper;
+ }
+
+ /**
+ * Factory method
+ * @param $user User
+ * @throws MWException
+ * @return MWEchoNotifUser
+ */
+ public static function newFromUser( User $user ) {
+ if ( $user->isAnon() ) {
+ throw new MWException( 'User must be logged in to view notification!' );
+ }
+ global $wgMemc;
+ return new MWEchoNotifUser(
+ $user, $wgMemc,
+ new EchoUserNotificationGateway( $user, MWEchoDbFactory::newFromDefault() ),
+ new EchoNotificationMapper(),
+ new EchoTargetPageMapper()
+ );
+ }
+
+ /**
+ * Check whether should trigger a query to fetch data for a section when making
+ * such request. This method normally should return true for all section.
+ * For some sections, it's better to save the result in cache and check before
+ * triggering a query. Flow is in very limited deployment, Most *users would
+ * not have flow notifications, it's better to save *this status in cache
+ * to save a query. In addition, Flow notification is far less than other
+ * notifications for most users at this moment. Querying could be expensive
+ * in extreme cases
+ * @param string $section
+ * @return boolean
+ */
+ public function shouldQuerySectionData( $section ) {
+ if ( !self::$sectionStatusCheckCache[$section] ) {
+ return true;
+ }
+ $cacheVal = $this->cache->get( $this->sectionStatusCacheKey( $section ) );
+ // '1' means should query
+ // '0' means should not query
+ // false means no cache and should query
+ if ( $cacheVal !== '0' ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Set section data status into cache, '1' means there is data for the section,
+ * '0' means there is no data for this section
+ * @param string $section
+ * @param int $num
+ */
+ public function setSectionStatusCache( $section, $num ) {
+ if ( !self::$sectionStatusCheckCache[$section] ) {
+ return;
+ }
+ $key = $this->sectionStatusCacheKey( $section );
+ // Set cache for 5 days
+ if ( $num > 0 ) {
+ $this->cache->set( $key, '1', 432000 );
+ } else {
+ $this->cache->set( $key, '0', 432000 );
+ }
+ }
+
+ /**
+ * Clear section data cache for the section
+ * @param string
+ */
+ public function clearSectionStatusCache( $section ) {
+ if ( !self::$sectionStatusCheckCache[$section] ) {
+ return;
+ }
+ $this->cache->delete(
+ $this->sectionStatusCacheKey( $section )
+ );
+ }
+
+ /**
+ * Get the section data status cache key
+ * @param string $section
+ * @return string
+ */
+ protected function sectionStatusCacheKey( $section ) {
+ global $wgEchoConfig;
+ return wfMemcKey(
+ 'echo-notification-section-exist',
+ $section,
+ $this->mUser->getId(),
+ $wgEchoConfig['version']
+ );
+ }
+
+ /**
+ * Clear talk page notification when users visit their talk pages. This
+ * only resets if the notification count is less than max notification
+ * count. If the user has 99+ notifications, decrementing 1 bundled talk
+ * page notification would not really affect the count
+ */
+ public function clearTalkNotification() {
+ // There is no new talk notification
+ if ( $this->cache->get( $this->getTalkNotificationCacheKey() ) === '0' ) {
+ return;
+ }
+
+ // Do nothing if the count display meets the max 99+
+ if ( $this->notifCountHasReachedMax() ) {
+ return;
+ }
+
+ // Mark the talk page notification as read
+ $this->markRead(
+ $this->userNotifGateway->getUnreadNotifications(
+ 'edit-user-talk'
+ )
+ );
+
+ $this->flagCacheWithNoTalkNotification();
+ }
+
+ /**
+ * Flag the cache with new talk notification
+ */
+ public function flagCacheWithNewTalkNotification() {
+ $this->cache->set( $this->getTalkNotificationCacheKey(), '1', 86400 );
+ }
+
+ /**
+ * Flag the cache with no talk notification
+ */
+ public function flagCacheWithNoTalkNotification() {
+ $this->cache->set( $this->getTalkNotificationCacheKey(), '0', 86400 );
+ }
+
+ /**
+ * Memcache key for talk notification
+ */
+ public function getTalkNotificationCacheKey() {
+ global $wgEchoConfig;
+
+ return wfMemcKey( 'echo-new-talk-notification', $this->mUser->getId(), $wgEchoConfig['version'] );
+ }
+
+ /**
+ * Check if the user has more notification count than max count display
+ * @return bool
+ */
+ public function notifCountHasReachedMax() {
+ global $wgEchoMaxNotificationCount;
+
+ if ( $this->getNotificationCount() > $wgEchoMaxNotificationCount ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Retrieves number of unread notifications that a user has, would return
+ * $wgEchoMaxNotificationCount + 1 at most
+ *
+ * @param boolean $cached Set to false to bypass the cache.
+ * @param int $dbSource Use master or slave database to pull count
+ * @param string $section Notification section
+ * @return int
+ */
+ public function getNotificationCount( $cached = true, $dbSource = DB_SLAVE, $section = EchoAttributeManager::ALL ) {
+ global $wgEchoConfig;
+
+ if ( $this->mUser->isAnon() ) {
+ return 0;
+ }
+
+ $memcKey = wfMemcKey(
+ 'echo-notification-count' . ( $section === EchoAttributeManager::ALL ? '' : ( '-' . $section ) ),
+ $this->mUser->getId(),
+ $wgEchoConfig['version']
+ );
+
+ if ( $cached && $this->cache->get( $memcKey ) !== false ) {
+ return (int)$this->cache->get( $memcKey );
+ }
+
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ if ( $section === EchoAttributeManager::ALL ) {
+ $eventTypesToLoad = $attributeManager->getUserEnabledEvents( $this->mUser, 'web' );
+ } else {
+ $eventTypesToLoad = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', array( $section ) );
+ }
+
+ $count = $this->userNotifGateway->getNotificationCount( $dbSource, $eventTypesToLoad );
+
+ $this->cache->set( $memcKey, $count, 86400 );
+
+ return (int)$count;
+ }
+
+ /**
+ * Mark one or more notifications read for a user.
+ * @param $eventIds Array of event IDs to mark read
+ * @return boolean
+ */
+ public function markRead( $eventIds ) {
+ $eventIds = array_filter( (array)$eventIds, 'is_numeric' );
+ if ( !$eventIds || wfReadOnly() ) {
+ return false;
+ }
+
+ $res = $this->userNotifGateway->markRead( $eventIds );
+ if ( $res ) {
+ // Delete records from echo_target_page
+ $this->targetPageMapper->deleteByUserEvents( $this->mUser, $eventIds );
+ // Update notification count in cache
+ $this->resetNotificationCount( DB_MASTER );
+ }
+ return $res;
+ }
+
+ /**
+ * Attempt to mark all or sections of notifications as read, this only
+ * updates up to $wgEchoMaxUpdateCount records per request, see more
+ * detail about this in Echo.php, the other reason is that mediawiki
+ * database interface doesn't support updateJoin() that would update
+ * across multiple tables, we would visit this later
+ *
+ * @param string[] $sections
+ * @return boolean
+ */
+ public function markAllRead( array $sections = array( EchoAttributeManager::ALL ) ) {
+ if ( wfReadOnly() ) {
+ return false;
+ }
+
+ global $wgEchoMaxUpdateCount;
+
+ // Mark all sections as read if this is the case
+ if ( in_array( EchoAttributeManager::ALL, $sections ) ) {
+ $sections = EchoAttributeManager::$sections;
+ }
+
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $eventTypes = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', $sections );
+
+ $notifs = $this->notifMapper->fetchUnreadByUser( $this->mUser, $wgEchoMaxUpdateCount, $eventTypes );
+
+ $eventIds = array_filter(
+ array_map( function( EchoNotification $notif ) {
+ // This should not happen at all, but use 0 in
+ // such case so to keep the code running
+ if ( $notif->getEvent() ) {
+ return $notif->getEvent()->getId();
+ } else {
+ return 0;
+ }
+ }, $notifs )
+ );
+
+ $res = $this->markRead( $eventIds );
+ if ( $res ) {
+ // Delete records from echo_target_page
+ $this->targetPageMapper->deleteByUserEvents( $this->mUser, $eventIds );
+ if ( count( $notifs ) < $wgEchoMaxUpdateCount ) {
+ $this->flagCacheWithNoTalkNotification();
+ }
+ }
+ return $res;
+ }
+
+ /**
+ * Recalculates the number of notifications that a user has.
+ * @param $dbSource int use master or slave database to pull count
+ */
+ public function resetNotificationCount( $dbSource = DB_SLAVE ) {
+ // Reset notification count for all sections as well
+ $this->getNotificationCount( false, $dbSource, EchoAttributeManager::ALL );
+ $this->getNotificationCount( false, $dbSource, EchoAttributeManager::ALERT );
+ $this->getNotificationCount( false, $dbSource, EchoAttributeManager::MESSAGE );
+ $this->mUser->invalidateCache();
+ }
+
+ /**
+ * Retrieves formatted number of unread notifications that a user has.
+ * @param boolean $cached Set to false to bypass the cache.
+ * @param int $dbSource use master or slave database to pull count
+ * @param string $section
+ * @return string
+ */
+ public function getFormattedNotificationCount( $cached = true, $dbSource = DB_SLAVE, $section = EchoAttributeManager::ALL ) {
+ return EchoNotificationController::formatNotificationCount(
+ $this->getNotificationCount( $cached, $dbSource, $section )
+ );
+ }
+
+ /**
+ * Get the user's email notification format
+ * @return string
+ */
+ public function getEmailFormat() {
+ global $wgAllowHTMLEmail;
+
+ if ( $wgAllowHTMLEmail ) {
+ return $this->mUser->getOption( 'echo-email-format' );
+ } else {
+ return EchoHooks::EMAIL_FORMAT_PLAIN_TEXT;
+ }
+ }
+
+}
diff --git a/Echo/includes/UserLocator.php b/Echo/includes/UserLocator.php
new file mode 100644
index 00000000..45f2b905
--- /dev/null
+++ b/Echo/includes/UserLocator.php
@@ -0,0 +1,156 @@
+<?php
+
+class EchoUserLocator {
+ /**
+ * Return all users watching the event title.
+ *
+ * The echo job queue must be enabled to prevent timeouts submitting to
+ * heavily watched pages when this is used.
+ *
+ * @param EchoEvent $event
+ * @return User[]
+ */
+ public static function locateUsersWatchingTitle( EchoEvent $event, $batchSize = 500 ) {
+ $title = $event->getTitle();
+ if ( !$title ) {
+ return array();
+ }
+
+ $it = new EchoBatchRowIterator(
+ wfGetDB( DB_SLAVE, 'watchlist' ),
+ /* $table = */ 'watchlist',
+ /* $primaryKeys = */ array( 'wl_user' ),
+ $batchSize
+ );
+ $it->addConditions( array(
+ 'wl_namespace' => $title->getNamespace(),
+ 'wl_title' => $title->getDBkey(),
+ ) );
+
+ // flatten the result into a stream of rows
+ $it = new RecursiveIteratorIterator( $it );
+
+ // add callback to convert user id to user objects
+ $it = new EchoCallbackIterator( $it, function( $row ) {
+ return User::newFromId( $row->wl_user );
+ } );
+
+ return $it;
+ }
+
+ /**
+ * If the event occured on the talk page of a registered
+ * user return that user.
+ *
+ * @param EchoEvent $event
+ * @return User[]
+ */
+ public static function locateTalkPageOwner( EchoEvent $event ) {
+ $title = $event->getTitle();
+ if ( !$title || $title->getNamespace() !== NS_USER_TALK ) {
+ return array();
+ }
+
+ $user = User::newFromName( $title->getDBkey() );
+ if ( $user && !$user->isAnon() ) {
+ return array( $user->getId() => $user );
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Return the event agent
+ *
+ * @param EchoEvent $event
+ * @return User[]
+ */
+ public static function locateEventAgent( EchoEvent $event ) {
+ $agent = $event->getAgent();
+ if ( $agent && !$agent->isAnon() ) {
+ return array( $agent->getId() => $agent );
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Return the user that created the first revision of the
+ * associated title.
+ *
+ * @param EchoEvent $evnet
+ * @return User[]
+ */
+ public static function locateArticleCreator( EchoEvent $event ) {
+ $agent = $event->getAgent();
+ $title = $event->getTitle();
+
+ if ( !$title || $title->getArticleID() <= 0 ) {
+ return array();
+ }
+ // why?
+ if ( !$agent ) {
+ return array();
+ }
+
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->selectRow(
+ array( 'revision' ),
+ array( 'rev_user' ),
+ array( 'rev_page' => $title->getArticleID() ),
+ __METHOD__,
+ array( 'LIMIT' => 1, 'ORDER BY' => 'rev_timestamp, rev_id' )
+ );
+ if ( !$res || !$res->rev_user ) {
+ return array();
+ }
+
+ $user = User::newFromId( $res->rev_user );
+ if ( $user ) {
+ return array( $user->getId() => $user );
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Fetch user ids from the event extra data. Requires additional
+ * parameter. Example $wgEchoNotifications parameter:
+ *
+ * 'user-locator' => array( array( 'event-extra', 'mentions' ) ),
+ *
+ * The above will look in the 'mentions' parameter for a user id or
+ * array of user ids. It will return all these users as notification
+ * targets.
+ *
+ * @param EchoEvent $event
+ * @param string[] $keys one or more keys to check for user ids
+ * @return User[]
+ */
+ public static function locateFromEventExtra( EchoEvent $event, array $keys ) {
+ $users = array();
+ foreach ( $keys as $key ) {
+ $userIds = $event->getExtraParam( $key );
+ if ( !$userIds ) {
+ continue;
+ } elseif ( !is_array( $userIds ) ) {
+ $userIds = array( $userIds );
+ }
+ foreach ( $userIds as $userId ) {
+ // we shouldn't receive User instances, but allow
+ // it for backward compatability
+ if ( $userId instanceof User ) {
+ if ( $userId->isAnon() ) {
+ continue;
+ }
+ $user = $userId;
+ } else {
+ $user = User::newFromId( $userId );
+ }
+ $users[$user->getId()] = $user;
+ }
+ }
+
+ return $users;
+ }
+}
diff --git a/Echo/includes/cache/LocalCache.php b/Echo/includes/cache/LocalCache.php
new file mode 100644
index 00000000..6d357340
--- /dev/null
+++ b/Echo/includes/cache/LocalCache.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * Base Local cache object, which borrows the concept from Flow user listener
+ */
+abstract class EchoLocalCache {
+
+ /**
+ * Max number of objects to hold in $targets. In theory, 1000
+ * is very hard to reach in a normal web request. We need to
+ * put cap so it doesn't reach memory limit when running email
+ * digest against large amount of notications
+ */
+ const TARGET_MAX_NUM = 1000;
+
+ /**
+ * Target object cache
+ * @var MapCacheLRU
+ */
+ protected $targets;
+
+ /**
+ * Lookup ids that have not been resolved for a target
+ * @param int[]
+ */
+ protected $lookups = array();
+
+ /**
+ * Resolve ids in lookups to targets
+ */
+ abstract protected function resolve();
+
+ /**
+ * Use Factory method like EchoTitleLocalCache::create()
+ */
+ protected function __construct() {
+ $this->targets = new MapCacheLRU( self::TARGET_MAX_NUM );
+ }
+
+ /**
+ * Add a key to the lookup and the key is used to resolve cache target
+ *
+ * @param int $key
+ */
+ public function add( $key, $target = null ) {
+ if (
+ count( $this->lookups ) < self::TARGET_MAX_NUM
+ && !$this->targets->get( $key )
+ ) {
+ $this->lookups[$key] = $key;
+ }
+ }
+
+ /**
+ * Get the cache target based on the key
+ *
+ * @param int $key
+ * @return mixed|null
+ */
+ public function get( $key ) {
+ $target = $this->targets->get( $key );
+ if ( $target ) {
+ return $target;
+ }
+
+ if ( isset( $this->lookups[$key] ) ) {
+ $this->resolve();
+ $target = $this->targets->get( $key );
+ if ( $target ) {
+ return $target;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Clear everything in local cache
+ */
+ public function clearAll() {
+ $this->targets->clear();
+ $this->lookups = array();
+ }
+
+ /**
+ * @return int[]
+ */
+ public function getLookups() {
+ return $this->lookups;
+ }
+
+ /**
+ * @return array
+ */
+ public function getTargets() {
+ return $this->targets;
+ }
+
+}
diff --git a/Echo/includes/cache/RevisionLocalCache.php b/Echo/includes/cache/RevisionLocalCache.php
new file mode 100644
index 00000000..6ef50030
--- /dev/null
+++ b/Echo/includes/cache/RevisionLocalCache.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * Cache class that maps revision id to Revision object
+ */
+class EchoRevisionLocalCache extends EchoLocalCache {
+
+ /**
+ * @var EchoRevisionLocalCache
+ */
+ private static $instance;
+
+ /**
+ * The current wiki id
+ * @var string|null
+ */
+ private static $wiki;
+
+ /**
+ * Create a EchoRevisionLocalCache object
+ * @return EchoRevisionLocalCache
+ */
+ public static function create() {
+ // A job queue may run against multiple wikis,
+ // initialize a new one for the current wiki
+ if ( wfWikiId() != self::$wiki ) {
+ self::$instance = null;
+ self::$wiki = wfWikiId();
+ }
+ if ( !self::$instance ) {
+ self::$instance = new EchoRevisionLocalCache();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function resolve() {
+ if ( $this->lookups ) {
+ // @Todo Add newFromIds() to Revision
+ $dbr = wfGetDB( DB_SLAVE );
+ $fields = array_merge(
+ Revision::selectFields(),
+ Revision::selectPageFields(),
+ Revision::selectUserFields()
+ );
+ $res = $dbr->select(
+ array( 'revision', 'page', 'user' ),
+ $fields,
+ array( 'rev_id' => $this->lookups ),
+ __METHOD__,
+ array(),
+ array(
+ 'page' => Revision::pageJoinCond(),
+ 'user' => Revision::userJoinCond()
+ )
+ );
+ if ( $res ) {
+ foreach ( $res as $row ) {
+ $this->targets->set( $row->rev_id, new Revision( $row ) );
+ }
+ $this->lookups = array();
+ }
+ }
+ }
+
+}
diff --git a/Echo/includes/cache/TitleLocalCache.php b/Echo/includes/cache/TitleLocalCache.php
new file mode 100644
index 00000000..1ca5c5db
--- /dev/null
+++ b/Echo/includes/cache/TitleLocalCache.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Cache class that maps article id to Title object
+ */
+class EchoTitleLocalCache extends EchoLocalCache {
+
+ /**
+ * @var EchoTitleLocalCache
+ */
+ private static $instance;
+
+ /**
+ * The current wiki id
+ * @var string|null
+ */
+ private static $wiki;
+
+ /**
+ * Create a TitleLocalCache object
+ * @return TitleLocalCache
+ */
+ public static function create() {
+ // A job queue may run against multiple wikis,
+ // initialize a new one for the current wiki
+ if ( wfWikiId() != self::$wiki ) {
+ self::$instance = null;
+ self::$wiki = wfWikiId();
+ }
+ if ( !self::$instance ) {
+ self::$instance = new EchoTitleLocalCache();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function resolve() {
+ if ( $this->lookups ) {
+ $titles = Title::newFromIDs( $this->lookups );
+ foreach ( $titles as $title ) {
+ $this->targets->set( $title->getArticleId(), $title );
+ }
+ $this->lookups = array();
+ }
+ }
+
+}
diff --git a/Echo/includes/exception/CatchableFatalErrorException.php b/Echo/includes/exception/CatchableFatalErrorException.php
new file mode 100644
index 00000000..500e6992
--- /dev/null
+++ b/Echo/includes/exception/CatchableFatalErrorException.php
@@ -0,0 +1,12 @@
+<?php
+
+class EchoCatchableFatalErrorException extends MWException {
+
+ public function __construct( $errno, $errstr, $errfile, $errline ) {
+ parent::__construct( "Catchable fatal error: $errstr", $errno );
+ // inherited protected variables from Exception
+ $this->file = $errfile;
+ $this->line = $errline;
+ }
+
+}
diff --git a/Echo/includes/gateway/UserNotificationGateway.php b/Echo/includes/gateway/UserNotificationGateway.php
new file mode 100644
index 00000000..5251b776
--- /dev/null
+++ b/Echo/includes/gateway/UserNotificationGateway.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * Database gateway which handles direct database interaction with the
+ * echo_notification & echo_event for a user, that wouldn't require
+ * loading data into models
+ */
+class EchoUserNotificationGateway {
+
+ /**
+ * @var MWEchoDbFactory
+ */
+ protected $dbFactory;
+
+ /**
+ * @var User
+ */
+ protected $user;
+
+ /**
+ * The tables for this gateway
+ */
+ protected static $eventTable = 'echo_event';
+ protected static $notificationTable = 'echo_notification';
+
+ /**
+ * @param User
+ * @param MWEchoDbFactory
+ */
+ public function __construct( User $user, MWEchoDbFactory $dbFactory ) {
+ $this->user = $user;
+ $this->dbFactory = $dbFactory;
+ }
+
+ /**
+ * Mark notifications as read
+ * @param $eventIDs array
+ * @return boolean
+ */
+ public function markRead( array $eventIDs ) {
+ if ( !$eventIDs ) {
+ return;
+ }
+
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ return $dbw->update(
+ self::$notificationTable,
+ array( 'notification_read_timestamp' => $dbw->timestamp( wfTimestampNow() ) ),
+ array(
+ 'notification_user' => $this->user->getId(),
+ 'notification_event' => $eventIDs,
+ 'notification_read_timestamp' => null,
+ ),
+ __METHOD__
+ );
+ }
+
+ /**
+ * Mark all notification as read, use MWEchoNotifUer::markAllRead() instead
+ * @deprecated may need this when running in a job or revive this when we
+ * have updateJoin()
+ */
+ public function markAllRead() {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ return $dbw->update(
+ self::$notificationTable,
+ array( 'notification_read_timestamp' => $dbw->timestamp( wfTimestampNow() ) ),
+ array(
+ 'notification_user' => $this->user->getId(),
+ 'notification_read_timestamp' => NULL,
+ 'notification_bundle_base' => 1,
+ ),
+ __METHOD__
+ );
+ }
+
+ /**
+ * Get notification count for the types specified
+ * @param int use master or slave storage to pull count
+ * @param array event types to retrieve
+ * @return int
+ */
+ public function getNotificationCount( $dbSource, array $eventTypesToLoad = array() ) {
+ // double check
+ if ( !in_array( $dbSource, array( DB_SLAVE, DB_MASTER ) ) ) {
+ $dbSource = DB_SLAVE;
+ }
+
+ if ( !$eventTypesToLoad ) {
+ return 0;
+ }
+
+ global $wgEchoMaxNotificationCount;
+
+ $db = $this->dbFactory->getEchoDb( $dbSource );
+ $res = $db->select(
+ array(
+ self::$notificationTable,
+ self::$eventTable
+ ),
+ array( 'notification_event' ),
+ array(
+ 'notification_user' => $this->user->getId(),
+ 'notification_bundle_base' => 1,
+ 'notification_read_timestamp' => null,
+ 'event_type' => $eventTypesToLoad,
+ ),
+ __METHOD__,
+ array( 'LIMIT' => $wgEchoMaxNotificationCount + 1 ),
+ array(
+ 'echo_event' => array( 'LEFT JOIN', 'notification_event=event_id' ),
+ )
+ );
+ if ( $res ) {
+ return $db->numRows( $res );
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * IMPORTANT: should only call this function if the number of unread notification
+ * is reasonable, for example, unread notification count is less than the max
+ * display defined in $wgEchoMaxNotificationCount
+ * @param string
+ * @return int[]
+ */
+ public function getUnreadNotifications( $type ) {
+ $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+ $res = $dbr->select(
+ array(
+ self::$notificationTable,
+ self::$eventTable
+ ),
+ array( 'notification_event' ),
+ array(
+ 'notification_user' => $this->user->getId(),
+ 'notification_bundle_base' => 1,
+ 'notification_read_timestamp' => null,
+ 'event_type' => $type,
+ 'notification_event = event_id'
+ ),
+ __METHOD__
+ );
+
+ $eventIds = array();
+ if ( $res ) {
+ foreach ( $res as $row ) {
+ $eventIds[$row->notification_event] = $row->notification_event;
+ }
+ }
+
+ return $eventIds;
+ }
+
+}
diff --git a/Echo/includes/iterator/CallbackFilterIterator.php b/Echo/includes/iterator/CallbackFilterIterator.php
new file mode 100644
index 00000000..4095d1d4
--- /dev/null
+++ b/Echo/includes/iterator/CallbackFilterIterator.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This class is implemented as part of SPL starting at PHP5.4. This
+ * re-implementation provides backwards compatibility to mediawiki
+ * running on PHP5.3.
+ */
+class CallbackFilterIterator extends FilterIterator {
+ protected $callback;
+
+ public function __construct( Iterator $iterator, $callback ) {
+ parent::__construct( $iterator );
+ $this->callback = $callback;
+ }
+
+ public function accept() {
+ return call_user_func(
+ $this->callback,
+ $this->current(),
+ $this->key(),
+ $this->getInnerIterator()
+ );
+ }
+}
diff --git a/Echo/includes/iterator/CallbackIterator.php b/Echo/includes/iterator/CallbackIterator.php
new file mode 100644
index 00000000..c4b7926b
--- /dev/null
+++ b/Echo/includes/iterator/CallbackIterator.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * Applies a callback to all values returned from the iterator
+ */
+class EchoCallbackIterator extends EchoIteratorDecorator {
+ protected $callable;
+
+ public function __construct( Iterator $iterator, $callable ) {
+ parent::__construct( $iterator );
+ $this->callable = $callable;
+ }
+
+ public function current() {
+ return call_user_func( $this->callable, $this->iterator->current() );
+ }
+}
diff --git a/Echo/includes/iterator/FilteredSequentialIterator.php b/Echo/includes/iterator/FilteredSequentialIterator.php
new file mode 100644
index 00000000..cc0271f9
--- /dev/null
+++ b/Echo/includes/iterator/FilteredSequentialIterator.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * Allows building a single iterator out of multiple iterators
+ * and filtering the results. Accepts plain arrays for the simple
+ * use case, also accepts Iterator instances for anything more complex.
+ *
+ * This exists so that EchoUserLocator implementations can return iterators
+ * that return potentially thousands of users without having to grab
+ * them all in one giant query.
+ *
+ * Usage:
+ * $users = new EchoFilteredSequentialIterator;
+ * $users->add( array( $userA, $userB, $userC ) );
+ *
+ * $it = new EchoBatchRowIterator( ... );
+ * ...
+ * $it = new RecursiveIteratorIterator( $it );
+ * $users->add( new EchoCallbackIterator( $it, function( $row ) {
+ * ...
+ * return $user;
+ * } ) );
+ *
+ * foreach ( $users as $user ) {
+ * ...
+ * }
+ *
+ * By default the EchoBatchRowIterator returns an array of rows, this class
+ * expects a stream of user objects. To bridge that gap the
+ * RecursiveIteratorIterator is used to flatten and the EchoCallbackIterator
+ * is used to transform each database $row into a User object.
+ *
+ * @todo name?
+ */
+class EchoFilteredSequentialIterator implements IteratorAggregate {
+ /**
+ * @var Iterator[]
+ */
+ protected $iterators = array();
+
+ /**
+ * @var callable[]
+ */
+ protected $filters = array();
+
+ /**
+ * @param Iterator|IteratorAggregate|array $users
+ */
+ public function add( $users ) {
+ if ( is_array( $users ) ) {
+ $it = new ArrayIterator( $users );
+ } elseif ( $users instanceof Iterator ) {
+ $it = $users;
+ } elseif ( $users instanceof IteratorAggregate ) {
+ $it = $users->getIterator();
+ } else {
+ throw new MWException( 'Expected array, Iterator or IteratorAggregate but received:' .
+ ( is_object( $users ) ? get_class( $users ) : gettype( $users ) )
+ );
+ }
+
+ $this->iterators[] = $it;
+ }
+
+ /**
+ * @param callable $callable
+ */
+ public function addFilter( $callable ) {
+ $this->filters[] = $callable;
+ }
+
+ /**
+ * Satisfies IteratorAggregate interface
+ *
+ * @return Iterator
+ */
+ public function getIterator() {
+ $it = $this->createIterator();
+ if ( $this->filters ) {
+ $it = new CallbackFilterIterator( $it, $this->createFilter() );
+ }
+
+ return $it;
+ }
+
+ /**
+ * @return Iterator
+ */
+ protected function createIterator() {
+ switch( count( $this->iterators ) ) {
+ case 0:
+ return new EmptyIterator;
+
+ case 1:
+ return reset( $this->iterators );
+
+ default:
+ return new RecursiveIteratorIterator( new EchoMultipleIterator( $this->iterators ) );
+ }
+ }
+
+ /**
+ * @return callable
+ */
+ protected function createFilter() {
+ switch( count( $this->filters ) ) {
+ case 0:
+ return function() { return true; };
+
+ case 1:
+ return reset( $this->filters );
+
+ default:
+ $filters = $this->filters;
+ return function( $user ) use( $filters ) {
+ foreach ( $filters as $filter ) {
+ if ( !call_user_func( $filter, $user ) ) {
+ return false;
+ }
+ }
+ return true;
+ };
+ }
+ }
+}
diff --git a/Echo/includes/iterator/IteratorDecorator.php b/Echo/includes/iterator/IteratorDecorator.php
new file mode 100644
index 00000000..825575da
--- /dev/null
+++ b/Echo/includes/iterator/IteratorDecorator.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * Allows extending classes to decorate an Iterator with
+ * reduced boilerplate.
+ */
+abstract class EchoIteratorDecorator implements Iterator {
+ protected $iterator;
+
+ public function __construct( Iterator $iterator ) {
+ $this->iterator = $iterator;
+ }
+
+ public function current() {
+ return $this->iterator->current();
+ }
+
+ public function key() {
+ return $this->iterator->key();
+ }
+
+ public function next() {
+ return $this->iterator->next();
+ }
+
+ public function rewind() {
+ return $this->iterator->rewind();
+ }
+
+ public function valid() {
+ return $this->iterator->valid();
+ }
+}
diff --git a/Echo/includes/iterator/MultipleIterator.php b/Echo/includes/iterator/MultipleIterator.php
new file mode 100644
index 00000000..4134326e
--- /dev/null
+++ b/Echo/includes/iterator/MultipleIterator.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * Presents a list of iterators as a single stream of results
+ * when wrapped with the RecursiveIteratorIterator.
+ *
+ * This differs from the SPL MultipleIterator in the following ways:
+ * * Does not return null for non-valid child iterators
+ * * implements RecursiveIterator
+ * * Lots less features(e.g. simple!)
+ */
+class EchoMultipleIterator implements RecursiveIterator {
+ protected $active = array();
+ protected $children;
+ protected $key = 0;
+
+ public function __construct( array $children ) {
+ $this->children = $children;
+ }
+
+ public function rewind() {
+ $this->active = $this->children;
+ $this->key = 0;
+ foreach ( $this->active as $key => $it ) {
+ $it->rewind();
+ if ( !$it->valid() ) {
+ unset( $this->active[$key] );
+ }
+ }
+ }
+
+ public function valid() {
+ return (bool)$this->active;
+ }
+
+ public function next() {
+ $this->key++;
+ foreach ( $this->active as $key => $it ) {
+ $it->next();
+ if ( !$it->valid() ) {
+ unset( $this->active[$key] );
+ }
+ }
+ }
+
+ public function current() {
+ $result = array();
+ foreach ( $this->active as $it ) {
+ $result[] = $it->current();
+ }
+ return $result;
+ }
+
+ public function key() {
+ return $this->key;
+ }
+
+ public function hasChildren() {
+ return (bool)$this->active;
+ }
+
+ public function getChildren() {
+ // The NotRecursiveIterator is used rather than a RecursiveArrayIterator
+ // so that nested arrays dont get recursed.
+ return new EchoNotRecursiveIterator( new ArrayIterator( $this->current() ) );
+ }
+}
diff --git a/Echo/includes/iterator/NotRecursiveIterator.php b/Echo/includes/iterator/NotRecursiveIterator.php
new file mode 100644
index 00000000..2bc002bf
--- /dev/null
+++ b/Echo/includes/iterator/NotRecursiveIterator.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * Wraps a non-recursive iterator with methods to be recursive
+ * without children.
+ *
+ * Alternatively wraps a recursive iterator to prevent recursing deeper
+ * than the wrapped iterator.
+ */
+class EchoNotRecursiveIterator extends EchoIteratorDecorator implements RecursiveIterator {
+ public function hasChildren() {
+ return false;
+ }
+
+ public function getChildren() {
+ return null;
+ }
+}
diff --git a/Echo/includes/mapper/AbstractMapper.php b/Echo/includes/mapper/AbstractMapper.php
new file mode 100644
index 00000000..a69aa105
--- /dev/null
+++ b/Echo/includes/mapper/AbstractMapper.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Abstract mapper for model
+ */
+abstract class EchoAbstractMapper {
+
+ /**
+ * Echo database factory
+ * @var MWEchoDbFactory
+ */
+ protected $dbFactory;
+
+ /**
+ * Event listeners for method like insert/delete
+ * @var array
+ */
+ protected $listeners;
+
+ /**
+ * @param MWEchoDbFactory|null
+ */
+ public function __construct( MWEchoDbFactory $dbFactory = null ) {
+ if ( $dbFactory === null ) {
+ $dbFactory = MWEchoDbFactory::newFromDefault();
+ }
+ $this->dbFactory = $dbFactory;
+ }
+
+ /**
+ * Attach a listener
+ *
+ * @param string $method Method name
+ * @param string $key Identification of the callable
+ * @param callable $callable
+ */
+ public function attachListener( $method, $key, $callable ) {
+ if ( !method_exists( $this, $method ) ) {
+ throw new MWException( $method . ' does not exist in ' . get_class( $this ) );
+ }
+ if ( !isset( $this->listeners[$method] ) ) {
+ $this->listeners[$method] = array();
+ }
+
+ $this->listeners[$method][$key] = $callable;
+ }
+
+ /**
+ * Detach a listener
+ *
+ * @param string $method Method name
+ * @param string $key identification of the callable
+ */
+ public function detachListener( $method, $key ) {
+ if ( isset( $this->listeners[$method] ) ) {
+ unset( $this->listeners[$method][$key] );
+ }
+ }
+
+ /**
+ * Get the listener for a method
+ *
+ * @return array
+ */
+ public function getMethodListeners( $method ) {
+ if ( !method_exists( $this, $method ) ) {
+ throw new MWException( $method . ' does not exist in ' . get_class( $this ) );
+ }
+ if ( isset( $this->listeners[$method] ) ) {
+ return $this->listeners[$method];
+ } else {
+ return array();
+ }
+ }
+
+}
diff --git a/Echo/includes/mapper/EventMapper.php b/Echo/includes/mapper/EventMapper.php
new file mode 100644
index 00000000..b9d3c32c
--- /dev/null
+++ b/Echo/includes/mapper/EventMapper.php
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Database mapper for EchoEvent model, which is an immutable class, there should
+ * not be any update to it
+ */
+class EchoEventMapper extends EchoAbstractMapper {
+
+ /**
+ * Insert an event record
+ *
+ * @param EchoEvent
+ * @return int|bool
+ */
+ public function insert( EchoEvent $event ) {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ $id = $dbw->nextSequenceValue( 'echo_event_id' );
+
+ $row = $event->toDbArray();
+ if ( $id ) {
+ $row['event_id'] = $id;
+ }
+
+ $res = $dbw->insert( 'echo_event', $row, __METHOD__ );
+
+ if ( $res ) {
+ if ( !$id ) {
+ $id = $dbw->insertId();
+ }
+ return $id;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Create an EchoEvent by id
+ *
+ * @param int
+ * @param boolean
+ * @return EchoEvent
+ * @throws MWException
+ */
+ public function fetchById( $id, $fromMaster = false ) {
+ $db = $fromMaster ? $this->dbFactory->getEchoDb( DB_MASTER ) : $this->dbFactory->getEchoDb( DB_SLAVE );
+
+ $row = $db->selectRow( 'echo_event', '*', array( 'event_id' => $id ), __METHOD__ );
+
+ if ( !$row && !$fromMaster ) {
+ return $this->fetchById( $id, true );
+ } elseif ( !$row ) {
+ throw new MWException( "No EchoEvent found with ID: $id" );
+ }
+
+ return EchoEvent::newFromRow( $row );
+ }
+
+ /**
+ * Get a list of echo events identified by user and bundle hash
+ *
+ * @param $user User
+ * @param $bundleHash string the bundle hash
+ * @param $type string distribution type
+ * @param $order string 'ASC'/'DESC'
+ * @param $limit int
+ * @return EchoEvent[]|bool
+ */
+ public function fetchByUserBundleHash( User $user, $bundleHash, $type = 'web', $order = 'DESC', $limit = 250 ) {
+ $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+
+ // We only display 99+ if the number is over 100, we can do limit 250, this should
+ // be sufficient to return 99 distinct group iterators, avoid select count( distinct )
+ // for the following reason:
+ // 1. it will not scale for large volume data
+ // 2. notification may have random grouping iterator
+ // 3. agent may be anonymous, can't do distinct over two columns: event_agent_id and event_agent_ip
+ if ( $type == 'web' ) {
+ $res = $dbr->select(
+ array( 'echo_notification', 'echo_event' ),
+ array( 'echo_event.*' ),
+ array(
+ 'notification_event=event_id',
+ 'notification_user' => $user->getId(),
+ 'notification_bundle_base' => 0,
+ 'notification_bundle_display_hash' => $bundleHash
+ ),
+ __METHOD__,
+ array( 'ORDER BY' => 'notification_timestamp ' . $order, 'LIMIT' => $limit )
+ );
+ // this would be email for now
+ } else {
+ $res = $dbr->select(
+ array( 'echo_email_batch', 'echo_event' ),
+ array( 'echo_event.*' ),
+ array(
+ 'eeb_event_id=event_id',
+ 'eeb_user_id' => $user->getId(),
+ 'eeb_event_hash' => $bundleHash
+ ),
+ __METHOD__,
+ array( 'ORDER BY' => 'eeb_event_id ' . $order, 'LIMIT' => $limit )
+ );
+ }
+
+ if ( $res ) {
+ $data = array();
+ foreach ( $res as $row ) {
+ $data[] = EchoEvent::newFromRow( $row );
+ }
+ return $data;
+ } else {
+ return false;
+ }
+ }
+
+}
diff --git a/Echo/includes/mapper/NotificationMapper.php b/Echo/includes/mapper/NotificationMapper.php
new file mode 100644
index 00000000..a3fef502
--- /dev/null
+++ b/Echo/includes/mapper/NotificationMapper.php
@@ -0,0 +1,312 @@
+<?php
+
+/**
+ * Database mapper for EchoNotification model
+ */
+class EchoNotificationMapper extends EchoAbstractMapper {
+
+ /**
+ * @var EchoTargetPageMapper
+ */
+ protected $targetPageMapper;
+
+ public function __construct(
+ MWEchoDbFactory $dbFactory = null,
+ EchoTargetPageMapper $targetPageMapper = null
+ ) {
+ parent::__construct( $dbFactory );
+ if ( $targetPageMapper === null ) {
+ $targetPageMapper = new EchoTargetPageMapper( $this->dbFactory );
+ }
+ $this->targetPageMapper = $targetPageMapper;
+ }
+
+ /**
+ * Insert a notification record
+ * @param EchoNotification
+ * @return null
+ */
+ public function insert( EchoNotification $notification ) {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ $fname = __METHOD__;
+ $row = $notification->toDbArray();
+ $listeners = $this->getMethodListeners( __FUNCTION__ );
+
+ $dbw->onTransactionIdle( function() use ( $dbw, $row, $fname, $listeners ) {
+ $dbw->startAtomic( $fname );
+ // reset the bundle base if this notification has a display hash
+ // the result of this operation is that all previous notifications
+ // with the same display hash are set to non-base because new record
+ // is becoming the bundle base
+ if ( $row['notification_bundle_display_hash'] ) {
+ $dbw->update(
+ 'echo_notification',
+ array( 'notification_bundle_base' => 0 ),
+ array(
+ 'notification_user' => $row['notification_user'],
+ 'notification_bundle_display_hash' => $row['notification_bundle_display_hash'],
+ 'notification_bundle_base' => 1
+ ),
+ $fname
+ );
+ }
+
+ $row['notification_timestamp'] = $dbw->timestamp( $row['notification_timestamp'] );
+ $res = $dbw->insert( 'echo_notification', $row, $fname );
+ $dbw->endAtomic( $fname );
+
+ if ( $res ) {
+ foreach ( $listeners as $listener ) {
+ call_user_func( $listener );
+ }
+ }
+ } );
+ }
+
+ /**
+ * Extract the offset used for notification list
+ * @param $continue String Used for offset
+ * @throws MWException
+ * @return int[]
+ */
+ protected function extractQueryOffset( $continue ) {
+ $offset = array (
+ 'timestamp' => 0,
+ 'offset' => 0,
+ );
+ if ( $continue ) {
+ $values = explode( '|', $continue, 3 );
+ if ( count( $values ) !== 2 ) {
+ throw new MWException( 'Invalid continue param: ' . $continue );
+ }
+ $offset['timestamp'] = (int)$values[0];
+ $offset['offset'] = (int)$values[1];
+ }
+
+ return $offset;
+ }
+
+ /**
+ * Get unread notifications by user in the amount specified by limit order by
+ * notification timestamp in descending order. We have an index to retrieve
+ * unread notifications but it's not optimized for ordering by timestamp. The
+ * descending order is only allowed if we keep the notification in low volume,
+ * which is done via a deleteJob
+ * @param User $user
+ * @param int $limit
+ * @param string[] $eventTypes
+ * @return EchoNotification[]
+ */
+ public function fetchUnreadByUser( User $user, $limit, array $eventTypes = array() ) {
+ $data = array();
+
+ if ( !$eventTypes ) {
+ return $data;
+ }
+
+ $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+ $res = $dbr->select(
+ array( 'echo_notification', 'echo_event' ),
+ '*',
+ array(
+ 'notification_user' => $user->getID(),
+ 'event_type' => $eventTypes,
+ 'notification_bundle_base' => 1,
+ 'notification_read_timestamp' => NULL
+ ),
+ __METHOD__,
+ array(
+ 'LIMIT' => $limit,
+ 'ORDER BY' => 'notification_timestamp DESC'
+ ),
+ array(
+ 'echo_event' => array( 'LEFT JOIN', 'notification_event=event_id' ),
+ )
+ );
+ if ( $res ) {
+ foreach ( $res as $row ) {
+ $data[$row->event_id] = EchoNotification::newFromRow( $row );
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Get Notification by user in batch along with limit, offset etc
+ *
+ * @param User $user the user to get notifications for
+ * @param int $limit The maximum number of notifications to return
+ * @param string $continue Used for offset
+ * @param array $eventTypes Event types to load
+ * @param array $excludeEventIds Event id's to exclude.
+ * @return EchoNotification[]
+ */
+ public function fetchByUser( User $user, $limit, $continue, array $eventTypes = array(), array $excludeEventIds = array() ) {
+ $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+
+ if ( !$eventTypes ) {
+ return array();
+ }
+
+ // There is a problem with querying by event type, if a user has only one or none
+ // flow notification and huge amount other notications, the lookup of only flow
+ // notification will result in a slow query. Luckily users won't have that many
+ // notifications. We should have some cron job to remove old notifications so
+ // the notification volume is in a reasonable amount for such case. The other option
+ // is to denormalize notification table with event_type and lookup index.
+ //
+ // Look for notifications with base = 1
+ $conds = array(
+ 'notification_user' => $user->getID(),
+ 'event_type' => $eventTypes,
+ 'notification_bundle_base' => 1
+ );
+
+ if ( $excludeEventIds ) {
+ $conds[] = 'event_id NOT IN ( ' . $dbr->makeList( $excludeEventIds ) . ' ) ';
+ }
+
+ $offset = $this->extractQueryOffset( $continue );
+
+ // Start points are specified
+ if ( $offset['timestamp'] && $offset['offset'] ) {
+ $ts = $dbr->addQuotes( $dbr->timestamp( $offset['timestamp'] ) );
+ // The offset and timestamp are those of the first notification we want to return
+ $conds[] = "notification_timestamp < $ts OR ( notification_timestamp = $ts AND notification_event <= " . $offset['offset'] . " )";
+ }
+
+ $res = $dbr->select(
+ array( 'echo_notification', 'echo_event', 'echo_target_page' ),
+ '*',
+ $conds,
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'notification_timestamp DESC, notification_event DESC',
+ 'LIMIT' => $limit,
+ ),
+ array(
+ 'echo_event' => array( 'LEFT JOIN', 'notification_event=event_id' ),
+ 'echo_target_page' => array( 'LEFT JOIN', array( 'notification_event=etp_event', 'notification_user=etp_user' ) ),
+ )
+ );
+
+
+ // query failure of some sort
+ if ( !$res ) {
+ return array();
+ }
+
+ $events = array();
+ foreach ( $res as $row ) {
+ $events[$row->event_id] = $row;
+ }
+
+ // query returned no events
+ if ( !$events ) {
+ return array();
+ }
+
+ $targetPages = $this->targetPageMapper->fetchByUserPageId( $user, array_keys( $events ) );
+
+ $data = array();
+ foreach ( $events as $eventId => $row ) {
+ try {
+ if ( isset( $targetPages[$row->event_id] ) ) {
+ $targets = $targetPages[$row->event_id];
+ } else {
+ $targets = null;
+ }
+ $data[$row->event_id] = EchoNotification::newFromRow( $row, $targets );
+ } catch ( Exception $e ) {
+ $id = isset( $row->event_id ) ? $row->event_id : 'unknown event';
+ wfDebugLog( 'Echo', __METHOD__ . ": Failed initializing event: $id" );
+ MWExceptionHandler::logException( $e );
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Get the last notification in a set of bundle-able notifications by a bundle hash
+ * @param User
+ * @param string The hash used to identify a set of bundle-able notifications
+ * @return EchoNotification|bool
+ */
+ public function fetchNewestByUserBundleHash( User $user, $bundleHash ) {
+ $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+
+ $row = $dbr->selectRow(
+ array( 'echo_notification', 'echo_event' ),
+ array( '*' ),
+ array(
+ 'notification_user' => $user->getId(),
+ 'notification_bundle_hash' => $bundleHash
+ ),
+ __METHOD__,
+ array( 'ORDER BY' => 'notification_timestamp DESC', 'LIMIT' => 1 ),
+ array(
+ 'echo_event' => array( 'LEFT JOIN', 'notification_event=event_id' ),
+ )
+ );
+ if ( $row ) {
+ return EchoNotification::newFromRow( $row );
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Fetch a notification by user in the specified offset. The caller should
+ * know that passing a big number for offset is NOT going to work
+ * @param User $user
+ * @param int $offset
+ * @return EchoNotification|bool
+ */
+ public function fetchByUserOffset( User $user, $offset ) {
+ $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+ $row = $dbr->selectRow(
+ array( 'echo_notification', 'echo_event' ),
+ array( '*' ),
+ array(
+ 'notification_user' => $user->getId(),
+ 'notification_bundle_base' => 1
+ ),
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'notification_timestamp DESC, notification_event DESC',
+ 'OFFSET' => $offset,
+ 'LIMIT' => 1
+ ),
+ array(
+ 'echo_event' => array( 'LEFT JOIN', 'notification_event=event_id' ),
+ )
+ );
+
+ if ( $row ) {
+ return EchoNotification::newFromRow( $row );
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Batch delete notifications by user and eventId offset
+ * @param User $user
+ * @param int $eventId
+ * @return boolean
+ */
+ public function deleteByUserEventOffset( User $user, $eventId ) {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+ $res = $dbw->delete(
+ 'echo_notification',
+ array(
+ 'notification_user' => $user->getId(),
+ 'notification_event < ' . (int)$eventId
+ ),
+ __METHOD__
+ );
+ return $res;
+ }
+
+}
diff --git a/Echo/includes/mapper/TargetPageMapper.php b/Echo/includes/mapper/TargetPageMapper.php
new file mode 100644
index 00000000..b4a2108d
--- /dev/null
+++ b/Echo/includes/mapper/TargetPageMapper.php
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * Database mapper for EchoTargetPage model
+ */
+class EchoTargetPageMapper extends EchoAbstractMapper {
+
+ /**
+ * List of db fields used to construct an EchoTargetPage model
+ * @var string[]
+ */
+ protected static $fields = array(
+ 'etp_user',
+ 'etp_page',
+ 'etp_event'
+ );
+
+ /**
+ * Fetch EchoTargetPage instances by user & page_id. The resulting
+ * array is indexed by the event id. Each entry contains an array
+ * of EchoTargetPage instances.
+ *
+ * @param User $user
+ * @param int|int[] $pageId One or more page ids to fetch target pages of
+ * @return EchoTargetPage[][]|boolean
+ */
+ public function fetchByUserPageId( User $user, $pageId ) {
+ $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+
+ $res = $dbr->select(
+ array( 'echo_target_page' ),
+ self::$fields,
+ array(
+ 'etp_user' => $user->getId(),
+ 'etp_page' => $pageId
+ ),
+ __METHOD__
+ );
+ if ( $res ) {
+ $targetPages = array();
+ foreach ( $res as $row ) {
+ $targetPages[$row->etp_event][] = EchoTargetPage::newFromRow( $row );
+ }
+ return $targetPages;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Insert an EchoTargetPage instance into the database
+ *
+ * @param EchoTargetPage $targetPage
+ * @return boolean
+ */
+ public function insert( EchoTargetPage $targetPage ) {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ $row = $targetPage->toDbArray();
+
+ $res = $dbw->insert( 'echo_target_page', $row, __METHOD__ );
+
+ return $res;
+ }
+
+ /**
+ * Delete an EchoTargetPage instance from the database
+ *
+ * @param EchoTargetPage
+ * @return boolean
+ */
+ public function delete( EchoTargetPage $targetPage ) {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ $res = $dbw->delete(
+ 'echo_target_page',
+ array(
+ 'etp_user' => $targetPage->getUser()->getId(),
+ 'etp_page' => $targetPage->getPageId(),
+ 'etp_event' => $targetPage->getEventId()
+ ),
+ __METHOD__
+ );
+ return $res;
+ }
+
+ /**
+ * Delete multiple EchoTargetPage records by user & set of event_id
+ *
+ * @param User $user
+ * @param int[] $eventIds
+ * @return boolean
+ */
+ public function deleteByUserEvents( User $user, array $eventIds ) {
+ if ( !$eventIds ) {
+ return true;
+ }
+
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ $res = $dbw->delete(
+ 'echo_target_page',
+ array(
+ 'etp_user' => $user->getId(),
+ 'etp_event' => $eventIds
+ ),
+ __METHOD__
+ );
+ return $res;
+ }
+
+ /**
+ * Delete multiple EchoTargetPage records by user & event_id offset
+ *
+ * @param User $user
+ * @param int $eventId
+ * @return boolean
+ */
+ public function deleteByUserEventOffset( User $user, $eventId ) {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ $res = $dbw->delete(
+ 'echo_target_page',
+ array(
+ 'etp_user' => $user->getId(),
+ 'etp_event < ' . (int)$eventId
+ ),
+ __METHOD__
+ );
+ return $res;
+ }
+
+ /**
+ * Delete multiple EchoTargetPage records by user
+ *
+ * @param User $user
+ * @return boolean
+ */
+ public function deleteByUser( User $user ) {
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+
+ $res = $dbw->delete(
+ 'echo_target_page',
+ array(
+ 'etp_user' => $user->getId()
+ ),
+ __METHOD__
+ );
+ return $res;
+ }
+
+}
diff --git a/Echo/includes/schemaUpdate.php b/Echo/includes/schemaUpdate.php
new file mode 100644
index 00000000..d8b62dec
--- /dev/null
+++ b/Echo/includes/schemaUpdate.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * Performs updates required for respecting suppression within echo:
+ * Updates event_page_id based on event_page_title and event_page_namespace
+ * Updates extra data for page-linked events to contain page id's
+ */
+class EchoSuppressionRowUpdateGenerator implements EchoRowUpdateGenerator
+{
+ /**
+ * @var callable Hack to allow replacing Title::newFromText in tests
+ */
+ protected $newTitleFromText = array( 'Title', 'newFromText' );
+
+ /**
+ * {@inheritDoc}
+ */
+ public function update( $row ) {
+ $update = $this->updatePageIdFromTitle( $row );
+ if ( $row->event_extra !== null && $row->event_type === 'page-linked' ) {
+ $update = $this->updatePageLinkedExtraData( $row, $update );
+ }
+
+ return $update;
+ }
+
+ /**
+ * Hackish method of mocking Title::newFromText for tests
+ *
+ * @param $callable callable
+ */
+ public function setNewTitleFromText( $callable ) {
+ $this->newTitleFromText = $callable;
+ }
+
+ /**
+ * Hackish method of mocking Title::newFromText for tests
+ *
+ * @param $text string The page name to look up
+ * @param $defaultNamespace integer The default namespace of the page to look up
+ * @return Title|null The title located for the text + namespace, or null if invalid
+ */
+ protected function newTitleFromText( $text, $defaultNamespace = NS_MAIN ) {
+ return call_user_func( $this->newTitleFromText, $text, $defaultNamespace );
+ }
+
+ /**
+ * Migrates all echo events from having page title and namespace as rows in the table
+ * to having only a page id in the table. Any event from a page that doesn't have an
+ * article id gets the title+namespace moved to the event extra data
+ *
+ * @param $row stdClass A row from the database
+ * @return array All updates required for this row
+ */
+ protected function updatePageIdFromTitle( $row ) {
+ $update = array();
+ $title = $this->newTitleFromText( $row->event_page_title, $row->event_page_namespace );
+ if ( $title !== null ) {
+ $pageId = $title->getArticleId();
+ if ( $pageId ) {
+ // If the title has a proper id from the database, store it
+ $update['event_page_id'] = $pageId;
+ } else {
+ // For titles that do not refer to a WikiPage stored in the database
+ // move the title/namespace into event_extra
+ $extra = $this->extra( $row );
+ $extra['page_title'] = $row->event_page_title;
+ $extra['page_namespace'] = $row->event_page_namespace;
+
+ $update['event_extra'] = serialize( $extra );
+ }
+ }
+
+ return $update;
+ }
+
+ /**
+ * Updates the extra data for page-linked events to point to the id of the article
+ * rather than the namespace+title combo.
+ *
+ * @param $row stdClass A row from the database
+ * @param $update array
+ *
+ * @return array All updates required for this row
+ */
+ protected function updatePageLinkedExtraData( $row, array $update ) {
+ $extra = $this->extra( $row, $update );
+
+ if ( isset( $extra['link-from-title'], $extra['link-from-namespace'] ) ) {
+ $title = $this->newTitleFromText( $extra['link-from-title'], $extra['link-from-namespace'] );
+ unset( $extra['link-from-title'], $extra['link-from-namespace'] );
+ // Link from page is always from a content page, if null or no article id it was
+ // somehow invalid
+ if ( $title !== null && $title->getArticleId() ) {
+ $extra['link-from-page-id'] = $title->getArticleId();
+ }
+
+ $update['event_extra'] = serialize( $extra );
+ }
+
+ return $update;
+ }
+
+ /**
+ * Return the extra data for a row, if an update wants to change the
+ * extra data returns that updated data rather than the origional. If
+ * no extra data exists returns array()
+ *
+ * @param $row stdClass The database row being updated
+ * @param $update array Updates that need to be applied to the database row
+ * @return array The event extra data
+ */
+ protected function extra( $row, array $update = array() ) {
+ if ( isset( $update['event_extra'] ) ) {
+ return unserialize( $update['event_extra'] );
+ } elseif ( $row->event_extra ) {
+ return unserialize( $row->event_extra );
+ }
+ return array();
+ }
+
+}
diff --git a/Echo/jobs/NotificationDeleteJob.php b/Echo/jobs/NotificationDeleteJob.php
new file mode 100644
index 00000000..4d5ae9f6
--- /dev/null
+++ b/Echo/jobs/NotificationDeleteJob.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * This job is created when sending notifications to the target users. The purpose
+ * of this job is to delete older notifications when the number of notifications a
+ * user has is more than $wgEchoMaxUpdateCount, it does not make sense to have tons
+ * of notifications in the history while users wouldn't bother to click 'load more'
+ * like 100 times to see them. What we gain from this is we could run expensive
+ * queries otherwise that would requires adding index and data denormalization.
+ */
+class EchoNotificationDeleteJob extends Job {
+
+ /**
+ * UserIds to be processed
+ * @var int[]
+ */
+ protected $userIds = array();
+
+ /**
+ * @var MWEchoDbFactory
+ */
+ protected $dbFactory;
+
+ /**
+ * @param Title
+ * @param array
+ */
+ function __construct( $title, $params ) {
+ parent::__construct( __CLASS__, $title, $params );
+ $this->userIds = $params['userIds'];
+ $this->dbFactory = MWEchoDbFactory::newFromDefault();
+ }
+
+ /**
+ * Run the job of finding & deleting older notifications
+ */
+ function run() {
+ global $wgEchoMaxUpdateCount;
+
+ $updateCount = 0;
+ $dbw = $this->dbFactory->getEchoDb( DB_MASTER );
+ $notifMapper = new EchoNotificationMapper();
+ $targetMapper = new EchoTargetPageMapper();
+
+ foreach ( $this->userIds as $userId ) {
+ $user = User::newFromId( $userId );
+ $notif = $notifMapper->fetchByUserOffset( $user, $wgEchoMaxUpdateCount );
+ if ( $notif ) {
+ $dbw->startAtomic( __METHOD__ );
+ $res = $notifMapper->deleteByUserEventOffset(
+ $user, $notif->getEvent()->getId()
+ );
+ if ( $res ) {
+ $res = $targetMapper->deleteByUserEventOffset(
+ $user, $notif->getEvent()->getId()
+ );
+ }
+ $dbw->endAtomic( __METHOD__ );
+ if ( $res ) {
+ $updateCount++;
+ $notifUser = MWEchoNotifUser::newFromUser( $user );
+ $notifUser->resetNotificationCount( DB_MASTER );
+ }
+ // Wait for slave if we are doing a lot of updates
+ if ( $updateCount > 10 ) {
+ $this->dbFactory->waitForSlaves();
+ $updateCount = 0;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/Echo/jobs/NotificationEmailBundleJob.php b/Echo/jobs/NotificationEmailBundleJob.php
new file mode 100644
index 00000000..fbb4ff89
--- /dev/null
+++ b/Echo/jobs/NotificationEmailBundleJob.php
@@ -0,0 +1,26 @@
+<?php
+
+class MWEchoNotificationEmailBundleJob extends Job {
+ function __construct( $title, $params ) {
+ parent::__construct( __CLASS__, $title, $params );
+ // If there is already a job with the same params, this job will be ignored
+ // for example, if there is a page link bundle notification job for article A
+ // created by user B, any subsequent jobs with the same data will be ignored
+ $this->removeDuplicates = true;
+ }
+
+ function run() {
+ $bundle = MWEchoEmailBundler::newFromUserHash(
+ User::newFromId( $this->params['user_id'] ),
+ $this->params['bundle_hash']
+ );
+
+ if ( $bundle ) {
+ $bundle->processBundleEmail();
+ } else {
+ throw new MWException( 'Fail to create bundle object for: user_id: ' . $this->params['user_id'] . ', bundle_hash: ' . $this->params['bundle_hash'] );
+ }
+
+ return true;
+ }
+}
diff --git a/Echo/jobs/NotificationJob.php b/Echo/jobs/NotificationJob.php
new file mode 100644
index 00000000..af7e1df6
--- /dev/null
+++ b/Echo/jobs/NotificationJob.php
@@ -0,0 +1,37 @@
+<?php
+
+class EchoNotificationJob extends Job {
+ function __construct( $title, $params ) {
+ parent::__construct( 'EchoNotificationJob', $title, $params );
+ $this->event = $params['event'];
+ }
+
+ function run() {
+ // back compat for jobs still in queue, new jobs
+ // masterPos is always set. remove after deploy.
+ if ( isset( $this->params['masterPos'] ) ) {
+ $masterPos = $this->params['masterPos'];
+ } else {
+ $masterPos = $this->getMasterPosition();
+ }
+
+ MWEchoDbFactory::newFromDefault()->waitFor( $masterPos );
+ EchoNotificationController::notify( $this->event, false );
+ return true;
+ }
+
+ // back compat detects masterPos from prior job params
+ function getMasterPosition() {
+ $masterPos = array(
+ 'wikiDb' => false,
+ 'echoDb' => false,
+ );
+ if ( !empty( $this->params['mainDbMasterPos'] ) ) {
+ $masterPos['wikiDb'] = $this->params['mainDbMasterPos'];
+ }
+ if ( !empty( $this->params['echoDbMasterPos'] ) ) {
+ $masterPos['echoDb'] = $this->params['echoDbMasterPos'];
+ }
+ return $masterPos;
+ }
+}
diff --git a/Echo/maintenance/processEchoEmailBatch.php b/Echo/maintenance/processEchoEmailBatch.php
new file mode 100644
index 00000000..222af2d6
--- /dev/null
+++ b/Echo/maintenance/processEchoEmailBatch.php
@@ -0,0 +1,67 @@
+<?php
+
+$IP = getenv( 'MW_INSTALL_PATH' );
+if ( $IP === false ) {
+ $IP = dirname( __FILE__ ) . '/../../..';
+}
+require_once( "$IP/maintenance/Maintenance.php" );
+
+/**
+ * A maintenance script that processes email digest
+ */
+class ProcessEchoEmailBatch extends Maintenance {
+
+ /**
+ * Max number of records to process at a time
+ * @var int
+ */
+ protected $batchSize = 300;
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Process email digest";
+ }
+
+ public function execute() {
+ global $wgEchoCluster;
+
+ $this->output( "Started processing... \n" );
+
+ $startUserId = 0;
+ $count = $this->batchSize;
+
+ while ( $count === $this->batchSize ) {
+ $count = 0;
+
+ $res = MWEchoEmailBatch::getUsersToNotify( $startUserId, $this->batchSize );
+
+ $updated = false;
+ foreach ( $res as $row ) {
+ $userId = intval( $row->eeb_user_id );
+ if ( $userId && $userId > $startUserId ) {
+ $emailBatch = MWEchoEmailBatch::newFromUserId( $userId );
+ if ( $emailBatch ) {
+ $this->output( "processing user_Id " . $userId . " \n" );
+ $emailBatch->process();
+ }
+ $startUserId = $userId;
+ $updated = true;
+ }
+ $count++;
+ }
+ wfWaitForSlaves( false, false, $wgEchoCluster );
+ // This is required since we are updating user properties in main wikidb
+ wfWaitForSlaves();
+
+ // double check to make sure that the id is updated
+ if ( !$updated ) {
+ break;
+ }
+ }
+
+ $this->output( "Completed \n" );
+ }
+}
+
+$maintClass = "ProcessEchoEmailBatch";
+require_once( DO_MAINTENANCE );
diff --git a/Echo/maintenance/removeInvalidNotification.php b/Echo/maintenance/removeInvalidNotification.php
new file mode 100644
index 00000000..c20f5021
--- /dev/null
+++ b/Echo/maintenance/removeInvalidNotification.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Remove invalid events from echo_event and echo_notification
+ *
+ * @ingroup Maintenance
+ */
+require_once ( getenv( 'MW_INSTALL_PATH' ) !== false
+ ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php'
+ : dirname( __FILE__ ) . '/../../../maintenance/Maintenance.php' );
+
+/**
+ * Maintenance script that removes invalid notifications
+ *
+ * @ingroup Maintenance
+ */
+class removeInvalidNotification extends Maintenance {
+
+ protected $batchSize = 500;
+ protected $invalidEventType = array( 'article-linked' );
+
+ public function execute() {
+ if ( !$this->invalidEventType ) {
+ $this->output( "There is nothing to process\n" );
+ return;
+ }
+
+ global $wgEchoCluster;
+
+ $dbw = MWEchoDbFactory::getDB( DB_MASTER );
+ $dbr = MWEchoDbFactory::getDB( DB_SLAVE );
+
+ $count = $this->batchSize;
+
+ while ( $count == $this->batchSize ) {
+ $res = $dbr->select(
+ array( 'echo_event' ),
+ array( 'event_id' ),
+ array(
+ 'event_type' => $this->invalidEventType,
+ ),
+ __METHOD__,
+ array( 'LIMIT' => $this->batchSize )
+ );
+
+ $event = array();
+ $count = 0;
+ foreach( $res as $row ) {
+ if ( !in_array( $row->event_id, $event ) ) {
+ $event[] = $row->event_id;
+ }
+ $count++;
+ };
+
+ if ( $event ) {
+ $dbw->begin();
+
+ $dbw->delete(
+ 'echo_event',
+ array( 'event_id' => $event ),
+ __METHOD__
+ );
+ $dbw->delete(
+ 'echo_notification',
+ array( 'notification_event' => $event ),
+ __METHOD__
+ );
+
+ $dbw->commit();
+
+ $this->output( "processing " . count( $event ) . " invalid events\n" );
+ wfWaitForSlaves( false, false, $wgEchoCluster );
+ }
+
+ // Cleanup is not necessary for
+ // 1. echo_email_batch, invalid notification is removed during the cron
+ }
+ }
+}
+
+$maintClass = 'removeInvalidNotification'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/Echo/maintenance/removeInvalidTargetPage.php b/Echo/maintenance/removeInvalidTargetPage.php
new file mode 100644
index 00000000..10cd0c4c
--- /dev/null
+++ b/Echo/maintenance/removeInvalidTargetPage.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Remove invalid records from echo_target_page. For instance, page has been
+ * deleted or removed, notification has somehow been marked as read
+ *
+ * @ingroup Maintenance
+ */
+require_once ( getenv( 'MW_INSTALL_PATH' ) !== false
+ ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php'
+ : __DIR__ . '/../../../maintenance/Maintenance.php' );
+
+/**
+ * Maintenance script that removes invalid target page
+ *
+ * @ingroup Maintenance
+ */
+class removeInvalidTargetPage extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Delete invalid records from echo_target_page";
+ $this->setBatchSize( 500 );
+ }
+
+ public function execute() {
+ global $wgEchoCluster;
+
+ $dbFactory = MWEchoDbFactory::newFromDefault();
+ $dbw = $dbFactory->getEchoDb( DB_MASTER );
+ $dbr = $dbFactory->getEchoDb( DB_SLAVE );
+
+ $count = $this->mBatchSize;
+ $userId = $eventId = 0;
+
+ while ( $count == $this->mBatchSize ) {
+ $res = $dbr->select(
+ array(
+ 'echo_target_page',
+ 'echo_notification'
+ ),
+ array(
+ 'etp_page',
+ 'etp_user',
+ 'etp_event',
+ 'notification_read_timestamp',
+ 'notification_bundle_base'
+ ),
+ array(
+ "etp_user > $userId OR ( etp_user = $userId AND etp_event > $eventId )"
+ ),
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'etp_user, etp_event',
+ 'LIMIT' => $this->mBatchSize
+ ),
+ array(
+ 'echo_notification' => array(
+ 'LEFT JOIN',
+ 'notification_event=etp_event AND notification_user = etp_user'
+ ),
+ )
+ );
+ if ( !$res ) {
+ $this->error( 'Could not select record from echo_target_page.', 1 );
+ }
+
+ $pageIds = $titles = array();
+ foreach ( $res as $row ) {
+ $pageIds[$row->etp_page] = $row->etp_page;
+ }
+ if ( $pageIds ) {
+ foreach ( Title::newFromIds( $pageIds ) as $title ) {
+ $titles[$title->getArticleID()] = true;
+ }
+ }
+
+ // Reset the head of the iterator
+ $res->rewind();
+ $count = $invalidCount = 0;
+ foreach( $res as $row ) {
+ if (
+ // Delete if notification is read
+ $row->notification_read_timestamp
+ // Delete if this is no longer a base event and
+ // it's not deleted from echo_target_page
+ || $row->notification_bundle_base == '0'
+ // Delete if title is no longer valid
+ || !isset( $titles[$row->etp_page] )
+ ) {
+ $dbw->delete(
+ 'echo_target_page',
+ array(
+ 'etp_user' => $row->etp_user,
+ 'etp_event' => $row->etp_event
+ ),
+ __METHOD__
+ );
+ $invalidCount++;
+ }
+
+ $userId = $row->etp_user;
+ $eventId = $row->etp_event;
+ $count++;
+ };
+
+ $this->output( "Deleted $invalidCount records from $count records\n" );
+ $dbFactory->waitForSlaves();
+ }
+ }
+}
+
+$maintClass = 'removeInvalidTargetPage'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/Echo/maintenance/testDiscussionParser.php b/Echo/maintenance/testDiscussionParser.php
new file mode 100644
index 00000000..d3564469
--- /dev/null
+++ b/Echo/maintenance/testDiscussionParser.php
@@ -0,0 +1,91 @@
+<?php
+
+$IP = getenv( 'MW_INSTALL_PATH' );
+if ( $IP === false ) {
+ $IP = dirname( __FILE__ ) . '/../../..';
+}
+require_once( "$IP/maintenance/Maintenance.php" );
+
+class TestDiscussionParser extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Takes enwiki revision IDs and attempts to identify interested users";
+
+ $this->addArg( 'revisions', 'Revision IDs, separated by commas', true /*required*/ );
+ }
+
+ public function execute() {
+ $apiURL = 'http://en.wikipedia.org/w/api.php';
+
+ $revisions = explode( ',', $this->getArg( 0 ) );
+
+ // Retrieve original revisions and their predecessors
+ $requestData = array(
+ 'format' => 'php',
+ 'action' => 'query',
+ 'prop' => 'revisions',
+ 'revids' => implode( '|', $revisions ),
+ );
+
+ $originalData = Http::post(
+ $apiURL,
+ array(
+ 'postData' => $requestData,
+ )
+ );
+
+ $data = unserialize( $originalData );
+
+ $pages = $data['query']['pages'];
+
+ foreach ( $pages as $page ) {
+ if ( count( $page['revisions'] ) != 1 ) {
+ continue;
+ }
+
+ $revid = $page['revisions'][0]['revid'];
+
+ $newRequest = array(
+ 'format' => 'php',
+ 'action' => 'query',
+ 'prop' => 'revisions',
+ 'titles' => $page['title'],
+ 'rvstartid' => $revid,
+ 'rvlimit' => 2,
+ 'rvprop' => 'ids|content|user',
+ );
+
+ $newData = Http::post(
+ $apiURL,
+ array(
+ 'postData' => $newRequest,
+ )
+ );
+
+ $newData = unserialize( $newData );
+
+ $oldText = '';
+ $newText = '';
+ $allData = $newData['query']['pages'];
+ $pageData = array_shift( $allData );
+ if ( count( $pageData['revisions'] ) == 2 ) {
+ $revision1 = $pageData['revisions'][0];
+ $revision2 = $pageData['revisions'][1];
+ $oldText = trim( $revision2['*'] ) . "\n";
+ $newText = trim( $revision1['*'] ) . "\n";
+ } elseif ( count( $pageData['revisions'] ) == 1 ) {
+ $revision1 = $pageData['revisions'][0];
+ $newText = trim( $revision1['*'] ) . "\n";
+ $oldText = '';
+ }
+
+ $user = $pageData['revisions'][0]['user'];
+
+ print "http://en.wikipedia.org/w/index.php?diff=prev&oldid=$revid\n";
+ EchoDiscussionParser::getInterestedUsers( $oldText, $newText, $user ); // FIXME: getInterestedUsers() is undefined
+ }
+ }
+}
+
+$maintClass = "TestDiscussionParser";
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/Echo/maintenance/updateEchoSchemaForSuppression.php b/Echo/maintenance/updateEchoSchemaForSuppression.php
new file mode 100644
index 00000000..1f186f12
--- /dev/null
+++ b/Echo/maintenance/updateEchoSchemaForSuppression.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Update event_page_id in echo_event based on event_page_title and
+ * event_page_namespace
+ *
+ * @ingroup Maintenance
+ */
+require_once ( getenv( 'MW_INSTALL_PATH' ) !== false
+ ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php'
+ : __DIR__ . '/../../../maintenance/Maintenance.php' );
+
+/**
+ * Maintenance script that populates the event_page_id column of echo_event
+ *
+ * @ingroup Maintenance
+ */
+class UpdateEchoSchemaForSuppression extends Maintenance {
+
+ /**
+ * @var $table string The table to update
+ */
+ protected $table = 'echo_event';
+
+ /**
+ * @var $idField string The primary key column of the table to update
+ */
+ protected $idField = 'event_id';
+
+ public function __construct() {
+ parent::__construct();
+ $this->setBatchSize( 500 );
+ }
+
+ public function execute() {
+ global $wgEchoCluster;
+
+ $reader = new EchoBatchRowIterator( MWEchoDbFactory::getDB( DB_SLAVE ), $this->table, $this->idField, $this->mBatchSize );
+ $reader->addConditions( array(
+ "event_page_title IS NOT NULL",
+ "event_page_id" => null,
+ ) );
+
+ $updater = new EchoBatchRowUpdate(
+ $reader,
+ new EchoBatchRowWriter( MWEchoDbFactory::getDB( DB_MASTER ), $this->table, $wgEchoCluster ),
+ new EchoSuppressionRowUpdateGenerator
+ );
+ $updater->setOutput( array( $this, '__internalOutput' ) );
+ $updater->execute();
+ }
+
+ /**
+ * Internal use only. parent::output() is a protected method, only way to access it from
+ * a callback in php5.3 is to make a public function. In 5.4 can replace with a Closure.
+ */
+ public function __internalOutput( $text ) {
+ $this->output( $text );
+ }
+}
+
+$maintClass = 'UpdateEchoSchemaForSuppression'; // Tells it to run the class
+require_once ( RUN_MAINTENANCE_IF_MAIN );
diff --git a/Echo/model/AbstractEntity.php b/Echo/model/AbstractEntity.php
new file mode 100644
index 00000000..fed21f4e
--- /dev/null
+++ b/Echo/model/AbstractEntity.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * Abstract entity for Echo model
+ */
+abstract class EchoAbstractEntity {
+
+ /**
+ * Convert an entity's property to array
+ * @return array
+ */
+ abstract public function toDbArray();
+
+}
diff --git a/Echo/model/Event.php b/Echo/model/Event.php
new file mode 100644
index 00000000..235c026f
--- /dev/null
+++ b/Echo/model/Event.php
@@ -0,0 +1,548 @@
+<?php
+
+/**
+ * Immutable class to represent an event.
+ * In Echo nomenclature, an event is a single occurrence.
+ */
+class EchoEvent extends EchoAbstractEntity{
+
+ protected $type = null;
+ protected $id = null;
+ protected $variant = null;
+ /**
+ * @var User
+ */
+ protected $agent = null;
+
+ /**
+ * Loaded dynamically on request
+ *
+ * @var Title
+ */
+ protected $title = null;
+ protected $pageId = null;
+
+ /**
+ * Loaded dynamically on request
+ *
+ * @var Revision
+ */
+ protected $revision = null;
+
+ protected $extra = array();
+
+ /**
+ * Notification timestamp
+ * @var string
+ */
+ protected $timestamp = null;
+
+ /**
+ * A hash used to bundle a set of events, events that can be
+ * grouped for a user has the same bundle hash
+ * @var string
+ */
+ protected $bundleHash;
+
+ /**
+ * You should not call the constructor.
+ * Instead use one of the factory functions:
+ * EchoEvent::create To create a new event
+ * EchoEvent::newFromRow To create an event object from a row object
+ * EchoEvent::newFromID To create an event object from the database given its ID
+ */
+ protected function __construct() {}
+
+ ## Save the id and timestamp
+ function __sleep() {
+ if ( !$this->id ) {
+ throw new MWException( "Unable to serialize an uninitialized EchoEvent" );
+ }
+ return array( 'id', 'timestamp' );
+ }
+
+ function __wakeup() {
+ $this->loadFromID( $this->id );
+ }
+
+ function __toString() {
+ return "EchoEvent(id={$this->id}; type={$this->type})";
+ }
+
+ /**
+ * Creates an EchoEvent object
+ * @param $info array Named arguments:
+ * type (required): The event type;
+ * variant: A variant of the type;
+ * agent: The user who caused the event;
+ * title: The page on which the event was triggered;
+ * extra: Event-specific extra information (e.g. post content)
+ *
+ * @throws MWException
+ * @return EchoEvent|bool false if aborted via hook
+ */
+ public static function create( $info = array() ) {
+ global $wgEchoNotifications;
+
+ // Do not create event and notifications if write access is locked
+ if ( wfReadOnly() ) {
+ throw new ReadOnlyError();
+ }
+
+ $obj = new EchoEvent;
+ static $validFields = array( 'type', 'variant', 'agent', 'title', 'extra' );
+
+ if ( empty( $info['type'] ) ) {
+ throw new MWException( "'type' parameter is mandatory" );
+ }
+
+ if ( !isset( $wgEchoNotifications[$info['type']] ) ) {
+ return false;
+ }
+
+ $obj->id = false;
+ $obj->timestamp = wfTimestampNow();
+
+ foreach ( $validFields as $field ) {
+ if ( isset( $info[$field] ) ) {
+ $obj->$field = $info[$field];
+ }
+ }
+
+ // If the extra size is more than 50000 bytes, that means there is
+ // probably a problem with the design of this notification type.
+ // There might be data loss if the size exceeds the DB column size of
+ // event_extra.
+ if ( strlen( $obj->serializeExtra() ) > 50000 ) {
+ wfDebugLog( __CLASS__, __FUNCTION__ . ': event extra data is too huge for ' . $info['type'] );
+ return false;
+ }
+
+ if ( $obj->title ) {
+ if ( !$obj->title instanceof Title ) {
+ throw new MWException( 'Invalid title parameter' );
+ }
+ $obj->setTitle( $obj->title );
+ }
+
+ if ( $obj->agent && !
+ ( $obj->agent instanceof User ||
+ $obj->agent instanceof StubObject )
+ ) {
+ throw new MWException( "Invalid user parameter" );
+ }
+
+ if ( !wfRunHooks( 'BeforeEchoEventInsert', array( $obj ) ) ) {
+ return false;
+ }
+
+ //@Todo - Database insert logic should not be inside the model
+ $obj->insert();
+
+ wfRunHooks( 'EchoEventInsertComplete', array( $obj ) );
+
+ global $wgEchoUseJobQueue;
+
+ EchoNotificationController::notify( $obj, $wgEchoUseJobQueue );
+
+ return $obj;
+ }
+
+ /**
+ * Convert the object's database property to array
+ * @return array
+ */
+ public function toDbArray() {
+ $data = array (
+ 'event_type' => $this->type,
+ 'event_variant' => $this->variant,
+ 'event_extra' => $this->serializeExtra()
+ );
+ if ( $this->id ) {
+ $data['event_id'] = $this->id;
+ }
+ if ( $this->agent ) {
+ if ( $this->agent->isAnon() ) {
+ $data['event_agent_ip'] = $this->agent->getName();
+ } else {
+ $data['event_agent_id'] = $this->agent->getId();
+ }
+ }
+
+ if ( $this->pageId ) {
+ $data['event_page_id'] = $this->pageId;
+ } elseif ( $this->title ) {
+ $pageId = $this->title->getArticleId();
+ // Don't need any special handling for title with no id
+ // as they are already stored in extra data array
+ if ( $pageId ) {
+ $data['event_page_id'] = $pageId;
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Check whether the echo event is an enabled event
+ * @return bool
+ */
+ public function isEnabledEvent() {
+ global $wgEchoNotifications;
+ if ( isset( $wgEchoNotifications[$this->getType()] ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Inserts the object into the database.
+ */
+ protected function insert() {
+ $eventMapper = new EchoEventMapper();
+ $this->id = $eventMapper->insert( $this );
+ }
+
+ /**
+ * Loads data from the provided $row into this object.
+ *
+ * @param $row stdClass row object from echo_event
+ */
+ public function loadFromRow( $row ) {
+ $this->id = $row->event_id;
+ $this->type = $row->event_type;
+
+ // If the object is loaded from __sleep(), timestamp should be already set
+ if ( !$this->timestamp ) {
+ if ( isset( $row->notification_timestamp ) ) {
+ $this->timestamp = wfTimestamp( TS_MW, $row->notification_timestamp );
+ } else {
+ $this->timestamp = wfTimestampNow();
+ }
+ }
+
+ $this->variant = $row->event_variant;
+ $this->extra = $row->event_extra ? unserialize( $row->event_extra ) : array();
+ $this->pageId = $row->event_page_id;
+
+ if ( $row->event_agent_id ) {
+ $this->agent = User::newFromID( $row->event_agent_id );
+ } elseif ( $row->event_agent_ip ) {
+ $this->agent = User::newFromName( $row->event_agent_ip, false );
+ }
+
+ // Lazy load the title from getTitle() so that we can do a batch-load
+ if (
+ isset( $this->extra['page_title'], $this->extra['page_namespace'] )
+ && !$row->event_page_id
+ ) {
+ $this->title = Title::makeTitleSafe(
+ $this->extra['page_namespace'],
+ $this->extra['page_title']
+ );
+ }
+ if ( $row->event_page_id ) {
+ $titleCache = EchoTitleLocalCache::create();
+ $titleCache->add( $row->event_page_id );
+ }
+ if ( isset( $this->extra['revid'] ) && $this->extra['revid'] ) {
+ $revisionCache = EchoRevisionLocalCache::create();
+ $revisionCache->add( $this->extra['revid'] );
+ }
+ }
+
+ /**
+ * Loads data from the database into this object, given the event ID.
+ * @param $id int Event ID
+ * @param $fromMaster bool
+ */
+ public function loadFromID( $id, $fromMaster = false ) {
+ $eventMapper = new EchoEventMapper();
+ $event = $eventMapper->fetchById( $id, $fromMaster );
+
+ // Copy over the attribute
+ $this->id = $event->id;
+ $this->type = $event->type;
+ $this->variant = $event->variant;
+ $this->extra = $event->extra;
+ $this->pageId = $event->pageId;
+ $this->agent = $event->agent;
+ $this->title = $event->title;
+ // Don't overwrite timestamp if it exists already
+ if ( !$this->timestamp ) {
+ $this->timestamp = $event->timestamp;
+ }
+ }
+
+ /**
+ * Creates an EchoEvent from a row object
+ *
+ * @param $row stdClass row object from echo_event
+ * @return EchoEvent object.
+ */
+ public static function newFromRow( $row ) {
+ $obj = new EchoEvent();
+ $obj->loadFromRow( $row );
+ return $obj;
+ }
+
+ /**
+ * Creates an EchoEvent from the database by ID
+ *
+ * @param $id int Event ID
+ * @return EchoEvent
+ */
+ public static function newFromID( $id ) {
+ $obj = new EchoEvent();
+ $obj->loadFromID( $id );
+ return $obj;
+ }
+
+ /**
+ * Serialize the extra data for event
+ * @return string
+ */
+ public function serializeExtra() {
+ if ( is_array( $this->extra ) || is_object( $this->extra ) ) {
+ $extra = serialize( $this->extra );
+ } elseif ( is_null( $this->extra ) ) {
+ $extra = null;
+ } else {
+ $extra = serialize( array( $this->extra ) );
+ }
+
+ return $extra;
+ }
+
+ /**
+ * Check if the event is dismissable for the given distribution type
+ *
+ * @param string $distribution notification distribution web/email
+ * @return bool
+ */
+ public function isDismissable( $distribution ) {
+ global $wgEchoNotificationCategories;
+
+ $category = $this->getCategory();
+ if ( isset( $wgEchoNotificationCategories[$category]['no-dismiss'] ) ) {
+ $noDismiss = $wgEchoNotificationCategories[$category]['no-dismiss'];
+ } else {
+ $noDismiss = array();
+ }
+ if ( !in_array( $distribution, $noDismiss ) && !in_array( 'all' , $noDismiss ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Determine if the current user is allowed to view a particular
+ * field of this revision, if it's marked as deleted. When no
+ * revision is attached always returns true.
+ *
+ * @param $field Integer:one of Revision::DELETED_TEXT,
+ * Revision::DELETED_COMMENT,
+ * Revision::DELETED_USER
+ * @param $user User object to check, or null to use $wgUser
+ * @return Boolean
+ */
+ public function userCan( $field, User $user = null ) {
+ $revision = $this->getRevision();
+ if ( $revision ) {
+ return $revision->userCan( $field, $user );
+ } else {
+ return true;
+ }
+ }
+
+ ## Accessors
+ /**
+ * @return int
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTimestamp() {
+ return $this->timestamp;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * @return string
+ */
+ public function getVariant() {
+ return $this->variant;
+ }
+
+ /**
+ * @return array|null
+ */
+ public function getExtra() {
+ return $this->extra;
+ }
+
+ public function getExtraParam( $key, $default = null ) {
+ return isset( $this->extra[$key] ) ? $this->extra[$key] : $default;
+ }
+
+ /**
+ * @return User
+ */
+ public function getAgent() {
+ return $this->agent;
+ }
+
+ /**
+ * @return Title|null
+ */
+ public function getTitle() {
+ if ( $this->title ) {
+ return $this->title;
+ } elseif ( $this->pageId ) {
+ $titleCache = EchoTitleLocalCache::create();
+ $title = $titleCache->get( $this->pageId );
+ if ( $title ) {
+ return $this->title = $title;
+ }
+ return $this->title = Title::newFromId( $this->pageId );
+ } elseif ( isset( $this->extra['page_title'], $this->extra['page_namespace'] ) ) {
+ return $this->title = Title::makeTitleSafe(
+ $this->extra['page_namespace'],
+ $this->extra['page_title']
+ );
+ }
+ return null;
+ }
+
+ /**
+ * @return Revision|null
+ */
+ public function getRevision() {
+ if ( $this->revision ) {
+ return $this->revision;
+ } elseif ( isset( $this->extra['revid'] ) ) {
+ $revisionCache = EchoRevisionLocalCache::create();
+ $revision = $revisionCache->get( $this->extra['revid'] );
+ if ( $revision ) {
+ return $this->revision = $revision;
+ }
+ return $this->revision = Revision::newFromId( $this->extra['revid'] );
+ }
+ return null;
+ }
+
+ /**
+ * Get the category of the event type
+ * @return string
+ */
+ public function getCategory() {
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ return $attributeManager->getNotificationCategory( $this->type );
+ }
+
+ /**
+ * Get the section of the event type
+ * @return string
+ */
+ public function getSection() {
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ return $attributeManager->getNotificationSection( $this->type );
+ }
+
+ /**
+ * Get the use-jobqueue attribute of an event type
+ * @FIXME - use global for now instead of attribute manager, we may need
+ * to cherry pick this to enwiki
+ * @return boolean
+ */
+ public function getUseJobQueue() {
+ global $wgEchoNotifications;
+ if ( isset( $wgEchoNotifications[$this->type]['use-jobqueue'] ) ) {
+ return (bool)$wgEchoNotifications[$this->type]['use-jobqueue'];
+ }
+ return false;
+ }
+
+ public function setType( $type ) {
+ $this->type = $type;
+ }
+
+ public function setVariant( $variant ) {
+ $this->variant = $variant;
+ }
+
+ public function setAgent( User $agent ) {
+ $this->agent = $agent;
+ }
+
+ public function setTitle( Title $title ) {
+ $this->title = $title;
+ $pageId = $title->getArticleId();
+ if ( $pageId ) {
+ $this->pageId = $pageId;
+ } else {
+ $this->extra['page_title'] = $title->getDBKey();
+ $this->extra['page_namespace'] = $title->getNamespace();
+ }
+
+ }
+
+ public function setExtra( $name, $value ) {
+ $this->extra[$name] = $value;
+ }
+
+ /**
+ * Get the message key of the primary or secondary link for a notification type.
+ *
+ * @param $rank String 'primary' or 'secondary'
+ * @return String i18n message key
+ */
+ public function getLinkMessage( $rank ) {
+ global $wgEchoNotifications;
+ $type = $this->getType();
+ if ( isset( $wgEchoNotifications[$type][$rank.'-link']['message'] ) ) {
+ return $wgEchoNotifications[$type][$rank.'-link']['message'];
+ }
+ return '';
+ }
+
+ /**
+ * Get the link destination of the primary or secondary link for a notification type.
+ *
+ * @param $rank String 'primary' or 'secondary'
+ * @return String The link destination, e.g. 'agent'
+ */
+ public function getLinkDestination( $rank ) {
+ global $wgEchoNotifications;
+ $type = $this->getType();
+ if ( isset( $wgEchoNotifications[$type][$rank.'-link']['destination'] ) ) {
+ return $wgEchoNotifications[$type][$rank.'-link']['destination'];
+ }
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function getBundleHash() {
+ return $this->bundleHash;
+ }
+
+ /**
+ * @param $hash string
+ */
+ public function setBundleHash( $hash ) {
+ $this->bundleHash = $hash;
+ }
+}
diff --git a/Echo/model/Notification.php b/Echo/model/Notification.php
new file mode 100644
index 00000000..17f2e0ed
--- /dev/null
+++ b/Echo/model/Notification.php
@@ -0,0 +1,308 @@
+<?php
+
+class EchoNotification extends EchoAbstractEntity {
+
+ /**
+ * @var User
+ */
+ protected $user;
+
+ /**
+ * @var EchoEvent
+ */
+ protected $event;
+
+ /**
+ * The target page object for the notification if there is one. Null means
+ * the information has not been loaded.
+ *
+ * @var EchoTargetPage[]|null
+ */
+ protected $targetPages;
+
+ /**
+ * @var string
+ */
+ protected $timestamp;
+
+ /**
+ * @var string
+ */
+ protected $readTimestamp;
+
+ /**
+ * Determine whether this is a bundle base. Default is 1,
+ * which means it's a bundle base
+ * @var int
+ */
+ protected $bundleBase = 1;
+
+ /**
+ * The hash used to determine if a set of event could be bundled
+ * @var string
+ */
+ protected $bundleHash = '';
+
+ /**
+ * The hash used to bundle events to display
+ * @var string
+ */
+ protected $bundleDisplayHash = '';
+
+ /**
+ * Do not use this constructor.
+ */
+ protected function __construct() {}
+
+ /**
+ * Creates an EchoNotification object based on event and user
+ * @param $info array The following keys are required:
+ * - 'event' The EchoEvent being notified about.
+ * - 'user' The User being notified.
+ * @throws MWException
+ * @return EchoNotification
+ */
+ public static function create( array $info ) {
+ $obj = new EchoNotification();
+ static $validFields = array( 'event', 'user' );
+
+ foreach ( $validFields as $field ) {
+ if ( isset( $info[$field] ) ) {
+ $obj->$field = $info[$field];
+ } else {
+ throw new MWException( "Field $field is required" );
+ }
+ }
+
+ if ( !$obj->user instanceof User && !$obj->user instanceof StubObject ) {
+ throw new MWException( 'Invalid user parameter, expected: User/StubObject object' );
+ }
+
+ if ( !$obj->event instanceof EchoEvent ) {
+ throw new MWException( 'Invalid event parameter, expected: EchoEvent object' );
+ }
+
+ // Notification timestamp should be the same as event timestamp
+ $obj->timestamp = $obj->event->getTimestamp();
+ // Safe fallback
+ if ( !$obj->timestamp ) {
+ $obj->timestamp = wfTimestampNow();
+ }
+
+ //@Todo - Database insert logic should not be inside the model
+ $obj->insert();
+
+ return $obj;
+ }
+
+ /**
+ * Adds this new notification object to the backend storage.
+ */
+ protected function insert() {
+ global $wgEchoNotifications;
+
+ $notifMapper = new EchoNotificationMapper();
+
+ // Get the bundle key for this event if web bundling is enabled
+ $bundleKey = '';
+ if ( !empty( $wgEchoNotifications[$this->event->getType()]['bundle']['web'] ) ) {
+ wfRunHooks( 'EchoGetBundleRules', array( $this->event, &$bundleKey ) );
+ }
+
+ // The list of event ids to be removed from echo_target_page,
+ // this is mainly for bundled notifications when an event is
+ // no longer the bundle base
+ $eventIds = array();
+ if ( $bundleKey ) {
+ $hash = md5( $bundleKey );
+ $this->bundleHash = $hash;
+ $lastNotif = $notifMapper->fetchNewestByUserBundleHash( $this->user, $hash );
+
+ // Use a new display hash if:
+ // 1. there was no last bundle notification
+ // 2. last bundle notification with the same hash was read
+ if ( $lastNotif && !$lastNotif->getReadTimestamp() ) {
+ $this->bundleDisplayHash = $lastNotif->getBundleDisplayHash();
+ $lastEvent = $lastNotif->getEvent();
+ if ( $lastEvent ) {
+ $eventIds[] = $lastEvent->getId();
+ }
+ } else {
+ $this->bundleDisplayHash = md5( $bundleKey . '-display-hash-' . wfTimestampNow() );
+ }
+ }
+
+ // Create a target page object if specified by event
+ $event = $this->event;
+ $user = $this->user;
+ $targetPages = self::resolveTargetPages( $event->getExtraParam( 'target-page' ) );
+ if ( $targetPages ) {
+ $notifMapper->attachListener( 'insert', 'add-target-page', function() use ( $event, $user, $eventIds, $targetPages ) {
+ $targetMapper = new EchoTargetPageMapper();
+ if ( $eventIds ) {
+ $targetMapper->deleteByUserEvents( $user, $eventIds );
+ }
+ foreach ( $targetPages as $title ) {
+ $targetPage = EchoTargetPage::create( $user, $title, $event );
+ if ( $targetPage ) {
+ $targetMapper->insert( $targetPage );
+ }
+ }
+ } );
+ }
+
+ // Add listener to refresh notification count upon insert
+ $notifMapper->attachListener( 'insert', 'refresh-notif-count',
+ function() use ( $user ) {
+ MWEchoNotifUser::newFromUser( $user )->resetNotificationCount( DB_MASTER );
+ }
+ );
+
+ $notifMapper->insert( $this );
+
+ // Clear applicable section status from cache upon new notification creation
+ MWEchoNotifUser::newFromUser( $this->user )->clearSectionStatusCache(
+ $this->event->getSection()
+ );
+
+ wfRunHooks( 'EchoCreateNotificationComplete', array( $this ) );
+ }
+
+ /**
+ * @param int[]|int|false $targetPageIds
+ * @return Title[]
+ */
+ protected static function resolveTargetPages( $targetPageIds ) {
+ if ( !$targetPageIds ) {
+ return array();
+ }
+ if ( !is_array( $targetPageIds ) ) {
+ $targetPageIds = array( $targetPageIds );
+ }
+ $result = array();
+ foreach ( $targetPageIds as $targetPageId ) {
+ // Make sure the target-page id is a valid id
+ $title = Title::newFromID( $targetPageId );
+ // Try master if there is no match
+ if ( !$title ) {
+ $title = Title::newFromID( $targetPageId, Title::GAID_FOR_UPDATE );
+ }
+ if ( $title ) {
+ $result[] = $title;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Load a notification record from std class
+ * @param stdClass
+ * @param EchoTargetPage[]|null An array of EchoTargetPage instances, or null if not loaded.
+ * @return EchoNotification
+ */
+ public static function newFromRow( $row, $targetPages = null ) {
+ $notification = new EchoNotification();
+
+ if ( property_exists( $row, 'event_type' ) ) {
+ $notification->event = EchoEvent::newFromRow( $row );
+ } else {
+ $notification->event = EchoEvent::newFromID( $row->notification_event );
+ }
+
+ $notification->targetPages = $targetPages;
+ $notification->user = User::newFromId( $row->notification_user );
+ // Notification timestamp should never be empty
+ $notification->timestamp = wfTimestamp( TS_MW, $row->notification_timestamp );
+ // Only convert to MW format if it is not empty, otherwise
+ // wfTimestamp would use current timestamp for empty cases
+ if ( $row->notification_read_timestamp ) {
+ $notification->readTimestamp = wfTimestamp( TS_MW, $row->notification_read_timestamp );
+ }
+ $notification->bundleBase = $row->notification_bundle_base;
+ $notification->bundleHash = $row->notification_bundle_hash;
+ $notification->bundleDisplayHash = $row->notification_bundle_display_hash;
+ return $notification;
+ }
+
+ /**
+ * Convert object property to database row array
+ * @return array
+ */
+ public function toDbArray() {
+ return array(
+ 'notification_event' => $this->event->getId(),
+ 'notification_user' => $this->user->getId(),
+ 'notification_timestamp' => $this->timestamp,
+ 'notification_read_timestamp' => $this->readTimestamp,
+ 'notification_bundle_base' => $this->bundleBase,
+ 'notification_bundle_hash' => $this->bundleHash,
+ 'notification_bundle_display_hash' => $this->bundleDisplayHash
+ );
+ }
+
+ /**
+ * Getter method
+ * @return EchoEvent The event for this notification
+ */
+ public function getEvent() {
+ return $this->event;
+ }
+
+ /**
+ * Getter method
+ * @return User The recipient of this notification
+ */
+ public function getUser() {
+ return $this->user;
+ }
+
+ /**
+ * Getter method
+ * @return string Notification creation timestamp
+ */
+ public function getTimestamp() {
+ return $this->timestamp;
+ }
+
+ /**
+ * Getter method
+ * @return string|null Notification read timestamp
+ */
+ public function getReadTimestamp() {
+ return $this->readTimestamp;
+ }
+
+ /**
+ * Getter method
+ * @return int Notification bundle base
+ */
+ public function getBundleBase() {
+ return $this->bundleBase;
+ }
+
+ /**
+ * Getter method
+ * @return string|null Notification bundle hash
+ */
+ public function getBundleHash() {
+ return $this->bundleHash;
+ }
+
+ /**
+ * Getter method
+ * @return string|null Notification bundle display hash
+ */
+ public function getBundleDisplayHash() {
+ return $this->bundleDisplayHash;
+ }
+
+ /**
+ * Getter method. Returns an array of EchoTargetPages, or null if they have
+ * not been loaded.
+ *
+ * @return EchoTargetPage[]|null
+ */
+ public function getTargetPages() {
+ return $this->targetPages;
+ }
+}
diff --git a/Echo/model/TargetPage.php b/Echo/model/TargetPage.php
new file mode 100644
index 00000000..cc846605
--- /dev/null
+++ b/Echo/model/TargetPage.php
@@ -0,0 +1,139 @@
+<?php
+
+/**
+ * Map a title to an echo notification so that we can mark a notification as read
+ * when visiting the page. This only supports titles with ids because majority
+ * of notifications have page_id and searching by namespace and title is slow
+ */
+class EchoTargetPage extends EchoAbstractEntity {
+
+ /**
+ * @var User
+ */
+ protected $user;
+
+ /**
+ * @var Title|null
+ */
+ protected $title;
+
+ /**
+ * @var int
+ */
+ protected $pageId;
+
+ /**
+ * @var EchoEvent|null
+ */
+ protected $event;
+
+ /**
+ * @var int
+ */
+ protected $eventId;
+
+ /**
+ * Only allow creating instance internally
+ */
+ protected function __construct() {}
+
+ /**
+ * Create a EchoTargetPage instance from User, Title and EchoEvent
+ *
+ * @param User $user
+ * @param Title $title
+ * @param EchoEvent $event
+ * @return TargetPage|null
+ */
+ public static function create( User $user, Title $title, EchoEvent $event ) {
+ // This only support title with a page_id
+ if ( $user->isAnon() || !$title->getArticleID() ) {
+ return null;
+ }
+ $obj = new self();
+ $obj->user = $user;
+ $obj->event = $event;
+ $obj->eventId = $event->getId();
+ $obj->title = $title;
+ $obj->pageId = $title->getArticleID();
+ return $obj;
+ }
+
+ /**
+ * Create a EchoTargetPage instance from stdClass object
+ *
+ * @param stdClass $row
+ * @return EchoTargetPage
+ * @throws MWException
+ */
+ public static function newFromRow( $row ) {
+ $requiredFields = array (
+ 'etp_user',
+ 'etp_page',
+ 'etp_event'
+ );
+ foreach ( $requiredFields as $field ) {
+ if ( !isset( $row->$field ) || !$row->$field ) {
+ throw new MWException( $field . ' is not set in the row!' );
+ }
+ }
+ $obj = new self();
+ $obj->user = User::newFromId( $row->etp_user );
+ $obj->pageId = $row->etp_page;
+ $obj->eventId = $row->etp_event;
+ return $obj;
+ }
+
+ /**
+ * @return User
+ */
+ public function getUser() {
+ return $this->user;
+ }
+
+ /**
+ * @return Title|null
+ */
+ public function getTitle() {
+ if ( !$this->title ) {
+ $this->title = Title::newFromId( $this->pageId );
+ }
+ return $this->title;
+ }
+
+ /**
+ * @return int
+ */
+ public function getPageId() {
+ return $this->pageId;
+ }
+
+ /**
+ * @return EchoEvent
+ */
+ public function getEvent() {
+ if ( !$this->event ) {
+ $this->event = EchoEvent::newFromID( $this->eventId );
+ }
+ return $this->event;
+ }
+
+ /**
+ * @return int
+ */
+ public function getEventId() {
+ return $this->eventId;
+ }
+
+ /**
+ * Convert the properties to a database row
+ * @return array
+ */
+ public function toDbArray() {
+ return array (
+ 'etp_user' => $this->user->getId(),
+ 'etp_page' => $this->pageId,
+ 'etp_event' => $this->eventId
+ );
+ }
+}
diff --git a/Echo/modules/alert/ext.echo.alert.less b/Echo/modules/alert/ext.echo.alert.less
new file mode 100644
index 00000000..510fdf7d
--- /dev/null
+++ b/Echo/modules/alert/ext.echo.alert.less
@@ -0,0 +1,12 @@
+#pt-mytalk {
+ white-space: nowrap;
+
+ /* High-specificity rule to override core styles for #p-personal li a */
+ a.mw-echo-alert {
+ border-radius: 2px;
+ background-color: #F9C557;
+ padding: 0.25em 0.8em 0.2em 0.8em;
+ color: #555555;
+ font-weight: normal;
+ }
+}
diff --git a/Echo/modules/alert/ext.echo.alert.modern.css b/Echo/modules/alert/ext.echo.alert.modern.css
new file mode 100644
index 00000000..66e440bb
--- /dev/null
+++ b/Echo/modules/alert/ext.echo.alert.modern.css
@@ -0,0 +1,4 @@
+/* No rounded corners for Modern skin */
+#pt-mytalk a.mw-echo-alert {
+ border-radius: 0;
+}
diff --git a/Echo/modules/alert/ext.echo.alert.monobook.css b/Echo/modules/alert/ext.echo.alert.monobook.css
new file mode 100644
index 00000000..97ee676c
--- /dev/null
+++ b/Echo/modules/alert/ext.echo.alert.monobook.css
@@ -0,0 +1,4 @@
+/* Different background color on hover for consistency with Monobook skin */
+#pt-mytalk a.mw-echo-alert:hover {
+ background-color: #FAB951;
+}
diff --git a/Echo/modules/badge/ext.echo.badge.less b/Echo/modules/badge/ext.echo.badge.less
new file mode 100644
index 00000000..d75a67f0
--- /dev/null
+++ b/Echo/modules/badge/ext.echo.badge.less
@@ -0,0 +1,30 @@
+/* We have to include the #pt-notifications selector due to monobook */
+#pt-notifications .mw-echo-notifications-badge {
+ min-width: 7px;
+ border-radius: 2px;
+ padding: 0.25em 0.45em 0.2em 0.45em;
+ margin-left: -4px;
+ text-align: center;
+ background-color: #d2d2d2;
+ font-weight: bold;
+ color: white;
+ cursor: pointer;
+ text-decoration: none;
+
+ &:hover,
+ &:active,
+ &:focus {
+ background-color: #c2c2c2;
+ outline: none;
+ -moz-outline-style: none;
+ }
+
+ &.mw-echo-unread-notifications {
+ background-color: #cc0000;
+ }
+
+ &.mw-echo-unread-notifications:hover {
+ background-color: #bf0000;
+ }
+}
+
diff --git a/Echo/modules/badge/ext.echo.badge.modern.css b/Echo/modules/badge/ext.echo.badge.modern.css
new file mode 100644
index 00000000..6bf18c9e
--- /dev/null
+++ b/Echo/modules/badge/ext.echo.badge.modern.css
@@ -0,0 +1,4 @@
+/* No rounded corners for modern skin */
+#pt-notifications .mw-echo-notifications-badge {
+ border-radius: 0;
+}
diff --git a/Echo/modules/badge/ext.echo.badge.monobook.css b/Echo/modules/badge/ext.echo.badge.monobook.css
new file mode 100644
index 00000000..900f55b1
--- /dev/null
+++ b/Echo/modules/badge/ext.echo.badge.monobook.css
@@ -0,0 +1,3 @@
+#p-personal #pt-notifications a.mw-echo-notifications-badge:hover {
+ background-color: #c2c2c2;
+}
diff --git a/Echo/modules/base/ext.echo.base.js b/Echo/modules/base/ext.echo.base.js
new file mode 100644
index 00000000..da3a90fb
--- /dev/null
+++ b/Echo/modules/base/ext.echo.base.js
@@ -0,0 +1,84 @@
+( function ( mw, $ ) {
+ 'use strict';
+
+ mw.echo = {
+
+ clickThroughEnabled: mw.config.get( 'wgEchoConfig' ).eventlogging.EchoInteraction.enabled,
+
+ /**
+ * Set up event logging for individual notification
+ * @param {jQuery} notification JQuery representing a single notification
+ * @param {string} context 'flyout'/'archive'
+ * @param {boolean} [mobile] True if interaction was on a mobile device
+ */
+ setupNotificationLogging: function ( notification, context, mobile ) {
+ var eventId = +notification.attr( 'data-notification-event' ),
+ eventType = notification.attr( 'data-notification-type' );
+
+ // Check if Schema:EchoInteraction is enabled
+ if ( !mw.echo.clickThroughEnabled ) {
+ return;
+ }
+ // Log the impression
+ mw.echo.logInteraction( 'notification-impression', context, eventId, eventType, mobile );
+ // Set up logging for clickthrough
+ notification.find( 'a' ).click( function () {
+ mw.echo.logInteraction( 'notification-link-click', context, eventId, eventType, mobile );
+ } );
+ },
+
+ /**
+ * Log all Echo interaction related events
+ * @param {string} action The interaction
+ * @param {string} [context] 'flyout'/'archive' or undefined for the badge
+ * @param {int} [eventId] Notification event id
+ * @param {string} [eventType] notification type
+ * @param {boolean} [mobile] True if interaction was on a mobile device
+ */
+ logInteraction: function ( action, context, eventId, eventType, mobile ) {
+ // Check if Schema:EchoInteraction is enabled
+ if ( !mw.echo.clickThroughEnabled ) {
+ return;
+ }
+
+ var myEvt = {
+ action: action
+ };
+
+ // All the fields below are optional
+ if ( context ) {
+ myEvt.context = context;
+ }
+ if ( eventId ) {
+ myEvt.eventId = eventId;
+ }
+ if ( eventType ) {
+ myEvt.notificationType = eventType;
+ }
+ if ( mobile ) {
+ myEvt.mobile = mobile;
+ }
+ mw.loader.using( 'ext.eventLogging', function() {
+ mw.eventLog.logEvent( 'EchoInteraction', myEvt );
+ } );
+ },
+ /**
+ * @method
+ * @return jQuery element corresponding to the badge reflecting the notification count
+ */
+ getBadge: function() {
+ return $( '.mw-echo-notifications-badge' );
+ }
+
+ };
+
+ if ( mw.echo.clickThroughEnabled ) {
+ mw.loader.using( 'ext.eventLogging', function() {
+ mw.eventLog.setDefaults( 'EchoInteraction', {
+ version: mw.config.get( 'wgEchoConfig' ).version,
+ userId: +mw.config.get( 'wgUserId' ),
+ editCount: +mw.config.get( 'wgUserEditCount' )
+ } );
+ } );
+ }
+} )( mediaWiki, jQuery );
diff --git a/Echo/modules/base/ext.echo.base.less b/Echo/modules/base/ext.echo.base.less
new file mode 100644
index 00000000..2bcca03e
--- /dev/null
+++ b/Echo/modules/base/ext.echo.base.less
@@ -0,0 +1,53 @@
+.mw-echo-title {
+ font-size: 1em;
+ line-height: 1.4em;
+}
+
+.mw-echo-content {
+ overflow: hidden;
+}
+
+.mw-echo-payload {
+ margin-top: 0.3em;
+}
+/* Including .mw-echo-timestamp for backwards compat */
+.mw-echo-timestamp, .mw-echo-notification-footer {
+ color: #6D6D6D;
+ font-size: 11px;
+ margin-top: 0.2em;
+}
+.mw-echo-notifications {
+ background-color: #EEEEEE;
+}
+.mw-echo-notification {
+ clear: both;
+ display: block;
+ color: #6D6D6D;
+ line-height: 90%;
+ margin: 0;
+ min-height: 30px;
+ background-color: white;
+ position: relative;
+ padding-top: 15px;
+ padding-bottom: 10px;
+ /* Force container to expand to height of floated contents */
+ overflow: hidden;
+ zoom: 1;
+
+ &.mw-echo-unread {
+ color: #252525;
+ }
+
+ span.autocomment {
+ color: inherit;
+ font-style: normal;
+ }
+}
+
+.mw-echo-icon {
+ width: 30px;
+ height: 30px;
+ float: left;
+ margin-right: 10px;
+ margin-left: 10px;
+}
diff --git a/Echo/modules/hooks.txt b/Echo/modules/hooks.txt
new file mode 100644
index 00000000..bad428af
--- /dev/null
+++ b/Echo/modules/hooks.txt
@@ -0,0 +1,7 @@
+hooks.txt
+
+This documents Echo's client-side hooks:
+
+'ext.echo.overlay.beforeShowingOverlay': Before showing the Echo overlay, it is
+passed to this hook, which can modify the DOM or take other actions.
+$overlay: the jQuery-wrapped element for the overlay
diff --git a/Echo/modules/icons/CrossReferenced.png b/Echo/modules/icons/CrossReferenced.png
new file mode 100644
index 00000000..74a191f5
--- /dev/null
+++ b/Echo/modules/icons/CrossReferenced.png
Binary files differ
diff --git a/Echo/modules/icons/Deletion.png b/Echo/modules/icons/Deletion.png
new file mode 100644
index 00000000..8abc2e3d
--- /dev/null
+++ b/Echo/modules/icons/Deletion.png
Binary files differ
diff --git a/Echo/modules/icons/Featured.png b/Echo/modules/icons/Featured.png
new file mode 100644
index 00000000..349892a7
--- /dev/null
+++ b/Echo/modules/icons/Featured.png
Binary files differ
diff --git a/Echo/modules/icons/Generic.png b/Echo/modules/icons/Generic.png
new file mode 100644
index 00000000..36a9fb1b
--- /dev/null
+++ b/Echo/modules/icons/Generic.png
Binary files differ
diff --git a/Echo/modules/icons/Gratitude.png b/Echo/modules/icons/Gratitude.png
new file mode 100644
index 00000000..d22e8b63
--- /dev/null
+++ b/Echo/modules/icons/Gratitude.png
Binary files differ
diff --git a/Echo/modules/icons/NotificationsPage-ltr.png b/Echo/modules/icons/NotificationsPage-ltr.png
new file mode 100644
index 00000000..065be02c
--- /dev/null
+++ b/Echo/modules/icons/NotificationsPage-ltr.png
Binary files differ
diff --git a/Echo/modules/icons/NotificationsPage-rtl.png b/Echo/modules/icons/NotificationsPage-rtl.png
new file mode 100644
index 00000000..09370026
--- /dev/null
+++ b/Echo/modules/icons/NotificationsPage-rtl.png
Binary files differ
diff --git a/Echo/modules/icons/Revert.png b/Echo/modules/icons/Revert.png
new file mode 100644
index 00000000..426ee050
--- /dev/null
+++ b/Echo/modules/icons/Revert.png
Binary files differ
diff --git a/Echo/modules/icons/Reviewed.png b/Echo/modules/icons/Reviewed.png
new file mode 100644
index 00000000..43cdd55f
--- /dev/null
+++ b/Echo/modules/icons/Reviewed.png
Binary files differ
diff --git a/Echo/modules/icons/ReviewedWithTags.png b/Echo/modules/icons/ReviewedWithTags.png
new file mode 100644
index 00000000..c18a2b8d
--- /dev/null
+++ b/Echo/modules/icons/ReviewedWithTags.png
Binary files differ
diff --git a/Echo/modules/icons/Settings.png b/Echo/modules/icons/Settings.png
new file mode 100644
index 00000000..f6cfc7a1
--- /dev/null
+++ b/Echo/modules/icons/Settings.png
Binary files differ
diff --git a/Echo/modules/icons/Talk.png b/Echo/modules/icons/Talk.png
new file mode 100644
index 00000000..41387cc0
--- /dev/null
+++ b/Echo/modules/icons/Talk.png
Binary files differ
diff --git a/Echo/modules/mixins.less b/Echo/modules/mixins.less
new file mode 100644
index 00000000..a993b320
--- /dev/null
+++ b/Echo/modules/mixins.less
@@ -0,0 +1,20 @@
+// Begin Mixins
+
+// FIXME: Use a core mixin.
+// truncated-text
+//
+// Add the truncated-text mixin to any element where long text is
+// expected, and truncating improves the UX.
+// Can be used with .truncated-text(true) to undo text truncation.
+//
+// Use in Flow, Echo and MobileFrontend extensions.
+.truncated-text(@undo: false) when not (@undo) {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.truncated-text(@undo: false) when (@undo) {
+ white-space: inherit;
+ overflow: inherit;
+ text-overflow: inherit;
+}
diff --git a/Echo/modules/overlay/Help.png b/Echo/modules/overlay/Help.png
new file mode 100644
index 00000000..5a7133d2
--- /dev/null
+++ b/Echo/modules/overlay/Help.png
Binary files differ
diff --git a/Echo/modules/overlay/PokeyNorth.png b/Echo/modules/overlay/PokeyNorth.png
new file mode 100644
index 00000000..af3f5ab6
--- /dev/null
+++ b/Echo/modules/overlay/PokeyNorth.png
Binary files differ
diff --git a/Echo/modules/overlay/ext.echo.overlay.init.js b/Echo/modules/overlay/ext.echo.overlay.init.js
new file mode 100644
index 00000000..534bebf5
--- /dev/null
+++ b/Echo/modules/overlay/ext.echo.overlay.init.js
@@ -0,0 +1,74 @@
+( function ( $, mw ) {
+ $( function () {
+ var $link = $( '#pt-notifications a' );
+ if ( ! $link.length ) {
+ return;
+ }
+
+ $link.click( function ( e ) {
+ var $target;
+
+ // log the badge click
+ mw.echo.logInteraction( 'ui-badge-link-click' );
+
+ e.preventDefault();
+
+ $target = $( e.target );
+ // If the user clicked on the overlay or any child, ignore the click
+ if ( $target.hasClass( 'mw-echo-overlay' ) || $target.is( '.mw-echo-overlay *' ) ) {
+ return;
+ }
+
+ if ( $( '.mw-echo-overlay' ).length ) {
+ mw.echo.overlay.removeOverlay();
+ return;
+ }
+
+ mw.echo.overlay.buildOverlay(
+ function ( $overlay ) {
+ $overlay
+ .hide()
+ .appendTo( document.body );
+
+ function positionOverlay() {
+ var offset = $( '#pt-notifications' ).offset();
+ $overlay.css( { left: offset.left - 190, top: offset.top + 50 } );
+ }
+ positionOverlay();
+ $( window ).on( 'resize', positionOverlay );
+ mw.hook( 'ext.echo.overlay.beforeShowingOverlay' ).fire( $overlay );
+
+ // Show the notifications overlay
+ $overlay.show();
+
+ // Make sure the overlay is visible, even if the badge is near the edge of browser window.
+ // 10 is an arbitrarily chosen "close enough" number.
+ // We are careful not to slide out from below the pokey (which is 21px wide) (200-21/2+1 == 189)
+ var
+ offset = $overlay.offset(),
+ width = $overlay.width(),
+ windowWidth = $( window ).width();
+ if ( offset.left < 10 ) {
+ $overlay.css( 'left', '+=' + Math.min( 189, 10 - offset.left ) );
+ } else if ( offset.left + width > windowWidth - 10 ) {
+ $overlay.css( 'left', '-=' + Math.min( 189, ( offset.left + width ) - ( windowWidth - 10 ) ) );
+ }
+ }
+ );
+ } );
+
+ $( 'body' ).click( function ( e ) {
+ if ( ! $( e.target ).is( '.mw-echo-overlay, .mw-echo-overlay *, #pt-notifications a' ) ) {
+ mw.echo.overlay.removeOverlay();
+ }
+ } );
+
+ // Closes the notifications overlay when ESC key pressed
+ $( document ).on( 'keydown', function ( e ) {
+ if ( e.which === 27 ) {
+ mw.echo.overlay.removeOverlay();
+ }
+ } );
+
+ } );
+}( jQuery, mediaWiki ));
diff --git a/Echo/modules/overlay/ext.echo.overlay.js b/Echo/modules/overlay/ext.echo.overlay.js
new file mode 100644
index 00000000..7d5dfca4
--- /dev/null
+++ b/Echo/modules/overlay/ext.echo.overlay.js
@@ -0,0 +1,429 @@
+/*global window:false */
+( function ( $, mw ) {
+ 'use strict';
+
+ // backwards compatibility <= MW 1.21
+ var getUrl = mw.util.getUrl || mw.util.wikiGetlink,
+ useLang = mw.config.get( 'wgUserLanguage' );
+
+ function EchoOverlay( apiResultNotifications ) {
+ this.api = mw.echo.overlay.api;
+ // set internal properties
+ this.tabs = [];
+ this._buildOverlay( apiResultNotifications );
+ }
+
+ function EchoOverlayTab( options, notifications ) {
+ this.api = mw.echo.overlay.api;
+ this.markOnView = options.markOnView;
+ this.markAsReadCallback = options.markAsReadCallback;
+ this.name = options.name;
+ this.unread = [];
+ this._totalUnread = notifications[this.name].rawcount;
+ this._buildList( notifications[this.name] );
+ }
+
+ EchoOverlayTab.prototype = {
+ /* @var integer totalUnread the number of unread notifications in this tab.
+ including those that are not visible. */
+ /**
+ * Return a list of unread and shown ids
+ * @method
+ * @param integer id of a notification to mark as read
+ * @return jQuery.Deferred
+ */
+ getUnreadIds: function() {
+ return this.unread;
+ },
+ /**
+ * Get a count the number of all unread notifications of this type
+ * @method
+ * @param integer id of a notification to mark as read
+ * @return integer
+ */
+ getNumberUnread: function() {
+ return this._totalUnread;
+ },
+ /**
+ * Mark all existing notifications as read
+ * @method
+ * @param integer id of a notification to mark as read
+ * @return jQuery.Deferred
+ */
+ markAsRead: function( id ) {
+ var self = this, data;
+ // only need to mark as read if there is unread item
+ if ( this.unread.length ) {
+ data = {
+ action: 'echomarkread',
+ token: mw.user.tokens.get( 'editToken' ),
+ uselang: useLang
+ };
+ if ( id ) {
+ // If id is given mark that as read otherwise use all unread messages
+ data.list = id;
+ } else {
+ data.sections = this.name;
+ }
+
+ return this.api.post( data ).then( function ( result ) {
+ return result.query.echomarkread;
+ } ).done( function( result ) {
+ // reset internal state of unread messages
+ if ( id ) {
+ if ( self.unread.indexOf( id ) > -1 ) {
+ self.unread.splice( self.unread.indexOf( id ), 1 );
+ }
+ } else {
+ self.unread = [];
+ }
+ // update the count
+ self._totalUnread = result[self.name].rawcount;
+ self.markAsReadCallback( result, id );
+ } );
+ } else {
+ return new $.Deferred();
+ }
+ },
+ /**
+ * Builds an Echo notifications list
+ * @method
+ * @param string tabName the tab
+ * @param object notifications as returned by the api of notification items
+ * @return jQuery element
+ */
+ _buildList: function( notifications ) {
+ var self = this,
+ $container = $( '<div class="mw-echo-notifications">' )
+ .data( 'tab', this )
+ .css( 'max-height', $( window ).height() - 140 ),
+ $ul = $( '<ul>' ).appendTo( $container );
+
+ $.each( notifications.index, function ( index, id ) {
+ var $wrapper,
+ data = notifications.list[id],
+ $li = $( '<li>' )
+ .data( 'details', data )
+ .data( 'id', id )
+ .attr( {
+ 'data-notification-category': data.category,
+ 'data-notification-event': data.id,
+ 'data-notification-type': data.type
+ } )
+ .addClass( 'mw-echo-notification' );
+
+ if ( !data['*'] ) {
+ return;
+ }
+
+ $li.append( data['*'] )
+ .appendTo( $ul );
+
+ if ( !data.read ) {
+ $li.addClass( 'mw-echo-unread' );
+ self.unread.push( id );
+ if ( !self.markOnView ) {
+ $( '<button class="mw-ui-button mw-ui-quiet">&times;</button>' )
+ .on( 'click', function( ev ) {
+ ev.preventDefault();
+ self.markAsRead( $( this ).closest( 'li' ).data( 'notification-event' ) );
+ } ).appendTo( $li );
+ }
+ }
+
+ // Grey links in the notification title and footer (except on hover)
+ $li.find( '.mw-echo-title a, .mw-echo-notification-footer a' )
+ .addClass( 'mw-echo-grey-link' );
+ $li.hover(
+ function() {
+ $( this ).find( '.mw-echo-title a, .mw-echo-notification-footer a' ).removeClass( 'mw-echo-grey-link' );
+ },
+ function() {
+ $( this ).find( '.mw-echo-title a, .mw-echo-notification-footer a' ).addClass( 'mw-echo-grey-link' );
+ }
+ );
+ // If there is a primary link, make the entire notification clickable.
+ // Yes, it is possible to nest <a> tags via DOM manipulation,
+ // and it works like one would expect.
+ if ( $li.find( '.mw-echo-notification-primary-link' ).length ) {
+ $wrapper = $( '<a>' )
+ .addClass( 'mw-echo-notification-wrapper' )
+ .attr( 'href', $li.find( '.mw-echo-notification-primary-link' ).attr( 'href' ) )
+ .click( function() {
+ if ( mw.echo.clickThroughEnabled ) {
+ // Log the clickthrough
+ mw.echo.logInteraction( 'notification-link-click', 'flyout', +data.id, data.type );
+ }
+ } );
+ } else {
+ $wrapper = $('<div>').addClass( 'mw-echo-notification-wrapper' );
+ }
+
+ $li.wrapInner( $wrapper );
+
+ mw.echo.setupNotificationLogging( $li, 'flyout' );
+
+ // Set up each individual notification with a close box and dismiss
+ // interface if it is dismissable.
+ if ( $li.find( '.mw-echo-dismiss' ).length ) {
+ mw.echo.setUpDismissability( $li );
+ }
+ } );
+
+ if ( !this.markOnView && this.unread.length ) {
+ $( '<button class="mw-ui-button mw-ui-quiet">' )
+ .text( mw.msg( 'echo-mark-all-as-read' ) )
+ .on( 'click', function() {
+ var $btn = $( this );
+ self.markAsRead().done( function() {
+ self.$el.find( '.mw-echo-unread' ).removeClass( 'mw-echo-unread' );
+ $btn.remove();
+ } );
+ } )
+ .prependTo( $container );
+ }
+ this.$el = $container;
+ }
+ };
+
+ EchoOverlay.prototype = {
+ /**
+ * @var array a list of EchoOverlayTabs
+ */
+ tabs: [],
+ /**
+ * @var object current count status of notification types
+ */
+ notificationCount: {
+ /* @var integer length of all notifications (both unread and read) that will be visible in the overlay */
+ all: 0,
+ /* @var string a string representation the current number of unread notifications (1, 99, 99+) */
+ unread: '0',
+ /* @var integer the total number of all unread notifications including those not in the overlay */
+ unreadRaw: 0
+ },
+
+ /**
+ * FIXME: This should be pulled out of EchoOverlay and use an EventEmitter.
+ * @param newCount formatted count
+ * @param rawCount unformatted count
+ */
+ updateBadgeCount: function ( newCount, rawCount ) {
+ var $badge = mw.echo.getBadge();
+ $badge.text( newCount );
+
+ if ( rawCount !== '0' && rawCount !== 0 ) {
+ $badge.addClass( 'mw-echo-unread-notifications' );
+ } else {
+ $badge.removeClass( 'mw-echo-unread-notifications' );
+ }
+ this.notificationCount.unread = newCount;
+ this.notificationCount.unreadRaw = rawCount;
+ mw.hook( 'ext.echo.updateNotificationCount' ).fire( rawCount );
+ },
+
+ configuration: mw.config.get( 'wgEchoOverlayConfiguration' ),
+
+ _getFooterElement: function() {
+ var $prefLink = $( '#pt-preferences a' ),
+ links = [
+ { url: getUrl( 'Special:Notifications' ), text: mw.msg( 'echo-overlay-link' ),
+ className: 'mw-echo-icon-all' },
+ { url: $prefLink.attr( 'href' ) + '#mw-prefsection-echo', text: $prefLink.text(),
+ className: 'mw-echo-icon-cog' }
+ ],
+ $overlayFooter = $( '<div class="mw-echo-overlay-footer">' );
+
+ $.each( links, function( i, link ) {
+ $( '<a class="mw-echo-grey-link">' )
+ .attr( 'href', link.url )
+ .addClass( link.className )
+ .text( link.text )
+ .appendTo( $overlayFooter );
+ } );
+ // add link to notifications archive
+ $overlayFooter.find( 'a' ).hover(
+ function() {
+ $( this ).removeClass( 'mw-echo-grey-link' );
+ },
+ function() {
+ $( this ).addClass( 'mw-echo-grey-link' );
+ }
+ );
+ return $overlayFooter;
+ },
+
+ _showTabList: function( tab ) {
+ var $lists = this.$el.find( '.mw-echo-notifications' ).hide();
+
+ this._activeTab = tab;
+ $lists.each( function() {
+ if ( $( this ).data( 'tab' ).name === tab.name ) {
+ $( this ).show();
+ if ( tab.markOnView ) {
+ tab.markAsRead();
+ }
+ }
+ } );
+ },
+
+
+ _updateTitleElement: function() {
+ var $header;
+ $header = this.$el.find( '.mw-echo-overlay-title' );
+ this._getTitleElement().insertBefore( $header );
+ $header.remove();
+ },
+
+ _getTabsElement: function() {
+ var $li,
+ $ul = $( '<ul>' ), self = this;
+
+ $.each( this.tabs, function( i, echoTab ) {
+ var
+ tabName = self.tabs.length > 1 ? echoTab.name : ( echoTab.name + '-text-only' ),
+ // Messages that can be used here:
+ // * echo-notification-alert
+ // * echo-notification-message
+ // * echo-notification-alert-text-only
+ // * echo-notification-message-text-only
+ // @todo: Unread value is inaccurate. If a user has more than mw.echo.overlay.notificationLimit
+ // API change needed
+ label = mw.msg(
+ 'echo-notification-' + tabName,
+ mw.language.convertNumber( echoTab.getNumberUnread() )
+ );
+
+ $li = $( '<li>' )
+ .appendTo( $ul );
+
+ $( '<a class="mw-ui-anchor mw-ui-progressive">' )
+ .on( 'click', function() {
+ var $this = $( this );
+ $ul.find( 'a' ).removeClass( 'mw-ui-quiet' ).addClass( 'mw-ui-active' );
+ $this.addClass( 'mw-ui-quiet' ).removeClass( 'mw-ui-active');
+ self._showTabList( $this.data( 'tab' ) );
+ } )
+ .data( 'tab', echoTab )
+ .addClass( echoTab.name === self._activeTab.name ? 'mw-ui-quiet' : 'mw-ui-active' )
+ .text( label ).appendTo( $li );
+ } );
+ return $ul;
+ },
+
+ getUnreadCount: function() {
+ var count = 0;
+ $.each( this.tabs, function( i, tab ) {
+ count += tab.getNumberUnread();
+ } );
+ return count;
+ },
+
+ _getTitleElement: function() {
+ var $title = $( '<div>' ).addClass( 'mw-echo-overlay-title' )
+ .append( this._getTabsElement() );
+ return $title;
+ },
+
+ _buildOverlay: function ( notifications ) {
+ var tabs,
+ self = this,
+ options = {
+ markAsReadCallback: function( data, id ) {
+ self.updateBadgeCount( data.count, data.rawcount );
+ self._updateTitleElement();
+ if ( id ) {
+ self.$el.find( '[data-notification-event="' + id + '"]').removeClass( 'mw-echo-unread' )
+ .find( 'button' ).remove();
+ }
+ }
+ },
+ $overlay = $( '<div>' ).addClass( 'mw-echo-overlay' );
+
+ this.$el = $overlay;
+
+ if ( notifications.message.index.length ) {
+ tabs = [ { name: 'alert', markOnView: true }, { name: 'message' } ];
+ } else {
+ tabs = [ { name: 'alert', markOnView: true } ];
+ }
+
+ $.each( tabs, function( i, tabOptions ) {
+ var tab = new EchoOverlayTab( $.extend( tabOptions, options ), notifications );
+ self.$el.append( tab.$el );
+ self.tabs.push( tab );
+ self.notificationCount.all += notifications[tabOptions.name].index.length;
+ } );
+
+ if ( tabs.length === 1 ) {
+ // only one tab exists
+ this._activeTab = this.tabs[0];
+ } else if (
+ notifications.message.rawcount > 0 &&
+ notifications.alert.rawcount === 0
+ ) {
+ // if there are new messages and no new alerts show the messages tab
+ this._activeTab = this.tabs[1];
+ } else {
+ // otherwise show the alerts tab
+ this._activeTab = this.tabs[0];
+ }
+
+ $overlay.prepend( this._getTitleElement() );
+ $overlay.append( this._getFooterElement() );
+ // Show the active tab.
+ this._showTabList( this._activeTab );
+ }
+ };
+
+ mw.echo.overlay = {
+ /**
+ * @var integer the maximum number of notifications to show in the overlay
+ */
+ notificationLimit: 25,
+ /**
+ * @var mw.Api
+ */
+ api: new mw.Api( { ajax: { cache: false } } ),
+ /**
+ * Create an Echo overlay
+ * @return jQuery.Deferred with new EchoOverlay passed in callback
+ */
+ getNewOverlay: function() {
+ var apiData = {
+ action: 'query',
+ meta: 'notifications',
+ notsections: 'alert|message',
+ notgroupbysection: 1,
+ notmessageunreadfirst: 1,
+ notformat: 'flyout',
+ notlimit: this.notificationLimit,
+ notprop: 'index|list|count',
+ uselang: useLang
+ };
+
+ return this.api.get( apiData ).then( function ( result ) {
+ return new EchoOverlay( result.query.notifications );
+ } );
+ },
+ /**
+ * Builds an overlay element
+ * @method
+ * @param callback a callback which passes the newly created overlay as a parameter
+ */
+ buildOverlay: function( callback ) {
+ this.getNewOverlay().done( function( overlay ) {
+ callback( overlay.$el );
+ } ).fail( function () {
+ window.location.href = $( '#pt-notifications a' ).attr( 'href' );
+ } );
+ },
+ removeOverlay: function () {
+ $( '.mw-echo-overlay' ).fadeOut( 'fast',
+ function () {
+ $( this ).remove();
+ }
+ );
+ }
+ };
+} )( jQuery, mediaWiki );
diff --git a/Echo/modules/overlay/ext.echo.overlay.less b/Echo/modules/overlay/ext.echo.overlay.less
new file mode 100644
index 00000000..930fdf59
--- /dev/null
+++ b/Echo/modules/overlay/ext.echo.overlay.less
@@ -0,0 +1,208 @@
+@import '../mixins.less';
+@import "mediawiki.mixins";
+@import "mediawiki.ui/variables";
+@import "mediawiki.ui/mixins";
+
+@offset: 200px;
+@chevronHeight: 11px;
+@headerFontSize: 13px;
+
+.mw-echo-overlay {
+ position: absolute;
+ top: 30px + @chevronHeight;
+ border: 1px solid silver;
+ background-color: #fff;
+ width: 450px;
+ min-height: 2em;
+ padding: 0;
+ color: #6D6D6D;
+ z-index: 100;
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.35);
+
+ // IE8
+ &:before,
+ &::before {
+ content: '';
+ background-image: url('PokeyNorth.png');
+ background-repeat: no-repeat;
+ width: 21px;
+ height: @chevronHeight;
+ position: absolute;
+ z-index: 101;
+ top: -@chevronHeight;
+
+ /* @noflip */ body.ltr & {
+ // subtract half the width from the offset and then add the left box shadow
+ /* @noflip */ left: @offset - 10px + 3px;
+ }
+
+ /* @noflip */ body.rtl & {
+ // subtract the box shadow
+ /* @noflip */ left: @offset - 3px;
+ }
+ }
+
+ button {
+ top: 15px;
+ right: 15px;
+ position: absolute;
+ padding: 0;
+ }
+
+ .mw-ui-progressive {
+ cursor: pointer;
+
+ &.mw-ui-quiet {
+ pointer-events: none;
+ color: #6D6D6D;
+ font-weight: bold;
+ }
+ }
+
+ .mw-echo-notifications,
+ ul {
+ overflow: auto;
+ padding: 0;
+ margin: 0;
+ }
+
+ .mw-echo-notifications {
+ button {
+ // Add 1px border to 15px line height so lines up with tabs
+ line-height: 16px;
+ font-size: @headerFontSize;
+ }
+ }
+
+ li.mw-echo-notification {
+ display: block;
+ padding: 0;
+
+ &:hover {
+ .mw-echo-notification-wrapper {
+ background-color: #F9F9F9;
+ }
+ }
+
+ .mw-echo-notification-wrapper {
+ display: block;
+ background-color: #F1F1F1;
+ border-bottom: 1px solid #DDDDDD;
+ padding: 15px 40px 10px 10px;
+ white-space: normal;
+ font-size: 13px;
+ line-height: 16px;
+ /* Suppress standard links styles */
+ color: inherit;
+ text-decoration: inherit;
+ }
+
+ &.mw-echo-unread {
+ .mw-echo-notification-wrapper {
+ background-color: white;
+ }
+
+ &:hover {
+ .mw-echo-notification-wrapper {
+ background-color: #F9F9F9;
+ }
+ }
+
+ button {
+ background: none;
+ border: none;
+ }
+ }
+
+ &:last-child {
+ .mw-echo-notification-wrapper {
+ border-bottom: none;
+ }
+ }
+ }
+}
+
+.mw-echo-title {
+ color: @colorTextLight;
+
+ .mw-echo-title-heading {
+ color: @colorTextLight;
+ font-size: 1.15em;
+
+ &, a {
+ font-weight: bold;
+ }
+ }
+
+ .mw-echo-title-heading,
+ .plainlinks {
+ .truncated-text();
+ max-width: 100%;
+ display: inline-block;
+ vertical-align: top;
+ }
+}
+
+.mw-echo-grey-link {
+ color: @colorTextLight;
+}
+
+.mw-echo-notification-primary-link {
+ display: none;
+}
+
+.mw-echo-overlay-title {
+ font-size: @headerFontSize;
+ line-height: 15px;
+ padding: 15px 15px 15px 28px;
+ border-bottom: 1px solid #DDDDDD;
+
+ li {
+ display: inline;
+ font-size: 1em;
+ margin-left: 0;
+
+ &::after {
+ content: " · ";
+ padding: 0 .25em;
+ }
+
+ &:last-child {
+ &::after {
+ content: '';
+ }
+ }
+ }
+}
+
+.mw-echo-overlay-footer {
+ padding: 0;
+ border-top: 1px solid #DDDDDD;
+ display: table;
+ width: 100%;
+
+ a {
+ border-left: 1px solid #DDDDDD;
+ float: none;
+ display: table-cell;
+ min-height: 14px;
+ font-size: @headerFontSize;
+ white-space: normal;
+ font-weight: bold;
+ padding: 15px 15px 15px 45px;
+
+ &:hover {
+ text-decoration: none;
+ }
+ }
+}
+
+.mw-echo-icon-all {
+ /* @embed */
+ background: url(../icons/NotificationsPage-ltr.png) no-repeat 20px 15px !important;
+}
+
+.mw-echo-icon-cog {
+ /* @embed */
+ background: url(../icons/Settings.png) no-repeat 20px 15px !important;
+}
diff --git a/Echo/modules/overlay/ext.echo.overlay.modern.css b/Echo/modules/overlay/ext.echo.overlay.modern.css
new file mode 100644
index 00000000..005e6d9e
--- /dev/null
+++ b/Echo/modules/overlay/ext.echo.overlay.modern.css
@@ -0,0 +1,37 @@
+body #p-personal {
+ overflow: visible;
+}
+
+#p-personal .mw-echo-overlay {
+ text-transform: none;
+ font-variant: normal;
+ font-weight: normal;
+ left: -20px;
+ top: 31px;
+}
+#p-personal #pt-notifications ul,
+#p-personal #pt-notifications li {
+ text-transform: none;
+ font-weight: normal;
+ height: auto;
+}
+#p-personal #mw-echo-overlay-link {
+ padding: 15px 15px 15px 60px;
+}
+#p-personal #mw-echo-overlay-pref-link {
+ padding: 15px 15px 15px 35px;
+}
+
+#p-personal .mw-echo-overlay a {
+ padding: 0;
+ color: #003366;
+}
+#p-personal .mw-echo-overlay a:visited {
+ padding: 0;
+ color: #5a3696;
+}
+#p-personal .mw-echo-overlay a:hover {
+ padding: 0;
+ color: #003366;
+ text-decoration: inherit;
+}
diff --git a/Echo/modules/overlay/ext.echo.overlay.monobook.css b/Echo/modules/overlay/ext.echo.overlay.monobook.css
new file mode 100644
index 00000000..e3fd2fe6
--- /dev/null
+++ b/Echo/modules/overlay/ext.echo.overlay.monobook.css
@@ -0,0 +1,18 @@
+#p-personal .mw-echo-overlay {
+ text-align: left;
+ text-transform: none;
+ font-weight: normal;
+}
+#p-personal .mw-echo-overlay ul {
+ text-align: left;
+ text-transform: none;
+}
+#p-personal #mw-echo-overlay-link {
+ padding-bottom: 15px;
+}
+#p-personal #mw-echo-overlay-pref-link {
+ padding-bottom: 15px;
+}
+#p-personal .mw-echo-overlay li.mw-echo-notification {
+ color: #6D6D6D;
+}
diff --git a/Echo/modules/special/Feedback.png b/Echo/modules/special/Feedback.png
new file mode 100644
index 00000000..a911d99d
--- /dev/null
+++ b/Echo/modules/special/Feedback.png
Binary files differ
diff --git a/Echo/modules/special/FeedbackHover.png b/Echo/modules/special/FeedbackHover.png
new file mode 100644
index 00000000..c46f04a0
--- /dev/null
+++ b/Echo/modules/special/FeedbackHover.png
Binary files differ
diff --git a/Echo/modules/special/Help.png b/Echo/modules/special/Help.png
new file mode 100644
index 00000000..e3de9a51
--- /dev/null
+++ b/Echo/modules/special/Help.png
Binary files differ
diff --git a/Echo/modules/special/MoreInfo.png b/Echo/modules/special/MoreInfo.png
new file mode 100644
index 00000000..6efb4473
--- /dev/null
+++ b/Echo/modules/special/MoreInfo.png
Binary files differ
diff --git a/Echo/modules/special/MoreInfoHover.png b/Echo/modules/special/MoreInfoHover.png
new file mode 100644
index 00000000..7607a7f0
--- /dev/null
+++ b/Echo/modules/special/MoreInfoHover.png
Binary files differ
diff --git a/Echo/modules/special/Preferences.png b/Echo/modules/special/Preferences.png
new file mode 100644
index 00000000..ff892422
--- /dev/null
+++ b/Echo/modules/special/Preferences.png
Binary files differ
diff --git a/Echo/modules/special/ext.echo.special.js b/Echo/modules/special/ext.echo.special.js
new file mode 100644
index 00000000..5ee0b368
--- /dev/null
+++ b/Echo/modules/special/ext.echo.special.js
@@ -0,0 +1,173 @@
+( function ( $, mw ) {
+ 'use strict';
+ var useLang = mw.config.get( 'wgUserLanguage' );
+
+ mw.echo.special = {
+
+ notcontinue: null,
+ header: '',
+ processing: false,
+
+ /**
+ * Initialize the property in special notification page.
+ */
+ initialize: function () {
+ var skin = mw.config.get('skin');
+
+ // Convert more link into a button
+ $( '#mw-echo-more' )
+ .addClass( 'mw-ui-button mw-ui-primary' )
+ .css( 'margin', '0.5em 0 0 0' )
+ .click( function ( e ) {
+ e.preventDefault();
+ if ( !mw.echo.special.processing ) {
+ mw.echo.special.processing = true;
+ mw.echo.special.loadMore();
+ }
+ }
+ );
+ mw.echo.special.notcontinue = mw.config.get( 'wgEchoNextContinue' );
+ mw.echo.special.header = mw.config.get( 'wgEchoDateHeader' );
+
+ // Set up each individual notification with eventlogging, a close
+ // box and dismiss interface if it is dismissable.
+ $( '.mw-echo-notification' ).each( function () {
+ mw.echo.setupNotificationLogging( $( this ), 'archive' );
+ if ( $( this ).find( '.mw-echo-dismiss' ).length ) {
+ mw.echo.setUpDismissability( this );
+ }
+ } );
+
+ $( '#mw-echo-moreinfo-link' ).click( function () {
+ mw.echo.logInteraction( 'ui-help-click', 'archive' );
+ } );
+ $( '#mw-echo-pref-link' ).click( function () {
+ mw.echo.logInteraction( 'ui-prefs-click', 'archive' );
+ } );
+
+ // Convert subtitle links into header icons for Vector and Monobook skins
+ if ( skin === 'vector' || skin === 'monobook' ) {
+ $( '#mw-echo-moreinfo-link, #mw-echo-pref-link' )
+ .empty()
+ .appendTo( '#firstHeading' );
+ $( '#contentSub' ).empty();
+ }
+
+ },
+
+ /**
+ * Load more notification records.
+ */
+ loadMore: function () {
+ var api = new mw.Api( { ajax: { cache: false } } ),
+ notifications, data, container, $li, that = this, unread = [], apiData;
+
+ apiData = {
+ action : 'query',
+ meta : 'notifications',
+ notformat : 'html',
+ notprop : 'index|list',
+ notcontinue: this.notcontinue,
+ notlimit: mw.config.get( 'wgEchoDisplayNum' ),
+ uselang: useLang
+ };
+
+ api.get( apiData ).done( function ( result ) {
+ container = $( '#mw-echo-special-container' );
+ notifications = result.query.notifications;
+ unread = [];
+
+ $.each( notifications.index, function ( index, id ) {
+ data = notifications.list[id];
+
+ if ( that.header !== data.timestamp.date ) {
+ that.header = data.timestamp.date;
+ $( '<li></li>' ).addClass( 'mw-echo-date-section' ).append( that.header ).appendTo( container );
+ }
+
+ $li = $( '<li></li>' )
+ .data( 'details', data )
+ .data( 'id', id )
+ .addClass( 'mw-echo-notification' )
+ .attr( {
+ 'data-notification-category': data.category,
+ 'data-notification-event': data.id,
+ 'data-notification-type': data.type
+ } )
+ .append( data['*'] )
+ .appendTo( container );
+
+ if ( !data.read ) {
+ $li.addClass( 'mw-echo-unread' );
+ unread.push( id );
+ }
+
+ mw.echo.setupNotificationLogging( $li, 'archive' );
+
+ if ( $li.find( '.mw-echo-dismiss' ).length ) {
+ mw.echo.setUpDismissability( $li );
+ }
+ } );
+
+ that.notcontinue = notifications['continue'];
+ if ( unread.length > 0 ) {
+ that.markAsRead( unread );
+ } else {
+ that.onSuccess();
+ }
+ } ).fail( function () {
+ that.onError();
+ } );
+ },
+
+ /**
+ * Mark notifications as read.
+ */
+ markAsRead: function ( unread ) {
+ var newCount, rawCount, $badge,
+ api = new mw.Api(), that = this;
+
+ api.post( {
+ action : 'echomarkread',
+ list : unread.join( '|' ),
+ token: mw.user.tokens.get( 'editToken' ),
+ uselang: useLang
+ } ).done( function ( result ) {
+ // update the badge if the link is enabled
+ if ( result.query.echomarkread.count !== undefined &&
+ $( '#pt-notifications').length
+ ) {
+ newCount = result.query.echomarkread.count;
+ rawCount = result.query.echomarkread.rawcount;
+ $badge = mw.echo.getBadge();
+ $badge.text( newCount );
+
+ if ( rawCount !== '0' && rawCount !== 0 ) {
+ $badge.addClass( 'mw-echo-unread-notifications' );
+ } else {
+ $badge.removeClass( 'mw-echo-unread-notifications' );
+ }
+ }
+ that.onSuccess();
+ } ).fail( function () {
+ that.onError();
+ } );
+ },
+
+ onSuccess: function () {
+ if ( !this.notcontinue ) {
+ $( '#mw-echo-more' ).hide();
+ }
+ this.processing = false;
+ },
+
+ onError: function () {
+ // Todo: Show detail error message based on error code
+ $( '#mw-echo-more' ).text( mw.msg( 'echo-load-more-error' ) );
+ this.processing = false;
+ }
+ };
+
+ $( document ).ready( mw.echo.special.initialize );
+
+} )( jQuery, mediaWiki );
diff --git a/Echo/modules/special/ext.echo.special.less b/Echo/modules/special/ext.echo.special.less
new file mode 100644
index 00000000..57cb9c20
--- /dev/null
+++ b/Echo/modules/special/ext.echo.special.less
@@ -0,0 +1,94 @@
+/* Echo specific CSS */
+
+#mw-echo-more {
+ display: block;
+ text-align: center;
+ font-size: 13px;
+ max-width: 600px;
+}
+
+/* Custom header styling for Vector and Monobook skins */
+.skin-vector #firstHeading,
+.skin-monobook #firstHeading {
+ max-width: 600px;
+}
+
+/* Special styles to use if we're converting subtitle links into header icons */
+#firstHeading {
+ .mw-echo-special-header-link {
+ display: block;
+ height: 19px;
+ width: 19px;
+ }
+
+ #mw-echo-pref-link {
+ float: right;
+ margin: 5px 3px;
+ /* @embed */
+ background-image: url(Preferences.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+
+ &:hover {
+ filter: alpha(opacity=100);
+ opacity: 1.0;
+ }
+ }
+
+ #mw-echo-moreinfo-link {
+ display: inline-block;
+ margin: 0 3px;
+ /* @embed */
+ background-image: url(Help.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+
+ &:hover {
+ filter: alpha(opacity=100);
+ opacity: 1.0;
+ }
+ }
+}
+
+.mw-echo-date-section {
+ font-weight: 800;
+ font-size: 1.1em;
+ text-transform: uppercase;
+ border-bottom: 1px solid #C9C9C9;
+ margin: 30px 0 5px 50px;
+ color: #686868;
+ max-width: 550px;
+}
+
+ul#mw-echo-special-container {
+ list-style: none none;
+ padding: 0;
+ margin: 30px 0 0 0;
+ max-width: 600px;
+}
+
+.mw-echo-notification {
+ padding: 15px 35px 10px 0;
+}
+
+#mw-echo-special-container {
+ .mw-echo-notification {
+ background-color: transparent;
+
+ &:hover {
+ /* Fallback for IE<=8 */
+ background-color: #F6F6F6;
+ background-color: rgba(0, 0, 0, 0.035);
+ }
+
+ &.mw-echo-unread {
+ .mw-echo-title {
+ font-weight: bold;
+ }
+ }
+ }
+}
diff --git a/Echo/package.json b/Echo/package.json
new file mode 100644
index 00000000..99e284df
--- /dev/null
+++ b/Echo/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "Echo-dependencies",
+ "description": "Node.js dependencies used in Echo development",
+ "version": "0.0.1",
+ "dependencies": {
+ "jshint": ">=1.1.0"
+ }
+}
diff --git a/Echo/scripts/gen-autoload.php b/Echo/scripts/gen-autoload.php
new file mode 100644
index 00000000..082e70a8
--- /dev/null
+++ b/Echo/scripts/gen-autoload.php
@@ -0,0 +1,30 @@
+<?php
+
+require_once __DIR__ . '/../../../includes/utils/AutoloadGenerator.php';
+
+function main() {
+ $base = dirname( __DIR__ );
+ $generator = new AutoloadGenerator( $base );
+ $dirs = array(
+ 'api',
+ 'controller',
+ 'formatters',
+ 'includes',
+ 'jobs',
+ 'model',
+ 'special',
+ 'tests',
+ );
+ foreach ( $dirs as $dir ) {
+ $generator->readDir( $base . '/' . $dir );
+ }
+ foreach ( glob( $base . '/*.php' ) as $file ) {
+ $generator->readFile( $file );
+ }
+
+ $generator->generateAutoload( basename( __DIR__ ) . '/' . basename( __FILE__ ) );
+
+ echo "Done.\n\n";
+}
+
+main();
diff --git a/Echo/scripts/generatecss.php b/Echo/scripts/generatecss.php
new file mode 100755
index 00000000..ed67a4fa
--- /dev/null
+++ b/Echo/scripts/generatecss.php
@@ -0,0 +1,29 @@
+<?php
+if ( sizeof( $argv ) < 3 ) {
+ print "Call with 2 arguments: the path to the load url and the file to output to";
+ exit();
+}
+$loadUrl = $argv[1];
+$outputFile = $argv[2];
+
+define( 'MEDIAWIKI', true );
+const NS_MAIN = 0;
+$wgVersion = 1.23;
+$wgSpecialPages = array();
+$wgResourceModules = array();
+
+include "Resources.php";
+
+$query = array();
+$blacklist = array(
+);
+foreach( $wgResourceModules as $moduleName => $def ) {
+ if ( !in_array( $moduleName, $blacklist ) ) {
+ $query[] = $moduleName;
+ }
+}
+
+$url = $loadUrl . '?only=styles&skin=vector&modules=' . implode( $query, '|' );
+echo $url;
+$css = file_get_contents($url);
+file_put_contents( $outputFile, $css );
diff --git a/Echo/scripts/qunit.sh b/Echo/scripts/qunit.sh
new file mode 100755
index 00000000..4af3391c
--- /dev/null
+++ b/Echo/scripts/qunit.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+echo "Running QUnit tests..."
+if command -v phantomjs > /dev/null ; then
+ URL=${MEDIAWIKI_URL:-"http://127.0.0.1:80/w/index.php/"}
+ echo "Using $URL as a development environment host."
+ echo "Please ensure \$wgEnableJavaScriptTest = true; in your LocalSettings.php"
+ echo "To specify a different host set MEDIAWIKI_URL environment variable"
+ echo '(e.g. by running "export MEDIAWIKI_URL=http://127.0.0.1:80/w/index.php/")'
+ phantomjs tests/externals/phantomjs-qunit-runner.js "${URL}Special:JavaScriptTest/qunit?filter=ext.echo"
+else
+ echo "You need to install PhantomJS to run QUnit tests in terminal!"
+ echo "See http://phantomjs.org/"
+ exit 1
+fi
diff --git a/Echo/scripts/remotecheck.sh b/Echo/scripts/remotecheck.sh
new file mode 100755
index 00000000..51278d2f
--- /dev/null
+++ b/Echo/scripts/remotecheck.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+if [ ! -e "scripts/remotes/gerrit.py" ]
+then
+ mkdir -p scripts/remotes
+ echo 'Installing GerritCommandLine tool'
+ curl -o scripts/remotes/gerrit.py https://raw.githubusercontent.com/jdlrobson/GerritCommandLine/master/gerrit.py
+ chmod +x scripts/remotes/gerrit.py
+fi
+if [ ! -e "scripts/remotes/message.py" ]
+then
+ mkdir -p scripts/remotes
+ echo 'Installing Message tool'
+ curl -o scripts/remotes/message.py https://raw.githubusercontent.com/jdlrobson/WikimediaMessageDevScript/master/message.py
+ chmod +x scripts/remotes/message.py
+fi
diff --git a/Echo/special/SpecialNotifications.php b/Echo/special/SpecialNotifications.php
new file mode 100644
index 00000000..1044df60
--- /dev/null
+++ b/Echo/special/SpecialNotifications.php
@@ -0,0 +1,169 @@
+<?php
+
+class SpecialNotifications extends SpecialPage {
+
+ /**
+ * Number of notification records to display per page/load
+ */
+ const DISPLAY_NUM = 20;
+
+ public function __construct() {
+ parent::__construct( 'Notifications' );
+ }
+
+ public function execute( $par ) {
+
+ $this->setHeaders();
+
+ $out = $this->getOutput();
+ $out->setPageTitle( $this->msg( 'echo-specialpage' )->text() );
+
+ $user = $this->getUser();
+ if ( $user->isAnon() ) {
+ // return to this title upon login
+ $returnTo = array( 'returnto' => $this->getPageTitle()->getPrefixedDBkey() );
+ // the html message for anon users
+ $anonMsgHtml = $this->msg(
+ 'echo-anon',
+ SpecialPage::getTitleFor( 'UserLogin', 'signup' )->getFullURL( $returnTo ),
+ SpecialPage::getTitleFor( 'UserLogin' )->getFullURL( $returnTo )
+ )->parse();
+ $out->addHTML( Html::rawElement( 'span', array( 'class' => 'plainlinks' ), $anonMsgHtml ) );
+ return;
+ }
+
+ $out->addSubtitle( $this->buildSubtitle() );
+
+ // The continue parameter to pull current set of data from, this
+ // would be used for browsers with javascript disabled
+ $continue = $this->getRequest()->getVal( 'continue', null );
+
+ // Pull the notifications
+ $notif = array();
+ $notificationMapper = new EchoNotificationMapper();
+
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $notifications = $notificationMapper->fetchByUser(
+ $user,
+ /* $limit = */self::DISPLAY_NUM + 1,
+ $continue,
+ $attributeManager->getUserEnabledEvents( $user, 'web' )
+ );
+ foreach ( $notifications as $notification ) {
+ $notif[] = EchoDataOutputFormatter::formatOutput( $notification, 'html', $user );
+ }
+
+ // If there are no notifications, display a message saying so
+ if ( !$notif ) {
+ $out->addWikiMsg( 'echo-none' );
+ return;
+ }
+
+ // Check if there is more data to load for next request
+ if ( count( $notif ) > self::DISPLAY_NUM ) {
+ $lastItem = array_pop( $notif );
+ $nextContinue = $lastItem['timestamp']['utcunix'] . '|' . $lastItem['id'];
+ } else {
+ $nextContinue = null;
+ }
+
+ // Add the notifications to the page (interspersed with date headers)
+ $dateHeader = '';
+ $notices = '';
+ $unread = array();
+ foreach ( $notif as $row ) {
+ $class = 'mw-echo-notification';
+ if ( !isset( $row['read'] ) ) {
+ $class .= ' mw-echo-unread';
+ if ( !$row['targetpage'] ) {
+ $unread[] = $row['id'];
+ }
+ }
+
+ if ( !$row['*'] ) {
+ continue;
+ }
+ // Output the date header if it has not been displayed
+ if ( $dateHeader !== $row['timestamp']['date'] ) {
+ $dateHeader = $row['timestamp']['date'];
+ $notices .= Html::rawElement( 'li', array( 'class' => 'mw-echo-date-section' ), $dateHeader );
+ }
+
+ $notices .= Html::rawElement(
+ 'li',
+ array(
+ 'class' => $class,
+ 'data-notification-category' => $row['category'],
+ 'data-notification-event' => $row['id'],
+ 'data-notification-type' => $row['type']
+ ),
+ $row['*']
+ );
+ }
+ $html = Html::rawElement( 'ul', array( 'id' => 'mw-echo-special-container' ), $notices );
+
+ // Build the more link
+ if ( $nextContinue ) {
+ $html .= Html::element(
+ 'a',
+ array(
+ 'href' => SpecialPage::getTitleFor( 'Notifications' )->getLinkURL(
+ array( 'continue' => $nextContinue )
+ ),
+ 'id' => 'mw-echo-more'
+ ),
+ $this->msg( 'moredotdotdot' )->text()
+ );
+ }
+
+ $out->addHTML( $html );
+ $out->addModules( 'ext.echo.special' );
+ $out->addJsConfigVars(
+ array(
+ 'wgEchoDisplayNum' => self::DISPLAY_NUM,
+ 'wgEchoNextContinue' => $nextContinue,
+ 'wgEchoDateHeader' => $dateHeader
+ )
+ );
+ // For no-js support
+ $out->addModuleStyles( "ext.echo.base" );
+ // Mark items as read
+ if ( $unread ) {
+ MWEchoNotifUser::newFromUser( $user )->markRead( $unread );
+ }
+ }
+
+ /**
+ * Build the subtitle (more info and preference links)
+ * @return string HTML for the subtitle
+ */
+ public function buildSubtitle() {
+ global $wgEchoHelpPage;
+ $lang = $this->getLanguage();
+ $subtitleLinks = array();
+ // More info link
+ $subtitleLinks[] = Html::rawElement(
+ 'a',
+ array(
+ 'href' => $wgEchoHelpPage,
+ 'id' => 'mw-echo-moreinfo-link',
+ 'class' => 'mw-echo-special-header-link',
+ 'title' => $this->msg( 'echo-more-info' )->text(),
+ 'target' => '_blank'
+ ),
+ $this->msg( 'echo-more-info' )->text()
+ );
+ // Preferences link
+ $subtitleLinks[] = Html::rawElement(
+ 'a',
+ array(
+ 'href' => SpecialPage::getTitleFor( 'Preferences' )->getLinkURL() . '#mw-prefsection-echo',
+ 'id' => 'mw-echo-pref-link',
+ 'class' => 'mw-echo-special-header-link',
+ 'title' => $this->msg( 'preferences' )->text()
+ ),
+ $this->msg( 'preferences' )->text()
+ );
+ return $lang->pipeList( $subtitleLinks );
+ }
+}
diff --git a/Echo/tests/bootstrap.php b/Echo/tests/bootstrap.php
new file mode 100644
index 00000000..cddd5d5a
--- /dev/null
+++ b/Echo/tests/bootstrap.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Find the correct path to /tests/phpunit/bootstrap.php in core
+ *
+ * Takes MW_INSTALL_PATH environment variable into account. This is used by the
+ * test suite defined in mfe.suite.xml for MobileFrontend phpunit testing.
+ */
+
+$IP = getenv( 'MW_INSTALL_PATH' );
+if ( $IP === false ) {
+ if ( realpath( '../..' ) ) {
+ $IP = realpath( '../..' );
+ } else {
+ $IP = dirname( dirname( dirname( __DIR__ ) ) );
+ }
+}
+
+require_once( $IP . "/tests/phpunit/bootstrap.php" );
+
diff --git a/Echo/tests/browser/features/flyout.feature b/Echo/tests/browser/features/flyout.feature
new file mode 100644
index 00000000..43072350
--- /dev/null
+++ b/Echo/tests/browser/features/flyout.feature
@@ -0,0 +1,17 @@
+@chrome @en.wikipedia.beta.wmflabs.org @firefox @login @test2.wikipedia.org
+Feature: Flyout
+
+ Background:
+ Given I am on the "Selenium Echo flyout test page" page
+
+ Scenario: Flyout button not present when anon
+ Then I do not see the notification flyout button
+
+ Scenario: Flyout button present
+ Given I am logged in
+ Then I see the notification flyout button
+
+ Scenario: Flyout button present
+ Given I am logged in
+ When I click the notification flyout button
+ Then I see the notification flyout
diff --git a/Echo/tests/browser/features/flyout_nojs.feature b/Echo/tests/browser/features/flyout_nojs.feature
new file mode 100644
index 00000000..5fc2894d
--- /dev/null
+++ b/Echo/tests/browser/features/flyout_nojs.feature
@@ -0,0 +1,12 @@
+@custom-browser @en.wikipedia.beta.wmflabs.org @firefox @login @test2.wikipedia.org
+Feature: Flyout (nojs)
+
+ Background:
+ Given I am using user agent "Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)"
+ And I am on the "Selenium Echo flyout test page" page
+
+ Scenario: Flyout button present
+ Given I am logged in
+ When I click the notification flyout button
+ Then I am on the Special Notifications page
+ And I see the first heading on the page says Notifications
diff --git a/Echo/tests/browser/features/messages.feature b/Echo/tests/browser/features/messages.feature
new file mode 100644
index 00000000..441596a9
--- /dev/null
+++ b/Echo/tests/browser/features/messages.feature
@@ -0,0 +1,15 @@
+@chrome @en.wikipedia.beta.wmflabs.org @firefox @login @test2.wikipedia.org
+Feature: Scenarios that trigger notifications
+
+ Scenario: Mark all as unread
+ Given I am logged in with no notifications
+ And I have a Flow message that triggers an alert notification
+ And another user mentions me on the wiki
+ And I am on the "Selenium Echo flyout test page" page
+ And I have new notifications
+ And I click the notification flyout button
+ And I see the notification flyout
+ And I click for the Messages view
+ When I click the mark all as read button
+ And I am on the "Selenium Echo flyout test page" page
+ Then I have no new notifications
diff --git a/Echo/tests/browser/features/notifications.feature b/Echo/tests/browser/features/notifications.feature
new file mode 100644
index 00000000..58feec9e
--- /dev/null
+++ b/Echo/tests/browser/features/notifications.feature
@@ -0,0 +1,40 @@
+@chrome @en.wikipedia.beta.wmflabs.org @firefox @login @test2.wikipedia.org
+Feature: Notification types
+
+ # Scenarios which trigger notifications
+ Scenario: Someone links to a page I created
+ Given I am logged in with no notifications
+ And another user has linked to a page I created from another page
+ And I reload the page 5 times or until a notification shows up
+ When I am on the "Selenium Echo flyout test page" page
+ Then I have new notifications
+
+ Scenario: Mention message triggers notification
+ Given I am logged in with no notifications
+ And another user mentions me on the wiki
+ And I reload the page 5 times or until a notification shows up
+ When I am on the "Selenium Echo flyout test page" page
+ Then I have new notifications
+
+ Scenario: Talk page message triggers talk notification
+ Given I am logged in with no notifications
+ # And I do not have Flow boards enabled on the user talk namespace
+ And another user writes on my talk page
+ And I reload the page 5 times or until a notification shows up
+ When I am on the "Selenium Echo flyout test page" page
+ Then I have new notifications
+
+ Scenario: New user gets a sign up notification
+ Given I am logged in as a new user
+ And I am on the "Selenium Echo flyout test page" page
+ Then I have new notifications
+
+ Scenario: Page revert
+ # Too hard. Will do later.
+
+ # Scenarios which do not trigger notifications (but might be expected to)
+ Scenario: The @ message is not a keyword
+ Given I am logged in with no notifications
+ And another user @s me on "Talk:Echo at test"
+ When I am on the "Selenium Echo flyout test page" page
+ Then I have no new notifications
diff --git a/Echo/tests/browser/features/notifications_userrights.feature b/Echo/tests/browser/features/notifications_userrights.feature
new file mode 100644
index 00000000..0e947e70
--- /dev/null
+++ b/Echo/tests/browser/features/notifications_userrights.feature
@@ -0,0 +1,10 @@
+@chrome @firefox @login
+Feature: User rights
+
+ Scenario: Change in user rights
+ Given I am logged in as a new user with no notifications
+ # This step requires user rights. Selenium user doesn't have sufficient user rights on beta labs.
+ When my user rights get changed
+ And I come back from grabbing a cup of coffee
+ And I am on the "Selenium Echo flyout test page" page
+ Then I have new notifications
diff --git a/Echo/tests/browser/features/step_definitions/common_steps.rb b/Echo/tests/browser/features/step_definitions/common_steps.rb
new file mode 100644
index 00000000..ca57e136
--- /dev/null
+++ b/Echo/tests/browser/features/step_definitions/common_steps.rb
@@ -0,0 +1,61 @@
+def new_username
+ "EchoUserNew#{@random_string}"
+end
+
+def session_username
+ "#{ENV['MEDIAWIKI_USER']}_#{@browser.name}"
+end
+
+def session_username_b
+ 'EchoUser'
+end
+
+Given(/^I am logged in as the user "(.*?)"$/) do |username|
+ step 'the user "' + username + '" exists'
+ visit(LoginPage).login_with(username, ENV['MEDIAWIKI_PASSWORD'])
+end
+
+# Note Echo redefines this so that the user is unique to the current browser
+Given(/^I am logged in my non-shared account$/) do
+ username = session_username
+ step 'I am logged in as the user "' + username + '"'
+end
+
+Given(/^I am on the "(.+)" page$/) do |title|
+ on(APIPage).create title, 'Test is used by Selenium web driver'
+ visit(ArticlePage, using_params: { article_name: title })
+end
+
+Given(/^I am using user agent "(.+)"$/) do |user_agent|
+ @user_agent = user_agent
+ @browser = browser(test_name(@scenario), user_agent: user_agent)
+ $session_id = @browser.driver.instance_variable_get(:@bridge).session_id
+end
+
+Given(/^my user rights get changed$/) do
+ @username = new_username
+ client = on(APIPage).client
+ client.log_in(ENV['MEDIAWIKI_USER'], ENV['MEDIAWIKI_PASSWORD'])
+ resp = client.query(action: 'query', list: 'users', ususers: @username, ustoken: 'userrights')
+ data = resp.data
+ @token = data['users'][0]['userrightstoken']
+ client.action('userrights', token_type: false, token: @token, add: 'bot', user: @username)
+end
+
+Given(/^the user "(.*?)" exists$/) do |username|
+ on(APIPage).client.log_in(ENV['MEDIAWIKI_USER'], ENV['MEDIAWIKI_PASSWORD'])
+ begin
+ on(APIPage).client.create_account(username, ENV['MEDIAWIKI_PASSWORD'])
+ puts 'Successfully created user ' + username
+ rescue MediawikiApi::ApiError
+ puts 'Assuming in step that user ' + username + ' already exists since was unable to create.'
+ end
+end
+
+Then(/^I am on the Special Notifications page$/) do
+ expect(@browser.url).to match 'Special:Notifications'
+end
+
+Then(/^I see the first heading on the page says Notifications$/) do
+ expect(on(ArticlePage).first_heading).to eq 'Notifications'
+end
diff --git a/Echo/tests/browser/features/step_definitions/flyout_steps.rb b/Echo/tests/browser/features/step_definitions/flyout_steps.rb
new file mode 100644
index 00000000..7474f6b2
--- /dev/null
+++ b/Echo/tests/browser/features/step_definitions/flyout_steps.rb
@@ -0,0 +1,18 @@
+When(/^I click the notification flyout button$/) do
+ # Sleep works around Chrome 40 issue that began
+ # ~2015-03-04
+ sleep 1
+ on(ArticlePage).flyout_link_element.when_present.click
+end
+
+Then(/^I do not see the notification flyout button$/) do
+ expect(on(ArticlePage).flyout_link_container_element).not_to be_visible
+end
+
+Then(/^I see the notification flyout$/) do
+ expect(on(ArticlePage).flyout_element.when_present).to be_visible
+end
+
+Then(/^I see the notification flyout button$/) do
+ expect(on(ArticlePage).flyout_link_container_element.when_present).to be_visible
+end
diff --git a/Echo/tests/browser/features/step_definitions/messages_steps.rb b/Echo/tests/browser/features/step_definitions/messages_steps.rb
new file mode 100644
index 00000000..d8d61034
--- /dev/null
+++ b/Echo/tests/browser/features/step_definitions/messages_steps.rb
@@ -0,0 +1,17 @@
+Given(/^I click for the Messages view$/) do
+ on(ArticlePage).messages_view_link_element.when_present.click
+end
+
+Given(/^I have a Flow message that triggers an alert notification$/) do
+ client = on(APIPage).client
+ username = session_username_b
+ step 'the user "' + username + '" exists'
+ client.log_in(username, ENV['MEDIAWIKI_PASSWORD'])
+ client.action(
+ 'flow', token_type: 'edit', submodule: 'new-topic', page: 'Talk:Flow QA', nttopic: 'Mention #1',
+ ntcontent: '[[User:' + session_username + ']] I wanted to say hello.')
+end
+
+When(/^I click the mark all as read button$/) do
+ on(ArticlePage).mark_as_read_element.when_present.click
+end
diff --git a/Echo/tests/browser/features/step_definitions/notifications_steps.rb b/Echo/tests/browser/features/step_definitions/notifications_steps.rb
new file mode 100644
index 00000000..37843a83
--- /dev/null
+++ b/Echo/tests/browser/features/step_definitions/notifications_steps.rb
@@ -0,0 +1,91 @@
+def make_page_with_user(title, text, username)
+ client = on(APIPage).client
+ client.log_in(username, ENV['MEDIAWIKI_PASSWORD'])
+ client.create_page(title, text)
+end
+
+def clear_notifications(username)
+ client = on(APIPage).client
+ step 'the user "' + username + '" exists'
+ client.log_in(username, ENV['MEDIAWIKI_PASSWORD'])
+ client.action('echomarkread', token_type: 'edit', all: '1')
+end
+
+def make_page_with_user_b(title, text)
+ username = session_username_b
+ step 'the user "' + username + '" exists'
+ make_page_with_user(title, text, username)
+end
+
+def make_page_with_user_a(title, text)
+ make_page_with_user(title, text, session_username)
+end
+
+def poll_for_new_notifications(number_of_polls)
+ number_of_polls.to_i.times do
+ step 'I am on the "Selenium Echo flyout test page" page'
+ break if on(ArticlePage).flyout_link_element.class_name =~ /mw-echo-unread-notifications/
+ end
+end
+
+Given(/^another user has linked to a page I created from another page$/) do
+ title = 'Selenium Echo link test ' + @random_string
+ make_page_with_user_a(title, 'Selenium test page. Feel free to delete me.')
+ title2 = title + ' ' + @random_string
+ make_page_with_user_b(title2, 'I am linking to [[' + title + ']].')
+end
+
+Given(/^another user writes on my talk page$/) do
+ make_page_with_user_b(
+ 'User talk:' + session_username,
+ "== Barnstar ==\nHello Selenium, here is a barnstar for all your testing! " +
+ @random_string + "~~~~\n")
+end
+
+Given(/^another user @s me on "(.*?)"$/) do |title|
+ username = session_username.sub('_', ' ')
+ text = '@' + username + ' Cho cho cho. ~~~~'
+ make_page_with_user_b(title, text)
+end
+
+Given(/^I reload the page (.*?) times or until a notification shows up$/) do |number_of_polls|
+ poll_for_new_notifications(number_of_polls)
+end
+
+Given(/^another user mentions me on the wiki$/) do
+ title = 'Selenium Echo mention test ' + @random_string
+ username = session_username.sub('_', ' ')
+ text = "== The walrus ==\n[[User:" + username + "]]: Cho cho cho. ~~~~\n"
+ make_page_with_user_b(title, text)
+end
+
+Given(/^I am logged in as a new user$/) do
+ @username = new_username
+ step 'I am logged in as the user "' + @username + '"'
+end
+
+Given(/^I am logged in as a new user with no notifications$/) do
+ @username = new_username
+ clear_notifications(@username)
+ step 'I am logged in as the user "' + @username + '"'
+end
+
+Given(/^I am logged in with no notifications$/) do
+ # Mark all messages as read
+ client = on(APIPage).client
+ username = session_username
+ step 'the user "' + username + '" exists'
+ client.log_in(username, ENV['MEDIAWIKI_PASSWORD'])
+ client.action('echomarkread', token_type: 'edit', all: '1')
+
+ step 'I am logged in my non-shared account'
+ step 'I have no new notifications'
+end
+
+Then(/^I have no new notifications$/) do
+ expect(on(ArticlePage).flyout_link_element.when_present.class_name).not_to match 'mw-echo-unread-notifications'
+end
+
+Then(/^I have new notifications$/) do
+ expect(on(ArticlePage).flyout_link_element.when_present.class_name).to match 'mw-echo-unread-notifications'
+end
diff --git a/Echo/tests/browser/features/support/env.rb b/Echo/tests/browser/features/support/env.rb
new file mode 100644
index 00000000..cdbe1a44
--- /dev/null
+++ b/Echo/tests/browser/features/support/env.rb
@@ -0,0 +1,12 @@
+require 'rubygems'
+require 'bundler/setup'
+
+Bundler.require
+
+if ENV['PAGE_WAIT_TIMEOUT']
+ PageObject.default_page_wait = ENV['PAGE_WAIT_TIMEOUT'].to_i
+end
+
+if ENV['ELEMENT_WAIT_TIMEOUT']
+ PageObject.default_element_wait = ENV['ELEMENT_WAIT_TIMEOUT'].to_i
+end
diff --git a/Echo/tests/browser/features/support/hooks.rb b/Echo/tests/browser/features/support/hooks.rb
new file mode 100644
index 00000000..7da02d58
--- /dev/null
+++ b/Echo/tests/browser/features/support/hooks.rb
@@ -0,0 +1,3 @@
+# Allow running of bundle exec cucumber --dry-run -f stepdefs
+require 'mediawiki_selenium'
+require 'page-object'
diff --git a/Echo/tests/browser/features/support/pages/article_page.rb b/Echo/tests/browser/features/support/pages/article_page.rb
new file mode 100644
index 00000000..d35f7330
--- /dev/null
+++ b/Echo/tests/browser/features/support/pages/article_page.rb
@@ -0,0 +1,16 @@
+# Page Object describing Headings, Flyouts, and Overlay in Echo
+class ArticlePage
+ include PageObject
+ include URL
+ page_url URL.url('<%=params[:article_name]%><%=params[:hash]%>')
+
+ h1(:first_heading, id: 'firstHeading')
+ li(:flyout_link_container, css: '#pt-notifications')
+ a(:flyout_link, css: '#pt-notifications a')
+ div(:flyout, css: '.mw-echo-overlay')
+
+ # Overlay header
+ a(:alert_tab_link, css: '.mw-echo-overlay-title ul li a', index: 1)
+ button(:mark_as_read, css: '.mw-echo-notifications > button')
+ a(:messages_view_link, css: '.mw-ui-active')
+end
diff --git a/Echo/tests/echo.suite.xml b/Echo/tests/echo.suite.xml
new file mode 100644
index 00000000..290d0720
--- /dev/null
+++ b/Echo/tests/echo.suite.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- colors don't work on Windows! -->
+<phpunit bootstrap="bootstrap.php"
+ colors="true"
+ backupGlobals="false"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ stopOnFailure="false"
+ timeoutForSmallTests="2"
+ timeoutForMediumTests="10"
+ timeoutForLargeTests="60"
+ strict="true"
+ verbose="true">
+ <testsuites>
+ <testsuite name="extensions">
+ <!-- assumes extension is installed to mediawiki/extensions/Echo -->
+ <file>../../../tests/phpunit/suites/ExtensionsTestSuite.php</file>
+ </testsuite>
+ </testsuites>
+ <groups>
+ <exclude>
+ <group>Utility</group>
+ <group>Broken</group>
+ <group>ParserFuzz</group>
+ <group>Stub</group>
+ </exclude>
+ </groups>
+</phpunit>
diff --git a/Echo/tests/externals/phantomjs-qunit-runner.js b/Echo/tests/externals/phantomjs-qunit-runner.js
new file mode 100644
index 00000000..4b1d38b1
--- /dev/null
+++ b/Echo/tests/externals/phantomjs-qunit-runner.js
@@ -0,0 +1,127 @@
+/*
+ * QtWebKit-powered headless test runner using PhantomJS
+ *
+ * PhantomJS binaries: http://phantomjs.org/download.html
+ * Requires PhantomJS 1.6+ (1.7+ recommended)
+ *
+ * Run with:
+ * phantomjs runner.js [url-of-your-qunit-testsuite]
+ *
+ * e.g.
+ * phantomjs runner.js http://localhost/qunit/test/index.html
+ */
+
+/*jshint latedef:false */
+/*global phantom:false, require:false, console:false, window:false, QUnit:false */
+
+(function() {
+ 'use strict';
+
+ var args = require('system').args;
+
+ // arg[0]: scriptName, args[1...]: arguments
+ if (args.length !== 2) {
+ console.error('Usage:\n phantomjs runner.js [url-of-your-qunit-testsuite]');
+ phantom.exit(1);
+ }
+
+ var url = args[1],
+ page = require('webpage').create();
+
+ // Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`)
+ page.onConsoleMessage = function(msg) {
+ console.log(msg);
+ };
+
+ page.onInitialized = function() {
+ page.evaluate(addLogging);
+ };
+
+ page.onCallback = function(message) {
+ var result,
+ failed;
+
+ if (message) {
+ if (message.name === 'QUnit.done') {
+ result = message.data;
+ failed = !result || result.failed;
+
+ phantom.exit(failed ? 1 : 0);
+ }
+ }
+ };
+
+ page.open(url, function(status) {
+ if (status !== 'success') {
+ console.error('Unable to access network: ' + status);
+ phantom.exit(1);
+ } else {
+ // Cannot do this verification with the 'DOMContentLoaded' handler because it
+ // will be too late to attach it if a page does not have any script tags.
+ var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); });
+ if (qunitMissing) {
+ console.error('The `QUnit` object is not present on this page.');
+ phantom.exit(1);
+ }
+
+ // Do nothing... the callback mechanism will handle everything!
+ }
+ });
+
+ function addLogging() {
+ window.document.addEventListener('DOMContentLoaded', function() {
+ var current_test_assertions = [];
+
+ QUnit.log(function(details) {
+ var response;
+
+ // Ignore passing assertions
+ if (details.result) {
+ return;
+ }
+
+ response = details.message || '';
+
+ if (typeof details.expected !== 'undefined') {
+ if (response) {
+ response += ', ';
+ }
+
+ response += 'expected: ' + details.expected + ', but was: ' + details.actual;
+ if (details.source) {
+ response += "\n" + details.source;
+ }
+ }
+
+ current_test_assertions.push('Failed assertion: ' + response);
+ });
+
+ QUnit.testDone(function(result) {
+ var i,
+ len,
+ name = result.module + ': ' + result.name;
+
+ if (result.failed) {
+ console.log('Test failed: ' + name);
+
+ for (i = 0, len = current_test_assertions.length; i < len; i++) {
+ console.log(' ' + current_test_assertions[i]);
+ }
+ }
+
+ current_test_assertions.length = 0;
+ });
+
+ QUnit.done(function(result) {
+ console.log('Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.');
+
+ if (typeof window.callPhantom === 'function') {
+ window.callPhantom({
+ 'name': 'QUnit.done',
+ 'data': result
+ });
+ }
+ });
+ }, false);
+ }
+})();
diff --git a/Echo/tests/phpunit/api/ApiEchoMarkReadTest.php b/Echo/tests/phpunit/api/ApiEchoMarkReadTest.php
new file mode 100644
index 00000000..104e0b00
--- /dev/null
+++ b/Echo/tests/phpunit/api/ApiEchoMarkReadTest.php
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * @group medium
+ * @group API
+ * @covers ApiQuery
+ */
+class ApiEchoMarkReadTest extends ApiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+ $this->doLogin();
+ }
+
+ function getTokens() {
+ return $this->getTokenList( self::$users['sysop'] );
+ }
+
+ public function testMarkReadWithList() {
+
+ $tokens = $this->getTokens();
+ // Grouping by section
+ $data = $this->doApiRequest( array(
+ 'action' => 'echomarkread',
+ 'notlist' => '121|122|123',
+ 'token' => $tokens['edittoken'] ) );
+
+ $this->assertArrayHasKey( 'query', $data[0] );
+ $this->assertArrayHasKey( 'echomarkread', $data[0]['query'] );
+
+ $result = $data[0]['query']['echomarkread'];
+
+ // General count
+ $this->assertArrayHasKey( 'count', $result );
+ $this->assertArrayHasKey( 'rawcount', $result );
+
+ // Alert
+ $this->assertArrayHasKey( 'alert', $result );
+ $alert = $result['alert'];
+ $this->assertArrayHasKey( 'rawcount', $alert );
+ $this->assertArrayHasKey( 'count', $alert );
+
+ // Message
+ $this->assertArrayHasKey( 'message', $result );
+ $message = $result['message'];
+ $this->assertArrayHasKey( 'rawcount', $message );
+ $this->assertArrayHasKey( 'count', $message );
+ }
+
+ public function testMarkReadWithAll() {
+
+ $tokens = $this->getTokens();
+ // Grouping by section
+ $data = $this->doApiRequest( array(
+ 'action' => 'echomarkread',
+ 'notall' => '1',
+ 'token' => $tokens['edittoken'] ) );
+
+ $this->assertArrayHasKey( 'query', $data[0] );
+ $this->assertArrayHasKey( 'echomarkread', $data[0]['query'] );
+
+ $result = $data[0]['query']['echomarkread'];
+
+ // General count
+ $this->assertArrayHasKey( 'count', $result );
+ $this->assertArrayHasKey( 'rawcount', $result );
+
+ // Alert
+ $this->assertArrayHasKey( 'alert', $result );
+ $alert = $result['alert'];
+ $this->assertArrayHasKey( 'rawcount', $alert );
+ $this->assertArrayHasKey( 'count', $alert );
+
+ // Message
+ $this->assertArrayHasKey( 'message', $result );
+ $message = $result['message'];
+ $this->assertArrayHasKey( 'rawcount', $message );
+ $this->assertArrayHasKey( 'count', $message );
+ }
+
+ public function testMarkReadWithSections() {
+
+ $tokens = $this->getTokens();
+ // Grouping by section
+ $data = $this->doApiRequest( array(
+ 'action' => 'echomarkread',
+ 'sections' => 'alert|message',
+ 'token' => $tokens['edittoken'] ) );
+
+ $this->assertArrayHasKey( 'query', $data[0] );
+ $this->assertArrayHasKey( 'echomarkread', $data[0]['query'] );
+
+ $result = $data[0]['query']['echomarkread'];
+
+ // General count
+ $this->assertArrayHasKey( 'count', $result );
+ $this->assertArrayHasKey( 'rawcount', $result );
+
+ // Alert
+ $this->assertArrayHasKey( 'alert', $result );
+ $alert = $result['alert'];
+ $this->assertArrayHasKey( 'rawcount', $alert );
+ $this->assertArrayHasKey( 'count', $alert );
+
+ // Message
+ $this->assertArrayHasKey( 'message', $result );
+ $message = $result['message'];
+ $this->assertArrayHasKey( 'rawcount', $message );
+ $this->assertArrayHasKey( 'count', $message );
+ }
+
+}
diff --git a/Echo/tests/phpunit/api/ApiEchoNotificationsTest.php b/Echo/tests/phpunit/api/ApiEchoNotificationsTest.php
new file mode 100644
index 00000000..cd1a9732
--- /dev/null
+++ b/Echo/tests/phpunit/api/ApiEchoNotificationsTest.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @group medium
+ * @group API
+ * @covers ApiQuery
+ */
+class ApiEchoNotificationsTest extends ApiTestCase {
+
+ public function testWithSectionGrouping() {
+ // Grouping by section
+ $data = $this->doApiRequest( array(
+ 'action' => 'query',
+ 'meta' => 'notifications',
+ 'notsections' => 'alert|message',
+ 'notgroupbysection' => 1,
+ 'notlimit' => 10,
+ 'notprop' => 'index|list|count' ) );
+
+ $this->assertArrayHasKey( 'query', $data[0] );
+ $this->assertArrayHasKey( 'notifications', $data[0]['query'] );
+
+ $result = $data[0]['query']['notifications'];
+
+ // General count
+ $this->assertArrayHasKey( 'count', $result );
+ $this->assertArrayHasKey( 'rawcount', $result );
+
+ // Alert
+ $this->assertArrayHasKey( 'alert', $result );
+ $alert = $result['alert'];
+ $this->assertArrayHasKey( 'list', $alert );
+ $this->assertArrayHasKey( 'continue', $alert );
+ $this->assertArrayHasKey( 'index', $alert );
+ $this->assertArrayHasKey( 'rawcount', $alert );
+ $this->assertArrayHasKey( 'count', $alert );
+
+ // Message
+ $this->assertArrayHasKey( 'message', $result );
+ $message = $result['message'];
+ $this->assertArrayHasKey( 'list', $message );
+ $this->assertArrayHasKey( 'continue', $message );
+ $this->assertArrayHasKey( 'index', $message );
+ $this->assertArrayHasKey( 'rawcount', $message );
+ $this->assertArrayHasKey( 'count', $message );
+ }
+
+ public function testWithoutSectionGrouping() {
+ $data = $this->doApiRequest( array(
+ 'action' => 'query',
+ 'meta' => 'notifications',
+ 'notsections' => 'alert|message',
+ 'notlimit' => 10,
+ 'notprop' => 'index|list|count' ) );
+
+ $this->assertArrayHasKey( 'query', $data[0] );
+ $this->assertArrayHasKey( 'notifications', $data[0]['query'] );
+
+ $result = $data[0]['query']['notifications'];
+
+ $this->assertArrayHasKey( 'count', $result );
+ $this->assertArrayHasKey( 'rawcount', $result );
+ $this->assertArrayHasKey( 'list', $result );
+ $this->assertArrayHasKey( 'continue', $result );
+ $this->assertArrayHasKey( 'index', $result );
+
+ $this->assertTrue( !isset( $result['alert'] ) );
+ $this->assertTrue( !isset( $result['message'] ) );
+ }
+
+}
diff --git a/Echo/tests/phpunit/controller/NotificationControllerTest.php b/Echo/tests/phpunit/controller/NotificationControllerTest.php
new file mode 100644
index 00000000..fdfb9c25
--- /dev/null
+++ b/Echo/tests/phpunit/controller/NotificationControllerTest.php
@@ -0,0 +1,220 @@
+<?php
+
+class NotificationControllerTest extends MediaWikiTestCase {
+
+ public function evaluateUserLocatorsProvider() {
+ return array(
+ array(
+ 'With no options no users are notified',
+ // expected result
+ array(),
+ // event user locator config
+ array(),
+ ),
+
+ array(
+ 'Does not error when given non-existant user-locator',
+ // expected result
+ array(),
+ // event user locator config
+ array( 'not-callable' ),
+ ),
+
+ array(
+ 'Calls selected locator and returns result',
+ // expected result
+ array( array( 123 ) ),
+ // event user locator config
+ function() { return array( 123 => 123 ); }
+ ),
+
+ array(
+ 'evaluates multiple locators',
+ // expected result
+ array( array( 123 ), array( 456 ) ),
+ // event user locator config
+ array(
+ function() { return array( 123 => 123 ); },
+ function() { return array( 456 => 456 ); },
+ ),
+ ),
+
+ array(
+ 'Passes parameters to locateFromEventExtra in expected manner',
+ // expected result
+ array( array( 123 ) ),
+ // event user locator config
+ array(
+ array( 'EchoUserLocator::locateFromEventExtra', array( 'other-user' ) ),
+ ),
+ // additional setup
+ function( $test, $event ) {
+ $event->expects( $test->any() )
+ ->method( 'getExtraParam' )
+ ->with( 'other-user' )
+ ->will( $test->returnValue( 123 ) );
+ }
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider evaluateUserLocatorsProvider
+ */
+ public function testEvaluateUserLocators( $message, $expect, $locatorConfigForEventType, $setup = null ) {
+ $this->setMwGlobals( array(
+ 'wgEchoNotifications' => array(
+ 'unit-test' => array(
+ 'user-locators' => $locatorConfigForEventType
+ ),
+ ),
+ ) );
+
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getType' )
+ ->will( $this->returnValue( 'unit-test' ) );
+
+ if ( $setup !== null ) {
+ $setup( $this, $event );
+ }
+
+ $result = EchoNotificationController::evaluateUserLocators( $event );
+ $this->assertEquals( $expect, array_map( 'array_keys', $result ), $message );
+ }
+
+ public function testEvaluateUserLocatorPassesParameters() {
+ $test = $this;
+ $callback = function( $event, $firstOption, $secondOption ) use( $test ) {
+ $test->assertInstanceOf( 'EchoEvent', $event );
+ $test->assertEquals( 'first', $firstOption );
+ $test->assertEquals( 'second', $secondOption );
+
+ return array();
+ };
+
+ self::testEvaluateUserLocators(
+ __FUNCTION__,
+ array( array() ),
+ array( array( $callback, 'first', 'second' ) )
+ );
+ }
+
+ public function getUsersToNotifyForEventProvider() {
+ return array(
+ array(
+ 'Filters anonymous users',
+ // expected result
+ array(),
+ // users returned from locator
+ array( User::newFromName( '4.5.6.7', false ) ),
+ ),
+
+ array(
+ 'Filters duplicate users',
+ // expected result
+ array( 123 ),
+ // users returned from locator
+ array( User::newFromId( 123 ), User::newFromId( 123 ) ),
+ ),
+
+ array(
+ 'Filters non-user objects',
+ // expected result
+ array( 123 ),
+ // users returned from locator
+ array( null, 'foo', User::newFromId( 123 ), new stdClass, 456 ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getUsersToNotifyForEventProvider
+ */
+ public function testGetUsersToNotifyForEvent(
+ $message,
+ $expect,
+ $users
+ ) {
+ $this->setMwGlobals( array(
+ 'wgEchoNotifications' => array(
+ 'unit-test' => array(
+ 'user-locators' => function() use( $users ) { return $users; },
+ ),
+ ),
+ ) );
+
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getType' )
+ ->will( $this->returnValue( 'unit-test' ) );
+
+ $result = EchoNotificationController::getUsersToNotifyForEvent( $event );
+ $ids = array();
+ foreach ( $result as $user ) {
+ $ids[] = $user->getId();
+ }
+ $this->assertEquals( $expect, $ids, $message );
+ }
+
+ public function testDoesNotDeliverDisabledEvent() {
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'isEnabledEvent' )
+ ->will( $this->returnValue( false ) );
+ // Assume it would have to check the event type to
+ // determine how to deliver
+ $event->expects( $this->never() )
+ ->method( 'getType' );
+
+ EchoNotificationController::notify( $event, false );
+ }
+
+ public static function getEventNotifyTypesProvider() {
+ return array(
+ array(
+ 'Selects the `all` configuration by default',
+ // expected result
+ array( 'web' ),
+ // event type
+ 'bar',
+ // default notification types configuration
+ array(
+ 'all' => array( 'web' => true ),
+ 'foo' => array( 'email' => true ),
+ ),
+ ),
+
+ array(
+ 'Overrides `all` configuration with event type configuration',
+ // expected result
+ array( 'web' ),
+ // event type
+ 'foo',
+ // default notification types configuration
+ array(
+ 'all' => array( 'web' => true, 'email' => true ),
+ 'foo' => array( 'email' => false ),
+ 'bar' => array( 'sms' => true ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getEventNotifyTypesProvider
+ */
+ public function testGetEventNotifyTypes( $message, $expect, $type, array $notificationTypes ) {
+ $this->setMwGlobals( array(
+ 'wgEchoDefaultNotificationTypes' => $notificationTypes,
+ ) );
+ $result = EchoNotificationController::getEventNotifyTypes( $type );
+ $this->assertEquals( $expect, $result, $message );
+ }
+}
diff --git a/Echo/tests/phpunit/formatters/NotificationFormatterTest.php b/Echo/tests/phpunit/formatters/NotificationFormatterTest.php
new file mode 100644
index 00000000..dd002414
--- /dev/null
+++ b/Echo/tests/phpunit/formatters/NotificationFormatterTest.php
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * @group Echo
+ */
+class EchoNotificationFormatterTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ parent::setUp();
+ $user = new User();
+ $user->setName( 'Notification-formatter-test' );
+ $user->addToDatabase();
+ $this->setMwGlobals( 'wgUser', $user );
+ }
+
+ public static function provider_editUserTalkEmail() {
+ return array(
+ array( '/Main_Page[^#]/', null ),
+ array( '/Main_Page#Section_8/', 'Section 8' ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_editUserTalkEmail
+ */
+ public function testEditUserTalkEmailNotificationLink( $pattern, $sectionTitle ) {
+ $event = $this->mockEvent( 'edit-user-talk', array(
+ 'section-title' => $sectionTitle,
+ ) );
+ $event->expects( $this->any() )
+ ->method( 'getTitle' )
+ ->will( $this->returnValue( Title::newMainPage() ) );
+ $formatted = $this->format( $event, 'email' );
+ if ( is_array( $formatted['body'] ) ) {
+ $this->assertRegExp( $pattern, $formatted['body']['text'] );
+ $this->assertRegExp( $pattern, $formatted['body']['html'] );
+ } else {
+ $this->assertRegExp( $pattern, $formatted['body'] );
+ }
+
+ # Reset the Title cache
+ $mainPage = Title::newMainPage();
+ $mainPage->setFragment('');
+ # And assert it has been cleaned up
+ $mainPageCached = Title::newMainPage();
+ $this->assertEquals( '', $mainPageCached->getFragment() );
+
+ }
+
+ public static function provider_editUserTalk() {
+ return array(
+ // if there is a section-title, the message should be '[[User:user_name|user_name]] left a message on
+ // your talk page in '[[User talk:user_name#section_title|section_title]]'
+ array( '/[[User talk:[^#]+#moar_cowbell|moar_cowbell]]/', 'moar_cowbell', 'text' ),
+ array( '/#moar_cowbell/', 'moar_cowbell', 'html' ),
+ array( '/#moar_cowbell/', 'moar_cowbell', 'flyout' ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_editUserTalk
+ */
+ public function testEditUserTalkFlyoutSectionLinkFragment( $pattern, $sectionTitle, $format ) {
+ // Required hack so parser doesnt turn the links into redlinks which contain no fragment
+ global $wgUser;
+ LinkCache::singleton()->addGoodLinkObj( 42, $wgUser->getTalkPage() );
+
+ $event = $this->mockEvent( 'edit-user-talk', array(
+ 'section-title' => $sectionTitle,
+ ) );
+ $this->assertRegExp( $pattern, $this->format( $event, $format ) );
+ }
+
+ public function provider_formatterDoesntFail() {
+ // Remove events from this array once they have specific tests for their formatting
+ $untested = array(
+ 'welcome' => array(),
+ 'reverted' => array(
+ 'revid' => 42,
+ 'reverted-user-id' => 77,
+ 'reverted-revision-id' => 13,
+ 'method' => 'undo',
+ ),
+ 'page-linked' => array(
+ 'link-from-page-id' => 42,
+ ),
+ 'mention' => array(
+ 'content' => 'lorem ipsum dolar sit amet',
+ 'section-title' => 'Zombies',
+ 'revid' => 42,
+ 'mentionedusers' => array( 101 => 101 ),
+ ),
+ 'user-rights' => array(
+ 'user' => 187,
+ 'add' => array( 'aaa', 'bbb' ),
+ 'remove' => array( 'other' ),
+ ),
+ );
+ $formats = array( 'html', 'flyout', 'email', 'text' );
+ $tests = array();
+ foreach ( $untested as $type => $extra ) {
+ foreach ( $formats as $format ) {
+ // Run tests with blank extra data and with the provided extra data
+ $tests[] = array( $format, $type, $extra );
+ $tests[] = array( $format, $type, array() );
+ }
+ }
+
+ return $tests;
+ }
+
+ public static function provider_revisionSummary() {
+ $sectionText = '(dummy comment)';
+
+ // Test the 4 different events that reference the summary, although they should follow mostly
+ // the same code they may use different classes extended from the EchoNotificationFormatter
+ $tests = array();
+ $events = array( 'edit-user-talk' );
+ foreach ( $events as $eventType ) {
+ $tests[] = array( $eventType, $sectionText, 0);
+ $tests[] = array( $eventType, $sectionText, Revision::DELETED_TEXT );
+ }
+
+ return $tests;
+ }
+
+ /**
+ * @dataProvider provider_revisionSummary
+ */
+ public function testRevisionSummarySuppression( $eventType, $text, $deleted ) {
+ // Revision needs a comment to attempt to format
+ $event = $this->mockEvent(
+ $eventType,
+ array( 'section-title' => 'Test Title', 'section-text' => $text ),
+ new Revision( compact( 'deleted' ) )
+ );
+ if ( $deleted === Revision::DELETED_TEXT ) {
+ $this->assertNotContains( $text, $this->format( $event, 'html' ) );
+ } else {
+ $this->assertContains( $text, $this->format( $event, 'html' ) );
+ }
+ }
+
+ public static function provider_revisionAgent() {
+ $userText = '10.2.3.4';
+ $suppressed = wfMessage( 'rev-deleted-user' )->text();
+
+ $tests = array();
+ $events = array( 'edit-user-talk', 'reverted', 'mention' );
+ foreach ( $events as $eventType ) {
+ $tests[] = array( $eventType, $userText, $userText, 0 );
+ $tests[] = array( $eventType, $suppressed, $userText, Revision::DELETED_USER );
+ }
+
+ return $tests;
+ }
+
+ /**
+ * @dataProvider provider_revisionAgent
+ */
+ public function testAgentSuppression( $eventType, $expect, $user_text, $deleted ) {
+ $event = $this->mockEvent(
+ $eventType,
+ array(),
+ new Revision( compact( 'user_text', 'deleted' ) )
+ );
+
+ $user = new User;
+ $user->setName( $user_text );
+ $event->expects( $this->any() )
+ ->method( 'getAgent' )
+ ->will( $this->returnValue( $user ) );
+
+ $this->assertContains( $expect, $this->format( $event, 'html' ) );
+ }
+
+ public static function provider_sectionTitle() {
+ $message = "some_section_title"; // underscores simplifies the test, since it will transform ' ' to '_'
+ $suppressed = wfMessage( 'echo-rev-deleted-text-view')->text();
+
+ $tests = array();
+ $events = array( 'mention' ); // currently only mention uses sectionTitle, but likely edit-user-talk will soon as well
+ foreach ( $events as $eventType ) {
+ $tests[] = array( $eventType, $message, $message, 0);
+ $tests[] = array( $eventType, $suppressed, $message, Revision::DELETED_TEXT );
+ }
+
+ return $tests;
+ }
+
+ /**
+ * @dataProvider provider_formatterDoesntFail
+ */
+ public function testFormatterDoesntFail( $format, $type, array $extra ) {
+ $result = $this->format( $this->mockEvent( $type, $extra ), $format );
+
+ // generic assertion, could do better
+ if ( $format === 'email' ) {
+ $this->assertInternalType( 'array', $result );
+ $this->assertCount( 2, $result );
+ } else {
+ $this->assertInternalType( 'string', $result );
+ $this->assertGreaterThan( 0, strlen( $result ) );
+ }
+ }
+
+ /**
+ * @dataProvider provider_sectionTitle
+ */
+ public function testMentionSubjectSectionTitleSuppression( $eventType, $expect, $sectionTitle, $deleted ) {
+ $event = $this->mockEvent(
+ $eventType,
+ array( 'section-title' => $sectionTitle ),
+ new Revision( compact( 'deleted' ) )
+ );
+
+ $this->assertContains( $expect, $this->format( $event, 'html' ) );
+ }
+
+ protected function format( EchoEvent $event, $format, $user = false, $type = 'web' ) {
+ if ( $user === false ) {
+ $user = User::newFromName('Notification-formatter-test');
+ }
+
+ // Notification users can not be anonymous, use a fake user id
+ return EchoNotificationController::formatNotification( $event, $user, $format, $type );
+ }
+
+ protected function mockEvent( $type, array $extra = array(), Revision $rev = null ) {
+ $methods = get_class_methods( 'EchoEvent' );
+ $methods = array_diff( $methods, array( 'userCan', 'getLinkMessage', 'getLinkDestination' ) );
+
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->setMethods( $methods )
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getType' )
+ ->will( $this->returnValue( $type ) );
+ $event->expects( $this->any() )
+ ->method( 'getExtra' )
+ ->will( $this->returnValue( $extra ) );
+ if ( $rev !== null ) {
+ $event->expects( $this->any() )
+ ->method( 'getRevision' )
+ ->will( $this->returnValue( $rev ) );
+ }
+ return $event;
+ }
+}
diff --git a/Echo/tests/phpunit/includes/AttributeManagerTest.php b/Echo/tests/phpunit/includes/AttributeManagerTest.php
new file mode 100644
index 00000000..cc23cb0e
--- /dev/null
+++ b/Echo/tests/phpunit/includes/AttributeManagerTest.php
@@ -0,0 +1,330 @@
+<?php
+
+class EchoAttributeManagerTest extends MediaWikiTestCase {
+
+ public function testNewFromGlobalVars() {
+ $this->assertInstanceOf( 'EchoAttributeManager', EchoAttributeManager::newFromGlobalVars() );
+ }
+
+ public static function getUserLocatorsProvider() {
+ return array(
+ array(
+ 'No errors when requesting unknown type',
+ // expected result
+ array(),
+ // event type
+ 'foo',
+ // notification configuration
+ array(),
+ ),
+
+ array(
+ 'Returns selected notification configuration',
+ // expected result
+ array( 'woot!' ),
+ // event type
+ 'magic',
+ // notification configuration
+ array(
+ 'foo' => array(
+ 'user-locators' => array( 'frown' ),
+ ),
+ 'magic' => array(
+ 'user-locators' => array( 'woot!' ),
+ ),
+ ),
+ ),
+
+ array(
+ 'Accepts user-locators as string and returns array',
+ // expected result
+ array( 'sagen' ),
+ // event type
+ 'challah',
+ // notification configuration
+ array(
+ 'challah' => array(
+ 'user-locators' => 'sagen',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getUserLocatorsProvider
+ */
+ public function testGetUserLocators( $message, $expect, $type, $notifications) {
+ $manager = new EchoAttributeManager( $notifications, array() );
+
+ $result = $manager->getUserLocators( $type );
+ $this->assertEquals( $expect, $result, $message );
+ }
+
+ public function testGetCategoryEligibility() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertTrue( $manager->getCategoryEligibility( $this->mockUser(), 'category_one' ) );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10,
+ 'usergroups' => array(
+ 'sysop'
+ )
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertFalse( $manager->getCategoryEligibility( $this->mockUser(), 'category_one' ) );
+ }
+
+ public function testGetNotificationCategory() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getNotificationCategory( 'event_one' ), 'category_one' );
+
+ $manager = new EchoAttributeManager( $notif, array() );
+ $this->assertEquals( $manager->getNotificationCategory( 'event_one' ), 'other' );
+
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_two'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getNotificationCategory( 'event_one' ), 'other' );
+ }
+
+ public function testGetCategoryPriority() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_two'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 6
+ ),
+ 'category_two' => array (
+ 'priority' => 100
+ ),
+ 'category_three' => array (
+ 'priority' => -10
+ ),
+ 'category_four' => array ()
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( 6, $manager->getCategoryPriority( 'category_one' ) );
+ $this->assertEquals( 10, $manager->getCategoryPriority( 'category_two' ) );
+ $this->assertEquals( 10, $manager->getCategoryPriority( 'category_three' ) );
+ $this->assertEquals( 10, $manager->getCategoryPriority( 'category_four' ) );
+ }
+
+ public function testGetNotificationPriority() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ 'event_two' => array (
+ 'category' => 'category_two'
+ ),
+ 'event_three' => array (
+ 'category' => 'category_three'
+ ),
+ 'event_four' => array (
+ 'category' => 'category_four'
+ )
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 6
+ ),
+ 'category_two' => array (
+ 'priority' => 100
+ ),
+ 'category_three' => array (
+ 'priority' => -10
+ ),
+ 'category_four' => array ()
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( 6, $manager->getNotificationPriority( 'event_one' ) );
+ $this->assertEquals( 10, $manager->getNotificationPriority( 'event_two' ) );
+ $this->assertEquals( 10, $manager->getNotificationPriority( 'event_three' ) );
+ $this->assertEquals( 10, $manager->getNotificationPriority( 'event_four' ) );
+ }
+
+ public function testGetMessageEvents() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one',
+ 'section' => 'message'
+ ),
+ 'event_two' => array (
+ 'category' => 'category_two'
+ ),
+ 'event_three' => array (
+ 'category' => 'category_three',
+ 'section' => 'message'
+ ),
+ 'event_four' => array (
+ 'category' => 'category_four'
+ )
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 6
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getMessageEvents(), array( 'event_one', 'event_three' ) );
+ }
+
+ public function testGetAlertEvents() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one',
+ 'section' => 'message'
+ ),
+ 'event_two' => array (
+ 'category' => 'category_two'
+ ),
+ 'event_three' => array (
+ 'category' => 'category_three',
+ 'section' => 'alert'
+ ),
+ 'event_four' => array (
+ 'category' => 'category_four'
+ )
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 6
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getAlertEvents(), array( 'event_two', 'event_three', 'event_four' ) );
+ }
+
+ public function testGetUserEnabledEvents() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ 'event_two' => array (
+ 'category' => 'category_two'
+ ),
+ 'event_three' => array (
+ 'category' => 'category_three'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10,
+ 'usergroups' => array(
+ 'sysop'
+ )
+ ),
+ 'category_two' => array (
+ 'priority' => 10,
+ 'usergroups' => array(
+ 'echo_group'
+ )
+ ),
+ 'category_three' => array (
+ 'priority' => 10,
+ ),
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getUserEnabledEvents( $this->mockUser(), 'web' ), array( 'event_two', 'event_three' ) );
+ }
+
+ public function testGetUserEnabledEventsbySections() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ 'event_two' => array (
+ 'category' => 'category_two',
+ 'section' => 'message'
+ ),
+ 'event_three' => array (
+ 'category' => 'category_three',
+ 'section' => 'alert'
+ ),
+ 'event_four' => array (
+ 'category' => 'category_three',
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10,
+ ),
+ 'category_two' => array (
+ 'priority' => 10,
+ ),
+ 'category_three' => array (
+ 'priority' => 10
+ ),
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $expected = array( 'event_one', 'event_three', 'event_four' );
+ $actual = $manager->getUserEnabledEventsBySections( $this->mockUser(), 'web', array( 'alert' ) );
+ sort( $expected );
+ sort( $actual );
+ $this->assertEquals( $actual, $expected );
+
+ $expected = array( 'event_two' );
+ $actual = $manager->getUserEnabledEventsBySections( $this->mockUser(), 'web', array( 'message' ) );
+ sort( $expected );
+ sort( $actual );
+ $this->assertEquals( $actual, $expected );
+
+ $expected = array( 'event_one', 'event_two', 'event_three', 'event_four' );
+ $actual = $manager->getUserEnabledEventsBySections( $this->mockUser(), 'web', array( 'message', 'alert' ) );
+ sort( $expected );
+ sort( $actual );
+ $this->assertEquals( $actual, $expected );
+ }
+
+ /**
+ * Mock object of User
+ */
+ protected function mockUser() {
+ $user = $this->getMockBuilder( 'User' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user->expects( $this->any() )
+ ->method( 'getID' )
+ ->will( $this->returnValue( 1 ) );
+ $user->expects( $this->any() )
+ ->method( 'getOption' )
+ ->will( $this->returnValue( true ) );
+ $user->expects( $this->any() )
+ ->method( 'getGroups' )
+ ->will( $this->returnValue( array( 'echo_group' ) ) );
+ return $user;
+ }
+}
diff --git a/Echo/tests/phpunit/includes/BatchRowUpdateTest.php b/Echo/tests/phpunit/includes/BatchRowUpdateTest.php
new file mode 100644
index 00000000..c9956287
--- /dev/null
+++ b/Echo/tests/phpunit/includes/BatchRowUpdateTest.php
@@ -0,0 +1,244 @@
+<?php
+
+require_once __DIR__ . "/../../../includes/BatchRowUpdate.php";
+
+/**
+ * Tests for BatchRowUpdate and its components
+ * @group Echo
+ */
+class BatchRowUpdateTest extends MediaWikiTestCase {
+
+ public function testWriterBasicFunctionality() {
+ $db = $this->mockDb();
+ $writer = new EchoBatchRowWriter( $db, 'echo_event' );
+
+ $updates = array(
+ self::mockUpdate( array( 'something' => 'changed' ) ),
+ self::mockUpdate( array( 'otherthing' => 'changed' ) ),
+ self::mockUpdate( array( 'and' => 'something', 'else' => 'changed' ) ),
+ );
+
+ $db->expects( $this->exactly( count( $updates ) ) )
+ ->method( 'update' );
+
+ $writer->write( $updates );
+ }
+
+ static protected function mockUpdate( array $changes ) {
+ static $i = 0;
+ return array(
+ 'primaryKey' => array( 'event_id' => $i++ ),
+ 'changes' => $changes,
+ );
+ }
+
+ public function testReaderBasicIterate() {
+ $db = $this->mockDb();
+ $batchSize = 2;
+ $reader = new EchoBatchRowIterator( $db, 'some_table', 'id_field', $batchSize );
+
+ $response = $this->genSelectResult( $batchSize, /*numRows*/ 5, function() {
+ static $i = 0;
+ return array( 'id_field' => ++$i );
+ } );
+ $db->expects( $this->exactly( count( $response ) ) )
+ ->method( 'select' )
+ ->will( $this->consecutivelyReturnFromSelect( $response ) );
+
+ $pos = 0;
+ foreach ( $reader as $rows ) {
+ $this->assertEquals( $response[$pos], $rows, "Testing row in position $pos" );
+ $pos++;
+ }
+ // -1 is because the final array() marks the end and isnt included
+ $this->assertEquals( count( $response ) - 1, $pos );
+ }
+
+ static public function provider_readerGetPrimaryKey() {
+ $row = array(
+ 'id_field' => 42,
+ 'some_col' => 'dvorak',
+ 'other_col' => 'samurai',
+ );
+ return array(
+
+ array(
+ 'Must return single column pk when requested',
+ array( 'id_field' => 42 ),
+ $row
+ ),
+
+ array(
+ 'Must return multiple column pks when requested',
+ array( 'id_field' => 42, 'other_col' => 'samurai' ),
+ $row
+ ),
+
+ );
+ }
+
+ /**
+ * @dataProvider provider_readerGetPrimaryKey
+ */
+ public function testReaderGetPrimaryKey( $message, array $expected, array $row ) {
+ $reader = new EchoBatchRowIterator( $this->mockDb(), 'some_table', array_keys( $expected ), 8675309 );
+ $this->assertEquals( $expected, $reader->extractPrimaryKeys( (object) $row ), $message );
+ }
+
+ static public function provider_readerSetFetchColumns() {
+ return array(
+
+ array(
+ 'Must merge primary keys into select conditions',
+ // Expected column select
+ array( 'foo', 'bar' ),
+ // primary keys
+ array( 'foo' ),
+ // setFetchColumn
+ array( 'bar' )
+ ),
+
+ array(
+ 'Must not merge primary keys into the all columns selector',
+ // Expected column select
+ array( '*' ),
+ // primary keys
+ array( 'foo' ),
+ // setFetchColumn
+ array( '*' ),
+ ),
+
+ array(
+ 'Must not duplicate primary keys into column selector',
+ // Expected column select.
+ // TODO: figure out how to only assert the array_values portion and not the keys
+ array( 0 => 'foo', 1 => 'bar', 3 => 'baz' ),
+ // primary keys
+ array( 'foo', 'bar', ),
+ // setFetchColumn
+ array( 'bar', 'baz' ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_readerSetFetchColumns
+ */
+ public function testReaderSetFetchColumns( $message, array $columns, array $primaryKeys, array $fetchColumns ) {
+ $db = $this->mockDb();
+ $db->expects( $this->once() )
+ ->method( 'select' )
+ ->with( 'some_table', $columns ) // only testing second parameter of DatabaseBase::select
+ ->will( $this->returnValue( new ArrayIterator( array() ) ) );
+
+ $reader = new EchoBatchRowIterator( $db, 'some_table', $primaryKeys, 22 );
+ $reader->setFetchColumns( $fetchColumns );
+ // triggers first database select
+ $reader->rewind();
+ }
+
+ static public function provider_readerSelectConditions() {
+ return array(
+
+ array(
+ "With single primary key must generate id > 'value'",
+ // Expected second iteration
+ array( "( id_field > '3' )" ),
+ // Primary key(s)
+ 'id_field',
+ ),
+
+ array(
+ 'With multiple primary keys the first conditions must use >= and the final condition must use >',
+ // Expected second iteration
+ array( "( id_field = '3' AND foo > '103' ) OR ( id_field > '3' )" ),
+ // Primary key(s)
+ array( 'id_field', 'foo' ),
+ ),
+
+ );
+ }
+
+ /**
+ * Slightly hackish to use reflection, but asserting different parameters
+ * to consecutive calls of DatabaseBase::select in phpunit is error prone
+ *
+ * @dataProvider provider_readerSelectConditions
+ */
+ public function testReaderSelectConditionsMultiplePrimaryKeys( $message, $expectedSecondIteration, $primaryKeys, $batchSize = 3 ) {
+ $results = $this->genSelectResult( $batchSize, $batchSize * 3, function() {
+ static $i = 0, $j = 100, $k = 1000;
+ return array( 'id_field' => ++$i, 'foo' => ++$j, 'bar' => ++$k );
+ } );
+ $db = $this->mockDbConsecutiveSelect( $results );
+
+ $conditions = array( 'bar' => 42, 'baz' => 'hai' );
+ $reader = new EchoBatchRowIterator( $db, 'some_table', $primaryKeys, $batchSize );
+ $reader->addConditions( $conditions );
+
+ $buildConditions = new ReflectionMethod( $reader, 'buildConditions' );
+ $buildConditions->setAccessible( true );
+
+ // On first iteration only the passed conditions must be used
+ $this->assertEquals( $conditions, $buildConditions->invoke( $reader ),
+ 'First iteration must return only the conditions passed in addConditions' );
+ $reader->rewind();
+
+ // Second iteration must use the maximum primary key of last set
+ $this->assertEquals(
+ $conditions + $expectedSecondIteration,
+ $buildConditions->invoke( $reader ),
+ $message
+ );
+ }
+
+ protected function mockDbConsecutiveSelect( array $retvals ) {
+ $db = $this->mockDb();
+ $db->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->consecutivelyReturnFromSelect( $retvals ) );
+ $db->expects( $this->any() )
+ ->method( 'addQuotes' )
+ ->will( $this->returnCallback( function( $value ) {
+ return "'$value'"; // not real quoting: doesn't matter in test
+ } ) );
+
+ return $db;
+ }
+
+ protected function consecutivelyReturnFromSelect( array $results ) {
+ $retvals = array();
+ foreach ( $results as $rows ) {
+ // The DatabaseBase::select method returns iterators, so we do too.
+ $retvals[] = $this->returnValue( new ArrayIterator( $rows ) );
+ }
+
+ return call_user_func_array( array( $this, 'onConsecutiveCalls' ), $retvals );
+ }
+
+
+ protected function genSelectResult( $batchSize, $numRows, $rowGenerator ) {
+ $res = array();
+ for ( $i = 0; $i < $numRows; $i += $batchSize ) {
+ $rows = array();
+ for ( $j = 0; $j < $batchSize && $i + $j < $numRows; $j++ ) {
+ $rows [] = (object) call_user_func( $rowGenerator );
+ }
+ $res[] = $rows;
+ }
+ $res[] = array(); // termination condition requires empty result for last row
+ return $res;
+ }
+
+ protected function mockDb() {
+ // Cant mock from DatabaseType or DatabaseBase, they dont
+ // have the full gamut of methods
+ $databaseMysql = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $databaseMysql->expects( $this->any() )
+ ->method( 'isOpen' )
+ ->will( $this->returnValue( true ) );
+ return $databaseMysql;
+ }
+}
diff --git a/Echo/tests/phpunit/includes/ContainmentSetTest.php b/Echo/tests/phpunit/includes/ContainmentSetTest.php
new file mode 100644
index 00000000..5c17f58f
--- /dev/null
+++ b/Echo/tests/phpunit/includes/ContainmentSetTest.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @group Echo
+ */
+class ContainmentSetTest extends MediaWikiTestCase {
+
+ public function testGenericContains() {
+ $list = new EchoContainmentSet();
+
+ $list->addArray( array( 'foo', 'bar' ) );
+ $this->assertTrue( $list->contains( 'foo' ) );
+ $this->assertTrue( $list->contains( 'bar' ) );
+ $this->assertFalse( $list->contains( 'whammo' ) );
+
+ $list->addArray( array( 'whammo' ) );
+ $this->assertTrue( $list->contains( 'whammo' ) );
+ }
+
+ public function testCachedListInnerListIsOnlyCalledOnce() {
+
+ // the global $wgMemc during tests is an EmptyBagOStuff, so it
+ // wont do anything. We use a HashBagOStuff to get more like a real
+ // client
+ $innerCache = new HashBagOStuff;
+
+ $inner = array( 'bing', 'bang' );
+ // We use a mock instead of the real thing for the $this->once() assertion
+ // verifying that the cache doesn't just keep asking the inner object
+ $list = $this->getMockBuilder('EchoArrayList')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $list->expects( $this->once() )
+ ->method( 'getValues' )
+ ->will( $this->returnValue( $inner ) );
+
+ $cached = new EchoCachedList( $innerCache, 'test_key', $list );
+
+ // First run through should hit the main list, and save to innerCache
+ $this->assertEquals( $inner, $cached->getValues() );
+ $this->assertEquals( $inner, $cached->getValues() );
+
+ // Reinitialize to get a fresh instance that will pull directly from
+ // innerCache without hitting the $list
+ $freshCached = new EchoCachedList( $innerCache, 'test_key', $list );
+ $this->assertEquals( $inner, $freshCached->getValues() );
+ }
+
+ /**
+ * @Database
+ */
+ public function testOnWikiList() {
+ $this->editPage( 'User:Foo/Bar-baz', "abc\ndef\r\nghi\n\n\n" );
+
+ $list = new EchoOnWikiList( NS_USER, "Foo/Bar-baz" );
+ $this->assertEquals(
+ array( 'abc', 'def', 'ghi' ),
+ $list->getValues()
+ );
+ }
+
+ public function testOnWikiListNonExistant() {
+ $list = new EchoOnWikiList( NS_USER, "Some_Non_Existant_Page" );
+ $this->assertEquals( array(), $list->getValues() );
+ }
+
+ protected function editPage( $pageName, $text, $summary = '', $defaultNs = NS_MAIN ) {
+ $title = Title::newFromText( $pageName, $defaultNs );
+ $page = WikiPage::factory( $title );
+
+ return $page->doEditContent( ContentHandler::makeContent( $text, $title ), $summary );
+ }
+}
diff --git a/Echo/tests/phpunit/includes/DiffParserTest.php b/Echo/tests/phpunit/includes/DiffParserTest.php
new file mode 100644
index 00000000..7db7de88
--- /dev/null
+++ b/Echo/tests/phpunit/includes/DiffParserTest.php
@@ -0,0 +1,190 @@
+<?php
+
+/**
+ * @group Echo
+ */
+class EchoDiffParserTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider provider_getChangeSet
+ */
+ public function testGetChangeSet( $message, array $expect, $leftText, $rightText ) {
+ $changeSet = EchoDiscussionParser::getMachineReadableDiff( $leftText, $rightText );
+ unset( $changeSet['_info'] );
+ $this->assertEquals( $expect, $changeSet, $message );
+ }
+
+ static public function provider_getChangeSet() {
+ return array(
+
+ array(
+ 'Duplicate content must generate no changes',
+ // Expected change set
+ array(),
+ // Left text
+ "a\nb\nc",
+ // Right text
+ "a\nb\nc",
+ ),
+
+ array(
+ 'Removing blank lines must generate no changes',
+ // Expected change set
+ array(),
+ // Left text
+ "a\n\nb\n\nc",
+ // Right text
+ "a\nb\nc\n",
+ ),
+
+ array(
+ 'Must generate a single add change with only lines added',
+ // Expected change set
+ array( self::mockAction( 'add', "foo\nbar", 1 ) ),
+ // Left
+ "something",
+ // Right
+ "foo\nbar\nsomething",
+ ),
+
+ array(
+ 'Must generate a single subtract change with only lines subtracted',
+ // Expected change set
+ array( self::mockAction( 'subtract', "Zomg\nHiHiHi", 2 ) ),
+ // Left
+ "dummy\nZomg\nHiHiHi",
+ // Right
+ "dummy",
+ ),
+
+ array(
+ 'Adding content seperated by no change must generate multiple changes',
+ // Expected change set
+ array(
+ self::mockAction( 'add', 'b1', 3 ),
+ self::mockAction( 'add', "d1\nd2", 5, 6 ),
+ ),
+ // Left text
+ "a\nb\nc\nd\ne\nf",
+ // Right text
+ "a\nb\nb1\nc\nd\nd1\nd2\ne\nf",
+ ),
+
+ array(
+ 'Extra blank lines on the edges must be trimmed',
+ // Expected change set
+ array( self::mockAction( 'add', "Zomg\nHiHiHi", 1 ) ),
+ // Left text
+ "",
+ // Right text
+ "\nZomg\nHiHiHi\n",
+ ),
+
+ array(
+ 'Extra blank lines inside the content must not be trimmed',
+ // Expected change set
+ array( self::mockAction( 'add', "\nZomg\nHiHiHi\n", 2 ) ),
+ // Left text
+ "foo\nbar",
+ // Right text
+ "foo\n\nZomg\nHiHiHi\n\nbar",
+ ),
+
+ array(
+ 'A blank line replaced with content must be an add',
+ // Expected change set
+ array( self::mockAction( 'add', 'cowbell', 1 ) ),
+ // Left Text
+ "",
+ // Right Text
+ "cowbell",
+ ),
+
+ array(
+ 'A blanked out line must be a subtraction',
+ // Expected change set
+ array( self::mockAction( 'subtract', 'cowbell', 1 ) ),
+ // Left text
+ "cowbell",
+ // Right text
+ "",
+ ),
+
+ array(
+ 'A line with its content replaced must be a change',
+ // Expected change set
+ array( self::mockChange( 'Its all about the journey', 'dummy', 1 ) ),
+ // Left text
+ "Its all about the journey",
+ // Right text
+ "dummy",
+ ),
+
+ array(
+ 'Changing lines and adding more must result in two changes',
+ // Expected change set
+ array(
+ self::mockChange( 'Must be in a hurry to finish this thing', 'Must be in a hurry', 1 ),
+ self::mockAction( 'add', 'Finish this thing', 2 ),
+ ),
+ // Left text
+ "Must be in a hurry to finish this thing",
+ // Right text
+ "Must be in a hurry\nFinish this thing",
+ ),
+
+ array(
+ 'Changing multiple lines and adding more must result in two changes',
+ // Expected change set
+ array(
+ self::mockChange( "Must not be\nin much of a hurry", "Must be\nin a hurry", 2 ),
+ self::mockAction( 'subtract', "to finish\nthis thing", 4 ),
+ ),
+ // Left text
+ "abc\nMust not be\nin much of a hurry\nto finish\nthis thing",
+ // Right text
+ "abc\nMust be\nin a hurry",
+ ),
+
+ array(
+ 'Must generate multiple add, change, and subtract actions',
+ // Expected change set
+ array(
+ self::mockChange( "abc\nSome", "Other\nThings", 1 ),
+ self::mockAction( 'subtract', "Stuff", 3 ),
+ self::mockChange( "And\nThen", "There\nWas", 6, 5 ),
+ self::mockAction( 'add', 'Fencing', 8, 7 ),
+ ),
+ // Left text
+ "abc\nSome\nStuff\ndef\nghi\nAnd\nThen\njkl\nmno",
+ // Right text
+ "\nOther\nThings\ndef\nghi\nThere\nWas\nFencing\njkl\nmno",
+ ),
+ );
+ }
+
+ static protected function mockAction( $action, $content, $left, $right = null ) {
+ if ( $right === null ) {
+ $right = $left;
+ }
+ return array(
+ 'action' => $action,
+ 'content' => $content,
+ 'left-pos' => $left,
+ 'right-pos' => $right,
+ );
+ }
+
+ static public function mockChange( $oldContent, $newContent, $left, $right = null ) {
+ if ( $right === null ) {
+ $right = $left;
+ }
+ return array(
+ 'action' => 'change',
+ 'old_content' => $oldContent,
+ 'new_content' => $newContent,
+ 'left-pos' => $left,
+ 'right-pos' => $right,
+ );
+ }
+}
diff --git a/Echo/tests/phpunit/includes/DiscussionParserTest.php b/Echo/tests/phpunit/includes/DiscussionParserTest.php
new file mode 100644
index 00000000..0b9f3c12
--- /dev/null
+++ b/Echo/tests/phpunit/includes/DiscussionParserTest.php
@@ -0,0 +1,1084 @@
+<?php
+
+/**
+ * @group Echo
+ * @group Database
+ */
+class EchoDiscussionParserTest extends MediaWikiTestCase {
+ /**
+ * @var array
+ */
+ protected $tablesUsed = array( 'user', 'revision', 'text', 'page' );
+
+ /**
+ * Users used in these tests: signature extraction, mentioned users, ... all
+ * assume a user exists.
+ *
+ * @var array [username => [user preference => preference value]]
+ */
+ protected $testUsers = array(
+ // username
+ 'Werdna' => array(
+ // user preferences
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'Werdna2' => array(
+ 'nickname' => '[[User:Werdna2|Andrew]]',
+ 'fancysig' => '1',
+ ),
+ 'Werdna3' => array(
+ 'nickname' => '[[User talk:Werdna3|Andrew]]',
+ 'fancysig' => '1',
+ ),
+ 'Werdna4' => array(
+ 'nickname' => '[[User:Werdna4|wer]dna]]',
+ 'fancysig' => '1',
+ ),
+ 'We buried our secrets in the garden' => array(
+ 'nickname' => '[[User talk:We buried our secrets in the garden#top|wbositg]]',
+ 'fancysig' => '1',
+ ),
+ 'I Heart Spaces' => array(
+ 'nickname' => '[[User:I_Heart_Spaces]] ([[User_talk:I_Heart_Spaces]])',
+ 'fancysig' => '1',
+ ),
+ 'Jam' => array(
+ 'nickname' => '[[User:Jam]]',
+ 'fancysig' => '1',
+ ),
+ 'Reverta-me' => array(
+ 'nickname' => "[[User:Reverta-me|<span style=\"font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;\">Aaaaa Bbbbbbb</span>]]'' <sup>[[User Talk:Reverta-me|<font color=\"gold\" face=\"Lucida Calligraphy\">Discussão</font>]]</sup>''",
+ 'fancysig' => '1',
+ ),
+ 'Jorm' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'Jdforrester' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'DarTar' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'Bsitu' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'JarJar' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'Schnark' => array(
+ 'nickname' => '[[Benutzer:Schnark]] ([[Benutzer:Schnark/js|js]])',
+ 'fancysig' => '1',
+ ),
+ 'Cwobeel' => array(
+ 'nickname' => '[[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]]',
+ 'fancysig' => '1',
+ ),
+ 'Bob K31416' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'X" onclick="alert(\'XSS\');" title="y' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'He7d3r' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'PauloEduardo' => array(
+ 'nickname' => "[[User:PauloEduardo|<span style=\"font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;\">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color=\"gold\" face=\"Lucida Calligraphy\">Discussão</font>]]</sup>''",
+ 'fancysig' => '1',
+ ),
+ 'PatHadley' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'Samwalton9' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'Kudpung' => array(
+ 'nickname' => '[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]])',
+ 'fancysig' => '1',
+ ),
+ 'Jim Carter' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ 'Buster7' => array(
+ 'nickname' => '',
+ 'fancysig' => '0',
+ ),
+ );
+
+ protected function setUp() {
+ parent::setUp();
+
+ // we only need to add these users once, we won't (can't) tear them down anyway
+ static $executed = false;
+ if ( $executed === true ) {
+ return;
+ }
+
+ foreach ( $this->testUsers as $username => $preferences ) {
+ $user = User::createNew( $username );
+
+ // set signature preferences
+ if ( $user ) {
+ foreach ( $preferences as $option => $value ) {
+ $user->setOption( $option, $value );
+ }
+ $user->saveSettings();
+ }
+ }
+
+ $executed = true;
+ }
+
+ protected function tearDown() {
+ parent::tearDown();
+
+ global $wgHooks;
+ unset( $wgHooks['BeforeEchoEventInsert'][999] );
+ }
+
+ public function generateEventsForRevisionData() {
+ return array(
+ array(
+ 'new' => 637638133,
+ 'old' => 637637213,
+ 'username' => 'Cwobeel',
+ 'lang' => 'en',
+ 'pages' => array(
+ // pages expected to exist (e.g. templates to be expanded)
+ 'Template:u' => '[[User:{{{1}}}|{{<includeonly>safesubst:</includeonly>#if:{{{2|}}}|{{{2}}}|{{{1}}}}}]]<noinclude>{{documentation}}</noinclude>',
+ ),
+ 'title' => 'UTPage', // can't remember, not important here
+ 'expected' => array(
+ // events expected to be fired going from old revision to new
+ array(
+ 'type' => 'mention',
+ 'agent' => 'Cwobeel',
+ /*
+ * I wish I could also compare EchoEvent::$extra data to
+ * compare user ids of mentioned users. However, due to
+ * How PHPUnit works, setUp won't be run by the time
+ * this dataset is generated, so we don't yet know the
+ * user ids of the folks we're about to insert...
+ * I'll skip that part for now.
+ */
+ ),
+ ),
+ ),
+ array(
+ 'new' => 138275105,
+ 'old' => 138274875,
+ 'username' => 'Schnark',
+ 'lang' => 'de',
+ 'pages' => array(),
+ 'title' => 'UTPage', // can't remember, not important here
+ 'expected' => array(
+ array(
+ 'type' => 'mention',
+ 'agent' => 'Schnark',
+ ),
+ ),
+ ),
+ array(
+ 'new' => 40610292,
+ 'old' => 40608353,
+ 'username' => 'PauloEduardo',
+ 'lang' => 'pt',
+ 'pages' => array(
+ 'Predefinição:U' => '[[User:{{{1|<noinclude>Exemplo</noinclude>}}}|{{{{{|safesubst:}}}#if:{{{2|}}}|{{{2}}}|{{{1|<noinclude>Exemplo</noinclude>}}}}}]]<noinclude>{{Atalho|Predefinição:U}}{{Documentação|Predefinição:Usuário/doc}}</noinclude>',
+ ),
+ 'title' => 'UTPage', // can't remember, not important here
+ 'expected' => array(
+ array(
+ 'type' => 'mention',
+ 'agent' => 'PauloEduardo',
+ ),
+ ),
+ ),
+ array(
+ 'new' => 646792804,
+ 'old' => 646790570,
+ 'username' => 'PatHadley',
+ 'lang' => 'en',
+ 'pages' => array(
+ 'Template:ping' => '{{SAFESUBST:<noinclude />#if:{{{1|<noinclude>$</noinclude>}}}
+ |<span class="template-ping">@[[:User:{{SAFESUBST:<noinclude />BASEPAGENAME:{{{1|Example}}}}}|{{SAFESUBST:<noinclude />BASEPAGENAME:{{{label1|{{{1|Example}}}}}}}}]]{{SAFESUBST:<noinclude />#if:{{{2|}}}
+ |, [[:User:{{SAFESUBST:<noinclude />BASEPAGENAME:{{{2|Example}}}}}|{{SAFESUBST:<noinclude />BASEPAGENAME:{{{label2|{{{2|Example}}}}}}}}]]{{SAFESUBST:<noinclude />#if:{{{3|}}}
+ |, [[:User:{{SAFESUBST:<noinclude />BASEPAGENAME:{{{3|Example}}}}}|{{SAFESUBST:<noinclude />BASEPAGENAME:{{{label3|{{{3|Example}}}}}}}}]]{{SAFESUBST:<noinclude />#if:{{{4|}}}
+ |, [[:User:{{SAFESUBST:<noinclude />BASEPAGENAME:{{{4|Example}}}}}|{{SAFESUBST:<noinclude />BASEPAGENAME:{{{label4|{{{4|Example}}}}}}}}]]{{SAFESUBST:<noinclude />#if:{{{5|}}}
+ |, [[:User:{{SAFESUBST:<noinclude />BASEPAGENAME:{{{5|Example}}}}}|{{SAFESUBST:<noinclude />BASEPAGENAME:{{{label5|{{{5|Example}}}}}}}}]]{{SAFESUBST:<noinclude />#if:{{{6|}}}
+ |, [[:User:{{SAFESUBST:<noinclude />BASEPAGENAME:{{{6|Example}}}}}|{{SAFESUBST:<noinclude />BASEPAGENAME:{{{label6|{{{6|Example}}}}}}}}]]{{SAFESUBST:<noinclude />#if:{{{7|}}}
+ |, [[:User:{{SAFESUBST:<noinclude />BASEPAGENAME:{{{7|Example}}}}}|{{SAFESUBST:<noinclude />BASEPAGENAME:{{{label7|{{{7|Example}}}}}}}}]]
+ }}
+ }}
+ }}
+ }}
+ }}
+ }}{{{p|:}}}</span>
+ |{{SAFESUBST:<noinclude />Error|Error in [[Template:Replyto]]: Username not given.}}
+}}<noinclude>
+
+{{documentation}}
+</noinclude>',
+ 'MediaWiki:Signature' => '[[User:$1|$2]] {{#ifeq:{{FULLPAGENAME}}|User talk:$1|([[User talk:$1#top|talk]])|([[User talk:$1|talk]])}}',
+ ),
+ 'title' => 'User_talk:PatHadley',
+ 'expected' => array(
+ array(
+ 'type' => 'mention',
+ 'agent' => 'PatHadley',
+ ),
+ array(
+ 'type' => 'edit-user-talk',
+ 'agent' => 'PatHadley',
+ ),
+ ),
+ 'precondition' => 'isParserFunctionsInstalled',
+ ),
+ array(
+ 'new' => 647260329,
+ 'old' => 647258025,
+ 'username' => 'Kudpung',
+ 'lang' => 'en',
+ 'pages' => array(
+ 'Template:U' => '[[User:{{{1}}}|{{<includeonly>safesubst:</includeonly>#if:{{{2|}}}|{{{2}}}|{{{1}}}}}]]<noinclude>{{documentation}}</noinclude>',
+ ),
+ 'title' => 'User_talk:Kudpung',
+ 'expected' => array(
+ array(
+ 'type' => 'mention',
+ 'agent' => 'Kudpung',
+ ),
+ array(
+ 'type' => 'edit-user-talk',
+ 'agent' => 'Kudpung',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider generateEventsForRevisionData
+ */
+ public function testGenerateEventsForRevision( $newId, $oldId, $username, $lang, $pages, $title, $expected, $precondition = '' ) {
+ if ( $precondition !== '' ) {
+ $result = $this->$precondition();
+ if ( $result !== true ) {
+ $this->markTestSkipped( $result );
+ return;
+ }
+ }
+
+ $this->setMwGlobals( array(
+ // this global is used by the code that interprets the namespace part of
+ // titles (Title::getTitleParser), so should be the fake language ;)
+ 'wgContLang' => Language::factory( $lang ),
+ // this one allows Mediawiki:xyz pages to be set as messages
+ 'wgUseDatabaseMessages' => true
+ ) );
+
+ // pages to be created: templates may be used to ping users (e.g.
+ // {{u|...}}) but if we don't have that template, it just won't work!
+ $pages += array( $title => '' );
+ foreach ( $pages as $pageTitle => $pageText ) {
+ $template = WikiPage::factory( Title::newFromText( $pageTitle ) );
+ $template->doEditContent( new WikitextContent( $pageText ), '' );
+ }
+
+ // force i18n messages to be reloaded (from DB, where a new message
+ // might have been created as page)
+ MessageCache::destroyInstance();
+
+ // grab revision excerpts (didn't include them in this src file because
+ // they can be pretty long)
+ $oldText = file_get_contents( __DIR__ . '/revision_txt/' . $oldId . '.txt' );
+ $newText = file_get_contents( __DIR__ . '/revision_txt/' . $newId . '.txt' );
+
+ // revision texts can be in different languages, where links etc are
+ // different (e.g. User: becomes Benutzer: in German), so let's pretend
+ // the page they belong to is from that language
+ $title = Title::newFromText( $title );
+ $object = new ReflectionObject( $title );
+ $property = $object->getProperty( 'mDbPageLanguage' );
+ $property->setAccessible( true );
+ $property->setValue( $title, $lang );
+
+ // create stub Revision object
+ $row = array(
+ 'id' => $newId,
+ 'user_text' => $username,
+ 'user' => User::newFromName( $username )->getId(),
+ 'parent_id' => $oldId,
+ 'text' => $newText,
+ 'title' => $title,
+ );
+ $revision = Revision::newFromRow( $row );
+
+ // generate diff between 2 revisions
+ $changes = EchoDiscussionParser::getMachineReadableDiff( $oldText, $newText );
+ $output = EchoDiscussionParser::interpretDiff( $changes, $revision->getUserText(), $title );
+
+ // store diff in some local cache var, to circumvent
+ // EchoDiscussionParser::getChangeInterpretationForRevision's attempt to
+ // retrieve parent revision from DB
+ $class = new ReflectionClass( 'EchoDiscussionParser' );
+ $property = $class->getProperty( 'revisionInterpretationCache' );
+ $property->setAccessible( true );
+ $property->setValue( array( $revision->getId() => $output ) );
+
+ // to catch the generated event, I'm going to attach a callback to the
+ // hook that's being run just prior to sending the notifications out
+ $events = array();
+ $callback = function( EchoEvent $event ) use ( &$events ) {
+ $events[] = array(
+ 'type' => $event->getType(),
+ 'agent' => $event->getAgent()->getName(),
+ );
+
+ // don't let the event go out, abort from within this hook
+ return false;
+ };
+
+ // can't use setMwGlobals here, so I'll just re-attach to the same key
+ // for every dataProvider value (and don't worry, I'm removing it on
+ // tearDown too - I just felt the attaching should be happening here
+ // instead of on setUp, or code would get too messy)
+ global $wgHooks;
+ $wgHooks['BeforeEchoEventInsert'][999] = $callback;
+
+ // finally, dear god, start generating the events already!
+ EchoDiscussionParser::generateEventsForRevision( $revision );
+
+ $this->assertEquals( $expected, $events );
+ }
+
+ // TODO test cases for:
+ // - stripHeader
+ // - stripIndents
+ // - stripSignature
+ // - getNotifiedUsersForComment
+
+ public function testDiscussionParserAcceptsInternalDiff() {
+ global $wgDiff;
+
+ $origWgDiff = $wgDiff;
+ $wgDiff = '/does/not/exist/or/at/least/we/hope/not';
+ try {
+ $res = EchoDiscussionParser::getMachineReadableDiff(
+ <<<TEXT
+line 1
+line 2
+line 3
+line 4
+TEXT
+ ,
+ <<<TEXT
+line 1
+line c
+line 4
+TEXT
+ );
+ } catch ( MWException $e ) {
+ $wgDiff = $origWgDiff;
+ throw $e;
+ }
+ $wgDiff = $origWgDiff;
+
+ // Test failure occurs when MWException is thrown due to parsing failure
+ $this->assertTrue( true );
+ }
+
+ public function testTimestampRegex() {
+ $exemplarTimestamp = self::getExemplarTimestamp();
+ $timestampRegex = EchoDiscussionParser::getTimestampRegex();
+
+ $match = preg_match( '/' . $timestampRegex . '/u', $exemplarTimestamp );
+ $this->assertEquals( 1, $match );
+ }
+
+ public function testGetTimestampPosition() {
+ $line = 'Hello World. '. self::getExemplarTimestamp();
+ $pos = EchoDiscussionParser::getTimestampPosition( $line );
+ $this->assertEquals( 13, $pos );
+ }
+
+ /**
+ * @dataProvider signingDetectionData
+ * FIXME some of the app logic is in the test...
+ */
+ public function testSigningDetection( $line, $expectedUser ) {
+ if ( !EchoDiscussionParser::isSignedComment( $line ) ) {
+ $this->assertEquals( $expectedUser, false );
+ return;
+ }
+
+ $output = EchoDiscussionParser::getUserFromLine( $line );
+
+ if ( $output === false ) {
+ $this->assertEquals( false, $expectedUser );
+ } elseif ( is_array( $expectedUser ) ) {
+ // Sometimes testing for correct user detection,
+ // sometimes testing for offset detection
+ $this->assertEquals( $expectedUser, $output );
+ } else {
+ $this->assertEquals( $expectedUser, $output[1] );
+ }
+ }
+
+ public function signingDetectionData() {
+ $ts = self::getExemplarTimestamp();
+ return array(
+ // Basic
+ array(
+ "I like this. [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ array(
+ 13,
+ 'Werdna'
+ ),
+ ),
+ // Confounding
+ array(
+ "[[User:Jorm]] is a meanie. --[[User:Werdna2|Andrew]] $ts",
+ array(
+ 29,
+ "Werdna2"
+ ),
+ ),
+ // Talk page link only
+ array(
+ "[[User:Swalling|Steve]] is the best person I have ever met. --[[User talk:Werdna3|Andrew]] $ts",
+ array(
+ 62,
+ 'Werdna3'
+ ),
+ ),
+ // Anonymous user
+ array(
+ "I am anonymous because I like my IP address. --[[Special:Contributions/127.0.0.1|127.0.0.1]] $ts",
+ array(
+ 47,
+ '127.0.0.1'
+ ),
+ ),
+ // No signature
+ array(
+ "Well, \nI do think that [[User:Newyorkbrad]] is pretty cool, but what do I know?",
+ false
+ ),
+ // Hash symbols in usernames
+ array(
+ "What do you think? [[User talk:We buried our secrets in the garden#top|wbositg]] $ts",
+ array(
+ 19,
+ 'We buried our secrets in the garden'
+ ),
+ ),
+ // Title that gets normalized different than it is provided in the wikitext
+ array(
+ "Beep boop [[User:I_Heart_Spaces]] ([[User_talk:I_Heart_Spaces]]) $ts",
+ array(
+ strlen( "Beep boop " ),
+ 'I Heart Spaces'
+ ),
+ ),
+ // Accepts ] in the pipe
+ array(
+ "Shake n Bake --[[User:Werdna4|wer]dna]] $ts",
+ array(
+ strlen( "Shake n Bake --" ),
+ 'Werdna4',
+ ),
+ ),
+
+ array(
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxã? [[User:Jam]] $ts",
+ array(
+ strlen( "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxã? " ),
+ "Jam"
+ ),
+ ),
+ // extra long signature
+ array(
+ "{{U|He7d3r}}, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxã? [[User:Reverta-me|<span style=\"font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;\">Aaaaa Bbbbbbb</span>]]'' <sup>[[User Talk:Reverta-me|<font color=\"gold\" face=\"Lucida Calligraphy\">Discussão</font>]]</sup>''",
+ array(
+ strlen( "{{U|He7d3r}}, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxã? " ),
+ 'Reverta-me',
+ ),
+ ),
+ // Bug: T87852
+ array(
+ "Test --[[Benutzer:Schnark]] ([[Benutzer:Schnark/js|js]])",
+ array(
+ strlen( "Test --" ),
+ 'Schnark',
+ ),
+ ),
+ // when adding additional tests, make sure to add the non-anon users
+ // to EchoDiscussionParserTest::$testusers - the DiscussionParser
+ // needs the users to exist, because it'll generate a comparison
+ // signature, which is different when the user is considered anon
+ );
+ }
+
+ /** @dataProvider diffData */
+ public function testDiff( $oldText, $newText, $expected ) {
+ $actual = EchoDiscussionParser::getMachineReadableDiff( $oldText, $newText );
+ unset( $actual['_info'] );
+ unset( $expected['_info'] );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function diffData() {
+ return array(
+ array(
+ <<<TEXT
+line 1
+line 2
+line 3
+line 4
+TEXT
+ ,<<<TEXT
+line 1
+line 3
+line 4
+TEXT
+ ,
+ array( array(
+ 'action' => 'subtract',
+ 'content' => 'line 2',
+ 'left-pos' => 2,
+ 'right-pos' => 2,
+ ) )
+ ),
+ array(
+ <<<TEXT
+line 1
+line 2
+line 3
+line 4
+TEXT
+ ,<<<TEXT
+line 1
+line 2
+line 2.5
+line 3
+line 4
+TEXT
+ ,
+ array( array(
+ 'action' => 'add',
+ 'content' => 'line 2.5',
+ 'left-pos' => 3,
+ 'right-pos' => 3,
+ ) )
+ ),
+ array(
+ <<<TEXT
+line 1
+line 2
+line 3
+line 4
+TEXT
+ ,<<<TEXT
+line 1
+line b
+line 3
+line 4
+TEXT
+ ,
+ array( array(
+ 'action' => 'change',
+ 'old_content' => 'line 2',
+ 'new_content' => 'line b',
+ 'left-pos' => 2,
+ 'right-pos' => 2,
+ ) )
+ ),
+ array(
+ <<<TEXT
+line 1
+line 2
+line 3
+line 4
+TEXT
+ ,<<<TEXT
+line 1
+line b
+line c
+line d
+line 3
+line 4
+TEXT
+ ,
+ array(
+ array(
+ 'action' => 'change',
+ 'old_content' => 'line 2',
+ 'new_content' => 'line b',
+ 'left-pos' => 2,
+ 'right-pos' => 2,
+ ),
+ array(
+ 'action' => 'add',
+ 'content' => 'line c
+line d',
+ 'left-pos' => 3,
+ 'right-pos' => 3,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /** @dataProvider annotationData */
+ public function testAnnotation( $message, $diff, $user, $expectedAnnotation ) {
+ $actual = EchoDiscussionParser::interpretDiff( $diff, $user );
+ $this->assertEquals( $expectedAnnotation, $actual, $message );
+ }
+
+ public function annotationData() {
+ $ts = self::getExemplarTimestamp();
+
+ return array(
+
+ array(
+ 'Must detect added comments',
+ // Diff
+ array(
+ // Action
+ array(
+ 'action' => 'add',
+ 'content' => ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ 'left-pos' => 3,
+ 'right-pos' => 3,
+ ),
+ '_info' => array(
+ 'lhs' => array(
+ '== Section 1 ==',
+ "I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts",
+ ),
+ 'rhs' => array(
+ '== Section 1 ==',
+ "I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts",
+ ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ ),
+ ),
+ ),
+ // User
+ 'Werdna',
+ // Expected annotation
+ array(
+ array(
+ 'type' => 'add-comment',
+ 'content' => ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ 'full-section' => <<<TEXT
+== Section 1 ==
+I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts
+:What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts
+TEXT
+ ),
+ ),
+ ),
+
+ array(
+ 'Full Section must not include the following pre-existing section',
+ // Diff
+ array(
+ // Action
+ array(
+ 'action' => 'add',
+ 'content' => ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ 'left-pos' => 3,
+ 'right-pos' => 3,
+ ),
+ '_info' => array(
+ 'lhs' => array(
+ '== Section 1 ==',
+ "I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts",
+ '== Section 2 ==',
+ "Well well well. [[User:DarTar|DarTar]] ([[User talk:DarTar|talk]]) $ts",
+ ),
+ 'rhs' => array(
+ '== Section 1 ==',
+ "I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts",
+ ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ '== Section 2 ==',
+ "Well well well. [[User:DarTar|DarTar]] ([[User talk:DarTar|talk]]) $ts",
+ ),
+ ),
+ ),
+ // User
+ 'Werdna',
+ // Expected annotation
+ array(
+ array(
+ 'type' => 'add-comment',
+ 'content' => ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ 'full-section' => <<<TEXT
+== Section 1 ==
+I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts
+:What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts
+TEXT
+ ),
+ ),
+ ),
+
+ array(
+ 'Must detect new-section-with-comment when a new section is added',
+ // Diff
+ array(
+ // Action
+ array(
+ 'action' => 'add',
+ 'content' => <<<TEXT
+== Section 1a ==
+Hmmm? [[User:Jdforrester|Jdforrester]] ([[User talk:Jdforrester|talk]]) $ts
+TEXT
+ ,
+ 'left-pos' => 4,
+ 'right-pos' => 4,
+ ),
+ '_info' => array(
+ 'lhs' => array(
+ '== Section 1 ==',
+ "I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts",
+ ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ '== Section 2 ==',
+ "Well well well. [[User:DarTar|DarTar]] ([[User talk:DarTar|talk]]) $ts",
+ ),
+ 'rhs' => array(
+ '== Section 1 ==',
+ "I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts",
+ ":What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts",
+ '== Section 1a ==',
+ 'Hmmm? [[User:Jdforrester|Jdforrester]] ([[User talk:Jdforrested|talk]]) $ts',
+ '== Section 2 ==',
+ "Well well well. [[User:DarTar|DarTar]] ([[User talk:DarTar|talk]]) $ts",
+ ),
+ ),
+ ),
+ // User
+ 'Jdforrester',
+ // Expected annotation
+ array(
+ array(
+ 'type' => 'new-section-with-comment',
+ 'content' => <<<TEXT
+== Section 1a ==
+Hmmm? [[User:Jdforrester|Jdforrester]] ([[User talk:Jdforrester|talk]]) $ts
+TEXT
+ ,
+ ),
+ ),
+ ),
+
+ array(
+ 'Must detect multiple added comments when multiple sections are edited',
+ EchoDiscussionParser::getMachineReadableDiff(
+ <<<TEXT
+== Section 1 ==
+I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts
+:What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts
+== Section 2 ==
+Well well well. [[User:DarTar|DarTar]] ([[User talk:DarTar|talk]]) $ts
+== Section 3 ==
+Hai [[User:Bsitu|Bsitu]] ([[User talk:Bsitu|talk]]) $ts
+TEXT
+ ,
+ <<<TEXT
+== Section 1 ==
+I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts
+:What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts
+:New Comment [[User:JarJar|JarJar]] ([[User talk:JarJar|talk]]) $ts
+== Section 2 ==
+Well well well. [[User:DarTar|DarTar]] ([[User talk:DarTar|talk]]) $ts
+== Section 3 ==
+Hai [[User:Bsitu|Bsitu]] ([[User talk:Bsitu|talk]]) $ts
+:Other New Comment [[User:JarJar|JarJar]] ([[User talk:JarJar|talk]]) $ts
+TEXT
+ ),
+ // User
+ 'JarJar',
+ // Expected annotation
+ array(
+ array(
+ 'type' => 'add-comment',
+ 'content' => ":New Comment [[User:JarJar|JarJar]] ([[User talk:JarJar|talk]]) $ts",
+ 'full-section' => <<<TEXT
+== Section 1 ==
+I do not like you. [[User:Jorm|Jorm]] ([[User talk:Jorm|talk]]) $ts
+:What do you think? [[User:Werdna|Werdna]] ([[User talk:Werdna|talk]]) $ts
+:New Comment [[User:JarJar|JarJar]] ([[User talk:JarJar|talk]]) $ts
+TEXT
+ ),
+ array(
+ 'type' => 'add-comment',
+ 'content' => ":Other New Comment [[User:JarJar|JarJar]] ([[User talk:JarJar|talk]]) $ts",
+ 'full-section' => <<<TEXT
+== Section 3 ==
+Hai [[User:Bsitu|Bsitu]] ([[User talk:Bsitu|talk]]) $ts
+:Other New Comment [[User:JarJar|JarJar]] ([[User talk:JarJar|talk]]) $ts
+TEXT
+ ),
+ ),
+ ),
+
+ array(
+ 'Bug T78424',
+ EchoDiscussionParser::getMachineReadableDiff(
+ <<<TEXT
+== Washington Post Reception Source ==
+
+''The Boston Post'' source that was used in the reception section has a couple of problems. First, it's actually a repost of ''The Washington Post'', but ''The Washington Post'' doesn't allow the Internet Archive to preserve it. Should it still be sourced to Boston or to Washington? Second, it seems to be a lot of analysis that can't be summed up easily without trimming it out, and doesn't really fit with the reception section and should probably moved next to Wilson's testimony. Any suggestions? --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 01:44, 11 December 2014 (UTC)
+TEXT
+ ,
+ <<<TEXT
+== Washington Post Reception Source ==
+
+''The Boston Post'' source that was used in the reception section has a couple of problems. First, it's actually a repost of ''The Washington Post'', but ''The Washington Post'' doesn't allow the Internet Archive to preserve it. Should it still be sourced to Boston or to Washington? Second, it seems to be a lot of analysis that can't be summed up easily without trimming it out, and doesn't really fit with the reception section and should probably moved next to Wilson's testimony. Any suggestions? --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 01:44, 11 December 2014 (UTC)
+
+== Grand jury no bill reception ==
+
+{{u|Bob K31416}} has started a process of summarizing that section, in a manner that I believe it to be counter productive. We have expert opinions from legal, law enforcement, politicians, and media outlets all of which are notable and informative. [[WP:NOTPAPER|Wikipedia is not paper]] – If the section is too long, the correct process to avoid losing good content that is well sources, is to create a sub-article with all the detail, and summarize here per [[WP:SUMMARY]]. But deleting useful and well sourced material, is not acceptable. We are here to build an encyclopedia. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 16:02, 11 December 2014 (UTC)
+TEXT
+ ),
+ // User
+ 'Cwobeel',
+ // Expected annotation
+ array(
+ array(
+ 'type' => 'new-section-with-comment',
+ 'content' => '== Grand jury no bill reception ==
+
+{{u|Bob K31416}} has started a process of summarizing that section, in a manner that I believe it to be counter productive. We have expert opinions from legal, law enforcement, politicians, and media outlets all of which are notable and informative. [[WP:NOTPAPER|Wikipedia is not paper]] – If the section is too long, the correct process to avoid losing good content that is well sources, is to create a sub-article with all the detail, and summarize here per [[WP:SUMMARY]]. But deleting useful and well sourced material, is not acceptable. We are here to build an encyclopedia. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 16:02, 11 December 2014 (UTC)',
+ ),
+ ),
+ ),
+ // when adding additional tests, make sure to add the non-anon users
+ // to EchoDiscussionParserTest::$testusers - the DiscussionParser
+ // needs the users to exist, because it'll generate a comparison
+ // signature, which is different when the user is considered anon
+ );
+ }
+
+ public static function getExemplarTimestamp() {
+ $title = Title::newMainPage();
+ $user = User::newFromName( 'Test' );
+ $options = new ParserOptions;
+
+ global $wgParser;
+ $exemplarTimestamp =
+ $wgParser->preSaveTransform( '~~~~~', $title, $user, $options );
+
+ return $exemplarTimestamp;
+ }
+
+ static public function provider_detectSectionTitleAndText() {
+ $name = 'Werdna'; // See EchoDiscussionParserTest::$testusers
+ $comment = self::signedMessage( $name );
+
+ return array(
+ array(
+ 'Must detect first sub heading when inserting in the middle of two sub headings',
+ // expected header content
+ 'Sub Heading 1',
+ // test content format
+ "
+== Heading ==
+$comment
+
+== Sub Heading 1 ==
+$comment
+%s
+
+== Sub Heading 2 ==
+$comment
+ ",
+ // user signing new comment
+ $name
+ ),
+
+ array(
+ 'Must detect second sub heading when inserting in the end of two sub headings',
+ // expected header content
+ 'Sub Heading 2',
+ // test content format
+ "
+== Heading ==
+$comment
+
+== Sub Heading 1 ==
+$comment
+
+== Sub Heading 2 ==
+$comment
+%s
+ ",
+ // user signing new comment
+ $name
+ ),
+
+ array(
+ 'Commenting in multiple sub-headings must result in no section link',
+ // expected header content
+ '',
+ // test content format
+ "
+== Heading ==
+$comment
+
+== Sub Heading 1 ==
+$comment
+%s
+
+== Sub Heading 2 ==
+$comment
+%s
+
+ ",
+ // user signing new comment
+ $name
+ ),
+
+ array(
+ 'Must accept headings without a space between the = and the section name',
+ // expected header content
+ 'Heading',
+ // test content format
+ "
+==Heading==
+$comment
+%s
+ ",
+ // user signing new comment
+ $name
+ ),
+
+ array(
+ 'Must not accept invalid headings split with a return',
+ // expected header content
+ '',
+ // test content format
+ "
+==Some
+Heading==
+$comment
+%s
+ ",
+ // user signing new comment
+ $name
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_detectSectionTitleAndText
+ */
+ public function testDetectSectionTitleAndText( $message, $expect, $format, $name ) {
+ // str_replace because we want to replace multiple instances of '%s' with the same value
+ $before = str_replace( '%s', '', $format );
+ $after = str_replace( '%s', self::signedMessage( $name ), $format );
+
+ $diff = EchoDiscussionParser::getMachineReadableDiff( $before, $after );
+ $interp = EchoDiscussionParser::interpretDiff( $diff, $name );
+
+ // There should be a section-text only if there is section-title
+ $expectText = $expect ? self::message( $name ) : '';
+ $this->assertEquals(
+ array( 'section-title' => $expect, 'section-text' => $expectText ),
+ EchoDiscussionParser::detectSectionTitleAndText( $interp ),
+ $message
+ );
+ }
+
+ protected static function signedMessage( $name ) {
+ return ": " . self::message() . " [[User:$name|$name]] ([[User talk:$name|talk]]) 00:17, 7 May 2013 (UTC)";
+ }
+
+ protected static function message() {
+ return 'foo';
+ }
+
+ static public function provider_getFullSection() {
+ $tests = array(
+ array(
+ 'Extracts full section',
+ // Full document content
+ <<<TEXT
+==Header 1==
+foo
+===Header 2===
+bar
+==Header 3==
+baz
+TEXT
+ ,
+ // Map of Line numbers to expanded section content
+ array(
+ 1 => "==Header 1==\nfoo",
+ 2 => "==Header 1==\nfoo",
+ 3 => "===Header 2===\nbar",
+ 4 => "===Header 2===\nbar",
+ 5 => "==Header 3==\nbaz",
+ 6 => "==Header 3==\nbaz",
+ ),
+ ),
+ );
+
+ // Allow for setting an array of line numbers to expand from rather than
+ // just a single line number
+ $retval = array();
+ foreach ( $tests as $test ) {
+ foreach ( $test[2] as $lineNum => $expected ) {
+ $retval[] = array(
+ $test[0],
+ $expected,
+ $test[1],
+ $lineNum,
+ );
+ }
+ }
+
+ return $retval;
+ }
+
+ /**
+ * @dataProvider provider_getFullSection
+ */
+ public function testGetFullSection( $message, $expect, $lines, $startLineNum ) {
+ $section = EchoDiscussionParser::getFullSection( explode( "\n", $lines ), $startLineNum );
+ $this->assertEquals( $expect, $section, $message );
+ }
+
+ public function testGetSectionCount() {
+ $one = "==Zomg==\nfoobar\n";
+ $two = "===SubZomg===\nHi there\n";
+ $three = "==Header==\nOh Hai!\n";
+
+ $this->assertEquals( 1, EchoDiscussionParser::getSectionCount( $one ) );
+ $this->assertEquals( 2, EchoDiscussionParser::getSectionCount( $one . $two ) );
+ $this->assertEquals( 2, EchoDiscussionParser::getSectionCount( $one . $three ) );
+ $this->assertEquals( 3, EchoDiscussionParser::getSectionCount( $one . $two . $three ) );
+ }
+
+ protected function isParserFunctionsInstalled() {
+ if ( class_exists( 'ExtParserFunctions' ) ) {
+ return true;
+ } else {
+ return "ParserFunctions not enabled";
+ }
+ }
+}
diff --git a/Echo/tests/phpunit/includes/EchoDbFactoryTest.php b/Echo/tests/phpunit/includes/EchoDbFactoryTest.php
new file mode 100644
index 00000000..61cffabf
--- /dev/null
+++ b/Echo/tests/phpunit/includes/EchoDbFactoryTest.php
@@ -0,0 +1,29 @@
+<?php
+
+class MWEchoDbFactoryTest extends MediaWikiTestCase {
+
+ public function testNewFromDefault() {
+ $db = MWEchoDbFactory::newFromDefault();
+ $this->assertInstanceOf( 'MWEchoDbFactory', $db );
+ return $db;
+ }
+
+ /**
+ * @depends testNewFromDefault
+ */
+ public function testGetEchoDb( MWEchoDbFactory $db ) {
+ $this->assertInstanceOf( 'DatabaseBase', $db->getEchoDb( DB_MASTER ) );
+ $this->assertInstanceOf( 'DatabaseBase', $db->getEchoDb( DB_SLAVE ) );
+ }
+
+ /**
+ * @depends testNewFromDefault
+ */
+ public function testGetLB( MWEchoDbFactory $db ) {
+ $reflection = new ReflectionClass( 'MWEchoDbFactory' );
+ $method = $reflection->getMethod( 'getLB' );
+ $method->setAccessible( true );
+ $this->assertInstanceOf( 'LoadBalancer', $method->invoke( $db ) );
+ }
+
+}
diff --git a/Echo/tests/phpunit/includes/EmailFormatterTest.php b/Echo/tests/phpunit/includes/EmailFormatterTest.php
new file mode 100644
index 00000000..555a0857
--- /dev/null
+++ b/Echo/tests/phpunit/includes/EmailFormatterTest.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @group Echo
+ */
+class EchoEmailFormatterTest extends MediaWikiTestCase {
+
+ private $emailSingle;
+ private $emailDigest;
+
+ public function setUp() {
+ parent::setUp();
+
+ global $wgEchoNotifications;
+
+ $this->setMwGlobals( 'wgAllowHTMLEmail', true );
+ $event = $this->mockEvent( 'edit-user-talk' );
+ $event->expects( $this->any() )
+ ->method( 'getTitle' )
+ ->will( $this->returnValue( Title::newMainPage() ) );
+
+ $formatter = EchoNotificationFormatter::factory( $wgEchoNotifications[$event->getType()] );
+ $formatter->setOutputFormat( 'email' );
+
+ $user = User::newFromId( 1 );
+ $user->setName( 'Test' );
+ $user->setOption( 'echo-email-format', EchoHooks::EMAIL_FORMAT_HTML );
+
+ $this->emailSingle = new EchoEmailSingle( $formatter, $event, $user );
+
+ $content[$event->getCategory()][] = EchoNotificationController::formatNotification( $event, $user, 'email', 'emaildigest' );
+ $this->emailDigest = new EchoEmailDigest( User::newFromId( 2 ), $content );
+ }
+
+ public function testEmailFormatter() {
+ $pattern = '/%%(.*?)%%/is';
+
+ // Single email mode
+ $textFormatter = new EchoTextEmailFormatter( $this->emailSingle );
+ $this->assertRegExp( $pattern, $this->emailSingle->getTextTemplate() );
+ $this->assertEquals( 0, preg_match ( $pattern, $textFormatter->formatEmail() ) );
+
+ $htmlFormatter = new EchoHTMLEmailFormatter( $this->emailSingle );
+ $this->assertRegExp( $pattern, $this->emailSingle->getHTMLTemplate() );
+ $this->assertEquals( 0, preg_match ( $pattern, $htmlFormatter->formatEmail() ) );
+
+ // Digest email mode
+ $textFormatter = new EchoTextEmailFormatter( $this->emailDigest );
+ $this->assertRegExp( $pattern, $this->emailSingle->getTextTemplate() );
+ $this->assertEquals( 0, preg_match ( $pattern, $textFormatter->formatEmail() ) );
+
+ $htmlFormatter = new EchoHTMLEmailFormatter( $this->emailDigest );
+ $this->assertRegExp( $pattern, $this->emailSingle->getHTMLTemplate() );
+ $this->assertEquals( 0, preg_match ( $pattern, $htmlFormatter->formatEmail() ) );
+ }
+
+ public function testBuildAction() {
+ $this->emailSingle->attachDecorator( new EchoTextEmailDecorator() );
+ $this->assertEquals( 0, preg_match ( '/<a /i', $this->emailSingle->buildAction() ) );
+
+ $this->emailSingle->attachDecorator( new EchoHTMLEmailDecorator() );
+ $this->assertRegExp( '/<a /i', $this->emailSingle->buildAction() );
+
+ $this->emailDigest->attachDecorator( new EchoTextEmailDecorator() );
+ $this->assertEquals( 0, preg_match ( '/<a /i', $this->emailDigest->buildAction() ) );
+
+ $this->emailDigest->attachDecorator( new EchoHTMLEmailDecorator() );
+ $this->assertRegExp( '/<a /i', $this->emailDigest->buildAction() );
+ }
+
+ protected function mockEvent( $type ) {
+ $methods = get_class_methods( 'EchoEvent' );
+ $methods = array_diff( $methods, array( 'userCan', 'getLinkMessage', 'getLinkDestination' ) );
+
+ $attribManager = EchoAttributeManager::newFromGlobalVars();
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->setMethods( $methods )
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getType' )
+ ->will( $this->returnValue( $type ) );
+ $event->expects( $this->any() )
+ ->method( 'getCategory' )
+ ->will( $this->returnValue( $attribManager->getNotificationCategory( $type ) ) );
+ return $event;
+ }
+
+}
diff --git a/Echo/tests/phpunit/includes/NotifUserTest.php b/Echo/tests/phpunit/includes/NotifUserTest.php
new file mode 100644
index 00000000..e1e69ce0
--- /dev/null
+++ b/Echo/tests/phpunit/includes/NotifUserTest.php
@@ -0,0 +1,210 @@
+<?php
+
+/**
+ * @group Echo
+ */
+class MWEchoNotifUserTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+ $this->setMwGlobals( 'wgMemc', new HashBagOStuff() );
+ }
+
+ public function testNewFromUser() {
+ $exception = false;
+ try {
+ MWEchoNotifUser::newFromUser( User::newFromId( 0 ) );
+ } catch ( Exception $e ) {
+ $exception = true;
+ $this->assertEquals( "User must be logged in to view notification!",
+ $e->getMessage() );
+ }
+ $this->assertTrue( $exception, "Got exception" );
+
+ $notifUser = MWEchoNotifUser::newFromUser( User::newFromId( 2 ) );
+ $this->assertInstanceOf( 'MWEchoNotifUser', $notifUser );
+ }
+
+ public function testFlagCacheWithNewTalkNotification() {
+ global $wgMemc;
+
+ $notifUser = MWEchoNotifUser::newFromUser( User::newFromId( 2 ) );
+
+ $notifUser->flagCacheWithNewTalkNotification();
+ $this->assertEquals( '1', $wgMemc->get( $notifUser->getTalkNotificationCacheKey() ) );
+ }
+
+ public function testFlagCacheWithNoTalkNotification() {
+ global $wgMemc;
+
+ $notifUser = MWEchoNotifUser::newFromUser( User::newFromId( 2 ) );
+
+ $notifUser->flagCacheWithNoTalkNotification();
+ $this->assertEquals( '0', $wgMemc->get( $notifUser->getTalkNotificationCacheKey() ) );
+ }
+
+ public function testNotifCountHasReachedMax() {
+ global $wgEchoMaxNotificationCount;
+
+ $notifUser = MWEchoNotifUser::newFromUser( User::newFromId( 2 ) );
+
+ if ( $notifUser->getNotificationCount() > $wgEchoMaxNotificationCount ) {
+ $this->assertTrue( $notifUser->notifCountHasReachedMax() );
+ } else {
+ $this->assertFalse( $notifUser->notifCountHasReachedMax() );
+ }
+ }
+
+ public function testClearTalkNotification() {
+ global $wgMemc;
+
+ $notifUser = MWEchoNotifUser::newFromUser( User::newFromId( 2 ) );
+
+ $notifUser->flagCacheWithNewTalkNotification();
+
+ $hasMax = $notifUser->notifCountHasReachedMax();
+
+ $notifUser->clearTalkNotification();
+ if ( $hasMax ) {
+ $this->assertEquals( '1', $wgMemc->get( $notifUser->getTalkNotificationCacheKey() ) );
+ } else {
+ $this->assertEquals( '0', $wgMemc->get( $notifUser->getTalkNotificationCacheKey() ) );
+ }
+ }
+
+ public function testGetEmailFormat() {
+ global $wgAllowHTMLEmail;
+
+ $format = $wgAllowHTMLEmail;
+
+ $user = User::newFromId( 2 );
+ $notifUser = MWEchoNotifUser::newFromUser( $user );
+
+ $this->setMwGlobals( 'wgAllowHTMLEmail', true );
+ $this->assertEquals( $notifUser->getEmailFormat(), $user->getOption( 'echo-email-format' ) );
+ $this->setMwGlobals( 'wgAllowHTMLEmail', false );
+ $this->assertEquals( $notifUser->getEmailFormat(), EchoHooks::EMAIL_FORMAT_PLAIN_TEXT );
+
+ $this->setMwGlobals( 'wgAllowHTMLEmail', $format );
+ }
+
+ public function testMarkRead() {
+ global $wgMemc;
+ $notifUser = new MWEchoNotifUser(
+ User::newFromId( 2 ),
+ $wgMemc,
+ $this->mockEchoUserNotificationGateway( array( 'markRead' => true ) ),
+ $this->mockEchoNotificationMapper(),
+ $this->mockEchoTargetPageMapper()
+ );
+ $this->assertFalse( $notifUser->markRead( array() ) );
+ $this->assertTrue( $notifUser->markRead( array( 1 ) ) );
+
+ $notifUser = new MWEchoNotifUser(
+ User::newFromId( 2 ),
+ $wgMemc,
+ $this->mockEchoUserNotificationGateway( array( 'markRead' => false ) ),
+ $this->mockEchoNotificationMapper(),
+ $this->mockEchoTargetPageMapper()
+ );
+ $this->assertFalse( $notifUser->markRead( array() ) );
+ $this->assertFalse( $notifUser->markRead( array( 1 ) ) );
+ }
+
+ public function testMarkAllRead() {
+ global $wgMemc;
+
+ // Successful mark as read & non empty fetch
+ $notifUser = new MWEchoNotifUser(
+ User::newFromId( 2 ),
+ $wgMemc,
+ $this->mockEchoUserNotificationGateway( array( 'markRead' => true ) ),
+ $this->mockEchoNotificationMapper( array( $this->mockEchoNotification() ) ),
+ $this->mockEchoTargetPageMapper()
+ );
+ $this->assertTrue( $notifUser->markAllRead() );
+
+ // Unsuccessful mark as read & non empty fetch
+ $notifUser = new MWEchoNotifUser(
+ User::newFromId( 2 ),
+ $wgMemc,
+ $this->mockEchoUserNotificationGateway( array( 'markRead' => false ) ),
+ $this->mockEchoNotificationMapper( array( $this->mockEchoNotification() ) ),
+ $this->mockEchoTargetPageMapper()
+ );
+ $this->assertFalse( $notifUser->markAllRead() );
+
+ // Successful mark as read & empty fetch
+ $notifUser = new MWEchoNotifUser(
+ User::newFromId( 2 ),
+ $wgMemc,
+ $this->mockEchoUserNotificationGateway( array( 'markRead' => true ) ),
+ $this->mockEchoNotificationMapper(),
+ $this->mockEchoTargetPageMapper()
+ );
+ $this->assertFalse( $notifUser->markAllRead() );
+
+ // Unsuccessful mark as read & empty fetch
+ $notifUser = new MWEchoNotifUser(
+ User::newFromId( 2 ),
+ $wgMemc,
+ $this->mockEchoUserNotificationGateway( array( 'markRead' => false ) ),
+ $this->mockEchoNotificationMapper(),
+ $this->mockEchoTargetPageMapper()
+ );
+ $this->assertFalse( $notifUser->markAllRead() );
+ }
+
+ public function mockEchoUserNotificationGateway( array $dbResult = array() ) {
+ $dbResult += array(
+ 'markRead' => true
+ );
+ $gateway = $this->getMockBuilder( 'EchoUserNotificationGateway' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $gateway->expects( $this->any() )
+ ->method( 'markRead' )
+ ->will( $this->returnValue( $dbResult['markRead'] ) );
+ return $gateway;
+ }
+
+ public function mockEchoNotificationMapper( array $result = array() ) {
+ $mapper = $this->getMockBuilder( 'EchoNotificationMapper' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mapper->expects( $this->any() )
+ ->method( 'fetchUnreadByUser' )
+ ->will( $this->returnValue( $result ) );
+ return $mapper;
+ }
+
+ public function mockEchoTargetPageMapper( array $result = array() ) {
+ $mapper = $this->getMockBuilder( 'EchoTargetPageMapper' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mapper->expects( $this->any() )
+ ->method( 'deleteByUserEvents' )
+ ->will( $this->returnValue( $result ) );
+ return $mapper;
+ }
+
+ protected function mockEchoNotification() {
+ $notification = $this->getMockBuilder( 'EchoNotification' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $notification->expects( $this->any() )
+ ->method( 'getEvent' )
+ ->will( $this->returnValue( $this->mockEchoEvent() ) );
+ return $notification;
+ }
+
+ protected function mockEchoEvent() {
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getId' )
+ ->will( $this->returnValue( 1 ) );
+ return $event;
+ }
+}
diff --git a/Echo/tests/phpunit/includes/TalkPageFunctionalTest.php b/Echo/tests/phpunit/includes/TalkPageFunctionalTest.php
new file mode 100644
index 00000000..8a3c4af5
--- /dev/null
+++ b/Echo/tests/phpunit/includes/TalkPageFunctionalTest.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @group Echo
+ * @group DataBase
+ * @group medium
+ */
+class EchoTalkPageFunctionalTest extends ApiTestCase {
+
+ protected $dbr;
+
+ public function setUp() {
+ parent::setUp();
+ $this->dbr = MWEchoDbFactory::getDB( DB_SLAVE );
+ }
+
+ /**
+ * Creates and updates a user talk page a few times to ensure proper events are
+ * created. The user performing the edits is self::$users['sysop'].
+ * @group Broken
+ */
+ public function testAddCommentsToTalkPage() {
+ $editor = self::$users['sysop']->user->getName();
+ $talkPage = self::$users['uploader']->user->getName();
+ // A set of messages which will be inserted
+ $messages = array(
+ 'Moar Cowbell',
+ "I can haz test\n\nplz?", // checks that the parser allows multi-line comments
+ 'blah blah',
+ );
+
+ $messageCount = 0;
+ $this->assertCount($messageCount, $this->fetchAllEvents() );
+
+ // Start a talkpage
+ $content = "== Section 8 ==\n\n" . $this->signedMessage( $editor, $messages[$messageCount] );
+ $this->editPage( $talkPage, $content, '', NS_USER_TALK );
+
+ // Ensure the proper event was created
+ $events = $this->fetchAllEvents();
+ $this->assertCount(1 + $messageCount, $events, 'After initial edit a single event must exist.'); // +1 is due to 0 index
+ $row = array_shift( $events );
+ $this->assertEquals( 'edit-user-talk', $row->event_type );
+ $this->assertEventSectionTitle( 'Section 8', $row );
+
+ // Add another message to the talk page
+ $messageCount++;
+ $content .= $this->signedMessage( $editor, $messages[$messageCount] );
+ $this->editPage( $talkPage, $content, '', NS_USER_TALK );
+
+ // Ensure another event was created
+ $events = $this->fetchAllEvents();
+ $this->assertCount(1 + $messageCount, $events);
+ $row = array_shift( $events );
+ $this->assertEquals( 'edit-user-talk', $row->event_type );
+ $this->assertEventSectionTitle( 'Section 8', $row );
+
+ // Add a new section and a message within it
+ $messageCount++;
+ $content .= "\n\n== EE ==\n\n" . $this->signedMessage( $editor, $messages[$messageCount] );
+ $this->editPage( $talkPage, $content, '', NS_USER_TALK );
+
+ // Ensure this event has the new section title
+ $events = $this->fetchAllEvents();
+ $this->assertCount(1 + $messageCount, $events);
+ $row = array_pop( $events );
+ $this->assertEquals( 'edit-user-talk', $row->event_type );
+ $this->assertEventSectionTitle( 'EE', $row );
+ }
+
+ protected function assertEventSectionTitle( $sectionTitle, $row ) {
+ $this->assertNotNull( $row->event_extra, 'Event must contain extra data.' );
+ $extra = unserialize( $row->event_extra );
+ $this->assertArrayHasKey( 'section-title', $extra, 'Extra data must include a section-title key.' );
+ $this->assertEquals( $sectionTitle, $extra['section-title'], 'Detected section title must match' );
+ }
+
+ /**
+ * @return array All events in db sorted from oldest to newest
+ */
+ protected function fetchAllEvents() {
+ $res = $this->dbr->select( 'echo_event', array( '*' ), array(), __METHOD__, array( 'ORDER BY' => 'event_id ASC' ) );
+
+ return iterator_to_array( $res );
+ }
+
+ protected function signedMessage( $name, $content = 'Moar cowbell', $depth = 1 ) {
+ return str_repeat(':', $depth)." $content [[User:$name|$name]] ([[User talk:$name|$name]]) 00:17, 7 May 2013 (UTC)\n";
+ }
+
+}
diff --git a/Echo/tests/phpunit/includes/UserLocatorTest.php b/Echo/tests/phpunit/includes/UserLocatorTest.php
new file mode 100644
index 00000000..47d86edd
--- /dev/null
+++ b/Echo/tests/phpunit/includes/UserLocatorTest.php
@@ -0,0 +1,270 @@
+<?php
+
+/**
+ * @Database
+ */
+class EchoUserLocatorTest extends MediaWikiTestCase {
+
+ protected $tablesUsed = array( 'user', 'watchlist' );
+
+ public function testLocateUsersWatchingTitle() {
+ $title = Title::makeTitleSafe( NS_USER_TALK, 'Something_something_something' );
+ $key = $title->getDBkey();
+
+ for ( $i = 1000; $i < 1050; ++$i ) {
+ $rows[] = array(
+ 'wl_user' => $i,
+ 'wl_namespace' => NS_USER_TALK,
+ 'wl_title' => $key
+ );
+ }
+ wfGetDB( DB_MASTER )->insert( 'watchlist', $rows, __METHOD__ );
+
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getTitle' )
+ ->will( $this->returnValue( $title ) );
+
+ $it = EchoUserLocator::locateUsersWatchingTitle( $event, 10 );
+ $count = 0;
+ foreach ( $it as $user ) {
+ ++$count;
+ }
+ $this->assertEquals( 50, $count );
+ // @todo assert more than one query was issued
+ }
+
+ public function locateTalkPageOwnerProvider() {
+ return array(
+ array(
+ 'Allows null event title',
+ // expected user id's
+ array(),
+ // event title
+ null
+ ),
+
+ array(
+ 'No users selected for non-user talk namespace',
+ // expected user id's
+ array(),
+ // event title
+ Title::newMainPage(),
+ ),
+
+ array(
+ 'Selects user from NS_USER_TALK',
+ // callback returning expected user ids and event title.
+ // required because database insert must be inside test.
+ function() {
+ $user = User::newFromName( 'UTUser' );
+ $user->addToDatabase();
+
+ return array(
+ array( $user->getId() ),
+ $user->getTalkPage(),
+ );
+ }
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider locateTalkPageOwnerProvider
+ */
+ public function testLocateTalkPageOwner( $message, $expect, Title $title = null ) {
+ if ( $expect instanceof Closure ) {
+ list( $expect, $title ) = $expect();
+ }
+ $event = $this->mockEchoEvent();
+ $event->expects( $this->any() )
+ ->method( 'getTitle' )
+ ->will( $this->returnValue( $title ) );
+
+ $users = EchoUserLocator::locateTalkPageOwner( $event );
+ $this->assertEquals( $expect, array_keys( $users ), $message );
+ }
+
+ public function locateArticleCreatorProvider() {
+ return array(
+ array(
+ 'Something',
+ function() {
+ $user = User::newFromName( 'UTUser' );
+ $user->addToDatabase();
+
+ return array(
+ array( $user->getId() ),
+ $user->getTalkPage(),
+ $user
+ );
+ }
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider locateArticleCreatorProvider
+ */
+ public function testLocateArticleCreator( $message, $initialize ) {
+
+ list( $expect, $title, $user ) = $initialize();
+ WikiPage::factory( $title )->doEditContent(
+ /* $content = */ ContentHandler::makeContent( 'content', $title ),
+ /* $summary = */ 'summary',
+ /* $flags = */ 0,
+ /* $baseRevId = */ false,
+ /* $user = */ $user
+ );
+
+ $event = $this->mockEchoEvent();
+ $event->expects( $this->any() )
+ ->method( 'getTitle' )
+ ->will( $this->returnValue( $title ) );
+ $event->expects( $this->any() )
+ ->method( 'getAgent' )
+ ->will( $this->returnValue( User::newFromId( 123 ) ) );
+
+ $users = EchoUserLocator::locateArticleCreator( $event );
+ $this->assertEquals( $expect, array_keys( $users ), $message );
+ }
+
+ public static function locateEventAgentProvider() {
+ return array(
+ array(
+ 'Null event agent returns no users',
+ // expected result user id's
+ array(),
+ // event agent
+ null,
+ ),
+
+ array(
+ 'Anonymous event agent returns no users',
+ // expected result user id's
+ array(),
+ // event agent
+ User::newFromName( '4.5.6.7', /* $validate = */ false ),
+ ),
+
+ array(
+ 'Registed event agent returned as user',
+ // expected result user id's
+ array( 42 ),
+ // event agent
+ User::newFromId( 42 ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider locateEventAgentProvider
+ */
+ public function testLocateEventAgent( $message, $expect, User $agent = null ) {
+ $event = $this->mockEchoEvent();
+ $event->expects( $this->any() )
+ ->method( 'getAgent' )
+ ->will( $this->returnValue( $agent ) );
+
+ $users = EchoUserLocator::locateEventAgent( $event );
+ $this->assertEquals( $expect, array_keys( $users ), $message );
+ }
+
+ public function locateFromEventExtraProvider() {
+ return array(
+ array(
+ 'Event without extra data returns empty result',
+ // expected user list
+ array(),
+ // event extra data
+ array(),
+ // extra keys to get ids from
+ array( 'foo' ),
+ ),
+
+ array(
+ 'Event with specified extra data returns expected result',
+ // expected user list
+ array( 123 ),
+ // event extra data
+ array( 'foo' => 123 ),
+ // extra keys to get ids from
+ array( 'foo' ),
+ ),
+
+ array(
+ 'Accepts User objects instead of user ids',
+ // expected user list
+ array( 123 ),
+ // event extra data
+ array( 'foo' => User::newFromId( 123 ) ),
+ // extra keys to get ids from
+ array( 'foo' ),
+ ),
+
+ array(
+ 'Allows inner key to be array of ids',
+ // expected user list
+ array( 123, 321 ),
+ // event extra data
+ array( 'foo' => array( 123, 321 ) ),
+ // extra keys to get ids from
+ array( 'foo' ),
+ ),
+
+ array(
+ 'Empty inner array causes no error',
+ // expected user list
+ array(),
+ // event extra data
+ array( 'foo' => array() ),
+ // extra keys to get ids from
+ array( 'foo' ),
+ ),
+
+ array(
+ 'Accepts User object at inner level',
+ // expected user list
+ array( 123 ),
+ // event extra data
+ array( 'foo' => array( User::newFromId( 123 ) ) ),
+ // extra keys to get ids from
+ array( 'foo' ),
+ ),
+
+ );
+ }
+
+ /**
+ * @dataProvider locateFromEventExtraProvider
+ */
+ public function testLocateFromEventExtra( $message, $expect, array $extra, array $keys ) {
+ $event = $this->mockEchoEvent();
+ $event->expects( $this->any() )
+ ->method( 'getExtra' )
+ ->will( $this->returnValue( $extra ) );
+ $event->expects( $this->any() )
+ ->method( 'getExtraParam' )
+ ->will( $this->returnValueMap( self::arrayToValueMap( $extra ) ) );
+
+ $users = EchoUserLocator::locateFromEventExtra( $event, $keys );
+ $this->assertEquals( $expect, array_keys( $users ), $message );
+ }
+
+ protected static function arrayToValueMap( array $array ) {
+ $result = array();
+ foreach ( $array as $key => $value ) {
+ // EchoEvent::getExtraParam second argument defaults to null
+ $result[] = array( $key, null, $value );
+ }
+ return $result;
+ }
+
+ protected function mockEchoEvent() {
+ return $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+}
diff --git a/Echo/tests/phpunit/includes/cache/TitleLocalCacheTest.php b/Echo/tests/phpunit/includes/cache/TitleLocalCacheTest.php
new file mode 100644
index 00000000..c295b947
--- /dev/null
+++ b/Echo/tests/phpunit/includes/cache/TitleLocalCacheTest.php
@@ -0,0 +1,89 @@
+<?php
+
+class EchoTitleLocalCacheTest extends MediaWikiTestCase {
+
+ public function testCreate() {
+ $cache = EchoTitleLocalCache::create();
+ $this->assertInstanceOf( 'EchoTitleLocalCache', $cache );
+ return $cache;
+ }
+
+ /**
+ * @depends testCreate
+ */
+ public function testAdd( $cache ) {
+ $cache->add( 1 );
+ $this->assertEquals( count( $cache->getLookups() ), 1 );
+ $this->assertArrayHasKey( 1, $cache->getLookups() );
+ }
+
+ /**
+ * @depends testCreate
+ */
+ public function testGet( $cache ) {
+ $lruMap = new MapCacheLRU( EchoLocalCache::TARGET_MAX_NUM );
+ $titleIds = array();
+ $res = $this->insertPage( "EchoTitleLocalCacheTest_testGet" );
+ $titleIds[$res['id']] = $res['id'];
+ // First title included in cache
+ $lruMap->set( $res['id'], $res['title'] );
+
+ // second title not in internal cache, resolves from db.
+ $res = $this->insertPage( "EchoTitleLocalCacheTest_testGet2" );
+ $titleIds[$res['id']] = $res['id'];
+
+ $object = new \ReflectionObject( $cache );
+
+ // Load our generated MapCacheLRU in as the targets(known mapping from
+ // title id to title object) into $cache
+ $targets = $object->getProperty( 'targets' );
+ $targets->setAccessible( true );
+ $targets->setValue( $cache, $lruMap );
+
+ // Load both of the titles we are curious about into the list of titles
+ // to be looked up
+ $lookups = $object->getProperty( 'lookups' );
+ $lookups->setAccessible( true );
+ $lookups->setValue( $cache, $titleIds );
+
+ // Requesting the first object, which is within the known targets, should
+ // not resolve the pending lookups.
+ $this->assertInstanceOf( 'Title', $cache->get( reset( $titleIds ) ) );
+ $this->assertGreaterThan( 0, count( $cache->getLookups() ) );
+
+ // Requesting the second object, which is not within the known targets, should
+ // resolve the pending lookups and reset the list to lookup.
+ $this->assertInstanceOf( 'Title', $cache->get( end( $titleIds ) ) );
+ $this->assertEquals( 0, count( $cache->getLookups() ) );
+ }
+
+ /**
+ * @depends testCreate
+ */
+ public function testClearAll( $cache ) {
+ $object = new \ReflectionObject( $cache );
+ $targets = $object->getProperty( 'targets' );
+ $targets->setAccessible( true );
+ $lruMap = new MapCacheLRU( EchoLocalCache::TARGET_MAX_NUM );
+ $lruMap->set( 1, $this->mockTitle() );
+ $targets->setValue( $cache, $lruMap );
+ $lookups = $object->getProperty( 'lookups' );
+ $lookups->setAccessible( true );
+ $lookups->setValue( $cache, array( '1' => '1', '2' => '2' ) );
+
+ $cache->clearAll();
+ $this->assertTrue( count( $cache->getLookups() ) == 0 );
+ $this->assertNull( $cache->getTargets()->get( 1 ) );
+ $this->assertNull( $cache->getTargets()->get( '1' ) );
+ }
+
+ /**
+ * Mock object of Title
+ */
+ protected function mockTitle() {
+ $title = $this->getMockBuilder( 'Title' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ return $title;
+ }
+}
diff --git a/Echo/tests/phpunit/includes/gateway/UserNotificationGatewayTest.php b/Echo/tests/phpunit/includes/gateway/UserNotificationGatewayTest.php
new file mode 100644
index 00000000..5fa9b0fc
--- /dev/null
+++ b/Echo/tests/phpunit/includes/gateway/UserNotificationGatewayTest.php
@@ -0,0 +1,120 @@
+<?php
+
+class EchoUserNotificationGatewayTest extends MediaWikiTestCase {
+
+ public function testMarkRead() {
+ // no event ids to mark
+ $gateway = new EchoUserNotificationGateway( User::newFromId( 1 ), $this->mockMWEchoDbFactory() );
+ $this->assertNull( $gateway->markRead( array() ) );
+
+ // successful update
+ $gateway = new EchoUserNotificationGateway( User::newFromId( 1 ), $this->mockMWEchoDbFactory( array( 'update' => true ) ) );
+ $this->assertTrue( $gateway->markRead( array( 2 ) ) );
+
+ // unsuccessful update
+ $gateway = new EchoUserNotificationGateway( User::newFromId( 1 ), $this->mockMWEchoDbFactory( array( 'update' => false ) ) );
+ $this->assertFalse( $gateway->markRead( array( 2 ) ) );
+ }
+
+ public function testMarkAllRead() {
+ // successful update
+ $gateway = new EchoUserNotificationGateway( User::newFromId( 1 ), $this->mockMWEchoDbFactory( array( 'update' => true ) ) );
+ $this->assertTrue( $gateway->markAllRead( array( 2 ) ) );
+
+ // unsuccessful update
+ $gateway = new EchoUserNotificationGateway( User::newFromId( 1 ), $this->mockMWEchoDbFactory( array( 'update' => false ) ) );
+ $this->assertFalse( $gateway->markAllRead( array( 2 ) ) );
+ }
+
+ public function testGetNotificationCount() {
+ // unsuccessful select
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(), $this->mockMWEchoDbFactory( array( 'select' => false ) ) );
+ $this->assertEquals( 0, $gateway->getNotificationCount( DB_SLAVE, array( 'event_one' ) ) );
+
+ // successful select of alert
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(), $this->mockMWEchoDbFactory( array( 'select' => array( 1, 2 ) ) ) );
+ $this->assertEquals( 2, $gateway->getNotificationCount( DB_SLAVE, array( 'event_one', 'event_two' ) ) );
+
+ // there is event, should return 0
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(), $this->mockMWEchoDbFactory( array( 'select' => array( 1, 2 ) ) ) );
+ $this->assertEquals( 0, $gateway->getNotificationCount( DB_SLAVE, array() ) );
+
+ // successful select
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(), $this->mockMWEchoDbFactory( array( 'select' => array( 1, 2, 3 ) ) ) );
+ $this->assertEquals( 3, $gateway->getNotificationCount( DB_SLAVE, array( 'event_one' ) ) );
+ }
+
+ public function testGetUnreadNotifications() {
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(), $this->mockMWEchoDbFactory( array( 'select' => false ) ) );
+ $this->assertEmpty( $gateway->getUnreadNotifications( 'user_talk' ) );
+
+ $dbResult = array(
+ (object)array( 'notification_event' => 1 ),
+ (object)array( 'notification_event' => 2 ),
+ (object)array( 'notification_event' => 3 ),
+ );
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(), $this->mockMWEchoDbFactory( array( 'select' => $dbResult ) ) );
+ $res = $gateway->getUnreadNotifications( 'user_talk' );
+ $this->assertEquals( $res, array( 1 => 1, 2 => 2, 3 => 3 ) );
+ }
+
+ /**
+ * Mock object of User
+ */
+ protected function mockUser( $group = 'echo_group' ) {
+ $user = $this->getMockBuilder( 'User' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user->expects( $this->any() )
+ ->method( 'getID' )
+ ->will( $this->returnValue( 1 ) );
+ $user->expects( $this->any() )
+ ->method( 'getOption' )
+ ->will( $this->returnValue( true ) );
+ $user->expects( $this->any() )
+ ->method( 'getGroups' )
+ ->will( $this->returnValue( array( $group ) ) );
+ return $user;
+ }
+
+ /**
+ * Mock object of MWEchoDbFactory
+ */
+ protected function mockMWEchoDbFactory( array $dbResult = array() ) {
+ $dbFactory = $this->getMockBuilder( 'MWEchoDbFactory' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $dbFactory->expects( $this->any() )
+ ->method( 'getEchoDb' )
+ ->will( $this->returnValue( $this->mockDb( $dbResult ) ) );
+ return $dbFactory;
+ }
+
+ /**
+ * Mock object of DatabaseMysql ( DatabaseBase )
+ */
+ protected function mockDb( array $dbResult = array() ) {
+ $dbResult += array(
+ 'update' => '',
+ 'select' => '',
+ 'selectRow' => '',
+ );
+ $db = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $db->expects( $this->any() )
+ ->method( 'update' )
+ ->will( $this->returnValue( $dbResult['update'] ) );
+ $db->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->returnValue( $dbResult['select'] ) );
+ $db->expects( $this->any() )
+ ->method( 'selectRow' )
+ ->will( $this->returnValue( $dbResult['selectRow'] ) );
+ $db->expects( $this->any() )
+ ->method( 'numRows' )
+ ->will( $this->returnValue( count( $dbResult['select'] ) ) );
+ return $db;
+ }
+
+}
diff --git a/Echo/tests/phpunit/includes/iterator/FilteredSequentialIteratorTest.php b/Echo/tests/phpunit/includes/iterator/FilteredSequentialIteratorTest.php
new file mode 100644
index 00000000..900db22b
--- /dev/null
+++ b/Echo/tests/phpunit/includes/iterator/FilteredSequentialIteratorTest.php
@@ -0,0 +1,104 @@
+<?php
+
+class FilteredSequentialIteratorTest extends MediaWikiTestCase {
+
+ public function testEchoCallbackIteratorDoesntBlowUp() {
+ $it = new EchoCallbackIterator(
+ new ArrayIterator( array( 1, 2, 3 ) ),
+ function( $num ) {
+ return "There were $num items";
+ }
+ );
+
+ foreach ( $it as $val ) {
+ $res[] = $val;
+ }
+
+ $expected = array( "There were 1 items", "There were 2 items", "There were 3 items" );
+ $this->assertEquals( $expected, $res, 'Basic iteration with callback applied' );
+ }
+
+ public static function echoFilteredSequentialIteratorProvider() {
+ $odd = function( $v ) { return $v & 1; };
+ $greaterThanFour = function( $v ) { return $v > 4; };
+
+ return array(
+ array(
+ 'Empty object still works',
+ // expected result
+ array(),
+ // list of iterators/arrays/etc each containing users
+ array(),
+ // list of filters to apply on output
+ array(),
+ ),
+ array(
+ 'Basic iteration with one array and no filters',
+ // expected result
+ array( 1, 2, 3 ),
+ // list of iterators/arrays/etc each containing users
+ array( array( 1, 2, 3 ) ),
+ // list of filters to apply on output
+ array()
+ ),
+ array(
+ 'Basic iteration with one array and one filters',
+ // expected result
+ array( 1, 3 ),
+ // list of tierators/arrays/etc each containing users
+ array( array( 1, 2, 3 ) ),
+ // list of filters to apply on output
+ array( $odd ),
+ ),
+ array(
+ 'Iteration with multiple input arrays and no filters',
+ // expected result (iterators are run in parallel)
+ array( 1, 4, 2, 5, 3 ),
+ // list of tierators/arrays/etc each containing users
+ array( array( 1, 2, 3 ), array( 4, 5 ) ),
+ // list of filters to apply on output
+ array(),
+ ),
+ array(
+ 'Iteration with multiple input arrays and multiple filters',
+ // expected result
+ array( 5 ),
+ // list of tierators/arrays/etc each containing users
+ array( array( 1, 2 ), array( 3, 4 ), array( 5, 6 ) ),
+ // list of filters to apply on output
+ array( $odd, $greaterThanFour ),
+ ),
+ array(
+ 'Iteration with interspersed empty arrays',
+ // expected result
+ array( 1, 3, 2 ),
+ // list of tierators/arrays/etc each containing users
+ array( array(), array( 1, 2 ), array( 3 ), array() ),
+ // list of filters to apply on output
+ array(),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider echoFilteredSequentialIteratorProvider
+ */
+ public function testEchoFilteredSequentialIterator( $message, $expect, $userLists, $filters ) {
+ $notify = new EchoFilteredSequentialIterator;
+
+ foreach ( $userLists as $userList ) {
+ $notify->add( $userList );
+ }
+
+ foreach ( $filters as $filter ) {
+ $notify->addFilter( $filter );
+ }
+
+ $result = array();
+ foreach ( $notify as $value ) {
+ $result[] = $value;
+ }
+
+ $this->assertEquals( $expect, $result, $message );
+ }
+}
diff --git a/Echo/tests/phpunit/includes/mapper/AbstractMapperTest.php b/Echo/tests/phpunit/includes/mapper/AbstractMapperTest.php
new file mode 100644
index 00000000..cf91a459
--- /dev/null
+++ b/Echo/tests/phpunit/includes/mapper/AbstractMapperTest.php
@@ -0,0 +1,75 @@
+<?php
+
+class EchoAbstractMapperTest extends MediaWikiTestCase {
+
+ public function testAttachListener() {
+ $mapper = new EchoAbstractMapperStub();
+ $mapper->attachListener( 'testMethod', 'key_a', function() {} );
+
+ $class = new ReflectionClass( 'EchoAbstractMapperStub' );
+ $property = $class->getProperty( 'listeners' );
+ $property->setAccessible( true );
+ $listeners = $property->getValue( $mapper );
+
+ $this->assertArrayHasKey( 'testMethod', $listeners );
+ $this->assertArrayHasKey( 'key_a', $listeners['testMethod'] );
+ $this->assertTrue( is_callable( $listeners['testMethod']['key_a'] ) );
+ return array( 'mapper' => $mapper, 'property' => $property );
+ }
+
+ /**
+ * @expectedException MWException
+ */
+ public function testAttachListenerWithException() {
+ $mapper = new EchoAbstractMapperStub();
+ $mapper->attachListener( 'nonExistingMethod', 'key_a', function() {} );
+ }
+
+ /**
+ * @depends testAttachListener
+ */
+ public function testGetMethodListeners( $data ) {
+ $mapper = $data['mapper'];
+ $property = $data['property'];
+
+ $listeners = $mapper->getMethodListeners( 'testMethod' );
+ $this->assertArrayHasKey( 'key_a', $listeners );
+ $this->assertTrue( is_callable( $listeners['key_a'] ) );
+ }
+
+ /**
+ * @depends testAttachListener
+ * @expectedException MWException
+ */
+ public function testGetMethodListenersWithException( $data ) {
+ $mapper = $data['mapper'];
+ $property = $data['property'];
+
+ $listeners = $mapper->getMethodListeners( 'nonExistingMethod' );
+ }
+
+ /**
+ * @depends testAttachListener
+ */
+ public function testDetachListener( $data ) {
+ $mapper = $data['mapper'];
+ $property = $data['property'];
+
+ $mapper->detachListener( 'testMethod', 'key_a' );
+ $listeners = $property->getValue( $mapper );
+ $this->assertArrayHasKey( 'testMethod', $listeners );
+ $this->assertTrue( !isset( $listeners['testMethod']['key_a'] ) );
+ }
+
+}
+
+/**
+ * Create a stub class for testing the abstract class
+ */
+class EchoAbstractMapperStub extends EchoAbstractMapper {
+
+ public function testMethod() {
+
+ }
+
+}
diff --git a/Echo/tests/phpunit/includes/mapper/EventMapperTest.php b/Echo/tests/phpunit/includes/mapper/EventMapperTest.php
new file mode 100644
index 00000000..834df687
--- /dev/null
+++ b/Echo/tests/phpunit/includes/mapper/EventMapperTest.php
@@ -0,0 +1,167 @@
+<?php
+
+class EchoEventMapperTest extends MediaWikiTestCase {
+
+ public function provideDataTestInsert() {
+ return array (
+ array (
+ 'successful insert with next sequence = 1',
+ array ( 'nextSequenceValue' => 1, 'insert' => true, 'insertId' => 2 ),
+ 1
+ ),
+ array (
+ 'successful insert with insert id = 2',
+ array ( 'nextSequenceValue' => null, 'insert' => true, 'insertId' => 2 ),
+ 2
+ ),
+ array (
+ 'unsuccessful insert',
+ array ( 'nextSequenceValue' => null, 'insert' => false, 'insertId' => 2 ),
+ false
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideDataTestInsert
+ */
+ public function testInsert( $message, $dbResult, $result ) {
+ $event = $this->mockEchoEvent();
+ $eventMapper = new EchoEventMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertEquals( $result, $eventMapper->insert( $event ), $message );
+ }
+
+ /**
+ * Successful fetchById()
+ */
+ public function testSuccessfulFetchById() {
+ $eventMapper = new EchoEventMapper(
+ $this->mockMWEchoDbFactory(
+ array(
+ 'selectRow' => (object)array (
+ 'event_id' => 1,
+ 'event_type' => 'test',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => ''
+ )
+ )
+ )
+ );
+ $res = $eventMapper->fetchById( 1 );
+ $this->assertInstanceOf( 'EchoEvent', $res );
+ }
+
+ /**
+ * @expectedException MWException
+ */
+ public function testUnsuccessfulFetchById() {
+ $eventMapper = new EchoEventMapper(
+ $this->mockMWEchoDbFactory(
+ array(
+ 'selectRow' => false
+ )
+ )
+ );
+ $res = $eventMapper->fetchById( 1 );
+ $this->assertInstanceOf( 'EchoEvent', $res );
+ }
+
+ public function testFetchByUserBundleHash() {
+ // Unsuccessful select
+ $event = $this->mockEchoEvent();
+ $eventMapper = new EchoEventMapper( $this->mockMWEchoDbFactory( array ( 'select' => false ) ) );
+ $res = $eventMapper->fetchByUserBundleHash( User::newFromId( 1 ), 'testhash', 'web', 'DESC', 250 );
+ $this->assertFalse( $res );
+
+ // Successful select
+ $event = $this->mockEchoEvent();
+ $dbResult = array (
+ (object)array (
+ 'event_id' => 1,
+ 'event_type' => 'test',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => ''
+ ),
+ (object)array (
+ 'event_id' => 2,
+ 'event_type' => 'test2',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => ''
+ )
+ );
+ $eventMapper = new EchoEventMapper( $this->mockMWEchoDbFactory( array ( 'select' => $dbResult ) ) );
+ $res = $eventMapper->fetchByUserBundleHash( User::newFromId( 1 ), 'testhash', 'web', 'DESC', 250 );
+ $this->assertTrue( is_array( $res ) );
+ foreach ( $res as $row ) {
+ $this->assertInstanceOf( 'EchoEvent', $row );
+ }
+ }
+
+ /**
+ * Mock object of EchoEvent
+ */
+ protected function mockEchoEvent() {
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'toDbArray' )
+ ->will( $this->returnValue( array() ) );
+ return $event;
+ }
+
+ /**
+ * Mock object of MWEchoDbFactory
+ */
+ protected function mockMWEchoDbFactory( $dbResult ) {
+ $dbFactory = $this->getMockBuilder( 'MWEchoDbFactory' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $dbFactory->expects( $this->any() )
+ ->method( 'getEchoDb' )
+ ->will( $this->returnValue( $this->mockDb( $dbResult ) ) );
+ return $dbFactory;
+ }
+
+ /**
+ * Mock object of DatabaseMysql ( DatabaseBase )
+ */
+ protected function mockDb( array $dbResult ) {
+ $dbResult += array(
+ 'nextSequenceValue' => '',
+ 'insert' => '',
+ 'insertId' => '',
+ 'select' => '',
+ 'selectRow' => ''
+ );
+ $db = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $db->expects( $this->any() )
+ ->method( 'nextSequenceValue' )
+ ->will( $this->returnValue( $dbResult['nextSequenceValue'] ) );
+ $db->expects( $this->any() )
+ ->method( 'insert' )
+ ->will( $this->returnValue( $dbResult['insert'] ) );
+ $db->expects( $this->any() )
+ ->method( 'insertId' )
+ ->will( $this->returnValue( $dbResult['insertId'] ) );
+ $db->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->returnValue( $dbResult['select'] ) );
+ $db->expects( $this->any() )
+ ->method( 'selectRow' )
+ ->will( $this->returnValue( $dbResult['selectRow'] ) );
+ return $db;
+ }
+
+}
diff --git a/Echo/tests/phpunit/includes/mapper/NotificationMapperTest.php b/Echo/tests/phpunit/includes/mapper/NotificationMapperTest.php
new file mode 100644
index 00000000..3a67219a
--- /dev/null
+++ b/Echo/tests/phpunit/includes/mapper/NotificationMapperTest.php
@@ -0,0 +1,262 @@
+<?php
+
+class EchoNotificationMapperTest extends MediaWikiTestCase {
+
+ /**
+ * @todo write this test
+ */
+ public function testInsert() {
+ $this->assertTrue( true );
+ }
+
+ public function fetchUnreadByUser( User $user, $limit, array $eventTypes = array() ) {
+ // Unsuccessful select
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'select' => false ) ) );
+ $res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, '' );
+ $this->assertEmpty( $res );
+
+ // Successful select
+ $dbResult = array(
+ (object)array (
+ 'event_id' => 1,
+ 'event_type' => 'test_event',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => '',
+ 'notification_user' => 1,
+ 'notification_timestamp' => '20140615101010',
+ 'notification_read_timestamp' => '',
+ 'notification_bundle_base' => 1,
+ 'notification_bundle_hash' => 'testhash',
+ 'notification_bundle_display_hash' => 'testdisplayhash'
+ )
+ );
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'select' => $dbResult ) ) );
+ $res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, '', array() );
+ $this->assertEmpty( $res );
+
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'select' => $dbResult ) ) );
+ $res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, '', array( 'test_event' ) );
+ $this->assertTrue( is_array( $res ) );
+ $this->assertGreaterThan( 0, count( $res ) );
+ foreach ( $res as $row ) {
+ $this->assertInstanceOf( 'EchoNotification', $row );
+ }
+ }
+
+ public function testFetchByUser() {
+ // Unsuccessful select
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'select' => false ) ) );
+ $res = $notifMapper->fetchByUser( $this->mockUser(), 10, '' );
+ $this->assertEmpty( $res );
+
+ // Successful select
+ $notifDbResult = array(
+ (object)array (
+ 'event_id' => 1,
+ 'event_type' => 'test_event',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => '',
+ 'notification_user' => 1,
+ 'notification_timestamp' => '20140615101010',
+ 'notification_read_timestamp' => '20140616101010',
+ 'notification_bundle_base' => 1,
+ 'notification_bundle_hash' => 'testhash',
+ 'notification_bundle_display_hash' => 'testdisplayhash'
+ )
+ );
+
+ $tpDbResult = array(
+ (object)array(
+ 'etp_user' => 1, // userid
+ 'etp_page' => 7, // pageid
+ 'etp_event' => 1, // eventid
+ ),
+ );
+
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'select' => $notifDbResult ) ) );
+ $res = $notifMapper->fetchByUser( $this->mockUser(), 10, '', array() );
+ $this->assertEmpty( $res );
+
+ $notifMapper = new EchoNotificationMapper(
+ $this->mockMWEchoDbFactory( array ( 'select' => $notifDbResult ) ),
+ new EchoTargetPageMapper(
+ $this->mockMWEchoDbFactory( array( 'select' => $tpDbResult ) )
+ )
+ );
+ $res = $notifMapper->fetchByUser( $this->mockUser(), 10, '', array( 'test_event' ) );
+ $this->assertTrue( is_array( $res ) );
+ $this->assertGreaterThan( 0, count( $res ) );
+ foreach ( $res as $row ) {
+ $this->assertInstanceOf( 'EchoNotification', $row );
+ }
+
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array() ) );
+ $res = $notifMapper->fetchByUser( $this->mockUser(), 10, '' );
+ $this->assertEmpty( $res );
+ }
+
+ public function testFetchNewestByUserBundleHash() {
+ // Unsuccessful select
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'selectRow' => false ) ) );
+ $res = $notifMapper->fetchNewestByUserBundleHash( User::newFromId( 1 ), 'testhash' );
+ $this->assertFalse( $res );
+
+ // Successful select
+ $dbResult = (object)array (
+ 'event_id' => 1,
+ 'event_type' => 'test',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => '',
+ 'notification_user' => 1,
+ 'notification_timestamp' => '20140615101010',
+ 'notification_read_timestamp' => '20140616101010',
+ 'notification_bundle_base' => 1,
+ 'notification_bundle_hash' => 'testhash',
+ 'notification_bundle_display_hash' => 'testdisplayhash'
+ );
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'selectRow' => $dbResult ) ) );
+ $row = $notifMapper->fetchNewestByUserBundleHash( User::newFromId( 1 ), 'testdisplayhash' );
+ $this->assertInstanceOf( 'EchoNotification', $row );
+ }
+
+ public function testFetchByUserOffset() {
+ // Unsuccessful select
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'selectRow' => false ) ) );
+ $res = $notifMapper->fetchByUserOffset( User::newFromId( 1 ), 500 );
+ $this->assertFalse( $res );
+
+ // Successful select
+ $dbResult = (object)array (
+ 'event_id' => 1,
+ 'event_type' => 'test',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => '',
+ 'notification_user' => 1,
+ 'notification_timestamp' => '20140615101010',
+ 'notification_read_timestamp' => '20140616101010',
+ 'notification_bundle_base' => 1,
+ 'notification_bundle_hash' => 'testhash',
+ 'notification_bundle_display_hash' => 'testdisplayhash'
+ );
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array ( 'selectRow' => $dbResult ) ) );
+ $row = $notifMapper->fetchNewestByUserBundleHash( User::newFromId( 1 ), 500 );
+ $this->assertInstanceOf( 'EchoNotification', $row );
+ }
+
+ public function testDeleteByUserEventOffset() {
+ $dbResult = array( 'delete' => true );
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertTrue( $notifMapper->deleteByUserEventOffset( User::newFromId( 1 ), 500 ) );
+
+ $dbResult = array( 'delete' => false );
+ $notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertFalse( $notifMapper->deleteByUserEventOffset( User::newFromId( 1 ), 500 ) );
+ }
+
+ /**
+ * Mock object of User
+ */
+ protected function mockUser() {
+ $user = $this->getMockBuilder( 'User' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user->expects( $this->any() )
+ ->method( 'getID' )
+ ->will( $this->returnValue( 1 ) );
+ $user->expects( $this->any() )
+ ->method( 'getOption' )
+ ->will( $this->returnValue( true ) );
+ $user->expects( $this->any() )
+ ->method( 'getGroups' )
+ ->will( $this->returnValue( array( 'echo_group' ) ) );
+ return $user;
+ }
+
+ /**
+ * Mock object of EchoNotification
+ */
+ protected function mockEchoNotification() {
+ $event = $this->getMockBuilder( 'EchoNotification' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'toDbArray' )
+ ->will( $this->returnValue( array() ) );
+ return $event;
+ }
+
+ /**
+ * Mock object of MWEchoDbFactory
+ */
+ protected function mockMWEchoDbFactory( $dbResult ) {
+ $dbFactory = $this->getMockBuilder( 'MWEchoDbFactory' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $dbFactory->expects( $this->any() )
+ ->method( 'getEchoDb' )
+ ->will( $this->returnValue( $this->mockDb( $dbResult ) ) );
+ return $dbFactory;
+ }
+
+ /**
+ * Mock object of DatabaseMysql ( DatabaseBase )
+ */
+ protected function mockDb( array $dbResult ) {
+ $dbResult += array(
+ 'insert' => '',
+ 'select' => '',
+ 'selectRow' => '',
+ 'delete' => ''
+ );
+
+ $db = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $db->expects( $this->any() )
+ ->method( 'insert' )
+ ->will( $this->returnValue( $dbResult['insert'] ) );
+ $db->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->returnValue( $dbResult['select'] ) );
+ $db->expects( $this->any() )
+ ->method( 'delete' )
+ ->will( $this->returnValue( $dbResult['delete'] ) );
+ $db->expects( $this->any() )
+ ->method( 'selectRow' )
+ ->will( $this->returnValue( $dbResult['selectRow'] ) );
+ $db->expects ( $this->any() )
+ ->method( 'onTransactionIdle' )
+ ->will( new EchoExecuteFirstArgumentStub );
+
+ return $db;
+ }
+
+}
+
+class EchoExecuteFirstArgumentStub implements PHPUnit_Framework_MockObject_Stub {
+ public function invoke( PHPUnit_Framework_MockObject_Invocation $invocation ) {
+ if ( !$invocation instanceof PHPUnit_Framework_MockObject_Invocation_Static ) {
+ throw new PHPUnit_Framework_Exception( 'wrong invocation type' );
+ }
+ if ( !$invocation->arguments ) {
+ throw new PHPUnit_Framework_Exception( 'Method call must have an argument' );
+ }
+ return call_user_func( reset( $invocation->arguments ) );
+ }
+
+ public function toString() {
+ return 'return result of call_user_func on first invocation argument';
+ }
+}
diff --git a/Echo/tests/phpunit/includes/mapper/TargetPageMapperTest.php b/Echo/tests/phpunit/includes/mapper/TargetPageMapperTest.php
new file mode 100644
index 00000000..6358df31
--- /dev/null
+++ b/Echo/tests/phpunit/includes/mapper/TargetPageMapperTest.php
@@ -0,0 +1,177 @@
+<?php
+
+class EchoTargetPageMapperTest extends MediaWikiTestCase {
+
+ public function testFetchByUserPageId() {
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( array ( 'select' => false ) ) );
+ $res = $targetMapper->fetchByUserPageId( User::newFromId( 1 ), 1 );
+ $this->assertFalse( $res );
+
+ $dbResult = array (
+ (object)array (
+ 'etp_user' => 1,
+ 'etp_page' => 2,
+ 'etp_event' => 3
+ ),
+ (object)array (
+ 'etp_user' => 1,
+ 'etp_page' => 2,
+ 'etp_event' => 7,
+ )
+ );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( array ( 'select' => $dbResult ) ) );
+ $res = $targetMapper->fetchByUserPageId( User::newFromId( 1 ), 2 );
+ $this->assertTrue( is_array( $res ) );
+ $this->assertCount( 2, $res );
+ foreach ( $res as $targetPages ) {
+ $this->assertTrue( is_array( $targetPages ) );
+ $this->assertCount( 1, $targetPages );
+ $this->assertInstanceOf( 'EchoTargetPage', reset( $targetPages ) );
+ }
+ }
+
+ public function provideDataTestInsert() {
+ return array (
+ array (
+ 'successful insert with next sequence = 1',
+ array ( 'nextSequenceValue' => 1, 'insert' => true, 'insertId' => 2 ),
+ 1
+ ),
+ array (
+ 'successful insert with insert id = 2',
+ array ( 'nextSequenceValue' => null, 'insert' => true, 'insertId' => 2 ),
+ 2
+ ),
+ array (
+ 'unsuccessful insert',
+ array ( 'nextSequenceValue' => null, 'insert' => false, 'insertId' => 2 ),
+ false
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideDataTestInsert
+ */
+ public function testInsert( $message, $dbResult, $result ) {
+ $target = $this->mockEchoTargetPage();
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertEquals( $result, $targetMapper->insert( $target ), $message );
+ }
+
+ public function testDelete() {
+ $dbResult = array( 'delete' => true );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertTrue( $targetMapper->delete( $this->mockEchoTargetPage() ) );
+
+ $dbResult = array( 'delete' => false );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertFalse( $targetMapper->delete( $this->mockEchoTargetPage() ) );
+ }
+
+ public function provideDataTestDeleteByUserEvents() {
+ return array(
+ array( true, array( 1 ), true ),
+ array( false, array( 1 ), false ),
+ array( true, array(), true ),
+ array( false, array(), true ),
+ );
+ }
+
+ /**
+ * @dataProvider provideDataTestDeleteByUserEvents
+ */
+ public function testDeleteByUserEvents( $deleteResult, $eventIds, $result ) {
+ $dbResult = array( 'delete' => $deleteResult );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertSame( $targetMapper->deleteByUserEvents( User::newFromId( 1 ), $eventIds ), $result );
+ }
+
+ public function testDeleteByUser() {
+ $dbResult = array( 'delete' => true );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertSame( $targetMapper->deleteByUser( User::newFromId( 1 ) ), true );
+
+ $dbResult = array( 'delete' => false );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertSame( $targetMapper->deleteByUser( User::newFromId( 1 ) ), false );
+ }
+
+ public function testDeleteByUserEventOffset() {
+ $dbResult = array( 'delete' => true );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertSame( $targetMapper->deleteByUserEventOffset( User::newFromId( 1 ), 500 ), true );
+
+ $dbResult = array( 'delete' => false );
+ $targetMapper = new EchoTargetPageMapper( $this->mockMWEchoDbFactory( $dbResult ) );
+ $this->assertSame( $targetMapper->deleteByUserEventOffset( User::newFromId( 1 ), 500 ), false );
+ }
+
+ /**
+ * Mock object of EchoTargetPage
+ */
+ protected function mockEchoTargetPage() {
+ $target = $this->getMockBuilder( 'EchoTargetPage' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $target->expects( $this->any() )
+ ->method( 'toDbArray' )
+ ->will( $this->returnValue( array() ) );
+ $target->expects( $this->any() )
+ ->method( 'getUser' )
+ ->will( $this->returnValue( User::newFromId( 1 ) ) );
+ $target->expects( $this->any() )
+ ->method( 'getPageId' )
+ ->will( $this->returnValue( 2 ) );
+ $target->expects( $this->any() )
+ ->method( 'getEventId' )
+ ->will( $this->returnValue( 3 ) );
+ return $target;
+ }
+
+ /**
+ * Mock object of MWEchoDbFactory
+ */
+ protected function mockMWEchoDbFactory( $dbResult ) {
+ $dbFactory = $this->getMockBuilder( 'MWEchoDbFactory' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $dbFactory->expects( $this->any() )
+ ->method( 'getEchoDb' )
+ ->will( $this->returnValue( $this->mockDb( $dbResult ) ) );
+ return $dbFactory;
+ }
+
+ /**
+ * Mock object of DatabaseMysql ( DatabaseBase )
+ */
+ protected function mockDb( array $dbResult ) {
+ $dbResult += array(
+ 'nextSequenceValue' => '',
+ 'insert' => '',
+ 'insertId' => '',
+ 'select' => '',
+ 'delete' => ''
+ );
+ $db = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $db->expects( $this->any() )
+ ->method( 'nextSequenceValue' )
+ ->will( $this->returnValue( $dbResult['nextSequenceValue'] ) );
+ $db->expects( $this->any() )
+ ->method( 'insert' )
+ ->will( $this->returnValue( $dbResult['insert'] ) );
+ $db->expects( $this->any() )
+ ->method( 'insertId' )
+ ->will( $this->returnValue( $dbResult['insertId'] ) );
+ $db->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->returnValue( $dbResult['select'] ) );
+ $db->expects( $this->any() )
+ ->method( 'delete' )
+ ->will( $this->returnValue( $dbResult['delete'] ) );
+ return $db;
+ }
+
+}
diff --git a/Echo/tests/phpunit/includes/revision_txt/138274875.txt b/Echo/tests/phpunit/includes/revision_txt/138274875.txt
new file mode 100644
index 00000000..a2416f1c
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/138274875.txt
@@ -0,0 +1,78 @@
+{{Autoarchiv
+|Alter=30
+|Mindestbeiträge=1
+|Klein=Ja
+|Ziel='Benutzer Diskussion:Schnark/Archiv4'
+|Übersicht=[[Spezial:Präfixindex/Benutzer Diskussion:Schnark/Archiv|Archiv]].</b> Das momentan verwendete Archiv ist <b>[[Benutzer Diskussion:Schnark/Archiv4|Archiv 4]]
+|Frequenz=sonntags
+}}
+
+== Code-Review (3. Versuch) ==
+
+Hallo Schnark, habe [[Benutzer Diskussion:Schnark/Archiv4#Code-Review|deine Einwände]] umgesetzt. Allerdings kann ich tatsächlich nicht sagen ob diese Bugfrei sind. Da diese Bananen-Methodik heutzutage jedoch gang und gebe ist, würde ich mich jedoch umgehend bzw. zeitnäher als bis jetzt um eine Bearbeitung kümmern.[http://de.wikipedia.beta.wmflabs.org/wiki/Benutzer:Perhelion Freundliche Grüße]<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 17:00, 16. Okt. 2014 (CEST)</small></kbd>
+
+:de.wikipedia.beta.wmflabs.org liefert mir seit Tagen nur Ladefehler, sodass ich deinen Code nicht sehen kann. --[[Benutzer:Schnark|Schnark]] 10:55, 17. Okt. 2014 (CEST)
+
+:: Schade, ich dachte das zwischen uns ist eine Win-win-Situation. (Leider bekomme ich langsam den Verdacht, dass du etwas gegen mich hast⁉) [[Datei:SMirC-bored.svg|18px|-.-]]<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 08:48, 31. Okt. 2014 (CET)</small></kbd>
+
+:::Labs hat etwas gegen mich und leitet mich noch immer stur auf HTTPS um, wo mir dann ein Serverfehler präsentiert wird. --[[Benutzer:Schnark|Schnark]] 09:35, 31. Okt. 2014 (CET)
+
+:::: Ach ok, das hatte ich auch. Ich musste erst meinen kompletten BrowserCache löschen (wie mir PeCh riet).<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 10:15, 31. Okt. 2014 (CET)</small></kbd>
+
+::::Irgendwo kam ein <code>forceHttps</code>-Cookie her, jetzt ist es weg. Es fallen immer noch viele Dinge beim reinen Überfliegen auf:
+::::http://de.wikipedia.beta.wmflabs.org/wiki/Benutzer:Perhelion/signing.js
+:::::<code>mw.loader.using('jquery.textSelection');</code> bringt in dieser Form nichts, du musst den Code, der auf die Funktionen aus <code>jquery.textSelection</code> angewiesen ist, als Callback-Funktion im zweiten Parameter übergeben oder alternativ dem zurückgegebenen Promise-Objekt anhängen.
+:::::<code>n.test(cfg.sigText[-1])</code> ist immer falsch
+:::::<code>pos = txt.indexOf('\n', pos);</code> schlägt fehl, wenn kein Zeilenumbruch mehr kommt (unwahrscheinlich, aber möglich)
+:::::<code>/de|als/.test(cfg.wgUserLanguage)</code>: Die Anzahl der Benutzer mit <code>ks-deva</code>, die keine deutsche Lokalisierung wollen oder der mit <code>pfl</code>, die Deutsch dem Englischen vorziehen, dürfte klein sein. Trotzdem solltest du <code>mw.language.getFallbackLanguageChain()</code> verwenden, dafür ist es da.
+:::::Den <code>wpAutoSummary</code>-Hack verstehe ich nicht, aber vermutlich führt er dazu, dass die Funktion „Warnen, wenn Zusammenfassung fehlt“ nicht mehr zuverlässig funktioniert.
+:::::Gibt es irgendeinen Grund <code>..updateTooltipAccessKeys()</code> nicht einfach für die eingefügten Elemente aufzurufen, statt irgendwelche komischen Hacks zu verwenden?
+::::http://de.wikipedia.beta.wmflabs.org/wiki/Benutzer:Perhelion/sectionSummary.js verwendet mit <code>$.unique</code> ''immer noch'' eine Funktion, die nur für DOM-Elemente funktioniert, für normale Arrays. --[[Benutzer:Schnark|Schnark]] 12:06, 6. Nov. 2014 (CET)
+:::::: Vielen Dank auch diesmal, ich denke morgen werde ich das signing-script updaten. Das sectionSummary habe ich soweit gefixt und auch gleich mit weiterer Funktion verbessert. Ein schönes Wochenende. VG<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 15:07, 15. Nov. 2014 (CET)</small></kbd>
+
+:::::::Was sollen die Änderungen von <code>foo !== -1</code> in <code>!~foo</code>? Ersteres ist deutlich verständlicher und gilt als performanter (in Firefox ist beides praktisch gleich schnell, aber im IE ist es wirklich ein Faktor 2 in der Laufzeit)? --[[Benutzer:Schnark|Schnark]] 09:20, 20. Nov. 2014 (CET)
+
+:::::::: Du siehst aber auch alles (wohl weil JSHint hier auch meckert). Ja hm* verständlicher ist relativ, also für mich ist es rein optisch schon verständlicher (hatte es einfach aus einem Code-Snippet, fand es einfach gut ohne einen Logical-Operator).[[Datei:SMirC-grin.svg|18px|X-)]] Vielen Dank für den Hinweis, ich werde es wieder rückgängig machen.
+:::::::: Bin jetzt auch mit dem autoSigning fertig (mit ebenfalls kleinen Verbesserungen). Mit dem <code>accessKey</code> hatte ich mich wirklich schwer getan (zudem der Tooltip in Chrome vorher auch nicht gestimmt hatte). Bis nachher VG<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 21:08, 20. Nov. 2014 (CET)</small></kbd>
+
+:::::::::Verständlich ist es nur dann, wenn man weiß, dass negative Integers intern als [[Zweierkomplement]] dargestellt werden, was in gewisser Hinsicht die natürlichste, aber keineswegs die offensichtlichste oder einzige Darstellung ist. Tatsächlich finde ich im ES5-Standard kein einziges Wort dazu, in ES6 auch nur eine sehr versteckte Erwähnung am Rande.
+:::::::::Warnungen von JSHint sind nicht dazu da Programmierer zu ärgern, sondern sollten von sehr wenigen Ausnahmefällen abgesehen immer beachtet werden.
+:::::::::In signing.js trifft mein Kommentar zum <code>wpAutoSummary</code>-Hack noch immer zu, das gilt natürlich auch für sectionSummary.js. <code>Array.prototype.filter</code> führt als ES5-Methode im IE8 zu Laufzeitfehlern. Wie gesagt, IE8 ist nicht das Maß aller Dinge, aber solange MW diesen Browser unterstützt, darf kein Skript Laufzeitfehler auslösen. Entweder lädst du den ES5-Shim oder schreibst die entsprechende Anweisung auf jQuery um. Gleiches gilt für ausgefallenere Methoden von <code>console</code>. --[[Benutzer:Schnark|Schnark]] 09:53, 21. Nov. 2014 (CET)
+┌{{padleft:┘|22|─}}<br />
+Ich kümmer mich die Woche drum (mir sind jetzt auch noch einige Kleinigkeiten bzw. Verbesserungen eingefallen, man muss sich ja immer wieder erst in den ganzen Code reindenken).
+@Hack: Ich finde auf Diskussionsseiten ist dieser Hack legitim, er kommt auch nur zur Anwendung wenn der Minor-Button aktiviert wurde, ansonsten wird der Wert wieder resettet.
+@sectionSummary kommt hinzu dass das Summary eh vom Script geändert wird und der Tocken hinfällig wird und tatsächlich wird der Tocken nur geändert wenn das Summary geändert wurde. Damit wollte ich auf die ganze Cookie-Komplikation (die sich ja auch dieses Jahr wieder geändert hat) umgehen. Daher würde ich dich bitten ein Zugeständnis zu machen und hier ein Auge zuzudrücken.[[Datei:SMirC-wink.svg|20px|;-)]]
+PS: Ich habe mal deinen alten Bugreport [[bugzilla:38829]] etwas Aufmerksamkeit zugeführt. [[Datei:SMirC-jealous.svg|20px|(°₀°)]] LG<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 13:26, 2. Dez. 2014 (CET)</small></kbd>
+
+:Ich verwende die Funktion „Warnen, wenn Zusammenfassung fehlt“ dazu, dass ich eine Bearbeitung wirklich erst dann speichere, wenn ich fertig bin, und fülle dazu die Zusammenfassungszeile erst ganz am Schluss aus. Sollte ich zwischendurch versehentlich auf „Speichern“ klicken, dann bekomme ich zuerst eine Warnung. Zudem kannst du dir nie sicher sein, was die Serverseite mit ungültigen MD5-Codes macht. Im Augenblick ignoriert sie diese Tatsache, es kann aber ohne Vorwarnung passieren, dass sich dieses Verhalten plötzlich ändert, und dann der Wert, den du dort speicherst, verworfen wird, oder der Benutzer ganz am Abspeichern gehindert wird. Darum: Ein Feld, dass den MD5-Hash einer Zusammenfassung enthalten soll, darf auch nur den MD5-Hash einer Zusammenfassung enthalten und sonst nichts.
+:happy5214 kümmert sich gerade sehr um meine Bugreports, [[phab:T39485]], den er auch behoben hat, war mir ehrlich gesagt wichtiger. --[[Benutzer:Schnark|Schnark]] 09:11, 3. Dez. 2014 (CET)
+:: Nun denn ein Frohes Neues! (Bevor der Thread wieder in der Versenkung verschwindet, ich habe deine Einwände betr. „Warnen“ dahingehend „gefixt“, dass das hidden Tocken-Feld vor dem Speichern gänzlich resetet wird.) Es scheint mir du würdest tatsächlich auf eine Cookielösung hinaus wollen (denn eine andere sehe ich jetzt nicht)⁉ OT: Mir scheint du hast dein [[Benutzer:Schnark/js/Wikisyntax-config.js|WSTM config]] gänzlich deaktiviert (oder ich habe deine Mühen zur Unterbindung fremder Einbindung nicht völlig erfasst, Z.151)!?<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]'' <small> 14:59, 3. Jan. 2015 (CET)</small></kbd>
+:::Selbst wenn du beim Abspeichern den Inhalt von wpAutoSummary beim Speichern wiederherstellst, reicht das nicht, es muss bei jeglicher Serverinteraktion, also auch bei der Vorschau, ein korrekter Wert übergeben werden, andernfalls musst du mit undefiniertem Verhalten rechnen. --[[Benutzer:Schnark|Schnark]] 09:28, 5. Jan. 2015 (CET)
+
+== Danke ==
+
+Vielen Dank für Deine sehr ausführliche und hilfreiche Antwort auf meine [[Wikipedia:Auskunft#Hilberts_Axiomensystem_der_euklidischen_Geometrie|Frage auf der Wikipedia-Asukunft]]. Mir ist gleich ein ganzer Kronleuchter aufgegangen... {{unsigniert|79.245.165.238|17:49, 8. Jan. 2015 (CET)‎}}
+
+:Gern geschehen! --[[Benutzer:Schnark|Schnark]] 09:03, 9. Jan. 2015 (CET)
+
+== Bug erstellen ==
+
+Hi Schnark, könntest Du bitte mal schauen, ob es zu dem [[Wikipedia:Bots/Anfragen/Archiv/2014-2#Referenzierungsfehler_finden|hier beschriebenem Problem]] schon einen Bug gibt und ihn ggf. erstellen?--[[Benutzer:Mabschaaf|Mabschaaf]] 23:20, 15. Jan. 2015 (CET)
+
+:Ehrlich gesagt ist mir der Abschnitt viel zu lang um ihn mir durchzulesen. Du kannst unter https://phabricator.wikimedia.org/maniphest/query/advanced/ selbst suchen, mit deinem Wikipedia-Konto kannst du dich inzwischen auch direkt bei Phabricator anmelden und selbst eine Task anlegen, wenn du nichts findest. So schwer ist das nicht, und wenn man beim ersten Mal etwas falsch macht, ist das auch nicht schlimm. --[[Benutzer:Schnark|Schnark]] 10:15, 16. Jan. 2015 (CET)
+::Du musst gar nicht den kompletten Abschnitt lesen, das erste Posting reicht. Ich werde auf phab sicher nicht aktiv.--[[Benutzer:Mabschaaf|Mabschaaf]] 16:08, 16. Jan. 2015 (CET)
+:::[[Benutzer:Se4598]] wars: [[phab:T85386]]. Was spricht gegen phab? (Oder jeden anderen Bug-Tracker?) [[Benutzer:Umherirrender|Der Umherirrende]] 16:50, 16. Jan. 2015 (CET)
+:::: Also ich finde (den Abschnitt auch zu lang), dass Phab fast in jeder Hinsicht ein Fortschritt zum alten Bugzilla ist (ein paar wenige Schwächen wird es wohl geben, aber darum soll es ja hier jetzt nicht gehen).<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]'' <small> 21:55, 16. Jan. 2015 (CET)</small></kbd>
+
+== Testwiki ==
+
+Hallo Schnark,
+ich bräuchte, um Dinge für [[WP:Meinungsbilder/Erweiterung der Sichterrechte|dieses MB]] eine Möglichkeit, in einem Wiki, in dem die Benutzerrechtskonfiguration mit einer Ausnahme genau wie hier sind, zu editiern und verschieben. Um genau zu sein geht es um eine zusätzliche Benutzergruppe mit move-subpages, suppressredirect und unwatchedpages. Was kann ich da machen? Eine eigene MediaWiki-Installattion habe ich noch nie gemacht. --[[Benutzer:MGChecker|MGChecker]] ([[Benutzer Diskussion:MGChecker|Disk.]] &#124; [[Spezial:Beiträge/MGChecker|Beitr.]] &#124; [[Benutzer:MGChecker/Bewertung|Bewert.]]) 12:44, 17. Jan. 2015 (CET)
+
+:Ich habe zwar ein privates Testwiki, aber dort funktioniert <code>$wgRateLimits</code> nicht (und den meisten anderen Testwiki-Besitzern wird das ähnlich gehen). Frag am besten mal unter [[mw:Project:Support desk]] nach, dort sollte es eigentlich jemand wissen. --[[Benutzer:Schnark|Schnark]] 10:37, 19. Jan. 2015 (CET)
+
+== Echo-Test ==
+
+[[Benutzer:X" onclick="alert('XSS');" title="y]] [[Benutzer Diskussion:Schnark]] 10:15, 29. Jan. 2015 (CET)
+
+[[Benutzer:X" onclick="alert('XSS');" title="y]] [[Benutzer:Schnark|<span>falsch]] verschachtelt</span> 10:20, 29. Jan. 2015 (CET)
diff --git a/Echo/tests/phpunit/includes/revision_txt/138275105.txt b/Echo/tests/phpunit/includes/revision_txt/138275105.txt
new file mode 100644
index 00000000..0e151d48
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/138275105.txt
@@ -0,0 +1,80 @@
+{{Autoarchiv
+|Alter=30
+|Mindestbeiträge=1
+|Klein=Ja
+|Ziel='Benutzer Diskussion:Schnark/Archiv4'
+|Übersicht=[[Spezial:Präfixindex/Benutzer Diskussion:Schnark/Archiv|Archiv]].</b> Das momentan verwendete Archiv ist <b>[[Benutzer Diskussion:Schnark/Archiv4|Archiv 4]]
+|Frequenz=sonntags
+}}
+
+== Code-Review (3. Versuch) ==
+
+Hallo Schnark, habe [[Benutzer Diskussion:Schnark/Archiv4#Code-Review|deine Einwände]] umgesetzt. Allerdings kann ich tatsächlich nicht sagen ob diese Bugfrei sind. Da diese Bananen-Methodik heutzutage jedoch gang und gebe ist, würde ich mich jedoch umgehend bzw. zeitnäher als bis jetzt um eine Bearbeitung kümmern.[http://de.wikipedia.beta.wmflabs.org/wiki/Benutzer:Perhelion Freundliche Grüße]<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 17:00, 16. Okt. 2014 (CEST)</small></kbd>
+
+:de.wikipedia.beta.wmflabs.org liefert mir seit Tagen nur Ladefehler, sodass ich deinen Code nicht sehen kann. --[[Benutzer:Schnark|Schnark]] 10:55, 17. Okt. 2014 (CEST)
+
+:: Schade, ich dachte das zwischen uns ist eine Win-win-Situation. (Leider bekomme ich langsam den Verdacht, dass du etwas gegen mich hast⁉) [[Datei:SMirC-bored.svg|18px|-.-]]<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 08:48, 31. Okt. 2014 (CET)</small></kbd>
+
+:::Labs hat etwas gegen mich und leitet mich noch immer stur auf HTTPS um, wo mir dann ein Serverfehler präsentiert wird. --[[Benutzer:Schnark|Schnark]] 09:35, 31. Okt. 2014 (CET)
+
+:::: Ach ok, das hatte ich auch. Ich musste erst meinen kompletten BrowserCache löschen (wie mir PeCh riet).<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 10:15, 31. Okt. 2014 (CET)</small></kbd>
+
+::::Irgendwo kam ein <code>forceHttps</code>-Cookie her, jetzt ist es weg. Es fallen immer noch viele Dinge beim reinen Überfliegen auf:
+::::http://de.wikipedia.beta.wmflabs.org/wiki/Benutzer:Perhelion/signing.js
+:::::<code>mw.loader.using('jquery.textSelection');</code> bringt in dieser Form nichts, du musst den Code, der auf die Funktionen aus <code>jquery.textSelection</code> angewiesen ist, als Callback-Funktion im zweiten Parameter übergeben oder alternativ dem zurückgegebenen Promise-Objekt anhängen.
+:::::<code>n.test(cfg.sigText[-1])</code> ist immer falsch
+:::::<code>pos = txt.indexOf('\n', pos);</code> schlägt fehl, wenn kein Zeilenumbruch mehr kommt (unwahrscheinlich, aber möglich)
+:::::<code>/de|als/.test(cfg.wgUserLanguage)</code>: Die Anzahl der Benutzer mit <code>ks-deva</code>, die keine deutsche Lokalisierung wollen oder der mit <code>pfl</code>, die Deutsch dem Englischen vorziehen, dürfte klein sein. Trotzdem solltest du <code>mw.language.getFallbackLanguageChain()</code> verwenden, dafür ist es da.
+:::::Den <code>wpAutoSummary</code>-Hack verstehe ich nicht, aber vermutlich führt er dazu, dass die Funktion „Warnen, wenn Zusammenfassung fehlt“ nicht mehr zuverlässig funktioniert.
+:::::Gibt es irgendeinen Grund <code>..updateTooltipAccessKeys()</code> nicht einfach für die eingefügten Elemente aufzurufen, statt irgendwelche komischen Hacks zu verwenden?
+::::http://de.wikipedia.beta.wmflabs.org/wiki/Benutzer:Perhelion/sectionSummary.js verwendet mit <code>$.unique</code> ''immer noch'' eine Funktion, die nur für DOM-Elemente funktioniert, für normale Arrays. --[[Benutzer:Schnark|Schnark]] 12:06, 6. Nov. 2014 (CET)
+:::::: Vielen Dank auch diesmal, ich denke morgen werde ich das signing-script updaten. Das sectionSummary habe ich soweit gefixt und auch gleich mit weiterer Funktion verbessert. Ein schönes Wochenende. VG<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 15:07, 15. Nov. 2014 (CET)</small></kbd>
+
+:::::::Was sollen die Änderungen von <code>foo !== -1</code> in <code>!~foo</code>? Ersteres ist deutlich verständlicher und gilt als performanter (in Firefox ist beides praktisch gleich schnell, aber im IE ist es wirklich ein Faktor 2 in der Laufzeit)? --[[Benutzer:Schnark|Schnark]] 09:20, 20. Nov. 2014 (CET)
+
+:::::::: Du siehst aber auch alles (wohl weil JSHint hier auch meckert). Ja hm* verständlicher ist relativ, also für mich ist es rein optisch schon verständlicher (hatte es einfach aus einem Code-Snippet, fand es einfach gut ohne einen Logical-Operator).[[Datei:SMirC-grin.svg|18px|X-)]] Vielen Dank für den Hinweis, ich werde es wieder rückgängig machen.
+:::::::: Bin jetzt auch mit dem autoSigning fertig (mit ebenfalls kleinen Verbesserungen). Mit dem <code>accessKey</code> hatte ich mich wirklich schwer getan (zudem der Tooltip in Chrome vorher auch nicht gestimmt hatte). Bis nachher VG<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 21:08, 20. Nov. 2014 (CET)</small></kbd>
+
+:::::::::Verständlich ist es nur dann, wenn man weiß, dass negative Integers intern als [[Zweierkomplement]] dargestellt werden, was in gewisser Hinsicht die natürlichste, aber keineswegs die offensichtlichste oder einzige Darstellung ist. Tatsächlich finde ich im ES5-Standard kein einziges Wort dazu, in ES6 auch nur eine sehr versteckte Erwähnung am Rande.
+:::::::::Warnungen von JSHint sind nicht dazu da Programmierer zu ärgern, sondern sollten von sehr wenigen Ausnahmefällen abgesehen immer beachtet werden.
+:::::::::In signing.js trifft mein Kommentar zum <code>wpAutoSummary</code>-Hack noch immer zu, das gilt natürlich auch für sectionSummary.js. <code>Array.prototype.filter</code> führt als ES5-Methode im IE8 zu Laufzeitfehlern. Wie gesagt, IE8 ist nicht das Maß aller Dinge, aber solange MW diesen Browser unterstützt, darf kein Skript Laufzeitfehler auslösen. Entweder lädst du den ES5-Shim oder schreibst die entsprechende Anweisung auf jQuery um. Gleiches gilt für ausgefallenere Methoden von <code>console</code>. --[[Benutzer:Schnark|Schnark]] 09:53, 21. Nov. 2014 (CET)
+┌{{padleft:┘|22|─}}<br />
+Ich kümmer mich die Woche drum (mir sind jetzt auch noch einige Kleinigkeiten bzw. Verbesserungen eingefallen, man muss sich ja immer wieder erst in den ganzen Code reindenken).
+@Hack: Ich finde auf Diskussionsseiten ist dieser Hack legitim, er kommt auch nur zur Anwendung wenn der Minor-Button aktiviert wurde, ansonsten wird der Wert wieder resettet.
+@sectionSummary kommt hinzu dass das Summary eh vom Script geändert wird und der Tocken hinfällig wird und tatsächlich wird der Tocken nur geändert wenn das Summary geändert wurde. Damit wollte ich auf die ganze Cookie-Komplikation (die sich ja auch dieses Jahr wieder geändert hat) umgehen. Daher würde ich dich bitten ein Zugeständnis zu machen und hier ein Auge zuzudrücken.[[Datei:SMirC-wink.svg|20px|;-)]]
+PS: Ich habe mal deinen alten Bugreport [[bugzilla:38829]] etwas Aufmerksamkeit zugeführt. [[Datei:SMirC-jealous.svg|20px|(°₀°)]] LG<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]''<small> 13:26, 2. Dez. 2014 (CET)</small></kbd>
+
+:Ich verwende die Funktion „Warnen, wenn Zusammenfassung fehlt“ dazu, dass ich eine Bearbeitung wirklich erst dann speichere, wenn ich fertig bin, und fülle dazu die Zusammenfassungszeile erst ganz am Schluss aus. Sollte ich zwischendurch versehentlich auf „Speichern“ klicken, dann bekomme ich zuerst eine Warnung. Zudem kannst du dir nie sicher sein, was die Serverseite mit ungültigen MD5-Codes macht. Im Augenblick ignoriert sie diese Tatsache, es kann aber ohne Vorwarnung passieren, dass sich dieses Verhalten plötzlich ändert, und dann der Wert, den du dort speicherst, verworfen wird, oder der Benutzer ganz am Abspeichern gehindert wird. Darum: Ein Feld, dass den MD5-Hash einer Zusammenfassung enthalten soll, darf auch nur den MD5-Hash einer Zusammenfassung enthalten und sonst nichts.
+:happy5214 kümmert sich gerade sehr um meine Bugreports, [[phab:T39485]], den er auch behoben hat, war mir ehrlich gesagt wichtiger. --[[Benutzer:Schnark|Schnark]] 09:11, 3. Dez. 2014 (CET)
+:: Nun denn ein Frohes Neues! (Bevor der Thread wieder in der Versenkung verschwindet, ich habe deine Einwände betr. „Warnen“ dahingehend „gefixt“, dass das hidden Tocken-Feld vor dem Speichern gänzlich resetet wird.) Es scheint mir du würdest tatsächlich auf eine Cookielösung hinaus wollen (denn eine andere sehe ich jetzt nicht)⁉ OT: Mir scheint du hast dein [[Benutzer:Schnark/js/Wikisyntax-config.js|WSTM config]] gänzlich deaktiviert (oder ich habe deine Mühen zur Unterbindung fremder Einbindung nicht völlig erfasst, Z.151)!?<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]'' <small> 14:59, 3. Jan. 2015 (CET)</small></kbd>
+:::Selbst wenn du beim Abspeichern den Inhalt von wpAutoSummary beim Speichern wiederherstellst, reicht das nicht, es muss bei jeglicher Serverinteraktion, also auch bei der Vorschau, ein korrekter Wert übergeben werden, andernfalls musst du mit undefiniertem Verhalten rechnen. --[[Benutzer:Schnark|Schnark]] 09:28, 5. Jan. 2015 (CET)
+
+== Danke ==
+
+Vielen Dank für Deine sehr ausführliche und hilfreiche Antwort auf meine [[Wikipedia:Auskunft#Hilberts_Axiomensystem_der_euklidischen_Geometrie|Frage auf der Wikipedia-Asukunft]]. Mir ist gleich ein ganzer Kronleuchter aufgegangen... {{unsigniert|79.245.165.238|17:49, 8. Jan. 2015 (CET)‎}}
+
+:Gern geschehen! --[[Benutzer:Schnark|Schnark]] 09:03, 9. Jan. 2015 (CET)
+
+== Bug erstellen ==
+
+Hi Schnark, könntest Du bitte mal schauen, ob es zu dem [[Wikipedia:Bots/Anfragen/Archiv/2014-2#Referenzierungsfehler_finden|hier beschriebenem Problem]] schon einen Bug gibt und ihn ggf. erstellen?--[[Benutzer:Mabschaaf|Mabschaaf]] 23:20, 15. Jan. 2015 (CET)
+
+:Ehrlich gesagt ist mir der Abschnitt viel zu lang um ihn mir durchzulesen. Du kannst unter https://phabricator.wikimedia.org/maniphest/query/advanced/ selbst suchen, mit deinem Wikipedia-Konto kannst du dich inzwischen auch direkt bei Phabricator anmelden und selbst eine Task anlegen, wenn du nichts findest. So schwer ist das nicht, und wenn man beim ersten Mal etwas falsch macht, ist das auch nicht schlimm. --[[Benutzer:Schnark|Schnark]] 10:15, 16. Jan. 2015 (CET)
+::Du musst gar nicht den kompletten Abschnitt lesen, das erste Posting reicht. Ich werde auf phab sicher nicht aktiv.--[[Benutzer:Mabschaaf|Mabschaaf]] 16:08, 16. Jan. 2015 (CET)
+:::[[Benutzer:Se4598]] wars: [[phab:T85386]]. Was spricht gegen phab? (Oder jeden anderen Bug-Tracker?) [[Benutzer:Umherirrender|Der Umherirrende]] 16:50, 16. Jan. 2015 (CET)
+:::: Also ich finde (den Abschnitt auch zu lang), dass Phab fast in jeder Hinsicht ein Fortschritt zum alten Bugzilla ist (ein paar wenige Schwächen wird es wohl geben, aber darum soll es ja hier jetzt nicht gehen).<kbd style="white-space:nowrap;color:#567"> ↔ ''[[User: Perhelion]]'' <small> 21:55, 16. Jan. 2015 (CET)</small></kbd>
+
+== Testwiki ==
+
+Hallo Schnark,
+ich bräuchte, um Dinge für [[WP:Meinungsbilder/Erweiterung der Sichterrechte|dieses MB]] eine Möglichkeit, in einem Wiki, in dem die Benutzerrechtskonfiguration mit einer Ausnahme genau wie hier sind, zu editiern und verschieben. Um genau zu sein geht es um eine zusätzliche Benutzergruppe mit move-subpages, suppressredirect und unwatchedpages. Was kann ich da machen? Eine eigene MediaWiki-Installattion habe ich noch nie gemacht. --[[Benutzer:MGChecker|MGChecker]] ([[Benutzer Diskussion:MGChecker|Disk.]] &#124; [[Spezial:Beiträge/MGChecker|Beitr.]] &#124; [[Benutzer:MGChecker/Bewertung|Bewert.]]) 12:44, 17. Jan. 2015 (CET)
+
+:Ich habe zwar ein privates Testwiki, aber dort funktioniert <code>$wgRateLimits</code> nicht (und den meisten anderen Testwiki-Besitzern wird das ähnlich gehen). Frag am besten mal unter [[mw:Project:Support desk]] nach, dort sollte es eigentlich jemand wissen. --[[Benutzer:Schnark|Schnark]] 10:37, 19. Jan. 2015 (CET)
+
+== Echo-Test ==
+
+[[Benutzer:X" onclick="alert('XSS');" title="y]] [[Benutzer Diskussion:Schnark]] 10:15, 29. Jan. 2015 (CET)
+
+[[Benutzer:X" onclick="alert('XSS');" title="y]] [[Benutzer:Schnark|<span>falsch]] verschachtelt</span> 10:20, 29. Jan. 2015 (CET)
+
+[[Benutzer:X" onclick="alert('XSS');" title="y]] --[[Benutzer:Schnark]] ([[Benutzer:Schnark/js|js]]) 10:26, 29. Jan. 2015 (CET)
diff --git a/Echo/tests/phpunit/includes/revision_txt/40608353.txt b/Echo/tests/phpunit/includes/revision_txt/40608353.txt
new file mode 100644
index 00000000..3d4bcba8
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/40608353.txt
@@ -0,0 +1,145 @@
+{{/D}}
+== Perfil ==
+
+Olá, Paulo!
+
+Verifiquei que no histórico do meu perfil aparece o teu nome como possível reversor do meu próprio perfil. Gostaria de esclarecimentos. Obrigado. Abraços [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 22h30min de 27 de outubro de 2014 (UTC)
+
+Entendi. Ainda há um outro erro, que não tem a ver com você. Meu perfil está relacionado com "Corsplarge" e essa relação me caracteriza como fantocheiro. Acabei de enviar uma mensagem para quem está no meu histórico e que acho que foi quem me caracterizou assim. Mas eu nunca usei outros nomes. Isso está errado. Como eu devo proceder nesse caso? [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 22h49min de 27 de outubro de 2014 (UTC)
+
+Ok. "Se ele parece um pato, nada como um pato e grasna como um pato, ele é provavelmente um pato". Prefiro a visão de René Magritte: "Isto não é um Cachimbo. Vê-se um cachimbo e afirma-se que não se trata de tal." Não menos importante é saber o porquê de estarem vigiando a minha página e até mesmo querendo dominar as informações do MEU próprio perfil, revertendo as informações que escolho tirar. É o meu perfil! Bem, obrigado pela ajuda. Abraços [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 23h13min de 27 de outubro de 2014 (UTC)
+
+Mas não há regra referente a proibir a remoção de conteúdo do meu histórico, apesar de não ser bem visto e tal. Mas não configura violação de regras da Wiki, porque é "meu perfil". Quando digo meu, quero dizer referente a mim.[[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 23h28min de 27 de outubro de 2014 (UTC)
+
+A questão é que não fico fuçando no perfil de ninguém. Se você altera o teu perfil, nem ligo. Se o Genaron, FSogumo ou o Lord Mota alteram os deles, penso que eles devem ter o seus motivos. Se alguém altera o meu, não há outra explicação a não ser a "pegação de pé" ou a falta do que fazer. Não entendo isso! Boa noite. Abraços [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 23h40min de 27 de outubro de 2014 (UTC)
+
+Apenas utilizei o nome deles como exemplo para argumentar, não os culpei. Não verifico quem reverteu ou bloqueou o meu nome. Mas a princípio achei estranho você se preocupar com o que eu faço no "meu" perfil. Mas agora entendi. [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 00h21min de 28 de outubro de 2014 (UTC)
+
+== Obrigado pela resposta ==
+
+Mais uma questão: ele também será eliminado da busca no google?<small>—''comentário [[Ajuda:Guia_de_edição/Assinar|não assinado]] de '' [[Usuário:Bernardo Rodrigues|Bernardo Rodrigues]] ([[Usuário Discussão:Bernardo Rodrigues|discussão]]&nbsp;•&nbsp;[[Especial:Contribuições/Bernardo Rodrigues|contrib]]) 20h07min de 28 de outubro de 2014‎ (UTC)</small><!-- Substituído da Predefinição:Não assinou -->
+
+== Maiores wikipédias ==
+
+Oi Paulo, percebi que usa a predefinição {{tl|Maiores Wikipedias}}, que atualmente está bastante impactada pelas pequenas wikis robotizadas. Note lá o cebuano, samarês e o vietnamita na frente da ptwiki, por exemplo, wikis notórias pela estratégia e que já provocaram grandes debates por aí. Não sei se era isso que queria mostrar, mas foi criada uma outra predefinição que leva em consideração a "profundidade" dos artigos, {{tl|Wikipédias com mais artigos desenvolvidos}}, que reflete melhor o papel da ptwiki (e da língua portuguesa) num cenário onde se pretende demonstrar "quem é maior", como é o caso destas predefs. Boas! [[Usuário:jbribeiro1|José Luiz]] <sup> [[Usuário Discussão:Jbribeiro1|disc]]</sup> 00h59min de 29 de outubro de 2014 (UTC)
+
+== Administrador ==
+<!-- Substituído da Predefinição:Novo administrador -->
+[[Imagem:Wikipedia Administrator.svg|direita|150px]]
+Caro usuário, informo que lhe foi <span class="plainlinks">[{{fullurl:Especial:Registro|type=rights&user=%C3%89rico+J%C3%BAnior+Wouters&page=Usuário:PauloEduardo&year=2014&month=10&hide_patrol_log=1}} atribuído]</span> o estatuto de [[Wikipédia:Administradores|administrador]] de acordo com a decisão da comunidade em [[Wikipédia:Pedidos de administração/PauloEduardo|votação]]. Por favor, apenas tenha em mente que:
+
+* Este estatuto lhe possibilita, de modo geral, o [[Especial:Registro/rights|gerenciamento de privilégios]], [[Wikipédia:Página protegida|proteção]], [[Wikipédia:eliminadores|eliminação]] e [[Wikipédia:Restauro|restauro de páginas]], além de [[Wikipédia:Administradores#Ferramentas|outras ferramentas]].
+* O abuso destas ferramentas poderá ocasionar a abertura de um [[Wikipédia:Pedidos de administração#Desnomeações do estatuto de administrador|pedido de desnomeação]]. Verifique atentamente como utilizar as suas permissões e como [[Wikipédia:Regras de conduta para administradores|deve proceder]].
+* Não se deve esquecer do que [[Wikipédia:O que os administradores não são|os administradores não são]].
+* Caso tenha quaisquer dúvidas sobre as ferramentas poderá perguntar aos outros administradores no <span class="plainlinks">[irc://freenode/wikipedia-pt-admins canal do IRC]</span>.
+* Existe a possibilidade de incluir em sua página de usuário a caixa {{tlu|Wikipédia:Userbox/Administrador}}, para fins de identificação.
+* Se, por qualquer motivo, decidir que não deseja mais usufruir desta permissão, poderá fazer um pedido de remoção no [[:m:Steward requests/Permissions|Meta-Wiki]].
+: Bom trabalho! [[Usuário:Érico Júnior Wouters|<font color="gray">'''Érico Wouters'''</font>]] <sup>[[Usuário discussão:Érico Júnior Wouters|msg]]</sup> 14h40min de 30 de outubro de 2014 (UTC)
+
+== Agradecimento ==
+
+Olá Paulo Eduardo! Agradeço a confiança pela atribuição do status de autorevisor. Parabenizo-o pela unanimidade na eleição de administrador. (não vi seu pedido, se tivesse visto votaria a favor. Suas contribuições são admiráveis.). E informo que você ganhou mais um xereta nas suas discussões...{{piscada}} {{llp}} [[Usuário:Ixocactus|Ixocactus]] ([[Usuário Discussão:Ixocactus|discussão]]) 18h45min de 30 de outubro de 2014 (UTC)
+
+== Uma medalha! ==
+
+{| style="background-color: #fdffe7; border: 1px solid #fceb92;"
+|rowspan="2" style="vertical-align: middle; padding: 5px;" | [[File:Special Barnstar Hires.png|100px]]
+|style="font-size: x-large; padding: 3px 3px 0 3px; height: 1.5em;" | '''Medalha especial'''
+|-
+|style="vertical-align: middle; padding: 3px;" | Entrego-lhe esta medalha pelas suas ótimas contribuições, pelo seu estatuto, e por ter me ajudado bastante quando eu comecei com o estatuto de reversor!
+Certamente suas dicas foram valiosas, você merece tudo de bom {{8D}}
+
+Abraços, <span style="font-family: Segoe Print, sans-serif;">[[Usuário:Jackgba|<span style="color:green;">'''Jack<span style="color:#1E90FF;">gba'''</span>]]</span></span><sup>[[Usuário Discussão:Jackgba|'''Msg''']]</sup> 16h58min de 31 de outubro de 2014 (UTC)
+|}
+
+== Vou entrar no tunel ==
+
+Olá colega, eu estava esperando para ver se ele aparecia de novo mas .... você foi rápido kkkk. É bom ver que tem outro sysop de madrugada, eu costumo passar as madrugadas sozinho. Um abraço [[Usuário:DARIO SEVERI|DARIO SEVERI]] ([[Usuário Discussão:DARIO SEVERI|discussão]]) 11h04min de 1 de novembro de 2014 (UTC)
+:Nove horas no sábado é ainda de madrugada, aqui são quase as 7 da noite e estou me preparando para sair com a minha noiva asiática, para dizer a verdade já é minha esposa. Abraço(s) + de um ... não quero ser considerado egoísta também hahaha. [[Usuário:DARIO SEVERI|DARIO SEVERI]] ([[Usuário Discussão:DARIO SEVERI|discussão]]) 11h40min de 1 de novembro de 2014 (UTC)
+
+== Wikipédia Discussão:Página de testes ==
+
+Para info:
+
+'''Wikipédia Discussão:Página de testes'''
+
+A página esta protegida desde 16h47min de 7 de maio de 2011 por EuTuga [edit=sysop] (infinito) [move=sysop] (infinito)
+
+Nenhum robô pode editar esta página.
+
+Sds, [[Usuário:Kim richard|Kim ®ichard]] <sup>[[Usuário Discussão:Kim richard|oi]]</sup> 15h48min de 4 de novembro de 2014 (UTC)
+
+:Entendi. Sinto não poder ajudar. Abraços [[Usuário:Kim richard|Kim ®ichard]] <sup>[[Usuário Discussão:Kim richard|oi]]</sup> 19h48min de 4 de novembro de 2014 (UTC)
+
+== Re: Reversão ==
+
+Erro meu. Quis reverter várias edições (incluindo a do ip anterior ao que você já tinha revertido) e em vez de clicar em desfazer, fui por engano, em "reverter" (o que desfez só a sua edição). Obrigado por avisar. [[Usuário(a):Eamaral|Eamaral]] ([[Usuário(a) Discussão:Eamaral|discussão]]) 22h51min de 10 de novembro de 2014 (UTC)
+== Discussão de bloqueio ==
+{{ambox|tipo=notícia|texto=Caro administrador, foi iniciado um pedido de revisão de bloqueio do(a) usuário(a) [[Usuário:Iacobus Artifex|Iacobus Artifex]].<br />A discussão está ocorrendo na seguinte página: [[Wikipédia:Pedidos a administradores/Discussão de bloqueio/Iacobus Artifex]].<br />Lembre-se de que a sua <u>[[Wikipédia:Pedidos a administradores/Discussão de bloqueio/Iacobus Artifex#Avaliação dos administradores|análise]]</u> do bloqueio deve ocorrer, obrigatoriamente, ao abrigo das [[Wikipédia:Políticas e recomendações|políticas e recomendações do projeto]] e da [[Wikipédia:Política de bloqueio|política de bloqueio]], incluindo, na medida do possível, uma síntese cuidadosa dos argumentos expostos.<br />Sua participação é importante.
+<div style="font-size: smaller; text-align: center;">Mensagem enviada automáticamente por [[User:Aleth Bot|Aleth Bot]].<br />Caso pretenda deixar de receber as notificações, avise o [[Utilizador discussão:Alchimista|operador]][[Usuária:Aleth Bot|Aleth Bot]] ([[Usuária Discussão:Aleth Bot|discussão]]) 03h26min de 11 de novembro de 2014 (UTC)}}
+
+== Moção ==
+
+Por favor, pode mover [[Não Adianta Chorar (desambiguação)]] para [[Não Adianta Chorar]]?
+
+Aproveitando a ocasião, há alguns pedidos dessa natureza em [[WP:PA/Outros]], aguardando atendimento. Se puder dar uma olhada, agradeço.
+
+[[Image:Fuchs-Vulcan salute.svg|20px|Piscada]]<!--code style="background:yellow">;-)</code--> ''Vida longa e próspera!''
+
+[[Usuário:Yanguas|<span style="color:#8b0000;font-family:Viner Hand ITC;font-size:11pt">Yanguas</span>]] <sup>[[Usuário Discussão:Yanguas|diz!]]-[[Especial:Contribuições/Yanguas|fiz]]</sup> 14h20min de 11 de novembro de 2014 (UTC)
+
+== IP :199.255.210.169 ==
+
+Olá PauloEduardo, bloqueia [https://pt.wikipedia.org/wiki/Usu%C3%A1rio(a)_Discuss%C3%A3o:199.255.210.169|esse usuário IP], ele também é um proxy aberto, fiz o pedido de bloqueio dele na [[WP:P/B]], mas como você mesmo pode conferir, lá ele aparece como um usuário inexistente, por isso to fazendo o pedido de bloqueio na sua PDU. {{llp}}--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 17h59min de 11 de novembro de 2014 (UTC)
+:{{U|Leon saudanha}}, aonde diz que esse IP é um proxy aberto? [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 18h02min de 11 de novembro de 2014 (UTC)
+[https://pt.wikipedia.org/wiki/Wikip%C3%A9dia:Detec%C3%A7%C3%A3o_de_proxies_abertos aqui], ele é um proxy aberto tão poderoso que consegue até mesmo ocultar seu endereço https de usuário aqui, por isso não dá pra chegar a ele apenas apontando o link de sua PDU--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 18h12min de 11 de novembro de 2014 (UTC)
+:OK {{U|Leon saudanha}}, a {{U|Belanidia}} já bloqueou. Mas não vá na hipótese que exista um proxy "tão poderoso" a ponto de não lhe permitir fazer [[User talk:199.255.210.169|isso]], ou [[Especial:Contribuições/199.255.210.169|isso]]. [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 18h18min de 11 de novembro de 2014 (UTC)
+Foi um erro de escrita rs. Ele é um anonimizador, provavelmente é por isso que não adiantou pedir o bloqueio dele na [[WP:P/B]]--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 18h23min de 11 de novembro de 2014 (UTC)
+:Certo {{U|Leon saudanha|Leon}}, sem problemas, hehehehe... Um abraço. [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 18h25min de 11 de novembro de 2014 (UTC)
+
+==[[:TV Globo América do Sul]]==
+<!-- O aviso a seguir foi substituído da Predefinição:Aviso-PE -->
+[[Imagem:Ambox warning yellow.svg|left|48px|]]
+
+O verbete [[:TV Globo América do Sul]], editado por você, foi marcado para [[Wikipédia:Eliminação por consenso|eliminação por consenso]], por ter sido considerado, por algum editor, não condizente com a Wikipédia; isso significa que o verbete talvez não satisfaça os [[Wikipédia:Critérios de notoriedade|critérios de notoriedade]] estabelecidos pela comunidade ou se encaixe no descrito em {{nowrap|[[Wikipédia:O que a Wikipédia não é|O que a Wikipédia não é]].}}
+
+Você poderá <u>'''[[Wikipédia:Páginas para eliminar/TV Globo América do Sul|expor seus argumentos na discussão]]'''</u> para manter ou eliminar, porém '''jamais''' remova o aviso de eliminação que está no verbete, pois seria considerado [[WP:vandalismo|vandalismo]].
+
+Boas contribuições! [[Usuário:GRS73|Fabiano]] <sup> [[Usuário Discussão:GRS73|'''msg''']]</sup> 22h28min de 11 de novembro de 2014 (UTC)
+
+== Usuário Atlanticidades IESF ==
+
+Olá Paulo, o usuário {{u|Atlanticidades IESF}} é provavelmente um [[WP:SOCK|fantoche]] do usuário {{u|Jorgesandramanuel}} usado para tentar recriar o artigo [[IESF]] após eu ter avisado na PDU dele que se insistisse com essa atitude, seria bloqueado--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 22h58min de 12 de novembro de 2014 (UTC)
+
+== Patrulhamento ==
+
+Poderia tentar [[Ajuda:Edição patrulhada|patrulhar]] as edições que reverte? Isso evitaria que elas aparecessem na lista de revisões que outros editores precisam conferir posteriormente... Aparentemente [[bugzilla:72433|o Huggle não faz isso automaticamente]] quando o utiliza em vez do sistema de ''rollback'' do próprio MediaWiki. [[Usuário(a):He7d3r|Helder]] 12h59min de 13 de novembro de 2014 (UTC)
+:Ah sim. E diferente do que disse, não sou reversor, sou administrador. E marquei a opção ''Use software rollback''. Vou tentar fazer um teste com essa opção marcada e desmarcada. Att, [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h19min de 13 de novembro de 2014 (UTC)
+::Estranho. Nenhuma das duas edições revertidas ([[Special:Diff/40601214|40601214]] e [[Special:Diff/40601225|40601225]]) foi [https://pt.wikipedia.org/w/index.php?title=Especial:Registo&dir=prev&offset=20141113000000&limit=10&type=patrol&user=&page=Usu%C3%A1rio%3APauloEduardo%2FTestes&tagfilter=&hide_patrol_log=1&hide_review_log=1&hide_thanks_log=1 registrada como patrulhada] (só as reversões propriamente ditas, [[Special:Diff/40601219|40601219]] e [[Special:Diff/40601231|40601231]]).
+::Sobre o que eu disse no bug, eu tinha informado ele antes de você ter adquirido as permissões administrativas. Atualizei lá com informações sobre os seus testes recentes. [[Usuário(a):He7d3r|Helder]] 13h31min de 13 de novembro de 2014 (UTC)
+:::{{Ping|He7d3r}} Entendi. Pensei que tinha feito o pedido recentemente. Estranho mesmo acontecer nas duas situações. [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h35min de 13 de novembro de 2014 (UTC)
+::::Pois é... Isso é muito inconveniente. [[Usuário(a):He7d3r|Helder]] 13h40min de 13 de novembro de 2014 (UTC)
+::::Também está acontecendo nas edições que o [[User:Vitor Mazuco|Vitor Mazuco]] reverte (por exemplo, eu tive que [https://pt.wikipedia.org/wiki/Especial:Registo/patrol?page=Coenzimas&uselang=en patrulhar] uma [[Special:Diff/40601249|edição]] que ele já havia revertido). [[Usuário(a):He7d3r|Helder]] 13h45min de 13 de novembro de 2014 (UTC)
+Hmmm, estranho, então não é só comigo. Chato é ter que marcar todas as edições que forem revertidas pelo Huggle como patrulhadas manualmente. [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h48min de 13 de novembro de 2014 (UTC)
+
+== Notificações ==
+Por algum motivo não fui notificado quando [[Special:Diff/40601300|mencionou meu nome de usuário]]. Poderia fazer um teste? Troque "Usuário" por "Usuário(a)" na sua assinatura e mencione meu nome de usuário novamente para conferirmos se funciona? [[Usuário(a):He7d3r|Helder]] 13h40min de 13 de novembro de 2014 (UTC)
+:{{Ping|He7d3r}} Com a assinatura normal foi feita em minha página de testes. Agora com Usuário(a) foi feito aqui. [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h45min de 13 de novembro de 2014 (UTC)
+::<del>Não funcionou. Estamos com azar hoje... [[Image:Sad.png]].</del> [[Usuário(a):He7d3r|Helder]] 13h49min de 13 de novembro de 2014 (UTC) <ins>Isso foi culpa do [[bugzilla:54639]]</ins>
+:::Não sei se lembra, mas não é a primeira vez que isso acontece comigo. Ora o usuário citado [https://pt.wikipedia.org/w/index.php?title=Especial:Restaurar&target=Usu%C3%A1rio%3APauloEduardo%2FTestes&timestamp=20141106213328&diff=prev recebe notificação], [[Wikipédia:Pedidos/Bloqueio#Albergue.alb|ora não]]. [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h52min de 13 de novembro de 2014 (UTC)
+::Eu informei no [[bugzilla:73366]] mas seria interessante fazermos mais alguns testes para descobrir exatamente em que situações esse problema ocorre. Poderia tentar me notificar mais uma vez, com a assinatura padrão (isto é, esvaziando o campo de assinatura personalizada e sem "Tratar assinatura como texto wiki")? [[Usuário(a):He7d3r|Helder]] 13h57min de 13 de novembro de 2014 (UTC)
+:::{{Ping|He7d3r}} em minha página de testes e aqui. Alguma coisa? [[Usuário:PauloEduardo|PauloEduardo]] ([[Usuário Discussão:PauloEduardo|discussão]]) 14h02min de 13 de novembro de 2014 (UTC)
+::::As edições [[Special:Diff/40601500|40601500]], [[Special:Diff/40601506|40601506]] e [[Special:Diff/40601521|40601521]] geraram uma notificação. Por outro lado, só agora notei que a [[Special:Diff/40601378|40601378]] do seu teste anterior não deveria ser considerada, pois pode ter sido afetada por [[bugzilla:54639|outro bug igualmente chato]], que ocorre quando alguém substitui um conteúdo que já existia na página. [[Usuário(a):He7d3r|Helder]] 14h07min de 13 de novembro de 2014 (UTC)
+:[[bugzilla:73366#c1|Resumo]]: parece que no momento só o que funciona é "User" e "Usuário" (antes, pelo que me recordo, só funcionavam "Usuário" e "Usuário(a)"). [[Usuário(a):He7d3r|Helder]] 14h42min de 13 de novembro de 2014 (UTC)
+::Entendi {{U|He7d3r}}, acho que é esse bug mesmo. {{=)}} [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 15h05min de 13 de novembro de 2014 (UTC)
+:::Com sorte será só [https://gerrit.wikimedia.org/r/#/c/173077/1/includes/DiscussionParser.php,unified este problema com os parêntesis] que acabaram de corrigir (mas que demorará uns dias para ficar online, eu acho). [[Usuário(a):He7d3r|Helder]] 22h25min de 13 de novembro de 2014 (UTC)
+::::Fiz alguns testes e agora todas as opções estão funcionando: "User", "Usuário", "Usuário(a)", "Usuária", "User talk", "Usuário Discussão", "Usuário(a) Discussão" e "Usuária Discussão". [[Usuário(a):He7d3r|Helder]] 11h31min de 14 de novembro de 2014 (UTC)
+
+== Uma medalha! ==
+
+{| style="background-color: #fdffe7; border: 1px solid #fceb92;"
+|rowspan="2" style="vertical-align: middle; padding: 5px;" | [[File:Barnstar of Reversion Hires.png|100px]]
+|style="font-size: x-large; padding: 3px 3px 0 3px; height: 1.5em;" | '''Medalha pelo combate ao vandalismo'''
+|-
+|style="vertical-align: middle; padding: 3px;" | Muito obrigado pelo bloqueio temporário da página, pois considero ato de reverter o trabalho de meses de um usuário, de má fé. Em breve entraremos em um consenso. [[Usuário(a):JoseAlfedo|JoseAlfedo]] ([[Usuário(a) Discussão:JoseAlfedo|discussão]]) 16h01min de 13 de novembro de 2014 (UTC)
+|}
diff --git a/Echo/tests/phpunit/includes/revision_txt/40610292.txt b/Echo/tests/phpunit/includes/revision_txt/40610292.txt
new file mode 100644
index 00000000..c08945d3
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/40610292.txt
@@ -0,0 +1,146 @@
+{{/D}}
+== Perfil ==
+
+Olá, Paulo!
+
+Verifiquei que no histórico do meu perfil aparece o teu nome como possível reversor do meu próprio perfil. Gostaria de esclarecimentos. Obrigado. Abraços [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 22h30min de 27 de outubro de 2014 (UTC)
+
+Entendi. Ainda há um outro erro, que não tem a ver com você. Meu perfil está relacionado com "Corsplarge" e essa relação me caracteriza como fantocheiro. Acabei de enviar uma mensagem para quem está no meu histórico e que acho que foi quem me caracterizou assim. Mas eu nunca usei outros nomes. Isso está errado. Como eu devo proceder nesse caso? [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 22h49min de 27 de outubro de 2014 (UTC)
+
+Ok. "Se ele parece um pato, nada como um pato e grasna como um pato, ele é provavelmente um pato". Prefiro a visão de René Magritte: "Isto não é um Cachimbo. Vê-se um cachimbo e afirma-se que não se trata de tal." Não menos importante é saber o porquê de estarem vigiando a minha página e até mesmo querendo dominar as informações do MEU próprio perfil, revertendo as informações que escolho tirar. É o meu perfil! Bem, obrigado pela ajuda. Abraços [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 23h13min de 27 de outubro de 2014 (UTC)
+
+Mas não há regra referente a proibir a remoção de conteúdo do meu histórico, apesar de não ser bem visto e tal. Mas não configura violação de regras da Wiki, porque é "meu perfil". Quando digo meu, quero dizer referente a mim.[[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 23h28min de 27 de outubro de 2014 (UTC)
+
+A questão é que não fico fuçando no perfil de ninguém. Se você altera o teu perfil, nem ligo. Se o Genaron, FSogumo ou o Lord Mota alteram os deles, penso que eles devem ter o seus motivos. Se alguém altera o meu, não há outra explicação a não ser a "pegação de pé" ou a falta do que fazer. Não entendo isso! Boa noite. Abraços [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 23h40min de 27 de outubro de 2014 (UTC)
+
+Apenas utilizei o nome deles como exemplo para argumentar, não os culpei. Não verifico quem reverteu ou bloqueou o meu nome. Mas a princípio achei estranho você se preocupar com o que eu faço no "meu" perfil. Mas agora entendi. [[Usuário:Montolive|ASP]] ([[Usuário Discussão:Montolive|discussão]]) 00h21min de 28 de outubro de 2014 (UTC)
+
+== Obrigado pela resposta ==
+
+Mais uma questão: ele também será eliminado da busca no google?<small>—''comentário [[Ajuda:Guia_de_edição/Assinar|não assinado]] de '' [[Usuário:Bernardo Rodrigues|Bernardo Rodrigues]] ([[Usuário Discussão:Bernardo Rodrigues|discussão]]&nbsp;•&nbsp;[[Especial:Contribuições/Bernardo Rodrigues|contrib]]) 20h07min de 28 de outubro de 2014‎ (UTC)</small><!-- Substituído da Predefinição:Não assinou -->
+
+== Maiores wikipédias ==
+
+Oi Paulo, percebi que usa a predefinição {{tl|Maiores Wikipedias}}, que atualmente está bastante impactada pelas pequenas wikis robotizadas. Note lá o cebuano, samarês e o vietnamita na frente da ptwiki, por exemplo, wikis notórias pela estratégia e que já provocaram grandes debates por aí. Não sei se era isso que queria mostrar, mas foi criada uma outra predefinição que leva em consideração a "profundidade" dos artigos, {{tl|Wikipédias com mais artigos desenvolvidos}}, que reflete melhor o papel da ptwiki (e da língua portuguesa) num cenário onde se pretende demonstrar "quem é maior", como é o caso destas predefs. Boas! [[Usuário:jbribeiro1|José Luiz]] <sup> [[Usuário Discussão:Jbribeiro1|disc]]</sup> 00h59min de 29 de outubro de 2014 (UTC)
+
+== Administrador ==
+<!-- Substituído da Predefinição:Novo administrador -->
+[[Imagem:Wikipedia Administrator.svg|direita|150px]]
+Caro usuário, informo que lhe foi <span class="plainlinks">[{{fullurl:Especial:Registro|type=rights&user=%C3%89rico+J%C3%BAnior+Wouters&page=Usuário:PauloEduardo&year=2014&month=10&hide_patrol_log=1}} atribuído]</span> o estatuto de [[Wikipédia:Administradores|administrador]] de acordo com a decisão da comunidade em [[Wikipédia:Pedidos de administração/PauloEduardo|votação]]. Por favor, apenas tenha em mente que:
+
+* Este estatuto lhe possibilita, de modo geral, o [[Especial:Registro/rights|gerenciamento de privilégios]], [[Wikipédia:Página protegida|proteção]], [[Wikipédia:eliminadores|eliminação]] e [[Wikipédia:Restauro|restauro de páginas]], além de [[Wikipédia:Administradores#Ferramentas|outras ferramentas]].
+* O abuso destas ferramentas poderá ocasionar a abertura de um [[Wikipédia:Pedidos de administração#Desnomeações do estatuto de administrador|pedido de desnomeação]]. Verifique atentamente como utilizar as suas permissões e como [[Wikipédia:Regras de conduta para administradores|deve proceder]].
+* Não se deve esquecer do que [[Wikipédia:O que os administradores não são|os administradores não são]].
+* Caso tenha quaisquer dúvidas sobre as ferramentas poderá perguntar aos outros administradores no <span class="plainlinks">[irc://freenode/wikipedia-pt-admins canal do IRC]</span>.
+* Existe a possibilidade de incluir em sua página de usuário a caixa {{tlu|Wikipédia:Userbox/Administrador}}, para fins de identificação.
+* Se, por qualquer motivo, decidir que não deseja mais usufruir desta permissão, poderá fazer um pedido de remoção no [[:m:Steward requests/Permissions|Meta-Wiki]].
+: Bom trabalho! [[Usuário:Érico Júnior Wouters|<font color="gray">'''Érico Wouters'''</font>]] <sup>[[Usuário discussão:Érico Júnior Wouters|msg]]</sup> 14h40min de 30 de outubro de 2014 (UTC)
+
+== Agradecimento ==
+
+Olá Paulo Eduardo! Agradeço a confiança pela atribuição do status de autorevisor. Parabenizo-o pela unanimidade na eleição de administrador. (não vi seu pedido, se tivesse visto votaria a favor. Suas contribuições são admiráveis.). E informo que você ganhou mais um xereta nas suas discussões...{{piscada}} {{llp}} [[Usuário:Ixocactus|Ixocactus]] ([[Usuário Discussão:Ixocactus|discussão]]) 18h45min de 30 de outubro de 2014 (UTC)
+
+== Uma medalha! ==
+
+{| style="background-color: #fdffe7; border: 1px solid #fceb92;"
+|rowspan="2" style="vertical-align: middle; padding: 5px;" | [[File:Special Barnstar Hires.png|100px]]
+|style="font-size: x-large; padding: 3px 3px 0 3px; height: 1.5em;" | '''Medalha especial'''
+|-
+|style="vertical-align: middle; padding: 3px;" | Entrego-lhe esta medalha pelas suas ótimas contribuições, pelo seu estatuto, e por ter me ajudado bastante quando eu comecei com o estatuto de reversor!
+Certamente suas dicas foram valiosas, você merece tudo de bom {{8D}}
+
+Abraços, <span style="font-family: Segoe Print, sans-serif;">[[Usuário:Jackgba|<span style="color:green;">'''Jack<span style="color:#1E90FF;">gba'''</span>]]</span></span><sup>[[Usuário Discussão:Jackgba|'''Msg''']]</sup> 16h58min de 31 de outubro de 2014 (UTC)
+|}
+
+== Vou entrar no tunel ==
+
+Olá colega, eu estava esperando para ver se ele aparecia de novo mas .... você foi rápido kkkk. É bom ver que tem outro sysop de madrugada, eu costumo passar as madrugadas sozinho. Um abraço [[Usuário:DARIO SEVERI|DARIO SEVERI]] ([[Usuário Discussão:DARIO SEVERI|discussão]]) 11h04min de 1 de novembro de 2014 (UTC)
+:Nove horas no sábado é ainda de madrugada, aqui são quase as 7 da noite e estou me preparando para sair com a minha noiva asiática, para dizer a verdade já é minha esposa. Abraço(s) + de um ... não quero ser considerado egoísta também hahaha. [[Usuário:DARIO SEVERI|DARIO SEVERI]] ([[Usuário Discussão:DARIO SEVERI|discussão]]) 11h40min de 1 de novembro de 2014 (UTC)
+
+== Wikipédia Discussão:Página de testes ==
+
+Para info:
+
+'''Wikipédia Discussão:Página de testes'''
+
+A página esta protegida desde 16h47min de 7 de maio de 2011 por EuTuga [edit=sysop] (infinito) [move=sysop] (infinito)
+
+Nenhum robô pode editar esta página.
+
+Sds, [[Usuário:Kim richard|Kim ®ichard]] <sup>[[Usuário Discussão:Kim richard|oi]]</sup> 15h48min de 4 de novembro de 2014 (UTC)
+
+:Entendi. Sinto não poder ajudar. Abraços [[Usuário:Kim richard|Kim ®ichard]] <sup>[[Usuário Discussão:Kim richard|oi]]</sup> 19h48min de 4 de novembro de 2014 (UTC)
+
+== Re: Reversão ==
+
+Erro meu. Quis reverter várias edições (incluindo a do ip anterior ao que você já tinha revertido) e em vez de clicar em desfazer, fui por engano, em "reverter" (o que desfez só a sua edição). Obrigado por avisar. [[Usuário(a):Eamaral|Eamaral]] ([[Usuário(a) Discussão:Eamaral|discussão]]) 22h51min de 10 de novembro de 2014 (UTC)
+== Discussão de bloqueio ==
+{{ambox|tipo=notícia|texto=Caro administrador, foi iniciado um pedido de revisão de bloqueio do(a) usuário(a) [[Usuário:Iacobus Artifex|Iacobus Artifex]].<br />A discussão está ocorrendo na seguinte página: [[Wikipédia:Pedidos a administradores/Discussão de bloqueio/Iacobus Artifex]].<br />Lembre-se de que a sua <u>[[Wikipédia:Pedidos a administradores/Discussão de bloqueio/Iacobus Artifex#Avaliação dos administradores|análise]]</u> do bloqueio deve ocorrer, obrigatoriamente, ao abrigo das [[Wikipédia:Políticas e recomendações|políticas e recomendações do projeto]] e da [[Wikipédia:Política de bloqueio|política de bloqueio]], incluindo, na medida do possível, uma síntese cuidadosa dos argumentos expostos.<br />Sua participação é importante.
+<div style="font-size: smaller; text-align: center;">Mensagem enviada automáticamente por [[User:Aleth Bot|Aleth Bot]].<br />Caso pretenda deixar de receber as notificações, avise o [[Utilizador discussão:Alchimista|operador]][[Usuária:Aleth Bot|Aleth Bot]] ([[Usuária Discussão:Aleth Bot|discussão]]) 03h26min de 11 de novembro de 2014 (UTC)}}
+
+== Moção ==
+
+Por favor, pode mover [[Não Adianta Chorar (desambiguação)]] para [[Não Adianta Chorar]]?
+
+Aproveitando a ocasião, há alguns pedidos dessa natureza em [[WP:PA/Outros]], aguardando atendimento. Se puder dar uma olhada, agradeço.
+
+[[Image:Fuchs-Vulcan salute.svg|20px|Piscada]]<!--code style="background:yellow">;-)</code--> ''Vida longa e próspera!''
+
+[[Usuário:Yanguas|<span style="color:#8b0000;font-family:Viner Hand ITC;font-size:11pt">Yanguas</span>]] <sup>[[Usuário Discussão:Yanguas|diz!]]-[[Especial:Contribuições/Yanguas|fiz]]</sup> 14h20min de 11 de novembro de 2014 (UTC)
+
+== IP :199.255.210.169 ==
+
+Olá PauloEduardo, bloqueia [https://pt.wikipedia.org/wiki/Usu%C3%A1rio(a)_Discuss%C3%A3o:199.255.210.169|esse usuário IP], ele também é um proxy aberto, fiz o pedido de bloqueio dele na [[WP:P/B]], mas como você mesmo pode conferir, lá ele aparece como um usuário inexistente, por isso to fazendo o pedido de bloqueio na sua PDU. {{llp}}--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 17h59min de 11 de novembro de 2014 (UTC)
+:{{U|Leon saudanha}}, aonde diz que esse IP é um proxy aberto? [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 18h02min de 11 de novembro de 2014 (UTC)
+[https://pt.wikipedia.org/wiki/Wikip%C3%A9dia:Detec%C3%A7%C3%A3o_de_proxies_abertos aqui], ele é um proxy aberto tão poderoso que consegue até mesmo ocultar seu endereço https de usuário aqui, por isso não dá pra chegar a ele apenas apontando o link de sua PDU--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 18h12min de 11 de novembro de 2014 (UTC)
+:OK {{U|Leon saudanha}}, a {{U|Belanidia}} já bloqueou. Mas não vá na hipótese que exista um proxy "tão poderoso" a ponto de não lhe permitir fazer [[User talk:199.255.210.169|isso]], ou [[Especial:Contribuições/199.255.210.169|isso]]. [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 18h18min de 11 de novembro de 2014 (UTC)
+Foi um erro de escrita rs. Ele é um anonimizador, provavelmente é por isso que não adiantou pedir o bloqueio dele na [[WP:P/B]]--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 18h23min de 11 de novembro de 2014 (UTC)
+:Certo {{U|Leon saudanha|Leon}}, sem problemas, hehehehe... Um abraço. [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 18h25min de 11 de novembro de 2014 (UTC)
+
+==[[:TV Globo América do Sul]]==
+<!-- O aviso a seguir foi substituído da Predefinição:Aviso-PE -->
+[[Imagem:Ambox warning yellow.svg|left|48px|]]
+
+O verbete [[:TV Globo América do Sul]], editado por você, foi marcado para [[Wikipédia:Eliminação por consenso|eliminação por consenso]], por ter sido considerado, por algum editor, não condizente com a Wikipédia; isso significa que o verbete talvez não satisfaça os [[Wikipédia:Critérios de notoriedade|critérios de notoriedade]] estabelecidos pela comunidade ou se encaixe no descrito em {{nowrap|[[Wikipédia:O que a Wikipédia não é|O que a Wikipédia não é]].}}
+
+Você poderá <u>'''[[Wikipédia:Páginas para eliminar/TV Globo América do Sul|expor seus argumentos na discussão]]'''</u> para manter ou eliminar, porém '''jamais''' remova o aviso de eliminação que está no verbete, pois seria considerado [[WP:vandalismo|vandalismo]].
+
+Boas contribuições! [[Usuário:GRS73|Fabiano]] <sup> [[Usuário Discussão:GRS73|'''msg''']]</sup> 22h28min de 11 de novembro de 2014 (UTC)
+
+== Usuário Atlanticidades IESF ==
+
+Olá Paulo, o usuário {{u|Atlanticidades IESF}} é provavelmente um [[WP:SOCK|fantoche]] do usuário {{u|Jorgesandramanuel}} usado para tentar recriar o artigo [[IESF]] após eu ter avisado na PDU dele que se insistisse com essa atitude, seria bloqueado--[[Usuário:Leon saudanha|<span style="color: #0ff; background: #000;">Leon saudanha</span>]] 22h58min de 12 de novembro de 2014 (UTC)
+
+== Patrulhamento ==
+
+Poderia tentar [[Ajuda:Edição patrulhada|patrulhar]] as edições que reverte? Isso evitaria que elas aparecessem na lista de revisões que outros editores precisam conferir posteriormente... Aparentemente [[bugzilla:72433|o Huggle não faz isso automaticamente]] quando o utiliza em vez do sistema de ''rollback'' do próprio MediaWiki. [[Usuário(a):He7d3r|Helder]] 12h59min de 13 de novembro de 2014 (UTC)
+:Ah sim. E diferente do que disse, não sou reversor, sou administrador. E marquei a opção ''Use software rollback''. Vou tentar fazer um teste com essa opção marcada e desmarcada. Att, [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h19min de 13 de novembro de 2014 (UTC)
+::Estranho. Nenhuma das duas edições revertidas ([[Special:Diff/40601214|40601214]] e [[Special:Diff/40601225|40601225]]) foi [https://pt.wikipedia.org/w/index.php?title=Especial:Registo&dir=prev&offset=20141113000000&limit=10&type=patrol&user=&page=Usu%C3%A1rio%3APauloEduardo%2FTestes&tagfilter=&hide_patrol_log=1&hide_review_log=1&hide_thanks_log=1 registrada como patrulhada] (só as reversões propriamente ditas, [[Special:Diff/40601219|40601219]] e [[Special:Diff/40601231|40601231]]).
+::Sobre o que eu disse no bug, eu tinha informado ele antes de você ter adquirido as permissões administrativas. Atualizei lá com informações sobre os seus testes recentes. [[Usuário(a):He7d3r|Helder]] 13h31min de 13 de novembro de 2014 (UTC)
+:::{{Ping|He7d3r}} Entendi. Pensei que tinha feito o pedido recentemente. Estranho mesmo acontecer nas duas situações. [[Usuário:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h35min de 13 de novembro de 2014 (UTC)
+::::Pois é... Isso é muito inconveniente. [[Usuário(a):He7d3r|Helder]] 13h40min de 13 de novembro de 2014 (UTC)
+::::Também está acontecendo nas edições que o [[User:Vitor Mazuco|Vitor Mazuco]] reverte (por exemplo, eu tive que [https://pt.wikipedia.org/wiki/Especial:Registo/patrol?page=Coenzimas&uselang=en patrulhar] uma [[Special:Diff/40601249|edição]] que ele já havia revertido). [[Usuário(a):He7d3r|Helder]] 13h45min de 13 de novembro de 2014 (UTC)
+Hmmm, estranho, então não é só comigo. Chato é ter que marcar todas as edições que forem revertidas pelo Huggle como patrulhadas manualmente. [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h48min de 13 de novembro de 2014 (UTC)
+
+== Notificações ==
+Por algum motivo não fui notificado quando [[Special:Diff/40601300|mencionou meu nome de usuário]]. Poderia fazer um teste? Troque "Usuário" por "Usuário(a)" na sua assinatura e mencione meu nome de usuário novamente para conferirmos se funciona? [[Usuário(a):He7d3r|Helder]] 13h40min de 13 de novembro de 2014 (UTC)
+:{{Ping|He7d3r}} Com a assinatura normal foi feita em minha página de testes. Agora com Usuário(a) foi feito aqui. [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h45min de 13 de novembro de 2014 (UTC)
+::<del>Não funcionou. Estamos com azar hoje... [[Image:Sad.png]].</del> [[Usuário(a):He7d3r|Helder]] 13h49min de 13 de novembro de 2014 (UTC) <ins>Isso foi culpa do [[bugzilla:54639]]</ins>
+:::Não sei se lembra, mas não é a primeira vez que isso acontece comigo. Ora o usuário citado [https://pt.wikipedia.org/w/index.php?title=Especial:Restaurar&target=Usu%C3%A1rio%3APauloEduardo%2FTestes&timestamp=20141106213328&diff=prev recebe notificação], [[Wikipédia:Pedidos/Bloqueio#Albergue.alb|ora não]]. [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 13h52min de 13 de novembro de 2014 (UTC)
+::Eu informei no [[bugzilla:73366]] mas seria interessante fazermos mais alguns testes para descobrir exatamente em que situações esse problema ocorre. Poderia tentar me notificar mais uma vez, com a assinatura padrão (isto é, esvaziando o campo de assinatura personalizada e sem "Tratar assinatura como texto wiki")? [[Usuário(a):He7d3r|Helder]] 13h57min de 13 de novembro de 2014 (UTC)
+:::{{Ping|He7d3r}} em minha página de testes e aqui. Alguma coisa? [[Usuário:PauloEduardo|PauloEduardo]] ([[Usuário Discussão:PauloEduardo|discussão]]) 14h02min de 13 de novembro de 2014 (UTC)
+::::As edições [[Special:Diff/40601500|40601500]], [[Special:Diff/40601506|40601506]] e [[Special:Diff/40601521|40601521]] geraram uma notificação. Por outro lado, só agora notei que a [[Special:Diff/40601378|40601378]] do seu teste anterior não deveria ser considerada, pois pode ter sido afetada por [[bugzilla:54639|outro bug igualmente chato]], que ocorre quando alguém substitui um conteúdo que já existia na página. [[Usuário(a):He7d3r|Helder]] 14h07min de 13 de novembro de 2014 (UTC)
+:[[bugzilla:73366#c1|Resumo]]: parece que no momento só o que funciona é "User" e "Usuário" (antes, pelo que me recordo, só funcionavam "Usuário" e "Usuário(a)"). [[Usuário(a):He7d3r|Helder]] 14h42min de 13 de novembro de 2014 (UTC)
+::Entendi {{U|He7d3r}}, acho que é esse bug mesmo. {{=)}} [[Usuário(a):PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 15h05min de 13 de novembro de 2014 (UTC)
+:::Com sorte será só [https://gerrit.wikimedia.org/r/#/c/173077/1/includes/DiscussionParser.php,unified este problema com os parêntesis] que acabaram de corrigir (mas que demorará uns dias para ficar online, eu acho). [[Usuário(a):He7d3r|Helder]] 22h25min de 13 de novembro de 2014 (UTC)
+::::Fiz alguns testes e agora todas as opções estão funcionando: "User", "Usuário", "Usuário(a)", "Usuária", "User talk", "Usuário Discussão", "Usuário(a) Discussão" e "Usuária Discussão". [[Usuário(a):He7d3r|Helder]] 11h31min de 14 de novembro de 2014 (UTC)
+{{U|He7d3r}}, o bug da autorrevisão do Huggle foi corrigido? [[User:PauloEduardo|<span style="font-size:13px; color:blue;font-family:Lucida Handwriting;text-shadow:aqua 5px 3px 12px;">Paulo Eduardo</span>]]'' <sup>[[User Talk:PauloEduardo|<font color="gold" face="Lucida Calligraphy">Discussão</font>]]</sup>'' 15h44min de 14 de novembro de 2014 (UTC)
+
+== Uma medalha! ==
+
+{| style="background-color: #fdffe7; border: 1px solid #fceb92;"
+|rowspan="2" style="vertical-align: middle; padding: 5px;" | [[File:Barnstar of Reversion Hires.png|100px]]
+|style="font-size: x-large; padding: 3px 3px 0 3px; height: 1.5em;" | '''Medalha pelo combate ao vandalismo'''
+|-
+|style="vertical-align: middle; padding: 3px;" | Muito obrigado pelo bloqueio temporário da página, pois considero ato de reverter o trabalho de meses de um usuário, de má fé. Em breve entraremos em um consenso. [[Usuário(a):JoseAlfedo|JoseAlfedo]] ([[Usuário(a) Discussão:JoseAlfedo|discussão]]) 16h01min de 13 de novembro de 2014 (UTC)
+|}
diff --git a/Echo/tests/phpunit/includes/revision_txt/637637213.txt b/Echo/tests/phpunit/includes/revision_txt/637637213.txt
new file mode 100644
index 00000000..12092f17
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/637637213.txt
@@ -0,0 +1,824 @@
+{{Skip to talk}}
+{{Talk header|search=yes}}
+{{Not a forum}}
+{{WikiProjectBannerShell|blpo=yes|collapsed=yes|banner collapsed=no|1=
+{{WikiProject Law Enforcement |class=C}}
+{{WikiProject Missouri |class=C |importance=Mid}}
+{{WikiProject Death |class=C |importance=Low}}
+{{WikiProject Discrimination |class=C |importance=Mid}}
+{{WikiProject Politics |class=C |importance=Low}}
+{{WikiProject St. Louis |class=C}}
+}}
+{{User:MiszaBot/config
+|archiveheader = {{talkarchivenav|noredlinks=y}}
+|maxarchivesize = 150K
+|counter = 19
+|minthreadsleft = 4
+|minthreadstoarchive = 1
+|algo = old(5d)
+|archive = Talk:Shooting of Michael Brown/Archive %(counter)d
+}}
+{{Calm}}
+{{Autoarchivingnotice|bot=MiszaBot|age=5|units=days}}
+{{article discretionary sanctions|topic=blp|style=long}}
+
+==RFC: ''Alleged'' theft of cigars from convenience store?==
+{{archivetop|result=Consensus is fairly clearly against using "alleged". [[User:Number 57|<font color="orange">Number</font>]] [[User talk:Number 57|<font color="green">5</font>]][[Special:Contributions/Number 57|<font color="blue">7</font>]] 12:36, 10 December 2014 (UTC)}}
+In references here to the theft and/or strong-arm robbery of cigars from a convenience store prior to the shooting of the decedent, should this article use the term ''alleged'' or ''allegedly'' before any such claims since the decedent was never and will never be charged or convicted of theft or robbery? <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 02:52, 29 November 2014 (UTC)
+===survey===
+*(As nom) '''Yes''', as that is Wikipedia's standard practice when a criminal act is alleged but will never be prosecuted. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 02:54, 29 November 2014 (UTC)
+* '''no''' There is video of the event. An admission from his friend who was present, and admission from the Brown family. We actually have numerous opposite examples of non-convicted persons who are described as having done certain illegal actions, and we have hundreds of reliable sources saying without qualification that brown took the Cigars without paying. However, describing that theft in a specific legal crime term should not be done as we do not have sufficient proof that all elements of a crime were done, it is enough to say "stole cigars" or "took cigars without paying" but not "committed robbery" etc. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 03:00, 29 November 2014 (UTC)
+:: In regard to the question whether there is "sufficient proof that all elements of a crime were done", we just need to follow the MO law. It says, "[http://law.justia.com/codes/missouri/2013/title-xxxviii/chapter-569/section-569.030/ A person commits the crime of robbery in the second degree when he forcibly steals property.]" Did he steal the items? Did he use force when confronted by the clerk? If you say yes to both questions, then all elements of the crime were done and the act is called robbery in the second degree. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 01:08, 30 November 2014 (UTC)
+
+*'''No''' per Gaijin42 above and also see Columbine Shooting, Sandy Hook Elementary Shooting,, Isla Vista Killings and numerous other articles here on WP where a crime has been committed with the individual being killed and/or suicide with no prosecution and/or conviction and the word alleged is not used in those articles. I would also note that the police have classified this case as being "exceptionally cleared", a stringent standard to meet in a case when there will be no prosecution or conviction.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 03:04, 29 November 2014 (UTC)
+*'''No''' - Alleged refers to something that is said, without proof, to have taken place or done. Also, by the same logic of Dwpaul, you cannot identify someone for a criminal act if they are incapable of being tried. Glad to know that despite the Columbine Shooting evidence that you are content to put "alleged", again a reference to "unproven", in front of any act or attribution of the killers. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 05:52, 29 November 2014 (UTC)
+:::Didn't say you "cannot identify someone for a criminal act"; simply said you should make clear you are not claiming they have been ''convicted'' of it, if only for your own protection (in this case, for the protection of the project). That is all ''allegedly'' does. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 06:05, 29 November 2014 (UTC)
+:::: We are not "convicting" anyone. Your understanding of "alleged"'s use is wrong according to the dictionary. Allegations in a legal sense are no different, but you should be aware of that process. Since this is not a pending court matter so kindly take your armchair lawyering off this page. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 06:31, 29 November 2014 (UTC)
+
+*'''No.''' According to [[WP:ALLEGED]], alleged is ''"appropriate when wrongdoing is asserted but undetermined, such as with people awaiting or undergoing a criminal trial."'' In this case, Brown will never go to trial so the issue won't be determined that way. However, we are not entirely without the ability to make an editorial determination here. We have a published security video showing what certainly appears to be a theft (or more accurately strong arm robbery) and there is the published testimony of Brown's friend Johnson describing the events in the store. That description supports that it was in fact a strong arm robbery. In addition, many (though not all) sources refer to the event as a theft and do not use the term "alleged". Taking all this into consideration, I think it's perfectly reasonable, neutral and accurate to treat it as an actual crime and leave out he word "alleged".
+
+:There have been theories suggesting that maybe Brown did pay for the cigars and the clerk just wanted an ID. This is an interesting theory, but entirely unsupported by ''anything''. Others note that no store employee contacted the police (a customer did). In no way does this cause other evidence to vanish. Again, taking ALL things into consideration from what is available to us, it is reasonable to say that a crime was committed and there is nothing "alleged" about it. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:11, 29 November 2014 (UTC)
+
+::That actually brings up an interesting question. Let's suppose Brown (who is of age) wants to buy cigars and the clerk wants to see an ID. Let's further suppose Brown throws down the money and says "screw the ID, here's the money" then grabs the cigars and leaves. The clerk tries to stop him still wanting to see the ID. Brown pushes past and exits the store (we'll forget about the hard shoving). Has a crime been committed? Or more specifically, is it theft? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:36, 29 November 2014 (UTC)
+
+:::If for some reasons you put a million dollars cash on the counter but the clerk refuses to "sell" an inexpensive product (no matter what it is) and you take that product anyway, then you use force to clear your way out of the store, you will still be charged with robbery in the second degree as per [http://m.willworshamlaw.com/Criminal-Defense-Home/Robbery.aspx MO law]. Even when give a correct amount of money to the clerk for the cigar, but the clerk refuses to sell that to you. The transaction does not take place. When you take valuable propety from that store when you have not been the owner of that property yet, it is stealing. To add to that, you use force, it's a robbery of the second degree. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 00:48, 30 November 2014 (UTC)
+:::: What a poor example - the discussion below shows it is closed and why. Original research or other accusations carry no real weight because the official report ''is'' our proper source. As a result, no matter what excuses or theoretical case you come up with, it does not apply to this case. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 05:06, 30 November 2014 (UTC)
+
+*'''No''' – In prior weeks there was some question from news sources whether Brown might have actually paid for the cigarillos, that analysis seems to have disappeared even in Brown-friendly news outlets as more information has come out. Also, [[John Wilkes Booth]] did not "allegedly" assassinate Abraham Lincoln, even though he was never convicted of it. —[[User:Megiddo1013|Megiddo1013]] 01:49, 30 November 2014 (UTC)
+
+* '''No''' - In the absence of any other reasonable explanations for what can be seen in the footage and testimonies, it seems safe to go with what the recently written RSs say on this one. [[User:AdventurousSquirrel|AdventurousSquirrel]] ([[User talk:AdventurousSquirrel|talk]]) 12:56, 30 November 2014 (UTC)
+
+* '''No''' - There's really no question at this point of what happened, and Brown is very much dead and thus we have no reason to worry about prejudicing a jury against him. It is safe to not use "alleged" here as we have video, testimony from his friend, RSs which don't use "alleged", and standard Wiki policy that in cases like this that we don't use it ([[John Wilkes Booth]], [[Columbine shooting]], ect.). [[User:Titanium Dragon|Titanium Dragon]] ([[User talk:Titanium Dragon|talk]]) 15:18, 30 November 2014 (UTC)
+
+*'''COMMENT''' Due to the apparent [[WP:SNOW]] above, I am going to remove the "allege"s that are referring to the robbery. However, the RFC remains open, and consensus could certainly swing the other way over the next days/weeks. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 15:25, 30 November 2014 (UTC)
+
+*'''No''' - Per the users above. There is no question as to the factual nature of the crime.--<span style="text-shadow:grey 0.125em 0.138em 0.118em; class=texhtml">[[User:TMDrew|<font color="black">'''TMD'''</font>]] [[User_talk:TMDrew|<small>Talk Page.</small>]]</span> 16:06, 30 November 2014 (UTC)
+
+*'''No''' Per [[User:AdventurousSquirrel|AdventurousSquirrel]]. We should be going with what the recent [[WP:RS]] are saying. [[User:rmosler2100|<span style="color:green">'''R'''</span><span style="color:black; font-variant:small-caps">'''mosler'''</span>]]&nbsp;|[[User_talk:Rmosler2100| <span style="color:black; font-variant:small-caps">●</span>]] 16:18, 1 December 2014 (UTC)
+
+===Threaded discussion===
+Can you include a source for the "exceptionally cleared" classification being applied to this case and its <s>meaning</s>significance, since this information (not there now) would be useful to include in the article? I can find references to the police report including this notation, but none that say it gives it some special degree of "truthiness".<span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 03:29, 29 November 2014 (UTC)
+:Exceptionally cleared is a [[Uniform Crime Reports]] term. It means "solved" by "exception" not the "awesome" meaning of exceptional http://www.fbi.gov/about-us/cjis/ucr/crime-in-the-u.s/2010/crime-in-the-u.s.-2010/clearances NPR is one of many many sources saying that the case was closed with this status, but they appear to be doing so based on just viewing the police report. http://www.npr.org/blogs/thetwo-way/2014/08/15/340594634/ferguson-police-release-name-of-officer-who-shot-michael-brown [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 03:38, 29 November 2014 (UTC)
+::Thank you. I was about to point out the same finding to {{U|Isaidnoway}}, with a caution against using it to suggest some special quality of the investigation. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 03:45, 29 November 2014 (UTC)
+:::Its not some special quality, but it does indicate that the case was formally solved including identifying the perp sufficient for FBI reporting purposes. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 03:49, 29 November 2014 (UTC)
+::::Well, that is one interpretation; I would tend to go with your suggestion above that the case was said to have been resolved "by exception", in this case by the death of the only suspect at the time rather than by diligent and detailed police work that would have achieved a conviction. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 03:52, 29 November 2014 (UTC)
+:::::From the Missouri Uniform Crime Reporting Program (Missouri State Highway Patrol):
+:::::Exceptional Clearance - If <u>all</u> four of the following questions can be answered 'Yes' the offense can be cleared “exceptionally”.
+
+:::::# Do you know who the offender is?
+:::::# Has the investigation determined there is enough information to support an arrest/charge of a specific individual?
+:::::# Is the location of this individual known so the subject could by taken into custody now?
+:::::# Is there some reason outside law enforcement‟s control that precludes arresting, charging, and prosecuting the offender?
+
+:::::Examples of exceptional clearances include: death (suicide or justifiable homicide where the offender is killed by a police officers or citizen). This case meets all the above criteria for the case to be closed as "exceptionally cleared".[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 07:04, 29 November 2014 (UTC)
+:The police report (external links) says that it has been exceptionally cleared and if you search the archives of this talk page, you will see that this very same discussion has been had before about using the word alleged in relation to this strong-arm robbery committed by Brown.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 03:43, 29 November 2014 (UTC)
+::Yes, I see [https://en.wikipedia.org/wiki/Talk:Shooting_of_Michael_Brown/Archive_7#Robbery_or_alleged_robbery this previous discussion from August], and I see you making the same arguments you're making now, but I don't see that any consensus evolved in support of them. In fact, I see quite a lot of dissent on the question. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 04:00, 29 November 2014 (UTC)
+:::Thanks for the RfC, maybe we can put these unsourced conspiracy theories to rest once and for all.
+:::*[http://www.ibtimes.com/michael-brown-robbed-convenience-store-stole-cigarillos-darren-wilson-shooting-dorian-1729359 Michael Brown Robbed Convenience Store, Stole Cigarillos Before Darren Wilson Shooting, Dorian Johnson Says]
+:::*[http://abcnews.go.com/US/wireStory/highlights-testimony-michael-brown-shooting-27157610 Dorian Johnson told the grand jury he was stunned when Brown stole cigarillos from the convenience store]
+:::*[http://www.nationalreview.com/corner/385499/attorney-brown-acquaintance-confirms-michael-brown-stole-cigars-greg-pollowitz The attorney for Dorian Johnson, the man who was with Michael Brown when he was shot, says it was Brown who stole the cigars from the store where police say the two were filmed before Brown’s death, and that the FBI is aware of it.][[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 06:33, 29 November 2014 (UTC)
+::::* Also... "Brown was a suspect in an alleged robbery" is horrendous writing because you cannot "allege a robbery" and the nature of the matter requires "alleged" be dropped. Either a robbery took place or it didn't; it is mutually exclusive here, just as you cannot be an "alleged suspect" in the case. One alleged needs to remain in the article: "Brown then allegedly attempted to seize Wilson's gun..." which has not been conclusively proven. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 06:40, 29 November 2014 (UTC)
+:::[[User:Dwpaul|Dwpaul]], I ended up as a main dissenter in that August discussion, based on the use of reliable sources available at that time. However, more information has been published since then, notably Dorian Johnson's testimony under oath, and I have more carefully reviewed the video, and I don't think that using allege is appropriate. It gives the impression that there is a reasonable doubt that Brown stole the cigars, which isn't the case. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 16:39, 29 November 2014 (UTC)
+:: Whether to use the word "alleged" or not, one thing clear is that we should not misrepresent the act as a theft or stealing. It should either be called "forcibly steal" or "robbery". Apparently, the force was involved. The first mentioning of the act as just stealing in the lead is actually misleading. See definitions here: [http://www.ksdk.com/story/news/local/2014/08/15/strong-arm-robbery-definition-st-louis-county/14122545/] [http://m.willworshamlaw.com/Criminal-Defense-Home/Robbery.aspx]. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 18:58, 29 November 2014 (UTC)
+{{archivebottom}}
+== Offensive Phrasing -- Style Question ==
+
+Under the section Grand Jury Hearing (which should be capitalized, but I don't have editing privileges), it refers to the grand jury's makeup as "three blacks". This usage of black as a noun is not considered acceptable any longer in American English and is specifically prohibited in most style guides (I don't know if this is covered in wikipedia's). <small class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[Special:Contributions/38.108.125.200|38.108.125.200]] ([[User talk:38.108.125.200|talk]]) 19:01, 1 December 2014 (UTC)</small><!-- Template:Unsigned IP --> <!--Autosigned by SineBot-->
+:It isn't offensive and is frequently used in American English. [https://www.google.com/search?q=blacks&es_sm=122&source=univ&tbm=nws&tbo=u&sa=X&ei=L758VJ3yMMP1oATQk4HQCQ&ved=0CFAQsQQ Google shows how many people use it to this very day], including places like the Huffington Post. [[User:Titanium Dragon|Titanium Dragon]] ([[User talk:Titanium Dragon|talk]]) 19:16, 1 December 2014 (UTC)
+:I checked the source used for that sentence, and the source uses the terms "blacks" and "whites" in relation to the race of the grand jury members. Based on that source, I don't see a problem.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 19:50, 1 December 2014 (UTC)
+
+:Isaidnoway is correct, but there is no requirement to match the specific source on something like this, which is not within a quotation. We paraphrase all the time, and what matters is that the world of reliable sources frequently uses "blacks" as a noun. Here's [http://www.nytimes.com/2014/11/26/us/after-ferguson-announcement-a-racial-divide-remains-over-views-of-justice.html an example from the New York Times], who are known for close attention to such details. Incidentally, the "Grand jury hearing" is correct; Wikipedia uses "sentence case" in section titles. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:07, 1 December 2014 (UTC)
+
+:This black/African-American question is not going to be solved in general anytime soon around here. Sources generally use a mix of "black" and "African-American" and so should we. Sources however do NOT generally use the word "Caucasian" when describing Wilson, so that has little place in this article. We're not here to worry about what is offensive to this person or that... we're here to reflect the sources in a neutral and balanced manner. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 00:24, 2 December 2014 (UTC)
+
+:From a strict stylistic standpoint, it'd probably be good to use BOTH terms in the same passage, as [[elegant variation]] (while our article on [[elegant variation]] disparages the practice - contrary to what I and other students in my technical writing degree program were taught - in this case it wouldn't be unnecessary, but would serve the purpose of placating people on each side of the "black"/"African-American" controversy). [[User:Vfrickey|loupgarous]] ([[User talk:Vfrickey|talk]]) 15:49, 6 December 2014 (UTC)
+
+::It may seem unnecessarily contentious to some, but I'm not interested in placating editors who misinterpret Wikipedia's mission as moving social trends rather than documenting them. These editors are simply wrong, and we follow the collective sources. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:06, 6 December 2014 (UTC)
+
+== Why are you calling Michael Brown a man when being eighteen did not qualify Eric David Harris a man????? ==
+
+{{edit semi-protected|Shooting of Michael Brown|answered=y}}
+<!-- Begin request -->If Eric Harris can be called a boy when he was also 18 yrs old when the shootings took place a Columbine High School, I believe we can come to the conclusion that Michael Brown was just a boy also. Stop making him out to be something another was not.......
+I do not know him personally, but you are adding to a problem that will not cease because of status that is not really true. He was only a boy!
+
+<!-- End request -->
+[[User:Butterflygem|Butterflygem]] ([[User talk:Butterflygem|talk]]) 09:01, 2 December 2014 (UTC)
+
+:It's true that [[Eric Harris and Dylan Klebold]] and [[Columbine High School massacre]] use the term "boys" in a few instances. That may or may not reflect source's descriptions of them. You would have to bring that up on those article's respective talk pages. Regarding this article, can you point out the specific part of the article you wish to change and what you'd like to see it changed to? Be prepared (if challenged) to back up your suggested edit with sourcing and a rationale that supports it following Wikipedia policies of [[WP:VERIFY|verifiability]], [[WP:NPOV|neutral point of view]], and [[WP:UNDUE|due weight]]. I'm not trying to make it hard on you, I'm just trying to show you that editing this encyclopedia is more than simply inserting one's opinion. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 11:09, 2 December 2014 (UTC)
+::To be quite honest, I am starting to see some unconscious racism creep in this manner in articles on wikipedia. Two white guys who shot up a school are boys but an unarmed black guy is a man. Just like [[missing white girl syndrome]] -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 12:10, 2 December 2014 (UTC)
+:::I don't think this has anything to do with "unconscious racism". It's hard to visualize, much less describe, anyone who is 6 ft 4 in (1.93 m) tall, weighs 292 lb (132 kg) and smokes cigars as a "boy". In every one of these cases, if the subjects are over 18, they should probably be described as "young men", but I think it's easy to see why the term "man" was used here instead of "boy". It's a bit too convenient to invoke the racism card when a simpler explanation will suffice. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 13:53, 2 December 2014 (UTC)
+:::I also don't think the "unconscious racisim" comment is helpful, it could be seen as casting aspersions and is not [[WP:AGF]]. If you believe that an editor is not following policies or POV pushing, discuss it here or their talk page with diffs. Man, boy, teenager, the choice of nouns should be by consensus and backed by [[WP:RS]]. If you have sources that would back a change, then please share them, and the proposed change. [[User:rmosler2100|<span style="color:green">'''R'''</span><span style="color:black; font-variant:small-caps">'''mosler'''</span>]]&nbsp;|[[User_talk:Rmosler2100| <span style="color:black; font-variant:small-caps">●</span>]] 14:03, 2 December 2014 (UTC)
+::::I'm not accusing any individual editors. I'm saying that RS's and all the editors as a whole(including me) are giving in to a very human tendency to judge on a class basis. -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 14:48, 2 December 2014 (UTC)
+:::::I'd be willing to bet that, if not for the POV implications in this case and a desire for him to be perceived as the victim, we'd just as likely be criticized for calling Brown a "boy" because of the connotations that term has had when applied to young black men in the past. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 14:53, 2 December 2014 (UTC)
+:[[File:Red information icon with gradient background.svg|20px|link=]] '''Not done:''' please establish a [[Wikipedia:Consensus|consensus]] for this alteration before using the {{tlx|edit semi-protected}} template.<!-- Template:ESp --> [[User:Anupmehra|<font size="3"><span style="font-family:Old English Text MT;color:black">Anupmehra</span></font>]] -[[User talk:Anupmehra|<font size="3"><span style="font-family:Monotype Corsiva;color:black">Let's talk!</span></font>]] 14:18, 2 December 2014 (UTC)
+:::Dear Myopia, I believe that your comments on "unconscious racism" amount to silly navel-gazing. Also a more fit subject for your talk page than here. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:12, 2 December 2014 (UTC)
+::::I think it was a constructive contribution, if only because it allowed us to address this aspect of the question from a perspective others may have had or will have in mind, even if they didn't frame their arguments in those terms. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 16:24, 2 December 2014 (UTC)
+:::::Empathize with stupidity and you're half way to thinking like an idiot. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:28, 2 December 2014 (UTC)
+::::::Sometimes that's a creative and useful method of problem solving. Think we're done here. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 16:36, 2 December 2014 (UTC)
+:::::::Dear @[[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]], I don't know what navel gazing is but if you want to cuss me out you might as well accept that you're going to violate [[WP:CIVIL]] anyway and do it properly. I disagree with your suggestion that it's more fit for my talk page. Racism is a core element of this issue and the deaths of black men at the hands of police in general. As far as you calling me stupid, '''that''' was a comment for my talk page. -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 23:41, 4 December 2014 (UTC)
+{{out}} Navel gazing is where you are desperate to find some major significance in a hopelessly insignificant detail of life. Imagine staring intently into your navel, and then you find a piece of lint and want to show your special insight to the world. That was an apt metaphor for your silly comment, in which you made an observation about extremely reasonable & accurate use of language & wondered aloud whether it wasn't actually the reasonableness or accuracy, but NAY SIRS, HIDDEN RACISM, that made us decide to be reasonable and accurate. If you don't see how that is at once both unconstructive & essentially impossible to discuss in connection with this WP article & insulting to other editors, and thus that there was no good reason to put it on the talk page, then I'm not sure what else to say. Then again, judging by your username and userpage — and the comment "Racism is a core element of this issue" — it's pretty clear you are just trolling. So I guess the joke's on me.
+P.S. it appears you don't know what "cussing someone out" means. Probably because of your unconscious racism. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:57, 5 December 2014 (UTC)
+:That someone failed to call an eighteen-year old man a "man" in Columbine, Colorado doesn't excuse repeating the error. We're not responsible for the press's errors nor obliged to repeat then in our articles. Eric Harris, Dylan Klebold, and Michael Brown were all eighteen years old at the time they become notable. That made them eligible for the military draft, capable of making valid legal contracts, and immune to curfews - in short, "men." "Young men," if you want to drive the point home that they couldn't legally buy alcohol in many jurisdictions. [[User:Vfrickey|loupgarous]] ([[User talk:Vfrickey|talk]]) 15:58, 6 December 2014 (UTC)
+::Minor correction... Dylan Klebold was 17. And if I recall, some of the instances of the word "boys" referred to events that happened before they turned 18. (Eric Harris turned 18 just before the shooting) &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:19, 6 December 2014 (UTC)
+
+:The OP's opening strategy is not meaningful. For any question, you can find other articles to support either of two opposing answers. This is the spirit of the essay, [[WP:OSE|Other stuff exists]]. We should confine ourselves to what is appropriate for this article, without cherry-picking other articles that support our point of view. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:26, 6 December 2014 (UTC)
+::Agreed, but no article exists in a vacuum. To ''completely'' disregard similar articles is not wise approach either. A certain amount of consistency is a good thing. Even the essay you mention has a section [[Wikipedia:Other_stuff_exists#Precedent_in_usage|Precedent_in_usage]]. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:38, 6 December 2014 (UTC)
+
+[[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] has engaged in one too many personal attacks. Editors were trying to reason with him on his userpage and I was being discussed and attacked perosnally. I attempted to end the matter peacefully on his userpage but his repeated personal attacks resulted in me snapping and violating [[WP:CIVIL]]. Therefore, I will not be editing this page if this person is involved as well. I have had enough of his bullshit. -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 16:43, 6 December 2014 (UTC)
+:You have made a grand total of zero constructive contributions to this article or Talk page, again it seems like you're just trying to bait negative responses, AKA trolling. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 19:37, 6 December 2014 (UTC)
+::At least one other editor disagrees with your premise, and Myopia123's constructive contributions to this page (including one section they started) are evident. In any case, it is not your place to determine the worthiness of other editors. Since the editor has drawn a line, kindly let them go on their way instead of goading them to cross it. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 20:00, 6 December 2014 (UTC)
+:::Not sure why you find the suggestion that hidden racism could possibly explain the most innocuous and obviously correct editorial decisions, and yet you ''don't'' find helpful the suggestion that such an idea possibly reflects irrational hysteria. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:12, 8 December 2014 (UTC)
+Back to the original question, while some of this can certainly be explained by the bias, or narrative the authors (of the RSs) wishes to tell, or political correctness, one must also remember that Columbine happened in school by and at attendees of that school, which makes the "boy" appellation a bit more contextual.[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:12, 7 December 2014 (UTC)
+
+== Shooting scene ==
+
+I made some edits to the shooting scene section. It's longer.
+
+I expanded the description of the street and indicated the directions in which the people involved were traveling. I added "left side" for those in right hand drive countries. I reorganized the evidence from three groups to two, anchoring the groups around the SUV and Brown's body, because the center group consists of one sandal.
+
+The contentious part of my edit is those ten shell casings. I didn't know they were ''there'' until I saw the diagram. At first I thought it had to be a mistake. I tried to be NPOV about it, but I don't have a good reference about those casings. It has to be mentioned, though.
+
+People (bystanders, parties involved, responders, investigators, etc.) move casings around crime scenes often, apparently. Sometimes it's inadvertent, or people take them as a souvenir, but sometimes people take them or move them simply to make things difficult for investigators, or in the worst case people might move them to make it look like a gun was fired in a different place. So, it's possible that the ten casings near Brown were put there to make it look like Wilson had shot Brown at close range.
+
+Please don't reply with wikilawyering, fellow editors. Change whatever you want, add references, but this is not original research or speculation or whatever. The article needs a diagram. The diagram shows 10 casings in an unusual place. Those 10 casings have to be explained, and the only way to explain them without invoking a conspiracy theory is that they were moved. We can't say how, we can't say when, we can't say by whom, but they must have been moved because all the other evidence points that way. Somewhere in the transcripts or in some article I haven't read there is a clear, solid explanation of how they got there. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 22:27, 4 December 2014 (UTC)
+
+:What are you talking about? They are there because they are near where wilson was standing at the time those shots were fired (plus random physics bounces and the like). There were other cops and media on the scene within seconds/minutes. When exactly do you think things were tampered with? What specifically do you think is proof that that cannot be the natural position of the casings? Where do you think those casings "really belong"?[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:32, 4 December 2014 (UTC)
+
+:Presumably from the blood stain at the far right, at some point Brown was standing near there during some of the shots. (with a fudge factor for how far blood may fly from being hit). Most of the witnesses, and Wilson say that they were about 20ft apart at that point. Wilson and some witnesses say that Brown moved forward, and Wilson says he was trying to backpedal to keep distance (while firing). . That explains the pattern of casings and blood fairly well to me, and more importantly, its all covered by reliable sources. [http://www.washingtonpost.com/politics/2014/11/29/b99ef7a8-75d3-11e4-a755-e32227229e7b_story.html] [http://listverse.com/2014/11/25/10-of-the-most-important-pieces-of-evidence-from-darren-wilson-testimony/][http://thehill.com/blogs/blog-briefing-room/news/225280-wilson-brown-looked-like-demon] [http://www.newyorker.com/news/john-cassidy/darren-wilson-testimony][http://abcnews.go.com/US/exclusive-police-officer-darren-wilson-discusses-moment-shot/story?id=27186946][http://edition.cnn.com/2014/11/25/justice/ferguson-grand-jury-documents/] Saying "speculation" and "original research" is not wikilawyering, its the foundation of the way the wiki works. Find a reliable source that discusses some alternative theory, and we can talk about adding it in. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:45, 4 December 2014 (UTC)
+
+:Roches, unless you can find reliable sources supporting this speculation it cannot go into the article. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:50, 4 December 2014 (UTC)
+
+::I don't have an agenda where I want to introduce an alternative theory. I guess the talk page comment was forceful. What I wanted to happen in the article was for someone who had more knowledge about the location of the casings to add detail. As I say below, I didn't want to say "The placement of the casings is unexplained" because it's not unexplained. It's probably explained in detail in the grand jury evidence. I don't have to be the one to find the evidence; this being a collaborative effort, I wanted the statement that there was something unusual about the placement of the casings to be a call for collaboration. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 06:20, 5 December 2014 (UTC)
+
+Having spent quite a bit of time working on the diagram, I can say that I was confused by the casings as well. Nothing nefarious, there though. What struck me is that Wilson pursued Brown for more than 150 yards, before shooting 10 times toward him. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:56, 5 December 2014 (UTC)
+
+:He didn't shoot while running the distance. He pursued, then stopped. There was a burst of a few shots, then as he backed up, a burst of a few more shots. According to Wilson's testimony, the casings are exactly where one would expect. And if editors haven't heard it yet, here is apparent [https://www.youtube.com/watch?v=BiL-E5WAaUU audio] of the shots. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 04:03, 5 December 2014 (UTC)
+:: Yes, that is what I mean. Wilson pursued Brown for 150 yards before shooting, which begs many questions that I will keep to myself. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 04:12, 5 December 2014 (UTC)
+:::Some of those questions might be answered by reading Wilson's testimony to the grand jury (if you haven't already). And it was 150 feet, not yards. Big difference. 150 feet is not that far a distance at all. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 04:17, 5 December 2014 (UTC)
+::::I think what Cwobeel is saying is that Wilson didn't shoot until Brown turned around and became threatening. And now for your listening and viewing pleasure is a music video by Queen.[https://www.youtube.com/v/g2N0TkfrQhY] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 05:59, 5 December 2014 (UTC)
+:::::It's official... I'm completely confused. No worries though... isn't the first time and won't be the last. If anyone wants to explain the last few posts of this thread to me using small words and short clear sentences, you know where to find me. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 06:22, 5 December 2014 (UTC)
+
+Thanks for not just reverting the whole edit. I'll explain:
+
+''This placement of casings supports the claim that shots were fired in close proximity to Brown.''
+
+I wanted to remind the reader of the early accounts that have Wilson walking up to Brown as he's laying on the pavement and shooting him. I wanted to say that in a neutral way. It's not really disputed that shots were fired in fairly close proximity, so I worded it that way.
+
+''However, shell casings can be moved either inadvertently or in a deliberate attempt to confound or manipulate the investigation of a crime scene.''
+
+This does not require a reference, and it's naive to think the presence of police or media makes a difference, especially considering there were specific requests for assistance regarding the crowd of people who gathered at the scene.
+
+''The grand jury's interpretation cannot be known, but their decision not to indict Wilson suggests they concluded that the casings had been moved.''
+
+I didn't want to say that the position of the casings was "unexplained," because I know there's an explanation, and I was sort of hoping someone would find that explanation and put it in the article. What I meant to say is that their decision not to indict does mean that they were convinced that Wilson did not execute Brown at close range. (The "without invoking a conspiracy theory" above means that we assume the jury decided in accordance with the evidence.) "They concluded the casings had been moved" was a plainly a bad choice of wording on my part. It's totally impossible to be objective, neutral '''and concise''' if people assume content is politically charged, but what I meant is "the decision not to indict Wilson means that they did not think he shot Brown multiple times while he was lying on the ground."
+
+I should apologize for the above assertion that the casings must have been moved. However, the shell casings shouldn't be used to establish the locations where shots were fired.
+
+Some of the casings directly south of the body are where they should be, but the ones to the east are up to 20 feet from what I take to be Wilson's easternmost point. Casings from a .40 cal [[SIG Sauer P229]] are ejected to the right and go slightly forwards or backwards. There are no casings in the area the west of the body, and there probably should be.
+
+Last thing: My interpretation of "reliable source" forbids me from citing a politically biased journalist that interprets a primary source for me. Objective facts from a primary source are not original research, and synthesis of objective facts ''when only one conclusion is possible'' is not speculation. It's badly worded, but the decision not to indict means the jury believed that Wilson accurately described where he shot from. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 06:15, 5 December 2014 (UTC)
+
+{{od}}
+If you have a non-reliable source that discusses a theory, you can bring it up here. We can't use it in the article, but it can certainly be a launching point for finding better sources.
+
+Assuming any particular scenario, particularly one that involves tampering with the scene when there were dozens of eyewitnesses, media, and additional cops (not to mention Wilson himself) within seconds/minutes and nobody mentions anything close to that, on any side of the issue, is absolutely something that requires sourcing
+
+While your conjecture that ""the decision not to indict Wilson means that they did not think he shot Brown multiple times while he was lying on the ground." is true, it is absolutely the type of thing that requires sourcing. We do not put thoughts/words into living people's heads. Ever.
+
+* You say "where only one conclusion is possible" but there are MANY possible conclusions.Here are a few I can think of in just a few minutes. I'm sure they are many more others could come up with. None of them should be discussed or hinted at without reliable sourcing.
+** Wilson could have been that far and moved backwards. (Wilson and witnesses testify to this one)
+** Brown could have had significant forward momentum as he fell putting his body in front of the casings
+** Wilson could have been further to the right side of the road (down on the diagram) so was shooting at an angle and not parallel to the road. Therefore "ejection to the right" would be further down the road
+** MOST guns eject back and to the right, but 20-30% of bullet cases even from those guns go somewhere else, and in a particular gun if the ejector has been modified or bent or something could be consistently sending cases in a different direction
+** If Wilson was [[Limp wristing]], or shooting with the gun tilted (either gangsta style, or canted up or down), or one handed, or any one of infinite shooting positions, it could have significantly affected the trajectory
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 15:34, 5 December 2014 (UTC)
+:As an aside, if and when the graphic is updated, could the caption be corrected from "shell casings" to the correct terminology "shell cases"? The press pretty frequently misuses the term but Wikipedia has it right, here: [[Cartridge (firearms)#Materials]]. Here's another example [http://www.nist.gov/pml/div683/casing-080812.cfm (NIST)]. — [[User:Brianhe|Brianhe]] ([[User talk:Brianhe|talk]]) 19:34, 5 December 2014 (UTC)
+::Meh, I've known my way around guns for almost 30 years and I've never heard the term used that way. Our sources say "shell casings" and I imagine that is what just about everybody says. WP is not a source, and the source you did provide appears to be a deadlink. What is it? It won't load but I notice that the URL includes the word "casing", not "case" or "cases" [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:19, 6 December 2014 (UTC)
+:::It is an NIST report titled "Shelling Out Evidence: NIST Ballistic Standard Helps Tie Guns to Criminals". It provides this definition: "Cartridge cases—the empty shells left behind after a gun is fired...". At some point in my firearms instructor coursework, "case" had been promulgated as the right term to use, "casings are for sausage" being a common mnemonic which you can see in this comment on an urban shooting [http://www.esquire.com/blogs/politics/a-lesson-on-guns-041913]. But on further research the [http://www.nraila.org/glossary.aspx NRA glossary] says they are interchangeable. Perhaps a readjustment to the realities popular usage. Bottom line: request for change is withdrawn. — [[User:Brianhe|Brianhe]] ([[User talk:Brianhe|talk]]) 15:58, 6 December 2014 (UTC)
+
+== Shooting scene diagram ==
+
+Obvious OR diagram by Cwobeel removed. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:02, 5 December 2014 (UTC)
+
+:It won't stay out long. Everything on it was taken directly (and accurately, as far as I can tell) from a grand jury exhibit diagram. No SYNTH occurred. For another example, see the map in [[Motor Torpedo Boat PT-109]], which I had another user create from an equivalent map produced by National Geographic. It has stood for close to a year I guess. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:07, 5 December 2014 (UTC)
+
+{{ec}}{{u|Factchecker_atyourservice}} The diagram is not OR. per [[WP:OI]] "Original images created by a Wikipedian are not considered original research, so long as they do not illustrate or introduce unpublished ideas or arguments" There are multiple RS that have produced virtually identical images, based directly off of the image used by the grand jury
+* http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/capture.png
+* http://graphics8.nytimes.com/newsgraphics/2014/08/13/ferguson-qa/2e754ae76c10ce9a0ea2e1dc9166a341312be797/testimony-Artboard_1.jpg
+* http://graphics.stltoday.com/img/grmp-brown_shooting_scene.png
+* http://news.bbcimg.co.uk/media/images/79290000/jpg/_79290150_ferguson_diagram_20142611_624_v3.jpg
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:07, 5 December 2014 (UTC)
+
+:I suppose it would be ''incredibly rude'' of me to ask about sourcing for the additional data points added to Cwobeel's diagram that do not appear to be in any of the other diagrams? [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:24, 5 December 2014 (UTC)
+::Which are? [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:25, 5 December 2014 (UTC)
+::: e.g. location of "interior side front door blood stains", 21'7" "distance from feet to farthest red stain". Just a suggestion — ''pick one of the published graphs and copy it exactly'', don't try to "amplify" or "improve upon" it with your own research. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:30, 5 December 2014 (UTC)
+::::Distance to the furthest stain is covered by [[WP:CALC]] because the legend that goes with the original grand jury diagram explicitly includes locations with distances. [http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/picture2.png] The word "Interior" could possibly be removed, but since there are a bazzilion sources saying there were stains on the interior doors, its really not an issue IMO. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:38, 5 December 2014 (UTC)
+:::::"provided there is consensus among editors that the result of the calculation is obvious, correct, and a meaningful reflection of the sources." Could anyone hazard an explanation of where that number comes from and why it is significant? Also I don't recall anything from any source giving us the location of interior bloodstains. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:48, 5 December 2014 (UTC)
+:::::::The source for that number comes directly from the legend of the original grand jury diagram, as I said in my previous comment where I gave you a link directly to that legend. It was added by Cwobeel at my request. Since there are witnesses that state that brown moved forward or charged, and there is blood at the furthest most point, I thought it would be a useful addition to give an indication of how far Brown ''may'' have moved (although such must be an inference by the reader, since all we know for sure is the distance to the blood, and not how the blood actually got there). At a minimum even without the inerence, it gives the reader the ability to tell the total size of the scene. There are numerous sources describing blood on the "interior left front door handle" and other locations of the car [http://abcnews.go.com/US/crucial-pieces-evidence-ferguson-grand-jury/story?id=27163048] [http://www.msnbc.com/msnbc/prosecutors-make-trove-michael-brown-case-documents-public] For the scale of the diagram we are will within "accurate" imo. But if you insist on having the word "interior" removed you are free to argue that. BTW, all of this stuff was discussed in quite a bit of detail towards the top of this page, where your suggestions would have been more than welcome, and where you can see the consensus for the image, rather than just charging in blindly and accusing people of breaking policy and deleting the image without discussion. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:55, 5 December 2014 (UTC)
+::::::::Since there is no 21 foot 7 inch figure in that jury page, it looks like you're still not done explaining the origin of the figure, and I confess I'm a bit hazy as to your rationale for having our WP article give an emphasis that the published sources didn't find necessary or relevant. Shall we also try to deduce how many feet or inches Brown would have had to walk to get off the street and onto the sidewalk in order to comply with Wilson's order? That would ''also'' help readers understand the total size of the scene. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 17:03, 5 December 2014 (UTC)
+{{od}} The legend has the position of Browns feet. The legend has the position of the stain. [[WP:CALC]] certainly allows simple vector subtraction. If you think it should be removed, build consensus for it, but since we have been discussing the diagram for 2 days now, and nobody else complained I think you are in the minority so far. Cwobeel has been quite compliant so far with changes to the diagram. If you can build a consensus for a change, I'm sure he would be happy to assist. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:14, 5 December 2014 (UTC)
+:I think that Centrify's concern about us picking that distance to highlight is a reasonable one, and can be addressed with a reliable source that specifically mentions that distance, or one similar. I seem to recall there is such a source, but offhand I don't have a link to it.
+
+:Re the 2 red dots next to the car and their identification, “Red stains driver’s side front door exterior and interior” — When I looked at the diagram for the first time, I thought the red dots indicated red stains on the ground, which they weren't. I would suggest removing the red dots and extending the blue arrow so that the arrowhead just touches the car. Also, I would suggest changing the identification to "Blood on the exterior and interior of the driver’s side front door", and we should include a reliable source for the blood on the car door. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 17:31, 5 December 2014 (UTC)
+
+:: The exhibits says "red stains", not blood stains, so I used the former. The exhibit also says interior and exterior. If you want to check the sources I used see the File page (also below for your convenience):
+::: * map : http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/capture.png
+::: * Legend : http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/picture2.png
+::: Other sources used: NYT [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html], WaPo [http://www.washingtonpost.com/wp-srv/special/national/ferguson-diagram-of-the-scene/], and another one from St Louis Post Dispatch (which I can't locate now, but was very similar to the others. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:51, 5 December 2014 (UTC)
+
+::I also wanted "blood" but thought it got too deep into [[WP:SYNTH]]. There are numerous sources calling out the distance from the blood at marker 19/20 to browns body. The NYTimes in particular called it out, and since THAT ARTICLE is the source for one of the diagrams that completely takes care of SYNTH in my mind "''Mr. Brown’s body was about 153 feet east of Officer Wilson’s car. Mr. Brown’s blood was about 25 feet east of his body. This evidence supports statements that Mr. Brown continued to move closer to the officer after being hit by an initial string of bullets.''"[http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html?hp&action=click&pgtype=Homepage&module=b-lede-package-region&region=top-news&WT.nav=top-news&_r=3] However, there are more. [http://www.washingtonpost.com/news/volokh-conspiracy/wp/2014/12/02/why-michael-browns-best-friends-story-is-incredible/] [http://edition.cnn.com/TRANSCRIPTS/1411/25/ath.01.html] (convenience link to video of previous transcript [http://therightscoop.com/cnn-analyst-reads-crucial-evidence-that-destroys-the-lies-about-michael-brown-shooting/]) [http://www.dailymail.co.uk/news/article-2848749/Highlights-testimony-heard-grand-jury-declined-indict-Ferguson-cop-Darren-Wilson-Michael-Brown-shooting.html][http://online.wsj.com/articles/law-and-evidence-tilted-in-ferguson-polices-favor-1416950255][[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:53, 5 December 2014 (UTC)
+
+If there are changes to be made, I will most certainly comply with requests that have consensus. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:55, 5 December 2014 (UTC)
+
+Also, to avoid re-litigating this issue in the future, we should add a commented section with the sources used to create the diagram. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:56, 5 December 2014 (UTC)
+:Or, even better, figure out a way to show normal citations there. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:12, 5 December 2014 (UTC)
+::We could add a caption to the image, and attach the refs to the caption. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:17, 5 December 2014 (UTC)
+
+:::I took a first shot at it, which can be cleaned up considerably. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:24, 5 December 2014 (UTC)
+:::Are the two NYT images in a NYT article? It's much easier to cite an article than an image. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:35, 5 December 2014 (UTC)
+::::The image created BY the NYT is in my comment just above. The official GJ images just hosted by the times I cant find where the times used them, but other sources do have the same image embedded too [http://www.motherjones.com/politics/2014/11/photos-michael-brown-darren-wilson-grand-jury] [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:40, 5 December 2014 (UTC)
+:::::Yeah, it would be great if we could find them in sources we're already using. We're suffering from ref bloat with a ton of redundant source overlap. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:46, 5 December 2014 (UTC)
+{{od}} They are in both GJ evidence links in the external links section, but those may not count as "refs".[http://www.stltoday.com/news/multimedia/special/the-testimony-the-grand-jury-heard-in-the-michael-brown/html_47d95368-a8f2-5ae1-9173-6653c15d0f0e.html][http://edition.cnn.com/interactive/2014/11/us/ferguson-grand-jury-docs/index.html] [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:54, 5 December 2014 (UTC)
+:No I can't reuse those in a citation, and it would be too hard to find what's being cited in those anyway. I'll figure something out, adding new sources if necessary. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 19:03, 5 December 2014 (UTC)
+
+The "red stains" at the scene were confirmed to be blood by the crime lab. It's not original research to synthesize those pieces of information.
+Please do not refer to publicly available information that was presented to the grand jury as "grand jury evidence." Only the transcripts of the hearing have been released, and nothing else can be released. Much of the evidence, such as photographs and audio recordings, is not public. The original map, if I remember correctly, was part of the medical examiner's office report. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 19:40, 5 December 2014 (UTC)
+
+Thanks Cwobeel and Gaijin42 for the links, which were very helpful.
+
+*Regarding the distance discussed previously — Here’s a source and excerpts that refer to the grand jury proceedings, which I think would justify our highlighting the distance from the blood to the body by showing it in the diagram.
+::http://edition.cnn.com/TRANSCRIPTS/1411/25/ath.01.html :
+
+::"They asked in great detail about the blood spatter evidence, which indicated that Michael Brown walked -- or may have indicated -- that walked back or ran back. There was blood further on down the line. His body ended up being 20 feet closer to Officer Wilson.”
+
+::"But it was the questions on pages 87 and 88 -- and I'm sure you can find these on CNN.com if you want to pore through them yourselves -- the grand juror asks questions of the detective trying to nail down what Mark and Sunny and you guys were just talking about: This physical evidence of blood and the blood pattern and whether or not this blood pattern establishes the distance that Michael Brown traveled when he charged at the officer. And so the grand juror asked this, 'So as far as physical evidence, we have the blood on the ground. That was about 21 or 22 feet from where Michael ground ended up.’ “
+
+:So I think the diagram is OK indicating this distance because it’s a notable distance.
+
+*Regarding the red stains on the car I suggest,
+
+:1. moving the red dots that are for the red stains on the car, to halfway overlap the car boundary, so as not to appear that they are on the ground. (Note this is the style used in this source [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html?hp&action=click&pgtype=Homepage&module=b-lede-package-region&region=top-news&WT.nav=top-news&_r=3].)
+
+:2. adding to the identification, the red stain on the exterior of the driver-side rear door[http://www.washingtonpost.com/wp-srv/special/national/ferguson-diagram-of-the-scene/]
+
+:3. adding the following sources for the red stains on the car [http://www.washingtonpost.com/wp-srv/special/national/ferguson-diagram-of-the-scene/] [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html]
+
+--[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 20:13, 5 December 2014 (UTC)
+:: Updated the infographic as requested. Pls check and let me know if understood you correctly. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:58, 5 December 2014 (UTC)
+:::Looks good. There's a few things I'm thinking about but haven't decided whether to suggest anything, e.g. "red stains" vs "blood stains", interior and exterior of front door, and using the word "feet" in the phrase "distance from feet to farthest red stain" doesn't read well for me. In any case, I consider all your work on the diagram a good job with a good spirit of collaboration. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:40, 6 December 2014 (UTC)
+:::: Please propose alternative wording, as we can always improve. Your feedback is welcome. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 02:10, 6 December 2014 (UTC)
+
+== Grand jury hearing section ==
+
+The grand jury hearing section has, as far as I can tell, only one statement by a law professor in MO. To get an accurate idea of whether the hearing was out-of-the-ordinary, it's got to be compared to other police-involved-shooting cases in the same state.
+
+I made some changes to the table. I know this makes it different than the Times' table, and it incorporates facts about grand juries from [[Grand juries in the United States]]. According to [http://www.stlouiscopa.com/Divisions.aspx?ID=151 this page from the St. Louis County Prosecuting Attorney,] "a little less than half" of the felony cases in the county result in a grand jury hearing and the others go to a judge for a preliminary examination. So this is not a "typical" MO grand jury case.
+
+I also removed a statement about witnesses being repeatedly asked about whether Brown appeared to reached for a gun "despite the fact that it was known he was unarmed." The Times has legitimate concerns about the grand jury hearing which are in the article, but this claim is faulty. In the last seconds of Brown's life, he knew he didn't have a gun, but nobody else did. That emerged later.
+
+Disclaimer: I hope that Wilson went through essentially the same process as any other officer, and I hope he had faced the same likelihood of being prosecuted. I deplore abuse of power, whether it's a court making an example of a person or a police officer using excessive force. But if the people of MO feel there is a need for change, it's a matter for the legislature, not the criminal courts. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 17:12, 5 December 2014 (UTC)
+
+: Look I am trying to AGF here, but you can't just make changes to a table sourced to a an RS and add whatever you want from material from other sources that it is not related to this incident. That is a violation of [[WP:OR]]. As for the "faulty" claim of the NYT, that is none of your business to assess. We need to stay close to the sources, regardless if we believe the source is wrong. See [[WP:V]] 15:17, 6 December 2014 (UTC)
+
+: I also warn you again, that [[WP:NOTFORUM|this page is not a forum]], so please keep your opinions out of it. It does not help. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:27, 6 December 2014 (UTC)
+
+::No troubles whatsoever AGF'ing, his good faith seems pretty obvious to me. Also he is correctly pointing out source misrepresentation. The NYT article does not say "it was known he was unarmed" and neither should. '''Of course, I am shocked, shocked, shocked that it was Cwobeel who edit warred to defend the source misrepresentation which was intended to wrongly defame a living person, because that's not like his MO or anything.''' [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:33, 6 December 2014 (UTC)
+::: Can you stop characterizations? It is becoming insufferable. If you wanted to restore that portion you could have done it. But instead you reverted everything back to OR. Stop the nonsense!!!! - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:56, 6 December 2014 (UTC)
+::::Try making objectionable edits all by themselves so that your other work won't be touched when the objectionable edits are reverted. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:44, 7 December 2014 (UTC)
+
+:This is what the source says {{talkquote|Over the months, the jurors seemed to focus intently on the final movement that Mr. Brown may have made toward Officer Wilson, after a brief chase. The prosecutor asked witness after witness if it seemed as if Mr. Brown were reaching for a weapon, though few said they saw anything like that. Mr. Brown was found to be unarmed.}} I am restorring the material with some tweaks. Next time, please read the source. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:05, 6 December 2014 (UTC)
+::''''Yes, that is precisely the source text which failed to substantiate your WP prose claim that "prosecutors ask[ed] witness after witness if Brown was appearing to be reaching for a weapon when confronting Wilson, while it was known that Brown was unarmed". You ought to be thanking me for removing that fact-falsifying, source-misrepresenting prose, and yup you do this all the time, it's super annoying. Now you have gotten all mad & chided me angrily for reading correctly & reverting you correctly.
+
+::In response, you've changed it to "prosecutors ask[ed] witness after witness if Brown was appearing to be reaching for a weapon when confronting Wilson, while none of the witnesses said anything about Brown being armed." '''Yet another editorial spin that is not found in the cited source.''' Reverted. You misrepresent sourced facts, you misrepresent sourced opinions, you do it over and over and you do it to further your own hyper-partisan anger and desire to defame people whom you despise. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:20, 7 December 2014 (UTC)
+::: I think ,y last edit is accurate, so instead of endlessly complaining, do the [[WP:EDITING|the hard work]] and make it better. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:32, 7 December 2014 (UTC)
+::::Please explain, as clearly as possible, how you think your last edit was accurate. Or any of them, for that matter. "despite the fact that it was known he was unarmed" wasn't right, "while it was known he was unarmed" wasn't right, and "while none of the witnesses said anything about Brown being armed" is not right. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:36, 7 December 2014 (UTC)
+
+{{od}} ''despite the fact that it was known he was unarmed" - refers to the prosecutors, not the witnesses. That is the point the source is making, at least that was what I understood. ''while none of the witnesses said anything about Brown being armed'', was my attempts to unpack the statement "The prosecutor asked witness after witness if it seemed as if Mr. Brown were reaching for a weapon, '''though few said they saw anything like that'''". I accept that it was not perfect, but still valid. Now, please propose how to include in your own word that last sentence, because you have deleted it and it is a crucial point in that reporting. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 16:33, 7 December 2014 (UTC)
+
+:Since the source didn't use those words — and since prosecutors, like Wilson, did not know at the time of the incident that Brown was unarmed — this sounds like obvious BS. Also, "few witnesses said they saw him reaching for a weapon" is not even remotely equivalent to "none of the witnesses said he was armed". So once again it looks like you're adding your own spin, and there is no "validity" to it. Could you please propose content here before adding it to the article so that others can remove the errors and policy violations first? [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:44, 7 December 2014 (UTC)
+:: . My read is this: The critique is that prosecutors were acting as defense attorneys trying to validate Wilson's testimony regarding his perception that Brown was reaching for a weapon, when actually no witness other than Wilson made that case, and the prosecutors were asking again and again about that, which was very unusual. That is my reading of the source. Please re-read the source in its entirety and propose how to best reflect it. BTW, I intend to add more from that source, currently working on it. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:14, 7 December 2014 (UTC)
+:::Thank you for spelling out your uninformed opinion which does not belong anywhere on Wikipedia. I decline the invitation to grind your axe for you. I have already read and re-read the source. You are now on triple-explicit notice that the source does not say ''any'' of the things you previously wrote into the article, and thus I humbly request you bring any further material from this source HERE, to the talk page, so it may be vetted by editors who aren't quite so prone to ''accidentally'' misrepresenting a source to defame a living person. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 18:47, 7 December 2014 (UTC)
+:::: Thank you for you suggestion, but I have no intentions to refrain from editing. I am working an additional material that I would add in due course. Thankfully, the collaborative process of Wikipedia will, as always, catch any mistake you or I make in our editing. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:44, 7 December 2014 (UTC)
+:::::"Mistakes", mmm, yes, it's quite amazing how your "mistakes" always result in WP prose that misrepresents a source to trash a living person, and it's further amazing how it's invariably, always and without exception, the targets of progressive wrath that get this treatment. What I find remarkable is that you do this deliberately, and repeatedly, and without the slightest hint of remorse '''and without the slightest hint of apology''' for those whom you dumbly snark at, threaten and insult, in the process of trying to defend an indefensible anti-policy edit. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 14:41, 8 December 2014 (UTC)
+::::::^When I posted the above, I hadn't see that you went ahead and added more source misrepresentation. Please be advised that all opinion commentary is supposed to be well-sourced to notable commentators, not Wikipedia editors. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 14:55, 8 December 2014 (UTC)
+
+{{od}} I guess we're fortunate in this case that the WP prose in question doesn't trash anyone. At any rate, I think it's worth mentioning that [[WP:LIMITED|paraphrasing]] "Mr Brown was found to be unarmed" is hardly an unsourced opinion, considering it's a [http://www.nytimes.com/2014/11/26/us/ferguson-grand-jury-weighed-mass-of-evidence-much-of-it-conflicting.html?_r=0 New York Times report]. If you were to provide a better paraphrase than any in the list that you've accumulated on Cwobeel's attempts, it would resolve this issue fairly easily. Explaining why the information shouldn't be included would also be informative. As an aside, the NYT article was corrected today as it misattributed questions asked of Wilson to the prosecutors. The questions were actually posed by one of the grand jurors. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 02:32, 9 December 2014 (UTC)
+:It has gradually evolved from something that misrepresented the source to defame McCullogh, into something that merely reports what the source says without WP-editor embellishment intended to defame McCullogh. And as an aside, Cwobeel's level of activity and "accidental source misrepresentation" is far too intense for me to go around actually ghostwriting his prose for him. Fortunately, BLP explicitly provides that I needn't do that. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:12, 9 December 2014 (UTC)
+::Except, again, nothing you edited out seems to show any hint of defaming McCulloch. The only thing that comes remotely close is this [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637172329&oldid=637172234 edit], which was neither libelous nor non-notable as it is a [[WP:WELLKNOWN|well-documented controversy about McCulloch]] by [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html?_r=1 at] [http://www.latimes.com/changebrowser#url=/#section/-1/article/p2p-82099652/ least] [http://www.huffingtonpost.com/mark-weisbrot/in-ferguson-a-prosecutor_b_6269872.html two] sources (the last link was to the source cited in the edit). The Huffington Post source brings a different perspective to the controversy, which merits it being referenced in the article in a neutral tone. Btw, perhaps it would be in everyone's best interests if you were to be [[WP:BOLD|bold]] and give insight into how to rewrite the prose in an acceptable way, or to provide justifications on why the information shouldn't be included. As far as I can tell, BLP doesn't provide defenses for not contributing rationale. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 19:26, 9 December 2014 (UTC)
+: Thanks for pointing out the correcting by the NYT. I have deleted the miss-attributed sentence. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:22, 9 December 2014 (UTC)
+
+== additional sources discussing eyewitness testimony discrepancies from evidence (from a scientific point of view) ==
+
+* http://www.forbes.com/sites/fayeflam/2014/12/01/what-science-says-about-the-ferguson-case-memory-can-be-hacked/
+* http://web.randi.org/swift/eyewitnesses-and-emotion-a-reminder-to-engage-critical-thinking
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 21:03, 5 December 2014 (UTC)
+
+I'm a scientist. I like the idea of critical thinking. I like the idea of testing a hypothesis with evidence before making a conclusion, rather than making the evidence fit the conclusion. The Swift article reminds me that the public doesn't have all the evidence (nor should they), that details were presented to the grand jury that we are not privy to. I'm also reminded of "extraordinary claims require extraordinary evidence."
+
+Gaijin42, can you help me avoid attempting to write things I don't need to write, by just saying why you posted this? Do you think Wilson was justified in killing Brown? (I do.) [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 23:29, 5 December 2014 (UTC)
+: May I remind you of [[WP:NOTFORUM]]? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:00, 6 December 2014 (UTC)
+
+{{ec}} The answer to your larger question I will reply to on your talk to avoid [[WP:FORUM]] (as Cwobeel is quite correct to point out). I posted these particular links because they can help to flesh out the "Accounts" section similarly to the existing Rashomon effect paragraph. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 00:02, 6 December 2014 (UTC)
+
+{{ec}} {{yo|Roches}} As fascinating as these articles may be, they have no place in this article. Of course, if this is an area of interest you are welcome to edit [[Eyewitness testimony]], [[Credible witness]], and [[Eyewitness identification]]- [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:03, 6 December 2014 (UTC)
+
+::Cwobeel, the articles were posted by me (gaijin), not Roches. Why do you think they have no place in this article? They are directly discussing the general testimony issues in the context of this case and the specific witness statements we have in this case. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 00:13, 6 December 2014 (UTC)
+
+: Oh, sorry. The only thing I see useful in the Forbes article is this passage
+:{{talkquote|Our instincts tell us that honest people remember events correctly and others are lying. Loftus, on reading the AP report, suggested that what witnesses remember is heavily influenced by the way they interpret what they are seeing. Different people heard shots and saw some kind of commotion. Was the victim charging, wobbling, or surrendering? People may have unconsciously filled in gaps in their perception with information based on their past experiences.}}
+: ... which could be added as the fully attributed opinion of Elizabeth Loftus, and the writer of the piece. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:32, 6 December 2014 (UTC)
+::I think that would be a fine quote to include since we already mention the AP report in question, that serves as a nice commentary about it. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 00:54, 6 December 2014 (UTC)
+:::Could probably also find sources talking about how the typical unreliability of witness testimony leads prosecutors to rely more heavily on physical evidence, which is what they did in this case. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:12, 6 December 2014 (UTC)
+:::: OK, go ahead, Gaijin. FCAYS: Just find a source that describes that opinion in the context of this incident and it can be included as well. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:15, 6 December 2014 (UTC)
+:::::Lazy Saturday, usually when I post about the possible existence of a source it's because I am hoping someone ''else'' will go find it. ;) [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:24, 6 December 2014 (UTC)
+
+== Release of video in lead & dispatch ==
+
+It seems to me that the fourth paragraph in the lead may be a little incomplete. At some point a dispatch went out mentioning the theft and Wilson claims this dispatch was something he considered before and during the altercation. Yet the only thing mentioned in the fourth paragraph is that some were pissed off about the release of the video and that it may shed light on Brown's state of mind at the time. I think this is an imbalance and should be briefly addressed, though I'm not entirely sure how. Thoughts? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 01:17, 6 December 2014 (UTC)
+
+:I [[Special:Diff/636975119|added]] a little to that paragraph. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 03:45, 7 December 2014 (UTC)
+
+== publisher= ==
+
+When standardizing refs in this article, I have dropped any {{para|publisher}} and replaced it with {{para|website}}. While many editors use {{para|publisher}}, they generally use it incorrectly per the documentation, which states: ''The [[publisher]] is the company that publishes the work being cited. Do not use the publisher parameter for the name of a work (e.g., a book, encyclopedia, newspaper, magazine, journal, website).''
+
+While you can code both {{para|website}} and {{para|publisher}}, I haven't felt that the latter is of enough use to the readers of this type of article to be worth the trouble and space. In many cases it would be a non-trivial task to determine the name of the publisher.
+
+I just noticed that the copy-and-paste "template" we have in the comments at the top of the References section includes {{para|publisher}}, and I'm writing this as the explanation for my removal of that. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:00, 6 December 2014 (UTC)
+
+:So if a ref is from www.cnn.com/blah/blah/blah/ you would prefer <tt>website=cnn.com</tt> rather than <tt>publisher=CNN</tt> ? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:13, 6 December 2014 (UTC)
+
+::No, the convention here is to use the website's branding, as {{para|website|CNN}} or {{para|website|The New York Times}}. In some cases the website seems to be branded in multiple alternative ways, so we are forced to choose one, but we are consistent with that choice. For local TV and radio stations we ignore branding such as "Fox2Now" and use the call letters, as {{para|website|KTVI}}. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:18, 6 December 2014 (UTC)
+
+:::So if a ref is from www.cnn.com/blah/blah/blah/ you would prefer <tt>website=CNN</tt> rather than <tt>publisher=CNN</tt>. Correct? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:26, 6 December 2014 (UTC)
+
+::::Yes. Or you can code it however you want and I'll convert it as part of standardization, which would probably be needed anyway. I rebuild every ref from scratch, unless it's already perfect per the local convention (hasn't happened yet). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:31, 6 December 2014 (UTC)
+
+:::::I'm reminded of a line from Godfather III.... ''"Our ships must all sail in the same direction"''. Forming the refs as you suggest is no problem at all as far as I'm concerned. And I'll assume you are correct in your rationale for doing it that way. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:40, 6 December 2014 (UTC)
+
+::::::Ok. I copy-and-paste an abbreviated "template" from a Notepad document, to save myself the trouble of removing multiple rarely-needed parameters. Then I can insert {{para|location}} for local TV and radio, add parameters for additional authors, and/or remove the archive parameters if the source won't archive. This abbreviated "template" is: <code><nowiki><ref name= >{{cite web |first= |last= |title= |date= |accessdate= |website= |url= |archiveurl= |archivedate= |deadurl=no}}</ref></nowiki></code>. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:47, 6 December 2014 (UTC)
+
+{{reflist-talk}}
+== "Crime scene" ==
+
+We refer to "crime scene" five times. I just wanted to confirm that this is deliberate and that the rationale is that some crime was committed there, the crime and perpetrator undetermined. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 06:02, 6 December 2014 (UTC)
+:While I think I understand your concern, I think this may be a situation in which the correct term just has unfortunate implications. In any trial in which the defendant is ultimately acquired (or not charged as in this case) those bits of evidence are still from the "crime scene" in general parlance. Charitably one could also interpret these scene as a crime as either Wilson or Browns take your pick depending on POV. But I would also not object to "incident scene" or "shooting scene" or something. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 15:24, 6 December 2014 (UTC)
+::"Incident scene" sounds like a form that HR has to fill out after a fight in the break room. "Shooting scene" is not as awkward, but I think we should just track the terminology used by sources and trust that our readers will be discerning. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:42, 6 December 2014 (UTC)
+:::If it's a crime scene, then what was the crime and who committed it? That's a pretty sticky question. Shooting scene seems most accurate to me, is well represented in sources and has zero stickiness. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:08, 6 December 2014 (UTC)
+::::Actually, since crime scene investigators (CSIs) work all homicides, justifiable or not, I'd support the use of the term "crime scene." Apart from that, the testimony of Officer Darren Wilson was that Michael Brown was guilty of initiating an assault on Darren Wilson at that location. At the time that data are recorded from the scene of any homicide, the possibility of a crime having been committed is assumed by first responders and crime scene investigators. Both Darren Wilson and Michael Brown were regarded by press accounts as criminal suspects when that crime was investigated. [[User:Vfrickey|loupgarous]] ([[User talk:Vfrickey|talk]]) 16:16, 6 December 2014 (UTC)
+:::::Would it be correct to say that a "crime scene" can also refer to an area of investigation where a crime ''may'' have been committed? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:22, 6 December 2014 (UTC)
+
+::::::That appears to be common usage, whether or not it's literally correct. Common usage is good enough for me. In any case, I think it's clear enough that at least one crime was committed there, assault on a police officer (aside from conspiracy theory, is there any other plausible explanation for the facial discoloration that persisted for hours?). There may or may not be mitigating circumstances, but it's still a crime AFAIK. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:47, 6 December 2014 (UTC)
+
+:::::::That seems a little loose. We've exposed criticism of the term "crime scene". Is there any direct criticism of the term "shooting scene"? Not asking if you prefer something else, but looking for direct criticism of the term itself such as being inaccurate or problematic in any way. <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Jbarta|Jbarta]] ([[User talk:Jbarta|talk]] • [[Special:Contributions/Jbarta|contribs]]) 17:11, 6 December 2014 (UTC)</span></small><!-- Template:Unsigned -->
+
+::::::::I wasn't advocating "crime scene" over "shooting scene", but merely saying I'm not opposed to "crime scene". I don't see "shooting scene" as being inaccurate or problematic in any way. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 17:18, 6 December 2014 (UTC)
+
+It's not called a "shooting scene," it's called a "crime scene." Call it what it's called, not what you think it should be called. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 17:57, 6 December 2014 (UTC)
+:How do you know it's called a "crime scene"? To you it seems crystal clear. To me it's not. What is it that you know that I don't? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 18:14, 6 December 2014 (UTC)
+::[[Crime scene]] says it's called a crime scene. Vfrickey gave a clear explanation of why it's called a crime scene. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 19:17, 6 December 2014 (UTC)
+:::[[Crime scene]] says ''"Crime scenes may or may not be where the crime was committed"'' which I admit I missed. However, despite explanations, I still find the rationale for calling it a crime scene a little shaky, and as discussed earlier, "shooting scene" isn't shaky at all. My preference (slight as it is) is still for "shooting scene", but it's arguably a minor matter and if a consensus of editors prefer "crime scene", then so be it. At least it was examined and discussed. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:17, 7 December 2014 (UTC)
+::::I think it is common knowledge what a ''crime scene'' is. We all understand that it is a place where police are investigating a possible crime. It does not mean that just because we have labelled it such that we have bypassed judge and jury and want to throw the suspect in prison because, oh yea, we called it a ''crime'' scene. I've never heard the terms "shooting scene", "robbery scene", "assault scene", "arson scene", "shoplifting scene", etc. in my entire life. —[[User:Megiddo1013|Megiddo1013]] 05:54, 7 December 2014 (UTC)
+:::::At the risk of beating an unconscious horse and just for the sake of argument, I'm really not moved by what you think everybody knows or what you think everybody understands or what you've never heard in your entire life. I was looking for some definitive evidence as to whether a scene that may or may not have been the scene of an actual crime (depending on who you ask) is still called a crime scene. The rest of my comments are above (I hate repeating myself). One more thought that I don't think was brought up... is the Ferguson Police (or State Police or FBI or whoever is investigating there) calling it a "crime scene"? If not, how do ''they'' refer to the site? Just a thought. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:22, 7 December 2014 (UTC)
+::::::I see [https://web.archive.org/web/20141207162706/http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/gj-testimony/grand-jury-volume-02.pdf here] the grand jury is hearing testimony from a "crime scene investigator" and they do mention the words "crime scene" several times. Other than simply "the scene", they don't really call it anything else. So I suppose if you walked up to the investigator while he was measuring and examining and asked him "Whatcha doin?", he would most likely reply with "Investigatin this here crime scene. Now get back behind that yellow line or someone's gonna shoot you too!" &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:41, 7 December 2014 (UTC)
+
+Micheal Brown attacked Officer Wilson there, as well as resisted arrest, so there's really no question that it is the scene of at least ''some'' crime committed, regardless of whether or not Wilson committed any crime. Crime scene, scene of the incident, scene of the shooting all seem to be pretty commonly used. I don't think it is unnecessarily POV; we should use whatever the sources use. [[User:Titanium Dragon|Titanium Dragon]] ([[User talk:Titanium Dragon|talk]]) 02:21, 11 December 2014 (UTC)
+
+== Incident reports ==
+
+I changed the incident report section. The complaints are really examples of journalists writing about how they think people should do their jobs; if this incident report isn't different than a normal one ''about the same thing'', then it's not lacking in information.
+
+The reason why the incident reports have very few details is that they are admissible in court. Filling in only basic information is a normal thing to do in a case like this, because the incident report is just the beginning of an investigation. In most cases, such as a collision involving a police vehicle, the incident report is a full description of the event because nothing more ever needs to be said about it. These incident reports are not the official story of the police department, they're the individual account of the person who might have to go to trial. Journalists should have known better than to speculate that details were being omitted improperly.
+
+Something was made of the date of the report (ten days after the shooting); this is the time the report was ''entered.'' The date it was ''submitted'' isn't there. The times of day must also not mean what they appear to mean, since other accounts have police arriving at the scene in much less than 40 minutes.
+
+[[User:Roches|Roches]] ([[User talk:Roches|talk]]) 18:12, 6 December 2014 (UTC)
+
+: No, no, and no. You are not here to decide what journalists should do or not do, or what they should report or not report. If you find a source that describes your opinion, by all means add it. But '''do not delete material just because you think the journalists are doing a poor job.''' Who cares what you (or I) think? We report what sources say. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:19, 6 December 2014 (UTC)
+::According to a spokesman for the St. Louis County police department, it's normal practice not to give out the details and that under the Missouri State “Sunshine” Law, the department was not required to release the information during a pending investigation.[http://time.com/3159680/ferguson-michael-brown-shooting-police-report/] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:31, 7 December 2014 (UTC)
+::: Then report that, alongside the critique from other media sources, even if unfounded. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 01:03, 7 December 2014 (UTC)
+
+Please don't tell me how Wikipedia works, even if it's using WP:article links to things that are not policy. I changed the section to describe the level of detail on the forms, and mentioned that Wilson sought legal advice about completing them. I kept the ACLU statement, because it is important to convey that people objected to the way the forms were completed, but I didn't keep the paraphrased list of things the HuffPo author thought were missing.
+
+Reporting the Huffington Post author's opinion of how police departments should fill out incident reporting forms is not NPOV. That's an opinion of one journalist at one source; the ACLU's public statement is a much better, and entirely sufficient, way to report objections to the way the forms were completed.. See [[WP:ONUS]]. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 04:37, 7 December 2014 (UTC) (Added policy link to post at 4:30.)
+
+:: we report opinions and attribute opinions to those that hold them. That is our work as editors, and not pass judgement. I will remove these edits and expect you to follow [[WP:BRD]], as there is an implicit consensus on material that has been in the article for a while. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:18, 7 December 2014 (UTC)
+:::If the opinion isn't found anywhere other than HuffPo, it's probably not notable. Notice also this was published in August and never followed up on. Not exactly quality sourcing. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:51, 7 December 2014 (UTC)
+
+I started looking over the current version of the section [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637070981#Incident_reporting_forms Incident reporting forms] and there was a problem with verifying the first two sentences.
+:"[[MSNBC]]'s [[Lawrence O'Donnell]] reported on {{nowrap|August 21}} that Wilson did not complete an incident report about the shooting, after being advised by a union lawyer not to do so.<sup>[68]</sup> According to O'Donnell, Wilson did file a report, but not until ten days after the shooting, and the report contained no information other than his name and the date.<sup>[68]</sup>
+
+:<small>68. {{cite episode |first=Lawrence |last=O'Donnell |title=Ferguson PD didn't file report after shooting |date=August 21, 2014 |accessdate=August 26, 2014 |series=The Last Word |network=MSNBC |url=http://www.msnbc.com/the-last-word}}</small>
+
+The link for the source doesn't go to the page where the info is, so I wasn’t able to verify the material using the citation. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 23:01, 7 December 2014 (UTC)
+:: Searching for the title of the source in the ref, yields this: http://www.msnbc.com/the-last-word-with-lawrence-odonnell/watch/ferguson-pd-didnt-file-report-after-shooting-320755267999 - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:07, 7 December 2014 (UTC)
+:::{{fixed}} &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:18, 7 December 2014 (UTC)
+:::On the other hand, that link is to a 1:16 clip, apparently the intro to the episode. I can't figure out how to get the whole thing. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:31, 7 December 2014 (UTC)
+
+So who is correct, the prosecutor's office, O'Donnel, the ACLU? Was or was not an incident report filed? Because they did release the reports when pressed to do so. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:51, 7 December 2014 (UTC)
+:Cwobeel, The current issue is verifying those two sentences. The link you just gave is insufficient. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:01, 8 December 2014 (UTC)
+:: Well, it was the when I sourced it, but it seems that it is gone. I will see if I can find it in the wayback machine. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:05, 8 December 2014 (UTC)
+
+The full episode may be on this page, but I am not 100% sure: [http://www.msnbc.com/msnbc/aclu-michael-brown-incident-report-lacks-key-details], OTOH, this is a good source that could be used: [http://www.thewire.com/national/2014/08/ferguson-police-waited-10-days-to-review-michael-brown-incidents-report/378972/] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:12, 8 December 2014 (UTC)
+
+Here's a relevant excerpt from a Nov 24 Newsweek source.[http://www.newsweek.com/no-charges-ferguson-michael-brown-shooting-case-285976 ]
+:"The official incident report filed by St. Louis county police 10 days after the shooting contains few hard details about the encounter, other than the fact that Brown was unarmed."
+--[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:24, 8 December 2014 (UTC)
+
+I made some edits involving the second and third sentences of the first paragraph, which currently is:[https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637098637#Incident_reporting_forms]
+
+:"[[MSNBC]]'s [[Lawrence O'Donnell]] reported on {{nowrap|August 21}} that Wilson did not complete an incident report about the shooting, after being advised by a union lawyer not to do so.<ref name=MSNBC.File/> According to the {{nowrap|St. Louis}} County Prosecutor's Office, the Ferguson police didn’t file an incident report on the shooting because the case was turned over to the county police almost immediately.<ref name=NBC.Why/><ref name=MSNBC.Details/><ref name=ACLU.FPDReport/> The St. Louis county police filed an incident report 10 days after the shooting with little information about what happened.<ref name=Newsweek.After/>"
+
+{{reflist-talk}}
+
+The first sentence is not supported by its source. The only thing it adds is the part about the lawyer. The rest is covered in the second sentence. I think we should delete it for now and consider restoring the lawyer info when there is a suitable source for it. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 01:23, 8 December 2014 (UTC) Deleted. [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637128797&oldid=637122667] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 14:44, 8 December 2014 (UTC)
+
+: Unfortunately the source is no longer online. In any case I think what we have there is covers this quote well. I have re-ordered the sentences for a narrative that makes sense. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 14:50, 8 December 2014 (UTC)
+::I don't think that was an improvement. I noticed that another editor reverted the re-ordering. [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637174390&oldid=637172965] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 16:40, 8 December 2014 (UTC)
+
+::: The version reverted to does not make sense. It starts by describing the reasons why a report was not filed, only to say in the following paragraphs that reports were indeed filed. when you removed the O'Donnell reference, the section came out of whack. I am still trying to find the original source from O'Donnell. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:07, 8 December 2014 (UTC)
+::::I think the lead paragraph is OK and shouldn't be touched for now. I've been working on the rest of the section to get it into better shape. After I complete that, I'll revisit the lead paragraph. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:25, 8 December 2014 (UTC)
+
+OK Found it. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:16, 8 December 2014 (UTC)
+
+{{talkquote|We have breaking news tonight in the killing of Michael Brown. St. Louis County prosecutors told NBC News today that the Ferguson Police Department has no incident report of the shooting of Michael Brown. Darren Wilson, the officer who shot and killed Michael Brown, did not write an incident report contrary to standard police procedure. […] Yesterday, in response to a lawsuit from the ACLU, the St. Louis County police released an incident report that says, in effect, nothing other than the time and proximate location of a homicide and the victim`s name, Michael Brown. That incident report indicates that it was not filed until possibly 10 days after the killing of Michael Brown. […] In the decades I`ve been studying these cases, most of them involve incident reports written by the officers involved with the shooting. In recent years, it has become customary for the police lawyer to run in, police union lawyer usually, and prevent the shooter from giving any kind of comment or writing any sort of incident report whatsoever. <ref>{{cite web |url=http://www.nbcnews.com/id/55915749/ns/msnbc/t/last-word-lawrence-odonnell-thursday-august-st/#.VIXbR6YqjoA|title= The Last word with Lawrence O'Donnell August 21, 2014|publisher=NBC News|accessdate=8 December 2014}}</ref> }}
+{{reflist-talk}}
+
+:The excerpt you gave doesn't say that Wilson was advised by a union lawyer not to complete an incident report. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 17:31, 8 December 2014 (UTC)
+:: See my edit, which attributes that opinion to O'Donnell. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:45, 8 December 2014 (UTC)
+:::I moved it from the article to here for discussion.
+
+::::"[[MSNBC]]'s [[Lawrence O'Donnell]] reported on {{nowrap|August 21}} that St. Louis County prosecutors told NBC News that they do not have an incident report from the shooting, contrary to standard police procedure, and described a pattern in which police union lawyers prevent shooters from commenting to filing incident reports.<ref>{{cite web |url=http://www.nbcnews.com/id/55915749/ns/msnbc/t/last-word-lawrence-odonnell-thursday-august-st/#.VIXbR6YqjoA|title= The Last Word with Laurence O'Donnell - August 21, 2014|publisher=NBC News|accessdate=8 December 2014}}</ref>"
+{{reflist-talk}}
+
+:::This Aug 21 item became obsolete when the police interview of Wilson, the day after the shooting, was released to the public. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:15, 8 December 2014 (UTC)
+::::: Really? Can you provide a source that describes the police interview that was released? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 18:25, 8 December 2014 (UTC)
+::::::Here's a link from a [http://edition.cnn.com/interactive/2014/11/us/ferguson-grand-jury-docs/index.html CNN webpage] to the interview. [https://www.documentcloud.org/documents/1370928-interview-po-darren-wilson.html] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:55, 8 December 2014 (UTC)
+::::: {{yo|Bob K31416}}I see what you mean. But you are confusing two things. What O'Donnell is referring to is an incident report. What you are refrring to is an interview with Wilson. These are two different things. Please restore that edit, as this section is all about incident reports and not interviews. - - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 18:31, 8 December 2014 (UTC)
+:::::<small>{{yo|Cwobeel}} - You have to add the ping (yo) and your sig in the same edit, or there is no notification. I learned that the hard way. {{yo|Bob K31416}} &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:50, 8 December 2014 (UTC) </small>
+::::::O'Donnell said, "any kind of comment or writing any sort of incident report whatsoever.” --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:55, 8 December 2014 (UTC)
+::::::: So what? The fact is that Wilson did not file an incident report. That is undisputed. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:39, 8 December 2014 (UTC)
+
+=== Break1 Incident reports ===
+{{yo|Bob K31416}} I added additional commentary from legal and law enforcement analysts. I also re-ordered the sentences to follow the chronology. I think I got it right, but please change it if it is not correct. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:58, 8 December 2014 (UTC)
+
+:(Here’s a link to the version after Cwobeel's recent edits [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637213737#Incident_reporting_forms] and a link to the version before [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637210952#Incident_reporting_forms] .)
+
+:[[User:Cwobeel|Cwobeel]], Here’s some comments on your recent edits of the section.
+
+::1) The first sentence of your version misstated the source. O'Donnell was referring to only the Ferguson incident report. The info was already in the first sentence that you moved.
+
+::2) The second sentence of your version about Lisa Bloom’s opinion misstates the source. Lisa Bloom didn’t say that Wilson refused to file a report.
+
+::3) Re the 3rd sentence of your version about Jim Cavanaugh’s comment — The info was already covered in the first and second sentences of the original version.
+
+::4) The 4th sentence of your version about the Ferguson police not filing an incident report was the original 1st sentence.
+
+::5) The 5th and last sentence of the lead paragraph of your version was about a use-of-force report and was formerly the last sentence of the section. I hadn’t worked on the placement or content of this sentence yet.
+
+::6) The 2nd and 3rd paragraphs of your version were obtained by switching the 2nd and 3rd paragraphs of the original version. I hadn’t worked on the content or placement of the material in these paragraphs yet.
+
+::7) The 4th and last paragraph of your version was the second sentence of the lead paragraph of the original version.
+
+:Before I try to edit the section again, could you list here in our discussion, in chronological order, the events that you are trying to portray in chronological order? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 01:33, 9 December 2014 (UTC)
+
+:: I cheeked again this evening and this is the correct chronology, my last edit was not correct:
+::* August 19 - (10 days after shooting) incident report filed by St. Louis county police
+::* August 21 - O'Donnel's reporting, commentary from Lisa Bloom and Jim Cavanaugh
+::* August 22 - St. Louis County Prosecutor's Office says that Ferguson police did not file a report because the case was assigned to county police
+::* August 26 - ACLU releases the report they received after their FOIA request
+::* August 26 - HuffPo reports on commentary by ACLU's Gupta
+::* Sept 25 - Yahoo News reports that key report does not exist
+:: Regarding Bloom and Cavanaugh:
+::* Lisa Bloom: ''And if he refuses to follow standard operating procedure in preparing a report about the taking of the human life, he should be fired."
+::* Jim Cavanaugh: That is an expert opinion that should be presented.
+:: I <s>will attempt again to correct</s> corrected the chronology. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:37, 9 December 2014 (UTC)
+
+:: {{yo|:Bob K31416}} feel free to copyedit my rendition of Bloom and Cavanugh's comments, if you can make it better and closer to the source. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:42, 9 December 2014 (UTC)
+:::[[User:Cwobeel|Cwobeel]], On giving the section another look, I noticed that it is about not releasing information that has now been released. It’s obsolete and a digression from the topic of the article, the shooting of Michael Brown. We could summarize the incident report issue in a couple of sentences and merge it with the Police section. Thoughts? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:48, 10 December 2014 (UTC)
+
+== Wholesale deletion of relevant material ==
+
+{{yo|Roches}} Why are you deleting perfectly good material without any discussion[https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=636909177&oldid=636903538]. I welcome your contributions, but you need to show some respect to the hard work from others. Deleting material that has been in the article for quite a while, and which represents an existing consensus is not acceptable - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:15, 6 December 2014 (UTC)
+
+And when you are it, explain this edit [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=636903538&oldid=636894100] in which you removed several key pieces of reporting. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:21, 6 December 2014 (UTC)
+
+I mean, how blatant can you be? You removed a key piece: {{talkquote|. Brown stumbled, stopped, put his hands up and said "OK, OK, OK, OK, OK." The worker believed Brown had been wounded. With his hands up, Brown began walking toward the officer, at which point Wilson began firing at Brown and backing away.}} - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:23, 6 December 2014 (UTC)
+
+:It's difficult to contribute anything at all if every aspect of every edit has to be justified. The fact that somebody said that something happened is not necessarily worth reporting here, and it does not remain worth reporting here. Editing material that was written some time ago is not destructive, it's just changing the article to represent the importance of that particular account ''as of right now.''
+
+:The construction worker's account describes Brown being hit from behind after being shot by one of three police officers. I thought it was acceptable to keep the broader details of the account. I did not remove all of the details in the "key piece" above. I only removed what the otherwise-unreliable account said Brown was saying. There's a reason for that. If someone reported that Brown said "I'm gonna kill you," then that conveys to readers the idea that Brown may have said that. Similarly, including a quotation from a possibly unreliable account, a quotation that other accounts don't include, can alter the opinions of readers in a different way than a retelling of what the worker said the people did. The edited account still conveys the worker's contention that Brown was trying to surrender, it just doesn't quote Brown in the retelling.
+
+:If that content represented an existing consensus between, say, ten editors, it no longer represents a consensus. I'm strongly opposed to it, I think it should be removed, so there isn't a consensus anymore. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 04:09, 7 December 2014 (UTC)
+
+::No comment on the rest, but I'll go out on a limb and challenge your last sentence based on the second sentence of [[WP:CONSENSUS]]: ''Consensus on Wikipedia does not mean unanimity (which, although an ideal result, is not always achievable)...''. In other words, consensus doesn't vanish the moment someone comes along and disagrees with it. It was rarely unanimous to begin with, as indicated in the quoted passage. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 04:39, 7 December 2014 (UTC)
+:::The part about hands up was removed. It was significant because it was supported by the following, which was also removed, "In a cellphone video obtained by CNN on {{nowrap|September 11}}, which captured the reaction of the construction worker and a colleague, one of them can be heard saying, "He had his fuckin' hands up." Does anyone know where the corresponding grand jury testimony is, volume, page number? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 05:04, 7 December 2014 (UTC)
+:::: I have restored the material that was deleted. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:28, 7 December 2014 (UTC)
+
+{{yo|Roches}}: ''It's difficult to contribute anything at all if every aspect of every edit has to be justified.'' Welcome to editing contentious articles in Wikipedia. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:30, 7 December 2014 (UTC)
+
+And a good reminder [[WP:NOTTRUTH]] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:32, 7 December 2014 (UTC)
+:Cwobeel, From the essay [[WP:NOTTRUTH]] that you referred to is the following, "The phrase 'the threshold for inclusion is verifiability, not truth' meant that verifiability is a necessary condition (a minimum requirement) for the inclusion of material, though it is not a sufficient condition (it may not be enough)." --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 05:45, 7 December 2014 (UTC)
+:: I agree with you in that context. I was referring to this section: [[WP:!TRUTHFINDERS]] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:50, 7 December 2014 (UTC)
+:::::[[User:Cwobeel|Cwobeel]], I don't think that part of the essay means that verifiability guarantees the inclusion of questionable material. Also, please note the statement at the top of that essay's page, "Essays are ''not'' [[Wikipedia:Policies and guidelines|Wikipedia policies or guidelines]]." Wikipedia policy says that [https://en.wikipedia.org/w/index.php?title=Wikipedia:Verifiability&oldid=634377638#Verifiability_does_not_guarantee_inclusion verifiability does not guarantee inclusion]. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 06:50, 7 December 2014 (UTC)
+:::::: I am fully aware that an essay is not policy. But the point made in that essay is a good one. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:24, 7 December 2014 (UTC)
+:::::::And what point is that? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 16:42, 7 December 2014 (UTC)
+
+::::From the St. Louis Post-Dispatch, talking about the construction worker's testimony to the grand jury - [http://www.stltoday.com/news/local/crime-and-courts/in-grand-jury-testimony-passion-but-little-agreement-from-witnesses/article_f2fc0e21-dc59-59bf-82bc-c0f35fd40572.html A landscape worker who lives in Jefferson County gave grand jurors one of the oddest accounts of the moments leading up to Brown's death. The man said he encountered Brown that morning. He was trying to cut through some tree roots and cursing at the difficulties of the job. Brown told him that Jesus would help him with his anger problem. A few minutes later, the man said, he heard gunshots. He looked up and saw Brown running. '''He said three officers were chasing Brown''', but only one of them was shooting. Brown appeared to have been shot as he fled, the worker said. Then Brown turned around, put his hands up and started yelling “OK.” "And within a couple of seconds the '''three officers came up''', and one just pulled up and shot him," the worker said.]--[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 05:36, 7 December 2014 (UTC)
+::::: Sure, but this article is not just about the testimony to the grand jury. This and other witnesses provided their accounts before that, such as in here [http://www.stltoday.com/news/local/crime-and-courts/workers-who-were-witnesses-provide-new-perspective-on-michael-brown/article_14a3e5f8-6c6a-5deb-92fe-87fcee622c29.html], the source used in that section. You are welcome to add his testimony to the grand jury for completeness. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:44, 7 December 2014 (UTC)
+
+::Restoring the original version reminded me of why I edited it. I'm not going to dissect the content line by line, feign outrage, or welcome you to Wikipedia. I especially do not like the last of these things, and I don't like when you tell me or other editors that we are free to add content to some section of the article, but not to another.
+
+::What I tried to do wasn't perfect, but if that content represents the hard work of many individuals working towards a consensus, the result was surprisingly awkward and difficult to read. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 06:22, 7 December 2014 (UTC)
+::: Fair enough. If you can improve content by copy editing, that would be most welcome. But there is a difference in making something more readable, and deleting content wholesale as you did. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 06:30, 7 December 2014 (UTC)
+
+== Fair use photos of Michael Brown and Darren Wilson ==
+
+I'm wondering about grabbing some photos of Brown and Wilson and uploading them as fair use. I have in mind these... [http://media4.s-nbcnews.com/i/newscms/2014_33/614086/140812-michael-brown-1338_8c5ad41dd423c28ed02e37e39222844e.jpg Brown],[http://i97.photobucket.com/albums/l217/Shockwave_73/Album%202/Darren-Wilson_zps70a1888c.jpg Wilson], and using them in a manner similar to the ones in [[Shooting of Trayvon Martin]]. Brown is dead so "historic portrait" applies, unless someone wants to argue that anyone who owns a photo of Brown ''could'' conceivably upload it here under some sort of free license. Wilson is still around, but I think the chances someone will upload a free picture of him anytime soon is pretty slim. And even if 30 years from now someone finally does, it won't do us much good in the meantime plus he won't look anything like he did during the event... which sort of kills the encyclopedic value. I think that since this a historic event (historic meaning this particular event happened at only one time in history), contemporary photos of the main participants are fair use. Thoughts on the validity of "fair-use" here? Thoughts on using the images in general? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:44, 8 December 2014 (UTC)
+:For Brown, we get one (and and only one) "fair use" photo under the "dead, no future free photos available" bits of [[WP:NFCC]]. So if consensus can be built on which photo to use, then we can go with it.
+:For Wilson, as he is living, we do not get such exceptions. I already uploaded a pic of Wilson's face injury under the NFCC for a non-reproduceable historical photo that is discussed in the article (the degree of injury or not). Having just an "What does Wilson look like" photo is not going to survive the fair use discussion tho.
+:The Trayvon Martin article is working under slightly different rules, because Florida does not allow state agencies to keep copyrights and so all of the evidence stuff is in the public domain. Missouri specifically does allow state agencies to keep copyright. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:52, 8 December 2014 (UTC)
+::That fair use can indeed encompass "what does a main participant look like?" in a very notable "moment in time" event is an incorrect belief? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 17:30, 8 December 2014 (UTC)
+:::Generally only if there is some specific thing that is being commented on significantly in the article that the "moment in time" captures. For example injuries, or "iconic" status. "Here is a random snapshot of Wilson" won't qualify. You can always try of course, but I've seen hundreds of photos trying that argument get deleted. The relevant criteria are [[Wikipedia:Non-free_content#UULP]]. In our case a hypothetical free replacement would let us see the general ID of Wilson just fine (As opposed to the injury photos, which cannot be replaced ever in the future). More detail can be found at [[Wikipedia:Replaceability_of_fair-use_images#Living_people]] [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:58, 8 December 2014 (UTC)
+::::I'm familiar with the guidelines, just wondering how far they can be stretched in this context. We could argue that not only is this hypothetical future free image of Wilson unlikely to materialize, but it may very well not capture him as he looked during the event. No doubt he'll probably lay low for the forseeable future, he may grow a beard, etc. So one way to look at it is that Wilson, as he was during the event, is in fact a not reasonably replacable historic image. Compare this context with say a movie star with a career that spans many years. If we don't get a picture of him today, he's likely to be out and about still making movies and appearing at events in the future, not to mention his notability is not tied to one particular moment in time. Very different context than Wilson here. I'm not looking for a "you can always try it and see how it goes". I'm looking for a consensus that a "what he looks like" image of Wilson is a valid application of fair-use and while stretching WP guidelines, doesn't necessarily run afoul of them.&ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 18:55, 8 December 2014 (UTC)
+:::::Actually, a re-read of [[Wikipedia:Replaceability_of_fair-use_images#Living_people]] (thank-you Gaijin42) makes me think a photo of Wilson is well within the guidelines simply as a "not reasonably replaceable image of a living person". Add to that the idea of his notability being tied to one moment in time, and it's starting to look like a pretty solid case. No? Again, I'm looking for a consensus on that point rather than a "try it and see how it goes". &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 19:25, 8 December 2014 (UTC)
+
+: I disagree with that choice of Michael Brown's photo, for several reasons. One reason is that is only shows his face. In the context of this article, I believe it is important to see his physical size (i.e., his body/frame/physique). Thanks. [[User:Joseph A. Spadaro|Joseph A. Spadaro]] ([[User talk:Joseph A. Spadaro|talk]]) 19:22, 8 December 2014 (UTC)
+::Can you point to any images you would prefer? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 19:28, 8 December 2014 (UTC)
+
+::: No, I don't have any access to such photos. And I don't particularly understand (or follow) all of the intricacies of the copyright/fair use rules, etc., as discussed above. Nonetheless, I disagree with this particular proposed photo. For the reason stated above, and for other reasons as well. I am sure that I have seen many photos of Brown in the news and on the internet, etc., over the past few months. I will see if I can point one out in particular. Thanks. [[User:Joseph A. Spadaro|Joseph A. Spadaro]] ([[User talk:Joseph A. Spadaro|talk]]) 19:32, 8 December 2014 (UTC)
+
+:::: Here is one photo: [http://www.bing.com/images/search?q=michael%20brown%20missouri%20&qs=n&form=QBIR&pq=michael%20brown%20missouri%20&sc=8-23&sp=-1&sk=#view=detail&id=70EF2F07F28C8C3A728820D8683ACDAB3256EB25&selectedIndex=3]. And I thought that I had seen this photo in a not-cropped version, showing his full-length body shot. [[User:Joseph A. Spadaro|Joseph A. Spadaro]] ([[User talk:Joseph A. Spadaro|talk]]) 19:37, 8 December 2014 (UTC)
+:::::Even if you have a full body shot, unless he's standing next to someone much smaller, you probably won't get a true sense of his size. And even if you did get such a photo, people will come out of the woodwork screaming that we're trying to portray him as a "big black monster". I'm thinking maybe it should be a neutral sort of image that no one has much of a problem with. Then again, he was a big dude and that certainly plays a part in the narrative. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 19:55, 8 December 2014 (UTC)
+::::::People can visualize 6'4" 300 lbs. without a photo. Unless we feel it useful to show that his build was more that of a lineman than a linebacker (I don't, particularly). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:02, 8 December 2014 (UTC)
+:::::: I think the proposed photo by JBarta is just fine, as it is the one that was used by most sources. Go head and add it. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:36, 8 December 2014 (UTC)
+:::::: To counteract Spadaro's comment, we are not showing a full body shot of Wilson who is 6' 4" either. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:38, 8 December 2014 (UTC)
+
+{{u|JBarta}} Regarding your question above about Wilson and replacability, I do not think the photo serves any purpose in the article that qualifies under NFCC. What he looked like in general is not a subject that is discussed in this article. Relative sizes between Brown and Wilson may be relevant, but the photos in question do not show that. Your proposed justification would basically apply to any photo of any person for almost any article, it renders the restriction meaningless. If NFCC had an exception for "this photo has been widely used by news media for this story" I would support that, and would perhaps support a change to NFCC to create such an exception, but as the policy currently stands, I think its pretty clear generic photos of Wilson do not make the cut. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 20:45, 8 December 2014 (UTC)
+: Agree. The photo showing the redness on the face, relates specifically to the investigation and thus it can squeeze through (hardly,IMO) under NFCC. A generic photo of Wilson would not. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:48, 8 December 2014 (UTC)
+::"What he looked like in general isn't important" could be similarly argued for ''any'' person who is dead, yet has a fair use photo in their article. By my reading of the guidelines, it's not the importance that is important, but whether the photo is reasonably replaceable. If one agrees that a photo of Darren Wilson (especially capturing him at this moment in time) is not reasonably replaceable to an extent similar to a person who has died, then I would think the guideline would apply to Wilson as well as a person who has died. It's not like Wilson is going to be out posing for photos at the next Fergson Community Days or anything. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 21:00, 8 December 2014 (UTC)
+:::Wikipedia works in hypotheticals quite often. [[WP:V]] has [[WP:V#Access_to_sources]] for example. (Its in a physical library in Peru in a village only accessible by foot. Doesn't mean it isn't verifiable. ) There is a zero percent chance of free photos of Brown being taken in the future. I can come up with many ways we could have photos of Wilson in the future. (someone catches him in public, federal evidence released, federal charges, cspan testimony) etc. The main point that its tripping you up on replacability is that you have not stated how a photograph of him at the time is of particular encyclopedic value to justify the copyright issues vs a hypothetical image of him from the future. What does his "look" at that moment in time illustrate for the article? His skin tone? his physical fitness? We discuss none of this in the article, therefore illustrating it is not adding anything. In any case, the general policy won't get changed here. As I said feel free to try, but I have seen literally hundreds of photos go down in flames on the same type of reasoning. And fair warning I would !vote as I have indicated here (although I certainly don't make the consensus alone). [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 21:09, 8 December 2014 (UTC)
+
+::::On the issue of having a photo of him at this time and its replacabiliy. Imagine for a minute an article about a famous fight between two boxers back in the 1970's. You show each boxer... one a contemporaneous photo, the other forty years later all crippled up hunched over a cane because we can't find a free image of that boxer from back in the 1970s. The article is about the fight in the 1970's. The recent image of the one fighter arguably has little to do with the fight. It's not the same person that was in the fight. The same replacabilty concern exists with Darren Wilson, only the circumstances are less extreme and we're at the beginning of not having an image of him rather than far down the road. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 21:33, 8 December 2014 (UTC)
+
+:::Per NPOV I don't see how we could justify a photo of one without a photo of the other. A photo would serve no purpose other than to personalize the subject for the reader. If you think we've seen battles here to date, just make the popcorn and add Brown without Wilson. We have the shot of Wilson's cheek, but that's not equivalent to a full face shot, with eye contact, in the subject's bio section (which I presume is where Brown's photo would go). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:19, 8 December 2014 (UTC)
+
+* [[User:Jbarta]] asked me to comment here.
+: Wilson: This person is still alive. Jbarta seems to be concerned that Wilson may look very different when a free image is created. However, I note that the event took place only four months ago. It is therefore obvious that the person ''currently'' looks more or less the same as he did when this event took place. There is a potential that someone might take a photo of him tomorrow, next week or in January, and that photograph would then serve as a free replacement. It is important to note that [[WP:NFCC#1]] disallows non-free content if free content ''can be created'', and it is perfectly possible to take photos of him for the moment. The image is therefore replaceable, at least for the moment. If, after 40 years, it turns out that there is still no one who has taken a free photo of him, things may be different and he may look a lot different. [[WP:NFCC#1]] allows non-free images in some situations if the person has changed a lot from the time when he became famous, but non-free images are not allowed in all such situations. It may be useful to point out that a similar situation (a child actor active in the 1990s) currently is being discussed at [[Wikipedia:Deletion review/Log/2014 December 3|deletion review]].
+: Brown: This person is dead, so non-free images of him are not replaceable. The image proposed by Jbarta, [http://media4.s-nbcnews.com/i/newscms/2014_33/614086/140812-michael-brown-1338_8c5ad41dd423c28ed02e37e39222844e.jpg], looks like an image of children at an amusement park or some similar kind of place. It looks as if Brown could easily be at about the same age as the children in the background. However, it says that he was 18 at the time of his death. Is this a 10-year-old photo or something? If Jbarta is concerned that the photo of Wilson must be contemporary, then why does {{gender:Jbarta|he|she}} think that the photo of Brown doesn't need to be contemporary? I suspect that this photograph isn't suitable for the article. However, I don't know what other photographs, if any, would be suitable. I am also not sure if it is necessary to include a photograph of him in this article per [[WP:NFCC#8]]. I believe that there have been other discussions about murdered people at FFD, but I don't remember the outcome.
+: [[Shooting of Trayvon Martin]]: Jbarta mentioned this article because this article also contains non-free pictures. This article seems to have problems, see [[Wikipedia:Files for deletion/{{#time:Y F j|00:19, 10 December 2014 (UTC)}}#Pictures of Trayvon Martin]]. --[[User:Stefan2|Stefan2]] ([[User talk:Stefan2|talk]]) 00:19, 10 December 2014 (UTC)
+::On the topic of Brown's age in [http://media4.s-nbcnews.com/i/newscms/2014_33/614086/140812-michael-brown-1338_8c5ad41dd423c28ed02e37e39222844e.jpg this] photo you'll notice the bit of beard on his chin. It's the same as [http://www.google.com/imgres?imgurl=http%3A%2F%2Fbloximages.newyork1.vip.townnews.com%2Fstltoday.com%2Fcontent%2Ftncms%2Fassets%2Fv3%2Feditorial%2Ff%2Fed%2Ffed5e621-f0a8-5baa-a11a-c748e5dc65cd%2F5407e41926d2b.preview-620.jpg&imgrefurl=http%3A%2F%2Fwww.stltoday.com%2Fnews%2Flocal%2Fcrime-and-courts%2Fofficial-autopsy-shows-michael-brown-had-close-range-wound-to%2Farticle_e98a4ce0-c284-57c9-9882-3fb7df75fef6.html&h=501&w=620&tbnid=-nkr8uIvwcLzZM%3A&zoom=1&docid=HhK_zehdqKbgJM&ei=2JWHVJWjKYKqgwTdwIGACA&tbm=isch&ved=0CDUQMygCMAI&iact=rc&uact=3&dur=3358&page=1&start=0&ndsp=14 this] photo where I assume he's graduating high school. I think the photo I chose isn't more than a year or so old. At any rate, I'm not firmly fixed on any photo. It doesn't entirely matter to me. No matter what photo is chosen there will be those who see some sort of suspicious reason for the choice.
+::And while it's "possible" someone could snap an image of Wilson in the near future and upload free it here, I'd say it's highly unlikely. I'd also like to point out again that Wilson fits ''precisely'' the criteria set out in the 'May not be reasonably replaceable' section of [[Wikipedia:Replaceability_of_fair-use_images#Living_people]]. He's the poster boy for not likely to get a free picture of him anytime soon. The ''only'' thing he's likely to show himself for is a possible lawsuit from Brown's family... but I suspect he won' be out front signing autographs. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 00:51, 10 December 2014 (UTC)
+:::I just noticed [[Wikipedia:Replaceability_of_fair-use_images]] is a failed proposal. It carries zero weight. My argument just took a shit. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 01:17, 10 December 2014 (UTC)
+::::Yes, [[WP:REFU]] appears to be a failed proposal. I obviously overlooked the beard on the photograph. --[[User:Stefan2|Stefan2]] ([[User talk:Stefan2|talk]]) 23:06, 10 December 2014 (UTC)
+::{{re|Stefan2}} You probably missed the goatee, Brown doesn't look 8 years old in that photo. Judging by the [http://documents.latimes.com/federal-autopsy-michael-brown/ federal autopsy report's description], the photo is probably recent, although it could use a bit of cropping. Trayvon Martin's photos aren't relevant to the discussion; as of when I wrote this there hasn't been any consensus regarding those images. That leaves Wilson's images. It's possible that a photo of Wilson might be released publicly, so NFCC#1 probably doesn't work here. The only nonfree image that's irreplaceable is that of Wilson's injuries, except they're probably not appropriate for the short biography. Those are better suited for descriptions of the shooting. I think that posting only an image of Brown with the biographies would violate [[WP:IMPARTIAL|impartiality]], so I don't think their photos should be posted in the article. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 02:00, 10 December 2014 (UTC)
+
+== "baseline position" on diagram ==
+
+{{u|Cwobeel}} I think it may be helpful to include a spot on the diagram for the "baseline" position where all the measurements are from. Note that this point is not a [[WP:SYNTH]] issue derived by us from the witness testimony/sources, this is the "zero" point for the diagram measurements, per the crime scene photographers/investigators, and that point is explicitly marked on the original diagram.
+
+As an aside, the quotes below has bearing on the "Crime Scene" discussion above, as we have the police specifically referring to this location as a crime scene.
+
+* [http://www.washingtonpost.com/news/volokh-conspiracy/wp/2014/12/08/the-overlooked-audiotape-of-the-michael-brown-shooting/] (See figure 2 cone photo)
+
+* https://s3.amazonaws.com/s3.documentcloud.org/documents/1370513/grand-jury-volume-24.txt
+**And why is it that this cone was placed at that location on Canfield Drive? A As best we could tell based off of witness accounts, that would have been the furthest point east that Michael Brown would have went to. So that intersection of roughly Coppercreek Court and Canfield Drive. or Canfield Road? [...]That was the point that they had made reference to and so we used that as the furthest eastern point to go to.
+**In terms of on August 9th, one of our crime scene detective's jobs was to '''take various measurements of items of evidence at the scene. And he used what starts as a baseline at Coppercreek Court and Canfield Court, and used this baseline here and measured items during the entire, I should say, within the entire crime scene and those items were documented in a diagram that he completed with specific measurements, feet down to inches.''' So when we went back out there to take those 360 degree panoramic shots, we based, obviously, Coppercreek Court and Canfield Drive is subjective in the sense that we are basing that off of where, again, witnesses were telling us is the furthest point east that Michael Brown would have went So that is a subjective point that we use that intersection, northwest corner of that intersection right there.
+* Witness 14 http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/interviews/interview-witness-14-01.pdf
+** "the boy was still standing on the, on the, on the partially on the parking lot and on the grass. 'Cause he had ran that way. The officer came out came around got into his stance. And he said ?stop.? Because the boy looked up at him and he took two steps, about two or three steps.
+** When [Brown] turned around he had about one foot on the grass and one on the driveway.
+* Dorian
+** [Brown] was barely on the sidewalk, he was barely on the sidewalk to the parking lot. He was going towards this building. I presume that’s the way he was running. He wasn’t really all the way on the driveway when the . . . shot went off, and he turned around, and he was in the street
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:48, 8 December 2014 (UTC)
+
+Do we have the exact position of the baseline cone? I don't see it on the police report diagram. Is it on the legend list? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:40, 8 December 2014 (UTC)
+::{{u|Cwobeel}} It is at 0 feet 0 inches for both directions. on the diagram (text at bottom right corner saying "Baseline starting at 0'0" ) with a line pointing to the corner. On the legend the very bottom says "baseline runs east to west on north side of canfield with 0'0" starting at copper creek ct." The testimony indicates why they chose that spot as the baseline, and that the cone in the photograph is that point. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 20:58, 8 December 2014 (UTC)
+::: Added baseline as suggested. Also added the cross street Copper Creek Ct. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:45, 8 December 2014 (UTC)
+::::Nice. Suggestions: 1. Extend the bottom curb to the right edge of the image, to show that Copper Creek does not cross Canfield. 2. Is there a little too much space between the C and T in CT., or is that just more flaky rendering? 3. If there is any way to establish the distance between the left edge and the baseline, I can use that to fine-tune our coordinates, using the distance measuring tool in Google Maps. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:55, 8 December 2014 (UTC)
+::::: {{Done}} . Thanks for the feedback. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:36, 8 December 2014 (UTC)
+
+:::::{{u|Mandruss}} The legend of the original diagram includes the exact distance in feet and inches to every other item from the baseline, so just pick the furthest left item? (looks like its one of the casings by the car) [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:15, 8 December 2014 (UTC)
+::::::Ok, I tweaked the coords to a position halfway between items 4 and 20, or about 105 ft NW of the baseline (they moved about 20 ft SE). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 22:28, 8 December 2014 (UTC)
+::::::Obsessively checking my work, I came up with 118 ft NW of the baseline, and the coords were already correct. I could be taking this accuracy thing too far, or perhaps someone as anal as I am would care to check my work. Item 4: 210' from baseline. Item 20: 26'7" from baseline. 26'7" = roughly 26.6 ft. ((210 - 26.6) / 2)) + 26.6 = 118.3. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 22:56, 8 December 2014 (UTC)
+::::::I vote accuracy too far. A few feet certainly won't matter for the purposes of the infobox. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:59, 8 December 2014 (UTC)
+:::::::Thought so. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:01, 8 December 2014 (UTC)
+
+As for the other witnesses narratives, that would be a good addition, as it explains the position of the casings and other evidence when the final shots were fired. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:46, 8 December 2014 (UTC)
+
+{{u|Cwobeel}} How are you making the SVG? Are you just eyeballing positions, or do you have it gridded out so you can convert from the actual feet/inches to the right pixels in some deterministic way? [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:10, 8 December 2014 (UTC)
+: Neither. I used the diagram of one of the media sources as an underlay, and positioned the evidence items accordingly. As the media sources did not have the baseline cone, that one I added by eyeballing. If we want to be scientific about it, I will have to re-do the position of each item using the measurements and converting the positions to the XY grid in Omnigraffle. Pretty laborious I'd say. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:29, 8 December 2014 (UTC)
+
+Can you explain how this is not original research or synthesis? You're converting a not-to-scale diagram to a scale diagram using information from two different primary sources. The article is in poor condition, with many outdated sections, far too many references, and duplicate information in several places. There are also far, far too many statements of the type "A B of XYZ News stated on August 21 that..."
+
+For comparison, [[2014 Grozny clashes]] has a better balance of opinion and fact, and an appropriate use of citations. That's just a random news article that I like the style of.
+
+Does this article require mediation? I haven't done that before, but I think there are issues that need to be addressed. I mean ownership, if it's not clear. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 05:06, 9 December 2014 (UTC)
+
+:From [[WP:Citing sources]]: ''Wikipedia's Verifiability policy requires inline citations for any material challenged or likely to be challenged, and for all quotations, anywhere in article space. However, editors are advised to provide citations for all material added to Wikipedia; any unsourced material risks being unexpectedly challenged or eventually removed.''
+
+:Based on the above, your concerns about too many references are unfounded and clearly unsupported by WP content guidelines.
+
+:I honestly don't see where you're getting the ownership claim, but please be specific and back it up.
+
+:I'll let others respond to your concerns about the diagram. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 05:14, 9 December 2014 (UTC)
+::I don't think Roches was referring to there being too many citations, but rather too many in-text attributions.
+::Regarding ownership, I think it's more a matter of there being some very active editors. This can result in there being misinformation and bias that would take more time than most have to correct it, but I don't see how that can be avoided, considering there is open editing. All I can say is to hang in there and do what you can.
+::Regarding the scale of the diagram, it looks like the same scale as the diagram in this source [http://www.stltoday.com/map-the-michael-brown-shooting-scene/html_0c861d0f-9a56-5769-8c16-d4b137af96e1.html]. In fact, the identifications and placement of the individual pieces of evidence look about the same too. If something is added to the diagram that is not supported by a reliable source, or it highlights something that is not specifically mentioned in a reliable source, then that might be a problem. So far I don't know of that happening here. Items that are the result of calculations can be questioned, but then there is the policy [[WP:CALC]] that allows some, and whether or not it is suitable for an article can be determined by consensus. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 13:01, 9 December 2014 (UTC)
+::On second thought it doesn't look like the same scale. [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637281752#Shooting_scene_evidence our article] [http://www.stltoday.com/map-the-michael-brown-shooting-scene/html_0c861d0f-9a56-5769-8c16-d4b137af96e1.html source] Maybe we need take out a ruler and check it and then add a note to the diagram, "not to scale", or redraw the diagram, using the source's diagram as a model for the scale. I notice that the source's diagram uses an actual picture of the street and surroundings on which it overlays the items in the crime scene. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 13:57, 9 December 2014 (UTC)
+::Update: I just now added the above source to the diagram. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 14:10, 9 December 2014 (UTC)
+:::My understanding is that the plotting of all points in the diagram used in the article was down to the inches from the baseline point based on the data published in that measurement table. If the scale in the diagram is questionable, it may be good for us to add a scale bar with 10-foot increment along the bottom part of the diagram. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 14:23, 9 December 2014 (UTC)
+
+:::Bob, I disagree that we need to inform the reader that the scale of our diagram is a little different from that of the source, for the sake of improved readability. All that matters is that the distance ''proportions'' are the same, and a "not to scale" statement could easily be interpreted as meaning that they are not. I think we're better off without it. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:51, 10 December 2014 (UTC)
+
+:About the diagram, as per [[WP:OI]], "Original images created by a Wikipedian are not considered original research, so long as they do not illustrate or introduce unpublished ideas or arguments, the core reason behind the NOR policy." This diagram was created from published data [http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/picture2.png here] and [http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/capture.png here], same document. There is no unpublished ideas or arguments included in the diagram, so it is not an original research, but it is just an original image. Also it is not synthesis because it is largely based on that same source. Other references listed next to the diagram were to show that same idea/argument has been published by multiple reliable sources. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 13:32, 9 December 2014 (UTC)
+
+Per the arguments above by Z22 and others, the diagram is not OR. Can it be improved? Sure, there is always that possibility. As for the state of the article referred to by Roches, same applies. It can always be improved, but generalizations don't help here. If there are specific things that you want addressed, join in and do the [[WP:EDITING|hard work]]. You may get reverted and challenged, but that is the way of this land. Collaborative editing is hard work and requires patience. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 8:39 am, Today (UTC−6)
+
+== Collaborating, OR, and inline attributions==
+Cwobeel, you have mentioned [[WP:OR]] three times since the talk page was last archived, and none of those instances were legitimately original research. I don't think the diagram is OR, actually, but it seemed inconsistent, for example, that you'd estimate the position of the baseline.
+
+I'd like to contribute in a collaborative and positive way, but that will require the active editors to assume competency on my part. I would use fewer in-line citations, I would use primary sources to some extent, and I would have to remove existing content in the process of editing it. I can't justify every change I make, but all the changes I make are justifiable. So, if I remove content, replace it, and if I make a change that needs justification, please ask for justification. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 15:46, 9 December 2014 (UTC)
+
+:Again, you call for fewer inline citations, but this time you're doing it without responding to the guideline excerpt that clearly says you're wrong on that. If you're in fact referring only to in-text attributions, as Bob said, then please use the correct term and say so.
+
+:If you want to work collaboratively on this article like the rest of us, I don't think anyone here will oppose that. We can use all the collaborative help we can get. Doing things like asserting, quite incorrectly, that your disagreement voids a consensus is not collaborative. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 17:26, 9 December 2014 (UTC)
+
+:: I second Mandruss comments about consensus. {{yo|Roches}} What I am puzzled about is your assertion that you want to {{tq|use primary sources to some extent}}. Can you clarify what do you mean by that? As discussed in [[Wikipedia_talk:Identifying_reliable_sources#Source_bombing]], while primary sources are not forbidden, most materials in articles are expected to be drawn from secondary sources. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:12, 9 December 2014 (UTC)
+
+:: A point about in-text attributions. These are needed in ''each and every case'' in which an opinion is expressed. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:15, 9 December 2014 (UTC)
+
+I'm referring to [[WP:BUNDLING]], not to any removal of inline citations or in-text attributions that are required. It didn't occur to me that there was even a possibility of someone thinking I meant removing references that needed to be there.
+
+About consensus: That was in reply to an assertion that I was deliberately removing content. The idea was that it had been there for a long time, and so it should stay. I thought that it needed to be updated, and that's all. If I was really trying to do something incorrect there, I would have undid the revert, and I didn't.
+
+About using primary sources to some extent: I really just meant what I said here (and everywhere else, for that matter). There are aspects of this case where primary sources are the best ones. An example would be the autopsy report, which is the work of a medical professional and makes all of the appropriate conclusions (and none of the inappropriate ones), as opposed to an article about the autopsy.
+
+In general: I don't have a lot of Wikipedia edits, but I've been using the site almost since the beginning. I've written and edited a substantial amount of scientific text, some of which is published. This does not mean I'm better than anyone else, but it's difficult for me to understand the hostility towards my comments here. (I don't mean replies to things that were already hostile.) It's even more difficult to understand the hostility I got when I tried to edit the article.
+
+I have posted to the admin noticeboards incident section. I tried to resolve this with the last post, but all that happened is that I got told I wasn't being collaborative. I can't see any reason why I was being uncollaborative that does not involve altering someone's content.
+
+[[User:Roches|Roches]] ([[User talk:Roches|talk]]) 20:35, 9 December 2014 (UTC)
+
+: I can understand your frustration. Expert editors sometimes have difficulties adapting to the realities of Wikipedia editing. A couple of good essay on the subject are [[WP:EXPERT]] and [[WP:EXR]] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:46, 9 December 2014 (UTC)
+
+The problem with [[WP:PRIMARY]] sources is that they can only be used for "straightforward, descriptive statements of facts that can be verified by any educated person with access to the primary source but without further, specialized knowledge" and "Any interpretation of primary source material requires a reliable secondary source for that interpretation". As can be seen in the "shell casing pattern" discussion above, deciding what is or isn't analysis vs objective fact is often itself controversial per your statement "''Objective facts from a primary source are not original research, and synthesis of objective facts when only one conclusion is possible is not speculation''". Clearly there is disagreement about how many conclusions are possible for almost all the facts of this case both on wiki and in the real world. Further, your specific example for wanting primary sources is itself problematic "''An example would be the autopsy report, which is the work of a medical professional and makes all of the appropriate conclusions (and none of the inappropriate ones), as opposed to an article about the autopsy''" By definition you are stating that your analysis of the primary source disagrees with the secondary source analysis of that same source. You may be right, you may be wrong, but policy prohibits any such analysis all together. There are plenty of places all of us disagree with various secondary sources, and think they got it wrong. The answer to that is to find an equally reliable secondary source that you think got it right and put it in, not just delete what we disagree with, or put in our own analysis. To some degree those restrictions are less ''on the talk page'' where we can briefly discuss why we think a particular fact or analsysis is relevant and worthy for inclusion in the article. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 21:06, 9 December 2014 (UTC)
+: I couldn't have argued it better. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:29, 9 December 2014 (UTC)
+
+Please don't be offended by the admin noticeboard post, at least not to a great extent. Things were gradually building up, and I held back from resorting to the admins for a while.
+
+The autopsy report may not be the best example, because that section is okay. I wouldn't analyze a primary source; there is always a need and a place for secondary sources. I just don't think secondary sources are necessarily better. Maybe a witness account is a better example; it could be quoted directly ''and supported by secondary sources'' rather than using several sources to write the account. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 23:14, 9 December 2014 (UTC)
+
+== Two witnesses found dead? ==
+
+According to this source, two witnesses, Shawn Gray, and DeAndre Joshua were found dead under suspicious circumstance. No idea if the source is reliable, but I doubt this is a made up story. [http://www.telesurtv.net/english/news/Another-Witness-in-Michael-Brown-Shooting-Found-Dead-20141208-0044.html]. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:33, 8 December 2014 (UTC)
+: After digging in a bit, it seems that there is a conspiracy theory garnering steam on the interwebs, that witnesses are being targeted. But reports I am seeing about the death of Shawn Gray, do not say anything about him being an witness in Brown's case. [http://www.stltoday.com/news/local/crime-and-courts/death-of-man-found-in-river-des-peres-in-st/article_f2e9ab3d-a536-573a-b85f-9d7cac03ed17.html] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:38, 8 December 2014 (UTC)
+
+::Joshua was the one found in the burned car. We have him in the unrest article with no connection to this case other than location. I don't see any reason to include random Internet conspiracy theories. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:45, 8 December 2014 (UTC)
+::: Neither do I. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:49, 8 December 2014 (UTC)
+
+== Anonymous released wrong name ==
+
+All right, here's a tricky issue.
+
+I went and tracked down the purportedly-[[Anonymous (group)]]-affiliated Twitter account's release of a police officer's name [[Shooting_of_Michael_Brown#Third_parties|mentioned in the article]], no doubt getting myself on all kinds of governmental watchlists in the process. It's not easy to find, but the name they released was '''not''' that of Darren Wilson. (Nobody type it here!) This fact seems inclusion-worthy despite (or, per [[WP:Recent]], particularly because) being out of the headlines, but the only RS I can find who have reported on this error mention the released incorrect name themselves, and it would be unethical and probably prohibited by [[WP:BLP]] to link to them.
+
+Should we just let this info fade into the Net? People will want to check the record next time Anonymous [[doxing|doxes]] someone in a high-profile situation like this, but maybe that's not our problem.
+
+Apologies for not posting links to what I'm talking about, but I shouldn't for obvious reasons. [[User:FourViolas|FourViolas]] ([[User talk:FourViolas|talk]]) 01:14, 9 December 2014 (UTC)
+
+:Are you talking about [[Shooting_of_Michael_Brown#Third_parties|this (fifth bullet, next-to-last sentence)]]? &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 01:17, 9 December 2014 (UTC)
+
+::That's the section I'm talking about, but not the citation. That one is from before Wilson's name was released, so all it says is that the police denied the allegation. It might be good enough for this article, though, as it allows readers to infer from the absence of an update saying "...but the police were lying, and it '''was''' Officer [redacted] after all." [[User:FourViolas|FourViolas]] ([[User talk:FourViolas|talk]]) 01:28, 9 December 2014 (UTC)
+
+:::I get you now. And you haven't found a source that says the Anonymous ID was wrong, without reporting the name of the innocent party. In that case, I agree with leaving it at is. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 01:34, 9 December 2014 (UTC)
+
+== New documents released ==
+
+New material has been released by the prosecutor's office. As I will not have much time today to work on this, maybe others can take a look. [http://www.latimes.com/nation/nationnow/la-na-nn-more-grand-jury-documents-michael-brown-shooting-20141208-story.html] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:18, 9 December 2014 (UTC)
+
+:So far the docs seem all over the place. A few supporting brown, a few supporting wilson, one completely off the wall "walk out" one that claimed to personally see Brown on his knees and Wilson shoot him in the head point blank, and then saw/heard 8 more shots into Brown while he was face down, who then stopped the interview when they were told what they were saying didn't match the evidence. Mostly they seem to be all followup interviews asking specific questions after the local interviews. On from the guy Brown was living with that week.[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 20:31, 9 December 2014 (UTC)
+
+:Added above source as LATimes.Documents. It includes a link to the federal autopsy report, and I added that report separately as LATimes.FederalAutopsy. Added mention of the release of the federal autopsy report. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:48, 9 December 2014 (UTC)
+
+== More terse summaries in the witness accounts ==
+
+As there are now a massive amount of witness statements available, I think we need to change how we are doing things in the accounts section. Obviously covering each account in the level of detail we currently have for dozens of additional accounts, and then criticisms of those accounts, would not be viable - it would be multiple standalone articles worth of content. Keeping things the way it is now represents an [[WP:NPOV]] issue as well. I suggest we move to a more [[WP:SUMMARY]] style overall bringing all of the media witnesses together under a [[WP:SUMMARY]] section (as they are mostly saying the same thing), and then a Grand Jury section that discusses the various testimonies again at a high level - Using sources such as the PBS comparison (even with its well known flaws) or the links that {{u|TParis}} pointed out in ANI.
+
+Perhaps the Police/Wilson and Johnson should keep standalone sections, as they are directly involved and therefore their statements have more importance, and have been scrutinized more carefully by the media and other analysts.
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:26, 9 December 2014 (UTC)
+
+I was saying this, thinking this, and in one case tried doing this, for several days before taking it to ANI. I don't like that I had to take it to ANI because of objections that it would destroy people's work or might constitute original research. There was no critical discussion of any witness that opposed Wilson, and much discussion of discrepancies and flaws in the few accounts that supported it.
+
+I've always thought there should be a section on Wilson's story and a section about the opposing views; I typed that a few days ago, though I'm not sure I posted it. I still think it's the best way to move forward. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 15:49, 10 December 2014 (UTC)
+
+==POV Issues Regarding Controversy Section==
+
+I pretty much agree with everything that TParis wrote at ani. This article has NPOV issues. The article relies too heavily on the opinions of non-notable commentators and their criticism. The article is also littered with weasel words and phrases like "some legal experts" and terms like "asserted" and "claimed", which are all discouraged by MOS. The controversy section for the grand jury hearing is a prime example of undue weight with the amount of criticism in that section. That table really needs to go too, what is the significance of having that, it's not even true. These jurors were a ''typical grand jury'' that were conducting ''typical'' grand jury business, doing exactly everything listed in the first column, before Wilson's case was given to them, there's no mention of that in the table. The criticism in Wilson's section has weasel phrases like "sources reported" and "other discrepancies" without defining who the sources are or what the other discrepancies are. It also provides no context at all either, like the fact that the grand jury was made aware of these inconsistencies before Wilson even testified. There just seems to be a lot of cherry-picking sources to negatively portray Wilson, law-enforcement officers, prosecutors and the grand jurors.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 02:10, 10 December 2014 (UTC)
+
+:I think the reason for at least one occurrence of "some legal experts" is that the source says "some legal experts". Obviously we can't say it in Wikipedia's voice, so are you suggesting it should be left out of the article because the source declined to identify the legal experts? I would disagree. As for "other discrepancies", if those were elaborated it would be attacked as undue weight, so it appears there's no way to include such material at all. It's either undue weight or weasel words. I'll abstain from discussion about the table for lack of competence in that area. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:28, 10 December 2014 (UTC)
+
+:First, this has almost nothing to do with {{u|Gaijin42}}'s post in [[#More terse summaries in the witness accounts]] and I've refactored it into a new section (if not, go ahead and undo it). I disagree that this article has NPOV issues. [[WP:NNC|Notability does not apply to content]], and we should instead be looking at due weight. In this case, it seems that the majority of opinions are biased against Wilson, the prosecution team and the grand jury, which is why it's reported so heavily in the article; unless it's out of proportion, there shouldn't be anything wrong with this. Sources that argue to the contrary are present; if there are others, they should be included to keep due weight. The "some legal experts" phrase is a leftover from the [http://www.latimes.com/nation/la-na-ferguson-da-analysis-20141126-story.html LA Times] article, which provided a number of legal opinions. While out of context it may seem like a weasel phrase, the rest of the section references by legal experts mentioned in the source by name, so it really isn't a weasel phrase. Assertions and claims are only weasel words when [[WP:ALLEGED|implying a point is inaccurate]], which is hardly the case here. The table is sourced to NYT, which is why we have it. I don't see what's the problem with having it here, maybe you could clarify? The other two instances are poorly paraphrased: the "sources reported" is actually the Huffington Post's analysis, but the analysis that went into their article was cut out of ours so that'll have to be reworked; there's only one discrepancy reported in the CNN article, so I went ahead and reworded that phrase. At any rate, there doesn't seem to be blatant cherry-picking of POVs as far as I can tell. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 03:01, 10 December 2014 (UTC)
+::Once you have summarized and presented information to the reader in an encyclopedic tone - following that up with an endless stream of cherry-picked opinions of non-notable commentators is undue piling on. I completely agree that the majority of the reporting is negative against Wilson and the other entities involved in this case, but that doesn't mean we pack as many negative opinions that we can into a section, or the article, and still claim it's NPOV, because that's not neutral. We should be summarizing and including the most notable opinions or academic opinions, instead of being a depository for negative opinions that don't really impart any encyclopedic information to the reader. The weasel phrases "some legal experts" and "sources reported" is exactly that - weasel phrasing - and should never be used in this article, especially when there are more than enough legal experts identified by name offering legal opinions.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 17:36, 10 December 2014 (UTC)
+:::I really don't think the opinions are cherry-picked unless we're missing pro-Wilson/prosecutor references, and notability really doesn't matter for sources. I took a closer look at the article though, and I noticed that we're quoting a lot of the opinions directly, which is probably compromising [[WP:IMPARTIAL|impartial tone]]. We should neutrally summarize the arguments instead of quoting them, and I think that should fix the POV problem. Btw, "some legal experts" isn't a [[WP:WEASEL|weasel phrase]] when used in the header or (especially) when the legal experts are clarified after the fact. Using that phrase should be ok. "Sources reported" is weasel phrasing, and I'll take the time to reword that sentence later today. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 19:33, 10 December 2014 (UTC)
+:::<s>P.S. And now my refactoring's a moot point. Whoops. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 19:37, 10 December 2014 (UTC)</s>
+I don't think there was blatant cherry-picking of POVs, but I think there was a desire to represent a greater variety of opinions than was necessary. There are so many opinions from so many sources that it would be much more helpful to avoid arguing why a given source is acceptable despite having issues like weasel words and unnamed sources. We could simply choose sources that don't do that.
+
+In general, I objected to the inclusion of journalists' opinions about the legal issues because there were also several published opinions from real lawyers about the legal issues. In the point where there was a formal statement from the ACLU and an analysis by the Huffington Post, the first source was a much better choice than the other. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 16:11, 10 December 2014 (UTC)
+
+== Differences between typical grand jury proceedings in Missouri and Wilson's case --should be removed or changed to reflect data and not opinion ==
+
+It should either compare this case with a low profile case or just give the facts of the case. It is copied almost word for word from the the NYT and is not fact but opinion. As there are no references to real data. <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Oceanisle2009|Oceanisle2009]] ([[User talk:Oceanisle2009|talk]] • [[Special:Contributions/Oceanisle2009|contribs]]) 03:12, 10 December 2014 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+:Which NYT source are you suggesting is an opinion piece? [[User:Dyrnych|Dyrnych]] ([[User talk:Dyrnych|talk]]) 03:17, 10 December 2014 (UTC)
+:In addition, if it reflects an analysis by (hence opinion of) a New York Times columnist or reporter, it should probably be adequate to simply make sure it is identified as such (inline attribution). Even opinion, when properly identified and attributed to a credible source, is fair content here. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 04:20, 10 December 2014 (UTC)
+:: I have no problems with attributing the content to the NYT. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:12, 10 December 2014 (UTC)
+:::Well, that solves that. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 07:17, 10 December 2014 (UTC)
+::::If the text of the table was copied verbatim, is there a problem with copyright infringement? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 11:01, 10 December 2014 (UTC)
+:::::: It was not copied verbatim. You can check and compare. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:08, 10 December 2014 (UTC)
+BTW, the [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637461101#Controversy Controversy section] that has the table is bloated and could use some summarizing. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 11:33, 10 December 2014 (UTC)
+
+The problem with the table is that it doesn't take into account what grand juries usually do, which is approving felony indictments that a prosecuting attorney's office has already decided to take to trial. The hearing in Wilson's case was intended to determine whether there was sufficient evidence for a trial. (A trial for second degree murder, since it was intentional but unplanned.)
+Now, I think this is the time when we got into why it's not up to us to decide when journalists are right or wrong. The table compares two very different things, and in so doing it misrepresents the purpose for the hearing in this case. I don't want to deal with opinions to any more of an extent than is absolutely necessary, but it's not right for Wikipedia to contain information that is factually wrong, or misrepresented, up to the point where one journalist discovers the error of another. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 16:03, 10 December 2014 (UTC)
+:I think your difference of purpose is the exact point of the criticism. The grand jury was not normal, and thats what the table points out. The prosecutors job is to prosecute, not decide if there is a crime. There is prosecutorial discretion, but if thats what was at play he should have just said so, and declined to prosecute. Having a show "trial" where he didn't actually prosecute did nothing except waste money and provide room for criticism. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:34, 10 December 2014 (UTC)
+::I disagree, in this specific instance, this was a "normal" grand jury conducting "normal" grand jury business, it just so happened in August that they were thrust into the spotlight and given an unusual case under unusual circumstances - and the table doesn't point that out. The table is confusing because it seems to imply that some kind of special grand jury was convened to hear this case, and that's not what happened. A ''typical'' grand jury had already been convened and were conducting ''typical'' grand jury business when they were suddenly tasked with an unusual and controversial case, that's what happened and that's what should be relayed to the reader in prose instead of a generic table that doesn't address the context in which this case was given to them.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 17:50, 10 December 2014 (UTC)
+::: Nothing is stopping you from adding other viewpoints about the grand jury process, besides the NYT's opinion and the other opinions already in the article. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 18:22, 10 December 2014 (UTC)
+:::Certainly the makeup and convening of the GJ was normal. But was the presentation of this case normal? The table is about the GJ proceedings, not the GJ itself. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:25, 10 December 2014 (UTC)
+::::From what I read from the bloated opinions in that section, it's the decision and the presentation of the case by the ''prosecutor McCulloch'' and the unusual way he used the grand jury - that is the controversy, at least that's what the overwhelming sources indicate and what and who they are specifically criticizing. If anything, there should be a table comparing "Similar cases handled by McCulloch" vs. "Wilsons case". The controversy/criticism revolves around McCulloch and the decisions he made. And I'd also point out that the table says that they met 25 days over 3 months, that was a decision that this specific GJ themselves elected to do, so that is specific to them and therefore makes it about "the GJ itself" and an apparent scheduling decision they made for convenience purposes. Gee, isn't that controversial? And I'd also make note of the fact that a "typical" grand jury does not meet for a day or less, it meets for a specific timeframe decided by a judge, and these grand jurors were originally appointed for a four-month term (and later extended).[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 22:44, 10 December 2014 (UTC)
+:::::FYI [[Grand juries in the United States|grand juries]] are not the same as [[Jury#Types of jury|trial juries]]. Trial juries are directed by judges; grand juries are directed by prosecutors. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 22:55, 10 December 2014 (UTC)
+{{od}} {{u|Isaidnoway}} You are completely misinterpreting the criticism Isaidnoway. Yes, the jury was convened for a set amount of time, but the amount of time they spent on a particular case was controlled by the prosecutor. This same GJ dealt with dozens of cases prior to this case, and most of them were less than a day. Probable cause is a really low standard. Did wilson shoot? Yes. Were there witnesses (that passed the initial "not obviously lying" test) that said Brown was surrendering? Yes. Ok, thats probable cause for a trial. Impeaching those witnesses, and showing the defensive evidence is the job of the defense, not the prosecutor. Self defense cases are tougher, because they need to show all the elements of the crime and one of those elements is "it wasn't justified" but its still a really low bar. I think there is no way they could get a conviction, but the criticism that the prosecutor would not be giving the random joe the same level of deference is absolutely correct. He used the GJ for political cover instead of just saying "I don't think there is a case here" Political cover is not one of the appropriate roles for a GJ.McCulloch essentially had a trial, where he was both the prosecution and the defense. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:01, 10 December 2014 (UTC)
+::The amount of time spent on a case is not controlled by a prosecutor, the time is controlled by the jurors themselves, as they are certainly allowed to ask questions of the witnesses and to individually examine the evidence as it suits them. And your explanation here on the talk page about how they dealt with dozens of cases with most of them being less than a day is great, but that explanation for the reader is absent from the table. The implication presently in the table is that a "typical" grand jury meets for a day or less, sans any explanation or context. Probable cause was never there for the prosecution, the physical evidence is in line with the officer's version of events.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 23:26, 10 December 2014 (UTC)
+:{{tq|" but it's not right for Wikipedia to contain information that is factually wrong"}} - Actually, the purpose of Wikipedia is to report what reliable sources say about a subject. If reliable source A said X, and X is factually incorrect because B says so, then we report what A said and what B said, and let our readers arrive to their own conclusions. But we can't avoid quoting A just because B said that A is factually incorrect. In addition, we can't use a primary source that contradicts A, unless the primary source refers to A's opinion. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:16, 10 December 2014 (UTC)
+::Policy doesn't say that we have to include questionable material. See the policy [https://en.wikipedia.org/w/index.php?title=Wikipedia:Verifiability&oldid=637531987#Verifiability_does_not_guarantee_inclusion Verifiability does not guarantee inclusion.]
+
+::There’s a false implication in the NYT table and ours that the prosecutor didn’t provide a range of charges. He provided five, from murder in the first degree to involuntary manslaughter.[http://abcnews.go.com/US/ferguson-grand-jury-indict-officer-darren-wilson-death/story?id=27146400][http://www.usatoday.com/story/news/nation/2014/11/24/ferguson-grand-jury-deliberations/19474907/]
+
+::In any case, I think we should summarize the information in the table with the following:
+:::According to ''The NY Times'', the grand jury proceedings were not typical of such proceedings in Missouri. They lasted much longer, the prosecutor did not recommend that the defendant be indicted, there was much more evidence presented, many more witnesses testified, the defendant testified, and all of the evidence and testimony was released to the public after the defendant was not indicted.
+::--[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 01:23, 11 December 2014 (UTC)
+::: Reverted per [[WP:BRD]]. I don't see any consensus emerging for this change. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:51, 11 December 2014 (UTC)
+::: Your summary is inaccurate, to say the least. Using generic terms such as "much longer" and "more evidence" when we have hard data that is measurable. I still believe the table is the best and easy to read and appreciate for our readers. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:54, 11 December 2014 (UTC)
+
+== On the issues raised on ANI ==
+
+I've posted replies under three sections that dealt with issues raised in the ANI discussion. Now, I'm going to voluntarily avoid this article and talk page for 48 hours, and after that I'll respond to any outstanding issues.
+
+For the editors who have worked on this article and who will be working on it, try to remember that this is one of the increasingly small number of places that people can go to even get a chance at not seeing news presented in the form of a top ten list. Your work is important, people read it, and it needs to be the best it can be. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 16:35, 10 December 2014 (UTC)
+
+== What gun was used? ==
+
+One of the key missing details is how the police officer's gun was wrested from him. I have tried to find the make and model gun used, as well as the make and model of holster. If this article was merely an overview, I could excuse it, but this article drills down to the level of "$48 worth of cigarillos." Not $47, not $49,but $48. I would like to see the same attention to detail for the gun issue.
+
+Was the gun a Glock, a Smith, etc.? Did the holster have a butt strap, or an internal locking device, etc.?
+
+Thanks for your attention. [[Special:Contributions/50.0.36.243|50.0.36.243]] ([[User talk:50.0.36.243|talk]]) 16:38, 10 December 2014 (UTC)
+
+:Not an answer to your question, but a while back I stumbled on this [https://www.youtube.com/watch?v=1PR9dAr9vDI YouTube video] that may be informative, or at the very least, interesting. (I'm not suggesting using it as a source nor suggesting the information contained is unimpeachable) &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:50, 10 December 2014 (UTC)
+
+:It was a .40 cal [[SIG_Sauer_P226#P229]]. Its a 12+1 gun, and Wilson had several spare mags. To my knowledge we do not know the type of holster he was using, but I don't think its relevant as there is no assertion that Brown went for the gun while it was in the holster - Wilson freely says he drew the gun from the holster himself. We don't talk about the gun much, because it has not been discussed much in reliable sources.
+
+:One interesting (to me, not covered in any sources I am aware of) discrepancy is that there were 12 cases found near the scene. Wilson states that after the shooting there was one round left in the magazine, which he removed. If there was a round in the magazine, there should also have been a round chambered. That there wasn't means that either there was a [[Firearm_malfunction#Failure_to_feed]] or the remaining bullet was not in the magazine but in the chamber, but wilson explicitly said "I lock the slide back, take the magazine out, take the one round that’s left in it out. I put it all in that bag, seal it with evidence tape and then sign it.".
+
+:http://listverse.com/2014/11/25/10-of-the-most-important-pieces-of-evidence-from-darren-wilson-testimony/ [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:04, 10 December 2014 (UTC)
+
+:: {{yo|Gaijin42}} There are 15 rounds on a P299 magazine, so 12 cases + 1 in the magazine according to Wilson, that leaves two rounds not accounted for? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:07, 10 December 2014 (UTC)
+:::{{yo|Cwobeel}} The .40 model uses 12-round magazines, it's the 9mm variant that has 15 rounds. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 23:11, 10 December 2014 (UTC)
+
+:::{{u|Cwobeel}}There are both 10, 12, and 14 round magazines for a 229.[http://shop.sigsauerguns.com/Magazines_2/P229-Magazines/] You can see Wilson's specific magazine in the photo at that listverse article I posted, and that it is a 12 round mag. The 14 round mag is longer (duh) so is more difficult to wear while seated. Some cops have the 14 rounders as their backup mags tho since you can move them around more easily than the holstered gun (Wilson said he had 2 additional mags, but their size was not released anywhere)[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:14, 10 December 2014 (UTC)
+:::: In my time in the army (not in the US), we used to chamber an extra round in our small arms in addition to the mag. Is that not a practice in law enforcement the US? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:36, 10 December 2014 (UTC)
+:::::Yes, that is standard practice here too. Its a 12+1 gun, so the +1 is the "extra". That chambered round would have been the first one fired in the car. Wilson fired 12 times, so the final round should have been chambered in the end, but it could have stayed in the magazine if there was a failure to feed. Per wilson's testimony he also had 2 failure to fires in the car during the time he says Brown's hand was on the gun (see the video posted above for a technical explanation of how his particular gun works in that regard) [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 01:37, 11 December 2014 (UTC)
+
+Also to add to my discrepancy above "locking the slide back" prior to removing the magazine would have loaded the round from the mag into the chamber. (This is why you ALWAYS REMOVE THE MAG FIRST WHEN UNLOADING A GUN) So my assumption is that what he meant to say was that he ejected the round from the chamber and removed the mag, but it was a sloppy way to talk, and I'm surprised nobody (rs) mentioned it, especially with how some sources (Shaun King etc) were saying he might have reloaded, and therefore exactly what happened to each round would be very relevant. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:28, 10 December 2014 (UTC)
+
+== Use of See also ==
+
+Resolution of [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637514479&oldid=637511493 my edit] and its [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637517371&oldid=637514479 revert] by {{u|Likeminas}}. Reason for revert was ''All these killings have been discussed as an overall recent trend in news articles''. I don't think that justifies the revert. The killings are included in the umbrella list article. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:22, 10 December 2014 (UTC)
+:With the exception of the Travon Martin shooting, all these cases are discussed in news articles as a recent trend of police abuse of force. i.e. Police officers killing people under questionable circumstances. In fact, there's a good amount of sources that mention them all in the same article.
+:The killings in the [[List of killings by law enforcement officers in the United States]] does not single out cases that have produced extensive news coverage and massive national outcry.
+:These cases are related and should be listed under 'See also' for readers that are interested in reading the most notorious cases in recent history. [[User:Likeminas|Likeminas]] ([[User talk:Likeminas|talk]]) 20:36, 10 December 2014 (UTC)
+
+:{{editconflict}} Garner, Rice and Gurley are at least related by timing. Martin and Diallo less so, since they aren't part of this recent chain of events. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 20:40, 10 December 2014 (UTC)
+::Agreed. Feel free to remove them, if chose to. Thanks [[User:Likeminas|Likeminas]] ([[User talk:Likeminas|talk]]) 20:44, 10 December 2014 (UTC)
+:::{{editconflict}} Done. Btw, should we keep the "hands up, don't shoot" in see also? We already have it in the navbox, having it in see also seems superfluous. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 20:48, 10 December 2014 (UTC)
+:Wikipedia has multiple articles addressing that topic, including [[Police brutality in the United States]] and [[Police misconduct]]. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:46, 10 December 2014 (UTC)
+::True, but the three deaths that are still in there are related by timing: The grand jury trial against the officer who killed Garner ended in non-indictment last week, and Rice and Gurley's deaths coincided with the grand jury case against Wilson. Brown's shooting at the very least had an influence on the reactions to these, so including them in 'see also' wouldn't be a bad idea. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 20:54, 10 December 2014 (UTC)
+
+== Common sense (wiki-linking Ferguson, Missouri) ==
+
+In the opening sentence, I [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637524325 linked] [[Missouri]], and unlinked "suburb" (edit summary: "some of us don't know where Missouri is; everyone knows what a suburb is"). I was reverted (twice), and instructed to "talk it to talk and stop edit warring". So, I leave it here for others to consider. Thanks. [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 21:15, 10 December 2014 (UTC)
+
+:This is two separate issues, which I will address separately. First, the Missouri linking. I don't know of a policy or guideline about this, but there is [[User:Tony1/Build_your_linking_skills|this essay]] by an editor very experienced with linking. I would encourage any editor to read all of it before becoming involved in any disputes about linking. It says, ''Uniqueness: Is the linked topic reachable—directly or indirectly—through another link in the vicinity? (If so, consider not linking.)'' In other words, [[Missouri]] is easily reachable via [[Ferguson, Missouri]], so it probably doesn't need to be linked here. The general idea is the concept of overlinking, which says that having fewer links increases the value of the remaining ones. That concept is covered in the essay as well as guidelines.
+
+:As to "suburb", I don't think it's all that clear that everyone knows what a suburb is, but I feel less strongly about that. I might even support unlinking suburb on overlinking grounds. Frankly I didn't even notice that was part of what I was reverting. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:27, 10 December 2014 (UTC)
+::The idea that it's "overlinking" because the link is available on another article is clearly wrong. (Incidentally, it's only available there because [https://en.wikipedia.org/w/index.php?title=Ferguson,_Missouri&oldid=637510044 I just added it].) You should always check what your reverting, before accusing editors of edit-warring, (and quoting irrelevant essays and policies). [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 21:35, 10 December 2014 (UTC)
+
+:::Please don't make statements about what's "clearly wrong" without some kind of backup; i.e., no matter how emphatically you present something as truth, that doesn't make it true. That's fundamental Wikipedia. And please don't lecture me about proper editing procedure while demonstrating complete ignorance of [[WP:BRD]]. The correct procedure was demonstrated in the dispute preceding this one. I was reverted once and I opened a talk discussion about it. You did not do that, instead re-reverting the revert, thereby starting an edit war. There is nothing gray or fuzzy about this area. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:42, 10 December 2014 (UTC)
+::::Firstly, I started this discussion, not you!
+::::Secondly, "overlinking" is best avoided for the reason that it draws attention away from the text. In this case, [[Ferguson, Missouri]] appeared entirely in blue, ie. identically to my edit, so this reason does not apply. And you apparently agree about "suburb". So, we are in agreement, then. [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 21:52, 10 December 2014 (UTC)
+::::And thirdly, to reiterate, you should always check what you're reverting ("fundamental Wikipedia"). [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 22:19, 10 December 2014 (UTC)
+
+I think [[Ferguson, Missouri]] is fine. No need to link the city and state separately. Regarding [[suburb]], I could go either way. I lean towards not linking it as relatively common knowledge. Then again, I'm from the U.S. If '"suburb" is not a commonly used term in oher English speaking countries then wikilink it. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:31, 10 December 2014 (UTC)
+:This will be my last comment. You failed to mention any reason why [[Ferguson, Missouri]] is better than [[Ferguson, Missouri|Ferguson]], [[Missouri]]. [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 22:46, 10 December 2014 (UTC)
+::First, never say "this is my last comment" because it rarely is. There's really no need to... if you're done commenting, just don't comment any more. No need for a parting shot. And if (like so many do) you re-enter the discussion, you re-enter it looking a little silly. We all look silly sometimes accidentally. There's really no need to do it on purpose. At any rate, to answer your question, while I know of no policy that prefers one way or another, I see no need to offer two links where one will do. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 23:03, 10 December 2014 (UTC)
+
+== Washington Post Reception Source ==
+
+''The Boston Post'' source that was used in the reception section has a couple of problems. First, it's actually a repost of ''The Washington Post'', but ''The Washington Post'' doesn't allow the Internet Archive to preserve it. Should it still be sourced to Boston or to Washington? Second, it seems to be a lot of analysis that can't be summed up easily without trimming it out, and doesn't really fit with the reception section and should probably moved next to Wilson's testimony. Any suggestions? --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 01:44, 11 December 2014 (UTC)
diff --git a/Echo/tests/phpunit/includes/revision_txt/637638133.txt b/Echo/tests/phpunit/includes/revision_txt/637638133.txt
new file mode 100644
index 00000000..4d6e2bba
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/637638133.txt
@@ -0,0 +1,828 @@
+{{Skip to talk}}
+{{Talk header|search=yes}}
+{{Not a forum}}
+{{WikiProjectBannerShell|blpo=yes|collapsed=yes|banner collapsed=no|1=
+{{WikiProject Law Enforcement |class=C}}
+{{WikiProject Missouri |class=C |importance=Mid}}
+{{WikiProject Death |class=C |importance=Low}}
+{{WikiProject Discrimination |class=C |importance=Mid}}
+{{WikiProject Politics |class=C |importance=Low}}
+{{WikiProject St. Louis |class=C}}
+}}
+{{User:MiszaBot/config
+|archiveheader = {{talkarchivenav|noredlinks=y}}
+|maxarchivesize = 150K
+|counter = 19
+|minthreadsleft = 4
+|minthreadstoarchive = 1
+|algo = old(5d)
+|archive = Talk:Shooting of Michael Brown/Archive %(counter)d
+}}
+{{Calm}}
+{{Autoarchivingnotice|bot=MiszaBot|age=5|units=days}}
+{{article discretionary sanctions|topic=blp|style=long}}
+
+==RFC: ''Alleged'' theft of cigars from convenience store?==
+{{archivetop|result=Consensus is fairly clearly against using "alleged". [[User:Number 57|<font color="orange">Number</font>]] [[User talk:Number 57|<font color="green">5</font>]][[Special:Contributions/Number 57|<font color="blue">7</font>]] 12:36, 10 December 2014 (UTC)}}
+In references here to the theft and/or strong-arm robbery of cigars from a convenience store prior to the shooting of the decedent, should this article use the term ''alleged'' or ''allegedly'' before any such claims since the decedent was never and will never be charged or convicted of theft or robbery? <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 02:52, 29 November 2014 (UTC)
+===survey===
+*(As nom) '''Yes''', as that is Wikipedia's standard practice when a criminal act is alleged but will never be prosecuted. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 02:54, 29 November 2014 (UTC)
+* '''no''' There is video of the event. An admission from his friend who was present, and admission from the Brown family. We actually have numerous opposite examples of non-convicted persons who are described as having done certain illegal actions, and we have hundreds of reliable sources saying without qualification that brown took the Cigars without paying. However, describing that theft in a specific legal crime term should not be done as we do not have sufficient proof that all elements of a crime were done, it is enough to say "stole cigars" or "took cigars without paying" but not "committed robbery" etc. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 03:00, 29 November 2014 (UTC)
+:: In regard to the question whether there is "sufficient proof that all elements of a crime were done", we just need to follow the MO law. It says, "[http://law.justia.com/codes/missouri/2013/title-xxxviii/chapter-569/section-569.030/ A person commits the crime of robbery in the second degree when he forcibly steals property.]" Did he steal the items? Did he use force when confronted by the clerk? If you say yes to both questions, then all elements of the crime were done and the act is called robbery in the second degree. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 01:08, 30 November 2014 (UTC)
+
+*'''No''' per Gaijin42 above and also see Columbine Shooting, Sandy Hook Elementary Shooting,, Isla Vista Killings and numerous other articles here on WP where a crime has been committed with the individual being killed and/or suicide with no prosecution and/or conviction and the word alleged is not used in those articles. I would also note that the police have classified this case as being "exceptionally cleared", a stringent standard to meet in a case when there will be no prosecution or conviction.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 03:04, 29 November 2014 (UTC)
+*'''No''' - Alleged refers to something that is said, without proof, to have taken place or done. Also, by the same logic of Dwpaul, you cannot identify someone for a criminal act if they are incapable of being tried. Glad to know that despite the Columbine Shooting evidence that you are content to put "alleged", again a reference to "unproven", in front of any act or attribution of the killers. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 05:52, 29 November 2014 (UTC)
+:::Didn't say you "cannot identify someone for a criminal act"; simply said you should make clear you are not claiming they have been ''convicted'' of it, if only for your own protection (in this case, for the protection of the project). That is all ''allegedly'' does. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 06:05, 29 November 2014 (UTC)
+:::: We are not "convicting" anyone. Your understanding of "alleged"'s use is wrong according to the dictionary. Allegations in a legal sense are no different, but you should be aware of that process. Since this is not a pending court matter so kindly take your armchair lawyering off this page. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 06:31, 29 November 2014 (UTC)
+
+*'''No.''' According to [[WP:ALLEGED]], alleged is ''"appropriate when wrongdoing is asserted but undetermined, such as with people awaiting or undergoing a criminal trial."'' In this case, Brown will never go to trial so the issue won't be determined that way. However, we are not entirely without the ability to make an editorial determination here. We have a published security video showing what certainly appears to be a theft (or more accurately strong arm robbery) and there is the published testimony of Brown's friend Johnson describing the events in the store. That description supports that it was in fact a strong arm robbery. In addition, many (though not all) sources refer to the event as a theft and do not use the term "alleged". Taking all this into consideration, I think it's perfectly reasonable, neutral and accurate to treat it as an actual crime and leave out he word "alleged".
+
+:There have been theories suggesting that maybe Brown did pay for the cigars and the clerk just wanted an ID. This is an interesting theory, but entirely unsupported by ''anything''. Others note that no store employee contacted the police (a customer did). In no way does this cause other evidence to vanish. Again, taking ALL things into consideration from what is available to us, it is reasonable to say that a crime was committed and there is nothing "alleged" about it. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:11, 29 November 2014 (UTC)
+
+::That actually brings up an interesting question. Let's suppose Brown (who is of age) wants to buy cigars and the clerk wants to see an ID. Let's further suppose Brown throws down the money and says "screw the ID, here's the money" then grabs the cigars and leaves. The clerk tries to stop him still wanting to see the ID. Brown pushes past and exits the store (we'll forget about the hard shoving). Has a crime been committed? Or more specifically, is it theft? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:36, 29 November 2014 (UTC)
+
+:::If for some reasons you put a million dollars cash on the counter but the clerk refuses to "sell" an inexpensive product (no matter what it is) and you take that product anyway, then you use force to clear your way out of the store, you will still be charged with robbery in the second degree as per [http://m.willworshamlaw.com/Criminal-Defense-Home/Robbery.aspx MO law]. Even when give a correct amount of money to the clerk for the cigar, but the clerk refuses to sell that to you. The transaction does not take place. When you take valuable propety from that store when you have not been the owner of that property yet, it is stealing. To add to that, you use force, it's a robbery of the second degree. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 00:48, 30 November 2014 (UTC)
+:::: What a poor example - the discussion below shows it is closed and why. Original research or other accusations carry no real weight because the official report ''is'' our proper source. As a result, no matter what excuses or theoretical case you come up with, it does not apply to this case. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 05:06, 30 November 2014 (UTC)
+
+*'''No''' – In prior weeks there was some question from news sources whether Brown might have actually paid for the cigarillos, that analysis seems to have disappeared even in Brown-friendly news outlets as more information has come out. Also, [[John Wilkes Booth]] did not "allegedly" assassinate Abraham Lincoln, even though he was never convicted of it. —[[User:Megiddo1013|Megiddo1013]] 01:49, 30 November 2014 (UTC)
+
+* '''No''' - In the absence of any other reasonable explanations for what can be seen in the footage and testimonies, it seems safe to go with what the recently written RSs say on this one. [[User:AdventurousSquirrel|AdventurousSquirrel]] ([[User talk:AdventurousSquirrel|talk]]) 12:56, 30 November 2014 (UTC)
+
+* '''No''' - There's really no question at this point of what happened, and Brown is very much dead and thus we have no reason to worry about prejudicing a jury against him. It is safe to not use "alleged" here as we have video, testimony from his friend, RSs which don't use "alleged", and standard Wiki policy that in cases like this that we don't use it ([[John Wilkes Booth]], [[Columbine shooting]], ect.). [[User:Titanium Dragon|Titanium Dragon]] ([[User talk:Titanium Dragon|talk]]) 15:18, 30 November 2014 (UTC)
+
+*'''COMMENT''' Due to the apparent [[WP:SNOW]] above, I am going to remove the "allege"s that are referring to the robbery. However, the RFC remains open, and consensus could certainly swing the other way over the next days/weeks. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 15:25, 30 November 2014 (UTC)
+
+*'''No''' - Per the users above. There is no question as to the factual nature of the crime.--<span style="text-shadow:grey 0.125em 0.138em 0.118em; class=texhtml">[[User:TMDrew|<font color="black">'''TMD'''</font>]] [[User_talk:TMDrew|<small>Talk Page.</small>]]</span> 16:06, 30 November 2014 (UTC)
+
+*'''No''' Per [[User:AdventurousSquirrel|AdventurousSquirrel]]. We should be going with what the recent [[WP:RS]] are saying. [[User:rmosler2100|<span style="color:green">'''R'''</span><span style="color:black; font-variant:small-caps">'''mosler'''</span>]]&nbsp;|[[User_talk:Rmosler2100| <span style="color:black; font-variant:small-caps">●</span>]] 16:18, 1 December 2014 (UTC)
+
+===Threaded discussion===
+Can you include a source for the "exceptionally cleared" classification being applied to this case and its <s>meaning</s>significance, since this information (not there now) would be useful to include in the article? I can find references to the police report including this notation, but none that say it gives it some special degree of "truthiness".<span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 03:29, 29 November 2014 (UTC)
+:Exceptionally cleared is a [[Uniform Crime Reports]] term. It means "solved" by "exception" not the "awesome" meaning of exceptional http://www.fbi.gov/about-us/cjis/ucr/crime-in-the-u.s/2010/crime-in-the-u.s.-2010/clearances NPR is one of many many sources saying that the case was closed with this status, but they appear to be doing so based on just viewing the police report. http://www.npr.org/blogs/thetwo-way/2014/08/15/340594634/ferguson-police-release-name-of-officer-who-shot-michael-brown [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 03:38, 29 November 2014 (UTC)
+::Thank you. I was about to point out the same finding to {{U|Isaidnoway}}, with a caution against using it to suggest some special quality of the investigation. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 03:45, 29 November 2014 (UTC)
+:::Its not some special quality, but it does indicate that the case was formally solved including identifying the perp sufficient for FBI reporting purposes. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 03:49, 29 November 2014 (UTC)
+::::Well, that is one interpretation; I would tend to go with your suggestion above that the case was said to have been resolved "by exception", in this case by the death of the only suspect at the time rather than by diligent and detailed police work that would have achieved a conviction. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 03:52, 29 November 2014 (UTC)
+:::::From the Missouri Uniform Crime Reporting Program (Missouri State Highway Patrol):
+:::::Exceptional Clearance - If <u>all</u> four of the following questions can be answered 'Yes' the offense can be cleared “exceptionally”.
+
+:::::# Do you know who the offender is?
+:::::# Has the investigation determined there is enough information to support an arrest/charge of a specific individual?
+:::::# Is the location of this individual known so the subject could by taken into custody now?
+:::::# Is there some reason outside law enforcement‟s control that precludes arresting, charging, and prosecuting the offender?
+
+:::::Examples of exceptional clearances include: death (suicide or justifiable homicide where the offender is killed by a police officers or citizen). This case meets all the above criteria for the case to be closed as "exceptionally cleared".[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 07:04, 29 November 2014 (UTC)
+:The police report (external links) says that it has been exceptionally cleared and if you search the archives of this talk page, you will see that this very same discussion has been had before about using the word alleged in relation to this strong-arm robbery committed by Brown.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 03:43, 29 November 2014 (UTC)
+::Yes, I see [https://en.wikipedia.org/wiki/Talk:Shooting_of_Michael_Brown/Archive_7#Robbery_or_alleged_robbery this previous discussion from August], and I see you making the same arguments you're making now, but I don't see that any consensus evolved in support of them. In fact, I see quite a lot of dissent on the question. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 04:00, 29 November 2014 (UTC)
+:::Thanks for the RfC, maybe we can put these unsourced conspiracy theories to rest once and for all.
+:::*[http://www.ibtimes.com/michael-brown-robbed-convenience-store-stole-cigarillos-darren-wilson-shooting-dorian-1729359 Michael Brown Robbed Convenience Store, Stole Cigarillos Before Darren Wilson Shooting, Dorian Johnson Says]
+:::*[http://abcnews.go.com/US/wireStory/highlights-testimony-michael-brown-shooting-27157610 Dorian Johnson told the grand jury he was stunned when Brown stole cigarillos from the convenience store]
+:::*[http://www.nationalreview.com/corner/385499/attorney-brown-acquaintance-confirms-michael-brown-stole-cigars-greg-pollowitz The attorney for Dorian Johnson, the man who was with Michael Brown when he was shot, says it was Brown who stole the cigars from the store where police say the two were filmed before Brown’s death, and that the FBI is aware of it.][[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 06:33, 29 November 2014 (UTC)
+::::* Also... "Brown was a suspect in an alleged robbery" is horrendous writing because you cannot "allege a robbery" and the nature of the matter requires "alleged" be dropped. Either a robbery took place or it didn't; it is mutually exclusive here, just as you cannot be an "alleged suspect" in the case. One alleged needs to remain in the article: "Brown then allegedly attempted to seize Wilson's gun..." which has not been conclusively proven. [[User:ChrisGualtieri|ChrisGualtieri]] ([[User talk:ChrisGualtieri|talk]]) 06:40, 29 November 2014 (UTC)
+:::[[User:Dwpaul|Dwpaul]], I ended up as a main dissenter in that August discussion, based on the use of reliable sources available at that time. However, more information has been published since then, notably Dorian Johnson's testimony under oath, and I have more carefully reviewed the video, and I don't think that using allege is appropriate. It gives the impression that there is a reasonable doubt that Brown stole the cigars, which isn't the case. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 16:39, 29 November 2014 (UTC)
+:: Whether to use the word "alleged" or not, one thing clear is that we should not misrepresent the act as a theft or stealing. It should either be called "forcibly steal" or "robbery". Apparently, the force was involved. The first mentioning of the act as just stealing in the lead is actually misleading. See definitions here: [http://www.ksdk.com/story/news/local/2014/08/15/strong-arm-robbery-definition-st-louis-county/14122545/] [http://m.willworshamlaw.com/Criminal-Defense-Home/Robbery.aspx]. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 18:58, 29 November 2014 (UTC)
+{{archivebottom}}
+== Offensive Phrasing -- Style Question ==
+
+Under the section Grand Jury Hearing (which should be capitalized, but I don't have editing privileges), it refers to the grand jury's makeup as "three blacks". This usage of black as a noun is not considered acceptable any longer in American English and is specifically prohibited in most style guides (I don't know if this is covered in wikipedia's). <small class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[Special:Contributions/38.108.125.200|38.108.125.200]] ([[User talk:38.108.125.200|talk]]) 19:01, 1 December 2014 (UTC)</small><!-- Template:Unsigned IP --> <!--Autosigned by SineBot-->
+:It isn't offensive and is frequently used in American English. [https://www.google.com/search?q=blacks&es_sm=122&source=univ&tbm=nws&tbo=u&sa=X&ei=L758VJ3yMMP1oATQk4HQCQ&ved=0CFAQsQQ Google shows how many people use it to this very day], including places like the Huffington Post. [[User:Titanium Dragon|Titanium Dragon]] ([[User talk:Titanium Dragon|talk]]) 19:16, 1 December 2014 (UTC)
+:I checked the source used for that sentence, and the source uses the terms "blacks" and "whites" in relation to the race of the grand jury members. Based on that source, I don't see a problem.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 19:50, 1 December 2014 (UTC)
+
+:Isaidnoway is correct, but there is no requirement to match the specific source on something like this, which is not within a quotation. We paraphrase all the time, and what matters is that the world of reliable sources frequently uses "blacks" as a noun. Here's [http://www.nytimes.com/2014/11/26/us/after-ferguson-announcement-a-racial-divide-remains-over-views-of-justice.html an example from the New York Times], who are known for close attention to such details. Incidentally, the "Grand jury hearing" is correct; Wikipedia uses "sentence case" in section titles. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:07, 1 December 2014 (UTC)
+
+:This black/African-American question is not going to be solved in general anytime soon around here. Sources generally use a mix of "black" and "African-American" and so should we. Sources however do NOT generally use the word "Caucasian" when describing Wilson, so that has little place in this article. We're not here to worry about what is offensive to this person or that... we're here to reflect the sources in a neutral and balanced manner. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 00:24, 2 December 2014 (UTC)
+
+:From a strict stylistic standpoint, it'd probably be good to use BOTH terms in the same passage, as [[elegant variation]] (while our article on [[elegant variation]] disparages the practice - contrary to what I and other students in my technical writing degree program were taught - in this case it wouldn't be unnecessary, but would serve the purpose of placating people on each side of the "black"/"African-American" controversy). [[User:Vfrickey|loupgarous]] ([[User talk:Vfrickey|talk]]) 15:49, 6 December 2014 (UTC)
+
+::It may seem unnecessarily contentious to some, but I'm not interested in placating editors who misinterpret Wikipedia's mission as moving social trends rather than documenting them. These editors are simply wrong, and we follow the collective sources. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:06, 6 December 2014 (UTC)
+
+== Why are you calling Michael Brown a man when being eighteen did not qualify Eric David Harris a man????? ==
+
+{{edit semi-protected|Shooting of Michael Brown|answered=y}}
+<!-- Begin request -->If Eric Harris can be called a boy when he was also 18 yrs old when the shootings took place a Columbine High School, I believe we can come to the conclusion that Michael Brown was just a boy also. Stop making him out to be something another was not.......
+I do not know him personally, but you are adding to a problem that will not cease because of status that is not really true. He was only a boy!
+
+<!-- End request -->
+[[User:Butterflygem|Butterflygem]] ([[User talk:Butterflygem|talk]]) 09:01, 2 December 2014 (UTC)
+
+:It's true that [[Eric Harris and Dylan Klebold]] and [[Columbine High School massacre]] use the term "boys" in a few instances. That may or may not reflect source's descriptions of them. You would have to bring that up on those article's respective talk pages. Regarding this article, can you point out the specific part of the article you wish to change and what you'd like to see it changed to? Be prepared (if challenged) to back up your suggested edit with sourcing and a rationale that supports it following Wikipedia policies of [[WP:VERIFY|verifiability]], [[WP:NPOV|neutral point of view]], and [[WP:UNDUE|due weight]]. I'm not trying to make it hard on you, I'm just trying to show you that editing this encyclopedia is more than simply inserting one's opinion. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 11:09, 2 December 2014 (UTC)
+::To be quite honest, I am starting to see some unconscious racism creep in this manner in articles on wikipedia. Two white guys who shot up a school are boys but an unarmed black guy is a man. Just like [[missing white girl syndrome]] -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 12:10, 2 December 2014 (UTC)
+:::I don't think this has anything to do with "unconscious racism". It's hard to visualize, much less describe, anyone who is 6 ft 4 in (1.93 m) tall, weighs 292 lb (132 kg) and smokes cigars as a "boy". In every one of these cases, if the subjects are over 18, they should probably be described as "young men", but I think it's easy to see why the term "man" was used here instead of "boy". It's a bit too convenient to invoke the racism card when a simpler explanation will suffice. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 13:53, 2 December 2014 (UTC)
+:::I also don't think the "unconscious racisim" comment is helpful, it could be seen as casting aspersions and is not [[WP:AGF]]. If you believe that an editor is not following policies or POV pushing, discuss it here or their talk page with diffs. Man, boy, teenager, the choice of nouns should be by consensus and backed by [[WP:RS]]. If you have sources that would back a change, then please share them, and the proposed change. [[User:rmosler2100|<span style="color:green">'''R'''</span><span style="color:black; font-variant:small-caps">'''mosler'''</span>]]&nbsp;|[[User_talk:Rmosler2100| <span style="color:black; font-variant:small-caps">●</span>]] 14:03, 2 December 2014 (UTC)
+::::I'm not accusing any individual editors. I'm saying that RS's and all the editors as a whole(including me) are giving in to a very human tendency to judge on a class basis. -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 14:48, 2 December 2014 (UTC)
+:::::I'd be willing to bet that, if not for the POV implications in this case and a desire for him to be perceived as the victim, we'd just as likely be criticized for calling Brown a "boy" because of the connotations that term has had when applied to young black men in the past. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 14:53, 2 December 2014 (UTC)
+:[[File:Red information icon with gradient background.svg|20px|link=]] '''Not done:''' please establish a [[Wikipedia:Consensus|consensus]] for this alteration before using the {{tlx|edit semi-protected}} template.<!-- Template:ESp --> [[User:Anupmehra|<font size="3"><span style="font-family:Old English Text MT;color:black">Anupmehra</span></font>]] -[[User talk:Anupmehra|<font size="3"><span style="font-family:Monotype Corsiva;color:black">Let's talk!</span></font>]] 14:18, 2 December 2014 (UTC)
+:::Dear Myopia, I believe that your comments on "unconscious racism" amount to silly navel-gazing. Also a more fit subject for your talk page than here. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:12, 2 December 2014 (UTC)
+::::I think it was a constructive contribution, if only because it allowed us to address this aspect of the question from a perspective others may have had or will have in mind, even if they didn't frame their arguments in those terms. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 16:24, 2 December 2014 (UTC)
+:::::Empathize with stupidity and you're half way to thinking like an idiot. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:28, 2 December 2014 (UTC)
+::::::Sometimes that's a creative and useful method of problem solving. Think we're done here. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 16:36, 2 December 2014 (UTC)
+:::::::Dear @[[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]], I don't know what navel gazing is but if you want to cuss me out you might as well accept that you're going to violate [[WP:CIVIL]] anyway and do it properly. I disagree with your suggestion that it's more fit for my talk page. Racism is a core element of this issue and the deaths of black men at the hands of police in general. As far as you calling me stupid, '''that''' was a comment for my talk page. -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 23:41, 4 December 2014 (UTC)
+{{out}} Navel gazing is where you are desperate to find some major significance in a hopelessly insignificant detail of life. Imagine staring intently into your navel, and then you find a piece of lint and want to show your special insight to the world. That was an apt metaphor for your silly comment, in which you made an observation about extremely reasonable & accurate use of language & wondered aloud whether it wasn't actually the reasonableness or accuracy, but NAY SIRS, HIDDEN RACISM, that made us decide to be reasonable and accurate. If you don't see how that is at once both unconstructive & essentially impossible to discuss in connection with this WP article & insulting to other editors, and thus that there was no good reason to put it on the talk page, then I'm not sure what else to say. Then again, judging by your username and userpage — and the comment "Racism is a core element of this issue" — it's pretty clear you are just trolling. So I guess the joke's on me.
+P.S. it appears you don't know what "cussing someone out" means. Probably because of your unconscious racism. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:57, 5 December 2014 (UTC)
+:That someone failed to call an eighteen-year old man a "man" in Columbine, Colorado doesn't excuse repeating the error. We're not responsible for the press's errors nor obliged to repeat then in our articles. Eric Harris, Dylan Klebold, and Michael Brown were all eighteen years old at the time they become notable. That made them eligible for the military draft, capable of making valid legal contracts, and immune to curfews - in short, "men." "Young men," if you want to drive the point home that they couldn't legally buy alcohol in many jurisdictions. [[User:Vfrickey|loupgarous]] ([[User talk:Vfrickey|talk]]) 15:58, 6 December 2014 (UTC)
+::Minor correction... Dylan Klebold was 17. And if I recall, some of the instances of the word "boys" referred to events that happened before they turned 18. (Eric Harris turned 18 just before the shooting) &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:19, 6 December 2014 (UTC)
+
+:The OP's opening strategy is not meaningful. For any question, you can find other articles to support either of two opposing answers. This is the spirit of the essay, [[WP:OSE|Other stuff exists]]. We should confine ourselves to what is appropriate for this article, without cherry-picking other articles that support our point of view. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:26, 6 December 2014 (UTC)
+::Agreed, but no article exists in a vacuum. To ''completely'' disregard similar articles is not wise approach either. A certain amount of consistency is a good thing. Even the essay you mention has a section [[Wikipedia:Other_stuff_exists#Precedent_in_usage|Precedent_in_usage]]. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:38, 6 December 2014 (UTC)
+
+[[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] has engaged in one too many personal attacks. Editors were trying to reason with him on his userpage and I was being discussed and attacked perosnally. I attempted to end the matter peacefully on his userpage but his repeated personal attacks resulted in me snapping and violating [[WP:CIVIL]]. Therefore, I will not be editing this page if this person is involved as well. I have had enough of his bullshit. -[[User:Myopia123|Myopia123]] ([[User talk:Myopia123|talk]]) 16:43, 6 December 2014 (UTC)
+:You have made a grand total of zero constructive contributions to this article or Talk page, again it seems like you're just trying to bait negative responses, AKA trolling. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 19:37, 6 December 2014 (UTC)
+::At least one other editor disagrees with your premise, and Myopia123's constructive contributions to this page (including one section they started) are evident. In any case, it is not your place to determine the worthiness of other editors. Since the editor has drawn a line, kindly let them go on their way instead of goading them to cross it. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 20:00, 6 December 2014 (UTC)
+:::Not sure why you find the suggestion that hidden racism could possibly explain the most innocuous and obviously correct editorial decisions, and yet you ''don't'' find helpful the suggestion that such an idea possibly reflects irrational hysteria. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:12, 8 December 2014 (UTC)
+Back to the original question, while some of this can certainly be explained by the bias, or narrative the authors (of the RSs) wishes to tell, or political correctness, one must also remember that Columbine happened in school by and at attendees of that school, which makes the "boy" appellation a bit more contextual.[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:12, 7 December 2014 (UTC)
+
+== Shooting scene ==
+
+I made some edits to the shooting scene section. It's longer.
+
+I expanded the description of the street and indicated the directions in which the people involved were traveling. I added "left side" for those in right hand drive countries. I reorganized the evidence from three groups to two, anchoring the groups around the SUV and Brown's body, because the center group consists of one sandal.
+
+The contentious part of my edit is those ten shell casings. I didn't know they were ''there'' until I saw the diagram. At first I thought it had to be a mistake. I tried to be NPOV about it, but I don't have a good reference about those casings. It has to be mentioned, though.
+
+People (bystanders, parties involved, responders, investigators, etc.) move casings around crime scenes often, apparently. Sometimes it's inadvertent, or people take them as a souvenir, but sometimes people take them or move them simply to make things difficult for investigators, or in the worst case people might move them to make it look like a gun was fired in a different place. So, it's possible that the ten casings near Brown were put there to make it look like Wilson had shot Brown at close range.
+
+Please don't reply with wikilawyering, fellow editors. Change whatever you want, add references, but this is not original research or speculation or whatever. The article needs a diagram. The diagram shows 10 casings in an unusual place. Those 10 casings have to be explained, and the only way to explain them without invoking a conspiracy theory is that they were moved. We can't say how, we can't say when, we can't say by whom, but they must have been moved because all the other evidence points that way. Somewhere in the transcripts or in some article I haven't read there is a clear, solid explanation of how they got there. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 22:27, 4 December 2014 (UTC)
+
+:What are you talking about? They are there because they are near where wilson was standing at the time those shots were fired (plus random physics bounces and the like). There were other cops and media on the scene within seconds/minutes. When exactly do you think things were tampered with? What specifically do you think is proof that that cannot be the natural position of the casings? Where do you think those casings "really belong"?[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:32, 4 December 2014 (UTC)
+
+:Presumably from the blood stain at the far right, at some point Brown was standing near there during some of the shots. (with a fudge factor for how far blood may fly from being hit). Most of the witnesses, and Wilson say that they were about 20ft apart at that point. Wilson and some witnesses say that Brown moved forward, and Wilson says he was trying to backpedal to keep distance (while firing). . That explains the pattern of casings and blood fairly well to me, and more importantly, its all covered by reliable sources. [http://www.washingtonpost.com/politics/2014/11/29/b99ef7a8-75d3-11e4-a755-e32227229e7b_story.html] [http://listverse.com/2014/11/25/10-of-the-most-important-pieces-of-evidence-from-darren-wilson-testimony/][http://thehill.com/blogs/blog-briefing-room/news/225280-wilson-brown-looked-like-demon] [http://www.newyorker.com/news/john-cassidy/darren-wilson-testimony][http://abcnews.go.com/US/exclusive-police-officer-darren-wilson-discusses-moment-shot/story?id=27186946][http://edition.cnn.com/2014/11/25/justice/ferguson-grand-jury-documents/] Saying "speculation" and "original research" is not wikilawyering, its the foundation of the way the wiki works. Find a reliable source that discusses some alternative theory, and we can talk about adding it in. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:45, 4 December 2014 (UTC)
+
+:Roches, unless you can find reliable sources supporting this speculation it cannot go into the article. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:50, 4 December 2014 (UTC)
+
+::I don't have an agenda where I want to introduce an alternative theory. I guess the talk page comment was forceful. What I wanted to happen in the article was for someone who had more knowledge about the location of the casings to add detail. As I say below, I didn't want to say "The placement of the casings is unexplained" because it's not unexplained. It's probably explained in detail in the grand jury evidence. I don't have to be the one to find the evidence; this being a collaborative effort, I wanted the statement that there was something unusual about the placement of the casings to be a call for collaboration. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 06:20, 5 December 2014 (UTC)
+
+Having spent quite a bit of time working on the diagram, I can say that I was confused by the casings as well. Nothing nefarious, there though. What struck me is that Wilson pursued Brown for more than 150 yards, before shooting 10 times toward him. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:56, 5 December 2014 (UTC)
+
+:He didn't shoot while running the distance. He pursued, then stopped. There was a burst of a few shots, then as he backed up, a burst of a few more shots. According to Wilson's testimony, the casings are exactly where one would expect. And if editors haven't heard it yet, here is apparent [https://www.youtube.com/watch?v=BiL-E5WAaUU audio] of the shots. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 04:03, 5 December 2014 (UTC)
+:: Yes, that is what I mean. Wilson pursued Brown for 150 yards before shooting, which begs many questions that I will keep to myself. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 04:12, 5 December 2014 (UTC)
+:::Some of those questions might be answered by reading Wilson's testimony to the grand jury (if you haven't already). And it was 150 feet, not yards. Big difference. 150 feet is not that far a distance at all. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 04:17, 5 December 2014 (UTC)
+::::I think what Cwobeel is saying is that Wilson didn't shoot until Brown turned around and became threatening. And now for your listening and viewing pleasure is a music video by Queen.[https://www.youtube.com/v/g2N0TkfrQhY] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 05:59, 5 December 2014 (UTC)
+:::::It's official... I'm completely confused. No worries though... isn't the first time and won't be the last. If anyone wants to explain the last few posts of this thread to me using small words and short clear sentences, you know where to find me. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 06:22, 5 December 2014 (UTC)
+
+Thanks for not just reverting the whole edit. I'll explain:
+
+''This placement of casings supports the claim that shots were fired in close proximity to Brown.''
+
+I wanted to remind the reader of the early accounts that have Wilson walking up to Brown as he's laying on the pavement and shooting him. I wanted to say that in a neutral way. It's not really disputed that shots were fired in fairly close proximity, so I worded it that way.
+
+''However, shell casings can be moved either inadvertently or in a deliberate attempt to confound or manipulate the investigation of a crime scene.''
+
+This does not require a reference, and it's naive to think the presence of police or media makes a difference, especially considering there were specific requests for assistance regarding the crowd of people who gathered at the scene.
+
+''The grand jury's interpretation cannot be known, but their decision not to indict Wilson suggests they concluded that the casings had been moved.''
+
+I didn't want to say that the position of the casings was "unexplained," because I know there's an explanation, and I was sort of hoping someone would find that explanation and put it in the article. What I meant to say is that their decision not to indict does mean that they were convinced that Wilson did not execute Brown at close range. (The "without invoking a conspiracy theory" above means that we assume the jury decided in accordance with the evidence.) "They concluded the casings had been moved" was a plainly a bad choice of wording on my part. It's totally impossible to be objective, neutral '''and concise''' if people assume content is politically charged, but what I meant is "the decision not to indict Wilson means that they did not think he shot Brown multiple times while he was lying on the ground."
+
+I should apologize for the above assertion that the casings must have been moved. However, the shell casings shouldn't be used to establish the locations where shots were fired.
+
+Some of the casings directly south of the body are where they should be, but the ones to the east are up to 20 feet from what I take to be Wilson's easternmost point. Casings from a .40 cal [[SIG Sauer P229]] are ejected to the right and go slightly forwards or backwards. There are no casings in the area the west of the body, and there probably should be.
+
+Last thing: My interpretation of "reliable source" forbids me from citing a politically biased journalist that interprets a primary source for me. Objective facts from a primary source are not original research, and synthesis of objective facts ''when only one conclusion is possible'' is not speculation. It's badly worded, but the decision not to indict means the jury believed that Wilson accurately described where he shot from. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 06:15, 5 December 2014 (UTC)
+
+{{od}}
+If you have a non-reliable source that discusses a theory, you can bring it up here. We can't use it in the article, but it can certainly be a launching point for finding better sources.
+
+Assuming any particular scenario, particularly one that involves tampering with the scene when there were dozens of eyewitnesses, media, and additional cops (not to mention Wilson himself) within seconds/minutes and nobody mentions anything close to that, on any side of the issue, is absolutely something that requires sourcing
+
+While your conjecture that ""the decision not to indict Wilson means that they did not think he shot Brown multiple times while he was lying on the ground." is true, it is absolutely the type of thing that requires sourcing. We do not put thoughts/words into living people's heads. Ever.
+
+* You say "where only one conclusion is possible" but there are MANY possible conclusions.Here are a few I can think of in just a few minutes. I'm sure they are many more others could come up with. None of them should be discussed or hinted at without reliable sourcing.
+** Wilson could have been that far and moved backwards. (Wilson and witnesses testify to this one)
+** Brown could have had significant forward momentum as he fell putting his body in front of the casings
+** Wilson could have been further to the right side of the road (down on the diagram) so was shooting at an angle and not parallel to the road. Therefore "ejection to the right" would be further down the road
+** MOST guns eject back and to the right, but 20-30% of bullet cases even from those guns go somewhere else, and in a particular gun if the ejector has been modified or bent or something could be consistently sending cases in a different direction
+** If Wilson was [[Limp wristing]], or shooting with the gun tilted (either gangsta style, or canted up or down), or one handed, or any one of infinite shooting positions, it could have significantly affected the trajectory
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 15:34, 5 December 2014 (UTC)
+:As an aside, if and when the graphic is updated, could the caption be corrected from "shell casings" to the correct terminology "shell cases"? The press pretty frequently misuses the term but Wikipedia has it right, here: [[Cartridge (firearms)#Materials]]. Here's another example [http://www.nist.gov/pml/div683/casing-080812.cfm (NIST)]. — [[User:Brianhe|Brianhe]] ([[User talk:Brianhe|talk]]) 19:34, 5 December 2014 (UTC)
+::Meh, I've known my way around guns for almost 30 years and I've never heard the term used that way. Our sources say "shell casings" and I imagine that is what just about everybody says. WP is not a source, and the source you did provide appears to be a deadlink. What is it? It won't load but I notice that the URL includes the word "casing", not "case" or "cases" [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:19, 6 December 2014 (UTC)
+:::It is an NIST report titled "Shelling Out Evidence: NIST Ballistic Standard Helps Tie Guns to Criminals". It provides this definition: "Cartridge cases—the empty shells left behind after a gun is fired...". At some point in my firearms instructor coursework, "case" had been promulgated as the right term to use, "casings are for sausage" being a common mnemonic which you can see in this comment on an urban shooting [http://www.esquire.com/blogs/politics/a-lesson-on-guns-041913]. But on further research the [http://www.nraila.org/glossary.aspx NRA glossary] says they are interchangeable. Perhaps a readjustment to the realities popular usage. Bottom line: request for change is withdrawn. — [[User:Brianhe|Brianhe]] ([[User talk:Brianhe|talk]]) 15:58, 6 December 2014 (UTC)
+
+== Shooting scene diagram ==
+
+Obvious OR diagram by Cwobeel removed. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:02, 5 December 2014 (UTC)
+
+:It won't stay out long. Everything on it was taken directly (and accurately, as far as I can tell) from a grand jury exhibit diagram. No SYNTH occurred. For another example, see the map in [[Motor Torpedo Boat PT-109]], which I had another user create from an equivalent map produced by National Geographic. It has stood for close to a year I guess. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:07, 5 December 2014 (UTC)
+
+{{ec}}{{u|Factchecker_atyourservice}} The diagram is not OR. per [[WP:OI]] "Original images created by a Wikipedian are not considered original research, so long as they do not illustrate or introduce unpublished ideas or arguments" There are multiple RS that have produced virtually identical images, based directly off of the image used by the grand jury
+* http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/capture.png
+* http://graphics8.nytimes.com/newsgraphics/2014/08/13/ferguson-qa/2e754ae76c10ce9a0ea2e1dc9166a341312be797/testimony-Artboard_1.jpg
+* http://graphics.stltoday.com/img/grmp-brown_shooting_scene.png
+* http://news.bbcimg.co.uk/media/images/79290000/jpg/_79290150_ferguson_diagram_20142611_624_v3.jpg
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:07, 5 December 2014 (UTC)
+
+:I suppose it would be ''incredibly rude'' of me to ask about sourcing for the additional data points added to Cwobeel's diagram that do not appear to be in any of the other diagrams? [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:24, 5 December 2014 (UTC)
+::Which are? [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:25, 5 December 2014 (UTC)
+::: e.g. location of "interior side front door blood stains", 21'7" "distance from feet to farthest red stain". Just a suggestion — ''pick one of the published graphs and copy it exactly'', don't try to "amplify" or "improve upon" it with your own research. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:30, 5 December 2014 (UTC)
+::::Distance to the furthest stain is covered by [[WP:CALC]] because the legend that goes with the original grand jury diagram explicitly includes locations with distances. [http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/picture2.png] The word "Interior" could possibly be removed, but since there are a bazzilion sources saying there were stains on the interior doors, its really not an issue IMO. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:38, 5 December 2014 (UTC)
+:::::"provided there is consensus among editors that the result of the calculation is obvious, correct, and a meaningful reflection of the sources." Could anyone hazard an explanation of where that number comes from and why it is significant? Also I don't recall anything from any source giving us the location of interior bloodstains. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:48, 5 December 2014 (UTC)
+:::::::The source for that number comes directly from the legend of the original grand jury diagram, as I said in my previous comment where I gave you a link directly to that legend. It was added by Cwobeel at my request. Since there are witnesses that state that brown moved forward or charged, and there is blood at the furthest most point, I thought it would be a useful addition to give an indication of how far Brown ''may'' have moved (although such must be an inference by the reader, since all we know for sure is the distance to the blood, and not how the blood actually got there). At a minimum even without the inerence, it gives the reader the ability to tell the total size of the scene. There are numerous sources describing blood on the "interior left front door handle" and other locations of the car [http://abcnews.go.com/US/crucial-pieces-evidence-ferguson-grand-jury/story?id=27163048] [http://www.msnbc.com/msnbc/prosecutors-make-trove-michael-brown-case-documents-public] For the scale of the diagram we are will within "accurate" imo. But if you insist on having the word "interior" removed you are free to argue that. BTW, all of this stuff was discussed in quite a bit of detail towards the top of this page, where your suggestions would have been more than welcome, and where you can see the consensus for the image, rather than just charging in blindly and accusing people of breaking policy and deleting the image without discussion. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:55, 5 December 2014 (UTC)
+::::::::Since there is no 21 foot 7 inch figure in that jury page, it looks like you're still not done explaining the origin of the figure, and I confess I'm a bit hazy as to your rationale for having our WP article give an emphasis that the published sources didn't find necessary or relevant. Shall we also try to deduce how many feet or inches Brown would have had to walk to get off the street and onto the sidewalk in order to comply with Wilson's order? That would ''also'' help readers understand the total size of the scene. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 17:03, 5 December 2014 (UTC)
+{{od}} The legend has the position of Browns feet. The legend has the position of the stain. [[WP:CALC]] certainly allows simple vector subtraction. If you think it should be removed, build consensus for it, but since we have been discussing the diagram for 2 days now, and nobody else complained I think you are in the minority so far. Cwobeel has been quite compliant so far with changes to the diagram. If you can build a consensus for a change, I'm sure he would be happy to assist. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:14, 5 December 2014 (UTC)
+:I think that Centrify's concern about us picking that distance to highlight is a reasonable one, and can be addressed with a reliable source that specifically mentions that distance, or one similar. I seem to recall there is such a source, but offhand I don't have a link to it.
+
+:Re the 2 red dots next to the car and their identification, “Red stains driver’s side front door exterior and interior” — When I looked at the diagram for the first time, I thought the red dots indicated red stains on the ground, which they weren't. I would suggest removing the red dots and extending the blue arrow so that the arrowhead just touches the car. Also, I would suggest changing the identification to "Blood on the exterior and interior of the driver’s side front door", and we should include a reliable source for the blood on the car door. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 17:31, 5 December 2014 (UTC)
+
+:: The exhibits says "red stains", not blood stains, so I used the former. The exhibit also says interior and exterior. If you want to check the sources I used see the File page (also below for your convenience):
+::: * map : http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/capture.png
+::: * Legend : http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/picture2.png
+::: Other sources used: NYT [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html], WaPo [http://www.washingtonpost.com/wp-srv/special/national/ferguson-diagram-of-the-scene/], and another one from St Louis Post Dispatch (which I can't locate now, but was very similar to the others. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:51, 5 December 2014 (UTC)
+
+::I also wanted "blood" but thought it got too deep into [[WP:SYNTH]]. There are numerous sources calling out the distance from the blood at marker 19/20 to browns body. The NYTimes in particular called it out, and since THAT ARTICLE is the source for one of the diagrams that completely takes care of SYNTH in my mind "''Mr. Brown’s body was about 153 feet east of Officer Wilson’s car. Mr. Brown’s blood was about 25 feet east of his body. This evidence supports statements that Mr. Brown continued to move closer to the officer after being hit by an initial string of bullets.''"[http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html?hp&action=click&pgtype=Homepage&module=b-lede-package-region&region=top-news&WT.nav=top-news&_r=3] However, there are more. [http://www.washingtonpost.com/news/volokh-conspiracy/wp/2014/12/02/why-michael-browns-best-friends-story-is-incredible/] [http://edition.cnn.com/TRANSCRIPTS/1411/25/ath.01.html] (convenience link to video of previous transcript [http://therightscoop.com/cnn-analyst-reads-crucial-evidence-that-destroys-the-lies-about-michael-brown-shooting/]) [http://www.dailymail.co.uk/news/article-2848749/Highlights-testimony-heard-grand-jury-declined-indict-Ferguson-cop-Darren-Wilson-Michael-Brown-shooting.html][http://online.wsj.com/articles/law-and-evidence-tilted-in-ferguson-polices-favor-1416950255][[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:53, 5 December 2014 (UTC)
+
+If there are changes to be made, I will most certainly comply with requests that have consensus. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:55, 5 December 2014 (UTC)
+
+Also, to avoid re-litigating this issue in the future, we should add a commented section with the sources used to create the diagram. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:56, 5 December 2014 (UTC)
+:Or, even better, figure out a way to show normal citations there. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:12, 5 December 2014 (UTC)
+::We could add a caption to the image, and attach the refs to the caption. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:17, 5 December 2014 (UTC)
+
+:::I took a first shot at it, which can be cleaned up considerably. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:24, 5 December 2014 (UTC)
+:::Are the two NYT images in a NYT article? It's much easier to cite an article than an image. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:35, 5 December 2014 (UTC)
+::::The image created BY the NYT is in my comment just above. The official GJ images just hosted by the times I cant find where the times used them, but other sources do have the same image embedded too [http://www.motherjones.com/politics/2014/11/photos-michael-brown-darren-wilson-grand-jury] [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:40, 5 December 2014 (UTC)
+:::::Yeah, it would be great if we could find them in sources we're already using. We're suffering from ref bloat with a ton of redundant source overlap. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:46, 5 December 2014 (UTC)
+{{od}} They are in both GJ evidence links in the external links section, but those may not count as "refs".[http://www.stltoday.com/news/multimedia/special/the-testimony-the-grand-jury-heard-in-the-michael-brown/html_47d95368-a8f2-5ae1-9173-6653c15d0f0e.html][http://edition.cnn.com/interactive/2014/11/us/ferguson-grand-jury-docs/index.html] [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:54, 5 December 2014 (UTC)
+:No I can't reuse those in a citation, and it would be too hard to find what's being cited in those anyway. I'll figure something out, adding new sources if necessary. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 19:03, 5 December 2014 (UTC)
+
+The "red stains" at the scene were confirmed to be blood by the crime lab. It's not original research to synthesize those pieces of information.
+Please do not refer to publicly available information that was presented to the grand jury as "grand jury evidence." Only the transcripts of the hearing have been released, and nothing else can be released. Much of the evidence, such as photographs and audio recordings, is not public. The original map, if I remember correctly, was part of the medical examiner's office report. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 19:40, 5 December 2014 (UTC)
+
+Thanks Cwobeel and Gaijin42 for the links, which were very helpful.
+
+*Regarding the distance discussed previously — Here’s a source and excerpts that refer to the grand jury proceedings, which I think would justify our highlighting the distance from the blood to the body by showing it in the diagram.
+::http://edition.cnn.com/TRANSCRIPTS/1411/25/ath.01.html :
+
+::"They asked in great detail about the blood spatter evidence, which indicated that Michael Brown walked -- or may have indicated -- that walked back or ran back. There was blood further on down the line. His body ended up being 20 feet closer to Officer Wilson.”
+
+::"But it was the questions on pages 87 and 88 -- and I'm sure you can find these on CNN.com if you want to pore through them yourselves -- the grand juror asks questions of the detective trying to nail down what Mark and Sunny and you guys were just talking about: This physical evidence of blood and the blood pattern and whether or not this blood pattern establishes the distance that Michael Brown traveled when he charged at the officer. And so the grand juror asked this, 'So as far as physical evidence, we have the blood on the ground. That was about 21 or 22 feet from where Michael ground ended up.’ “
+
+:So I think the diagram is OK indicating this distance because it’s a notable distance.
+
+*Regarding the red stains on the car I suggest,
+
+:1. moving the red dots that are for the red stains on the car, to halfway overlap the car boundary, so as not to appear that they are on the ground. (Note this is the style used in this source [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html?hp&action=click&pgtype=Homepage&module=b-lede-package-region&region=top-news&WT.nav=top-news&_r=3].)
+
+:2. adding to the identification, the red stain on the exterior of the driver-side rear door[http://www.washingtonpost.com/wp-srv/special/national/ferguson-diagram-of-the-scene/]
+
+:3. adding the following sources for the red stains on the car [http://www.washingtonpost.com/wp-srv/special/national/ferguson-diagram-of-the-scene/] [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html]
+
+--[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 20:13, 5 December 2014 (UTC)
+:: Updated the infographic as requested. Pls check and let me know if understood you correctly. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:58, 5 December 2014 (UTC)
+:::Looks good. There's a few things I'm thinking about but haven't decided whether to suggest anything, e.g. "red stains" vs "blood stains", interior and exterior of front door, and using the word "feet" in the phrase "distance from feet to farthest red stain" doesn't read well for me. In any case, I consider all your work on the diagram a good job with a good spirit of collaboration. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:40, 6 December 2014 (UTC)
+:::: Please propose alternative wording, as we can always improve. Your feedback is welcome. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 02:10, 6 December 2014 (UTC)
+
+== Grand jury hearing section ==
+
+The grand jury hearing section has, as far as I can tell, only one statement by a law professor in MO. To get an accurate idea of whether the hearing was out-of-the-ordinary, it's got to be compared to other police-involved-shooting cases in the same state.
+
+I made some changes to the table. I know this makes it different than the Times' table, and it incorporates facts about grand juries from [[Grand juries in the United States]]. According to [http://www.stlouiscopa.com/Divisions.aspx?ID=151 this page from the St. Louis County Prosecuting Attorney,] "a little less than half" of the felony cases in the county result in a grand jury hearing and the others go to a judge for a preliminary examination. So this is not a "typical" MO grand jury case.
+
+I also removed a statement about witnesses being repeatedly asked about whether Brown appeared to reached for a gun "despite the fact that it was known he was unarmed." The Times has legitimate concerns about the grand jury hearing which are in the article, but this claim is faulty. In the last seconds of Brown's life, he knew he didn't have a gun, but nobody else did. That emerged later.
+
+Disclaimer: I hope that Wilson went through essentially the same process as any other officer, and I hope he had faced the same likelihood of being prosecuted. I deplore abuse of power, whether it's a court making an example of a person or a police officer using excessive force. But if the people of MO feel there is a need for change, it's a matter for the legislature, not the criminal courts. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 17:12, 5 December 2014 (UTC)
+
+: Look I am trying to AGF here, but you can't just make changes to a table sourced to a an RS and add whatever you want from material from other sources that it is not related to this incident. That is a violation of [[WP:OR]]. As for the "faulty" claim of the NYT, that is none of your business to assess. We need to stay close to the sources, regardless if we believe the source is wrong. See [[WP:V]] 15:17, 6 December 2014 (UTC)
+
+: I also warn you again, that [[WP:NOTFORUM|this page is not a forum]], so please keep your opinions out of it. It does not help. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:27, 6 December 2014 (UTC)
+
+::No troubles whatsoever AGF'ing, his good faith seems pretty obvious to me. Also he is correctly pointing out source misrepresentation. The NYT article does not say "it was known he was unarmed" and neither should. '''Of course, I am shocked, shocked, shocked that it was Cwobeel who edit warred to defend the source misrepresentation which was intended to wrongly defame a living person, because that's not like his MO or anything.''' [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:33, 6 December 2014 (UTC)
+::: Can you stop characterizations? It is becoming insufferable. If you wanted to restore that portion you could have done it. But instead you reverted everything back to OR. Stop the nonsense!!!! - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:56, 6 December 2014 (UTC)
+::::Try making objectionable edits all by themselves so that your other work won't be touched when the objectionable edits are reverted. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:44, 7 December 2014 (UTC)
+
+:This is what the source says {{talkquote|Over the months, the jurors seemed to focus intently on the final movement that Mr. Brown may have made toward Officer Wilson, after a brief chase. The prosecutor asked witness after witness if it seemed as if Mr. Brown were reaching for a weapon, though few said they saw anything like that. Mr. Brown was found to be unarmed.}} I am restorring the material with some tweaks. Next time, please read the source. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:05, 6 December 2014 (UTC)
+::''''Yes, that is precisely the source text which failed to substantiate your WP prose claim that "prosecutors ask[ed] witness after witness if Brown was appearing to be reaching for a weapon when confronting Wilson, while it was known that Brown was unarmed". You ought to be thanking me for removing that fact-falsifying, source-misrepresenting prose, and yup you do this all the time, it's super annoying. Now you have gotten all mad & chided me angrily for reading correctly & reverting you correctly.
+
+::In response, you've changed it to "prosecutors ask[ed] witness after witness if Brown was appearing to be reaching for a weapon when confronting Wilson, while none of the witnesses said anything about Brown being armed." '''Yet another editorial spin that is not found in the cited source.''' Reverted. You misrepresent sourced facts, you misrepresent sourced opinions, you do it over and over and you do it to further your own hyper-partisan anger and desire to defame people whom you despise. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:20, 7 December 2014 (UTC)
+::: I think ,y last edit is accurate, so instead of endlessly complaining, do the [[WP:EDITING|the hard work]] and make it better. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:32, 7 December 2014 (UTC)
+::::Please explain, as clearly as possible, how you think your last edit was accurate. Or any of them, for that matter. "despite the fact that it was known he was unarmed" wasn't right, "while it was known he was unarmed" wasn't right, and "while none of the witnesses said anything about Brown being armed" is not right. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:36, 7 December 2014 (UTC)
+
+{{od}} ''despite the fact that it was known he was unarmed" - refers to the prosecutors, not the witnesses. That is the point the source is making, at least that was what I understood. ''while none of the witnesses said anything about Brown being armed'', was my attempts to unpack the statement "The prosecutor asked witness after witness if it seemed as if Mr. Brown were reaching for a weapon, '''though few said they saw anything like that'''". I accept that it was not perfect, but still valid. Now, please propose how to include in your own word that last sentence, because you have deleted it and it is a crucial point in that reporting. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 16:33, 7 December 2014 (UTC)
+
+:Since the source didn't use those words — and since prosecutors, like Wilson, did not know at the time of the incident that Brown was unarmed — this sounds like obvious BS. Also, "few witnesses said they saw him reaching for a weapon" is not even remotely equivalent to "none of the witnesses said he was armed". So once again it looks like you're adding your own spin, and there is no "validity" to it. Could you please propose content here before adding it to the article so that others can remove the errors and policy violations first? [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:44, 7 December 2014 (UTC)
+:: . My read is this: The critique is that prosecutors were acting as defense attorneys trying to validate Wilson's testimony regarding his perception that Brown was reaching for a weapon, when actually no witness other than Wilson made that case, and the prosecutors were asking again and again about that, which was very unusual. That is my reading of the source. Please re-read the source in its entirety and propose how to best reflect it. BTW, I intend to add more from that source, currently working on it. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:14, 7 December 2014 (UTC)
+:::Thank you for spelling out your uninformed opinion which does not belong anywhere on Wikipedia. I decline the invitation to grind your axe for you. I have already read and re-read the source. You are now on triple-explicit notice that the source does not say ''any'' of the things you previously wrote into the article, and thus I humbly request you bring any further material from this source HERE, to the talk page, so it may be vetted by editors who aren't quite so prone to ''accidentally'' misrepresenting a source to defame a living person. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 18:47, 7 December 2014 (UTC)
+:::: Thank you for you suggestion, but I have no intentions to refrain from editing. I am working an additional material that I would add in due course. Thankfully, the collaborative process of Wikipedia will, as always, catch any mistake you or I make in our editing. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:44, 7 December 2014 (UTC)
+:::::"Mistakes", mmm, yes, it's quite amazing how your "mistakes" always result in WP prose that misrepresents a source to trash a living person, and it's further amazing how it's invariably, always and without exception, the targets of progressive wrath that get this treatment. What I find remarkable is that you do this deliberately, and repeatedly, and without the slightest hint of remorse '''and without the slightest hint of apology''' for those whom you dumbly snark at, threaten and insult, in the process of trying to defend an indefensible anti-policy edit. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 14:41, 8 December 2014 (UTC)
+::::::^When I posted the above, I hadn't see that you went ahead and added more source misrepresentation. Please be advised that all opinion commentary is supposed to be well-sourced to notable commentators, not Wikipedia editors. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 14:55, 8 December 2014 (UTC)
+
+{{od}} I guess we're fortunate in this case that the WP prose in question doesn't trash anyone. At any rate, I think it's worth mentioning that [[WP:LIMITED|paraphrasing]] "Mr Brown was found to be unarmed" is hardly an unsourced opinion, considering it's a [http://www.nytimes.com/2014/11/26/us/ferguson-grand-jury-weighed-mass-of-evidence-much-of-it-conflicting.html?_r=0 New York Times report]. If you were to provide a better paraphrase than any in the list that you've accumulated on Cwobeel's attempts, it would resolve this issue fairly easily. Explaining why the information shouldn't be included would also be informative. As an aside, the NYT article was corrected today as it misattributed questions asked of Wilson to the prosecutors. The questions were actually posed by one of the grand jurors. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 02:32, 9 December 2014 (UTC)
+:It has gradually evolved from something that misrepresented the source to defame McCullogh, into something that merely reports what the source says without WP-editor embellishment intended to defame McCullogh. And as an aside, Cwobeel's level of activity and "accidental source misrepresentation" is far too intense for me to go around actually ghostwriting his prose for him. Fortunately, BLP explicitly provides that I needn't do that. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 16:12, 9 December 2014 (UTC)
+::Except, again, nothing you edited out seems to show any hint of defaming McCulloch. The only thing that comes remotely close is this [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637172329&oldid=637172234 edit], which was neither libelous nor non-notable as it is a [[WP:WELLKNOWN|well-documented controversy about McCulloch]] by [http://www.nytimes.com/interactive/2014/08/13/us/ferguson-missouri-town-under-siege-after-police-shooting.html?_r=1 at] [http://www.latimes.com/changebrowser#url=/#section/-1/article/p2p-82099652/ least] [http://www.huffingtonpost.com/mark-weisbrot/in-ferguson-a-prosecutor_b_6269872.html two] sources (the last link was to the source cited in the edit). The Huffington Post source brings a different perspective to the controversy, which merits it being referenced in the article in a neutral tone. Btw, perhaps it would be in everyone's best interests if you were to be [[WP:BOLD|bold]] and give insight into how to rewrite the prose in an acceptable way, or to provide justifications on why the information shouldn't be included. As far as I can tell, BLP doesn't provide defenses for not contributing rationale. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 19:26, 9 December 2014 (UTC)
+: Thanks for pointing out the correcting by the NYT. I have deleted the miss-attributed sentence. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:22, 9 December 2014 (UTC)
+
+== additional sources discussing eyewitness testimony discrepancies from evidence (from a scientific point of view) ==
+
+* http://www.forbes.com/sites/fayeflam/2014/12/01/what-science-says-about-the-ferguson-case-memory-can-be-hacked/
+* http://web.randi.org/swift/eyewitnesses-and-emotion-a-reminder-to-engage-critical-thinking
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 21:03, 5 December 2014 (UTC)
+
+I'm a scientist. I like the idea of critical thinking. I like the idea of testing a hypothesis with evidence before making a conclusion, rather than making the evidence fit the conclusion. The Swift article reminds me that the public doesn't have all the evidence (nor should they), that details were presented to the grand jury that we are not privy to. I'm also reminded of "extraordinary claims require extraordinary evidence."
+
+Gaijin42, can you help me avoid attempting to write things I don't need to write, by just saying why you posted this? Do you think Wilson was justified in killing Brown? (I do.) [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 23:29, 5 December 2014 (UTC)
+: May I remind you of [[WP:NOTFORUM]]? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:00, 6 December 2014 (UTC)
+
+{{ec}} The answer to your larger question I will reply to on your talk to avoid [[WP:FORUM]] (as Cwobeel is quite correct to point out). I posted these particular links because they can help to flesh out the "Accounts" section similarly to the existing Rashomon effect paragraph. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 00:02, 6 December 2014 (UTC)
+
+{{ec}} {{yo|Roches}} As fascinating as these articles may be, they have no place in this article. Of course, if this is an area of interest you are welcome to edit [[Eyewitness testimony]], [[Credible witness]], and [[Eyewitness identification]]- [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:03, 6 December 2014 (UTC)
+
+::Cwobeel, the articles were posted by me (gaijin), not Roches. Why do you think they have no place in this article? They are directly discussing the general testimony issues in the context of this case and the specific witness statements we have in this case. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 00:13, 6 December 2014 (UTC)
+
+: Oh, sorry. The only thing I see useful in the Forbes article is this passage
+:{{talkquote|Our instincts tell us that honest people remember events correctly and others are lying. Loftus, on reading the AP report, suggested that what witnesses remember is heavily influenced by the way they interpret what they are seeing. Different people heard shots and saw some kind of commotion. Was the victim charging, wobbling, or surrendering? People may have unconsciously filled in gaps in their perception with information based on their past experiences.}}
+: ... which could be added as the fully attributed opinion of Elizabeth Loftus, and the writer of the piece. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:32, 6 December 2014 (UTC)
+::I think that would be a fine quote to include since we already mention the AP report in question, that serves as a nice commentary about it. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 00:54, 6 December 2014 (UTC)
+:::Could probably also find sources talking about how the typical unreliability of witness testimony leads prosecutors to rely more heavily on physical evidence, which is what they did in this case. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:12, 6 December 2014 (UTC)
+:::: OK, go ahead, Gaijin. FCAYS: Just find a source that describes that opinion in the context of this incident and it can be included as well. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:15, 6 December 2014 (UTC)
+:::::Lazy Saturday, usually when I post about the possible existence of a source it's because I am hoping someone ''else'' will go find it. ;) [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:24, 6 December 2014 (UTC)
+
+== Release of video in lead & dispatch ==
+
+It seems to me that the fourth paragraph in the lead may be a little incomplete. At some point a dispatch went out mentioning the theft and Wilson claims this dispatch was something he considered before and during the altercation. Yet the only thing mentioned in the fourth paragraph is that some were pissed off about the release of the video and that it may shed light on Brown's state of mind at the time. I think this is an imbalance and should be briefly addressed, though I'm not entirely sure how. Thoughts? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 01:17, 6 December 2014 (UTC)
+
+:I [[Special:Diff/636975119|added]] a little to that paragraph. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 03:45, 7 December 2014 (UTC)
+
+== publisher= ==
+
+When standardizing refs in this article, I have dropped any {{para|publisher}} and replaced it with {{para|website}}. While many editors use {{para|publisher}}, they generally use it incorrectly per the documentation, which states: ''The [[publisher]] is the company that publishes the work being cited. Do not use the publisher parameter for the name of a work (e.g., a book, encyclopedia, newspaper, magazine, journal, website).''
+
+While you can code both {{para|website}} and {{para|publisher}}, I haven't felt that the latter is of enough use to the readers of this type of article to be worth the trouble and space. In many cases it would be a non-trivial task to determine the name of the publisher.
+
+I just noticed that the copy-and-paste "template" we have in the comments at the top of the References section includes {{para|publisher}}, and I'm writing this as the explanation for my removal of that. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:00, 6 December 2014 (UTC)
+
+:So if a ref is from www.cnn.com/blah/blah/blah/ you would prefer <tt>website=cnn.com</tt> rather than <tt>publisher=CNN</tt> ? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:13, 6 December 2014 (UTC)
+
+::No, the convention here is to use the website's branding, as {{para|website|CNN}} or {{para|website|The New York Times}}. In some cases the website seems to be branded in multiple alternative ways, so we are forced to choose one, but we are consistent with that choice. For local TV and radio stations we ignore branding such as "Fox2Now" and use the call letters, as {{para|website|KTVI}}. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:18, 6 December 2014 (UTC)
+
+:::So if a ref is from www.cnn.com/blah/blah/blah/ you would prefer <tt>website=CNN</tt> rather than <tt>publisher=CNN</tt>. Correct? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:26, 6 December 2014 (UTC)
+
+::::Yes. Or you can code it however you want and I'll convert it as part of standardization, which would probably be needed anyway. I rebuild every ref from scratch, unless it's already perfect per the local convention (hasn't happened yet). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:31, 6 December 2014 (UTC)
+
+:::::I'm reminded of a line from Godfather III.... ''"Our ships must all sail in the same direction"''. Forming the refs as you suggest is no problem at all as far as I'm concerned. And I'll assume you are correct in your rationale for doing it that way. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:40, 6 December 2014 (UTC)
+
+::::::Ok. I copy-and-paste an abbreviated "template" from a Notepad document, to save myself the trouble of removing multiple rarely-needed parameters. Then I can insert {{para|location}} for local TV and radio, add parameters for additional authors, and/or remove the archive parameters if the source won't archive. This abbreviated "template" is: <code><nowiki><ref name= >{{cite web |first= |last= |title= |date= |accessdate= |website= |url= |archiveurl= |archivedate= |deadurl=no}}</ref></nowiki></code>. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:47, 6 December 2014 (UTC)
+
+{{reflist-talk}}
+== "Crime scene" ==
+
+We refer to "crime scene" five times. I just wanted to confirm that this is deliberate and that the rationale is that some crime was committed there, the crime and perpetrator undetermined. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 06:02, 6 December 2014 (UTC)
+:While I think I understand your concern, I think this may be a situation in which the correct term just has unfortunate implications. In any trial in which the defendant is ultimately acquired (or not charged as in this case) those bits of evidence are still from the "crime scene" in general parlance. Charitably one could also interpret these scene as a crime as either Wilson or Browns take your pick depending on POV. But I would also not object to "incident scene" or "shooting scene" or something. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 15:24, 6 December 2014 (UTC)
+::"Incident scene" sounds like a form that HR has to fill out after a fight in the break room. "Shooting scene" is not as awkward, but I think we should just track the terminology used by sources and trust that our readers will be discerning. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:42, 6 December 2014 (UTC)
+:::If it's a crime scene, then what was the crime and who committed it? That's a pretty sticky question. Shooting scene seems most accurate to me, is well represented in sources and has zero stickiness. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:08, 6 December 2014 (UTC)
+::::Actually, since crime scene investigators (CSIs) work all homicides, justifiable or not, I'd support the use of the term "crime scene." Apart from that, the testimony of Officer Darren Wilson was that Michael Brown was guilty of initiating an assault on Darren Wilson at that location. At the time that data are recorded from the scene of any homicide, the possibility of a crime having been committed is assumed by first responders and crime scene investigators. Both Darren Wilson and Michael Brown were regarded by press accounts as criminal suspects when that crime was investigated. [[User:Vfrickey|loupgarous]] ([[User talk:Vfrickey|talk]]) 16:16, 6 December 2014 (UTC)
+:::::Would it be correct to say that a "crime scene" can also refer to an area of investigation where a crime ''may'' have been committed? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:22, 6 December 2014 (UTC)
+
+::::::That appears to be common usage, whether or not it's literally correct. Common usage is good enough for me. In any case, I think it's clear enough that at least one crime was committed there, assault on a police officer (aside from conspiracy theory, is there any other plausible explanation for the facial discoloration that persisted for hours?). There may or may not be mitigating circumstances, but it's still a crime AFAIK. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 16:47, 6 December 2014 (UTC)
+
+:::::::That seems a little loose. We've exposed criticism of the term "crime scene". Is there any direct criticism of the term "shooting scene"? Not asking if you prefer something else, but looking for direct criticism of the term itself such as being inaccurate or problematic in any way. <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Jbarta|Jbarta]] ([[User talk:Jbarta|talk]] • [[Special:Contributions/Jbarta|contribs]]) 17:11, 6 December 2014 (UTC)</span></small><!-- Template:Unsigned -->
+
+::::::::I wasn't advocating "crime scene" over "shooting scene", but merely saying I'm not opposed to "crime scene". I don't see "shooting scene" as being inaccurate or problematic in any way. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 17:18, 6 December 2014 (UTC)
+
+It's not called a "shooting scene," it's called a "crime scene." Call it what it's called, not what you think it should be called. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 17:57, 6 December 2014 (UTC)
+:How do you know it's called a "crime scene"? To you it seems crystal clear. To me it's not. What is it that you know that I don't? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 18:14, 6 December 2014 (UTC)
+::[[Crime scene]] says it's called a crime scene. Vfrickey gave a clear explanation of why it's called a crime scene. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 19:17, 6 December 2014 (UTC)
+:::[[Crime scene]] says ''"Crime scenes may or may not be where the crime was committed"'' which I admit I missed. However, despite explanations, I still find the rationale for calling it a crime scene a little shaky, and as discussed earlier, "shooting scene" isn't shaky at all. My preference (slight as it is) is still for "shooting scene", but it's arguably a minor matter and if a consensus of editors prefer "crime scene", then so be it. At least it was examined and discussed. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 02:17, 7 December 2014 (UTC)
+::::I think it is common knowledge what a ''crime scene'' is. We all understand that it is a place where police are investigating a possible crime. It does not mean that just because we have labelled it such that we have bypassed judge and jury and want to throw the suspect in prison because, oh yea, we called it a ''crime'' scene. I've never heard the terms "shooting scene", "robbery scene", "assault scene", "arson scene", "shoplifting scene", etc. in my entire life. —[[User:Megiddo1013|Megiddo1013]] 05:54, 7 December 2014 (UTC)
+:::::At the risk of beating an unconscious horse and just for the sake of argument, I'm really not moved by what you think everybody knows or what you think everybody understands or what you've never heard in your entire life. I was looking for some definitive evidence as to whether a scene that may or may not have been the scene of an actual crime (depending on who you ask) is still called a crime scene. The rest of my comments are above (I hate repeating myself). One more thought that I don't think was brought up... is the Ferguson Police (or State Police or FBI or whoever is investigating there) calling it a "crime scene"? If not, how do ''they'' refer to the site? Just a thought. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:22, 7 December 2014 (UTC)
+::::::I see [https://web.archive.org/web/20141207162706/http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/gj-testimony/grand-jury-volume-02.pdf here] the grand jury is hearing testimony from a "crime scene investigator" and they do mention the words "crime scene" several times. Other than simply "the scene", they don't really call it anything else. So I suppose if you walked up to the investigator while he was measuring and examining and asked him "Whatcha doin?", he would most likely reply with "Investigatin this here crime scene. Now get back behind that yellow line or someone's gonna shoot you too!" &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:41, 7 December 2014 (UTC)
+
+Micheal Brown attacked Officer Wilson there, as well as resisted arrest, so there's really no question that it is the scene of at least ''some'' crime committed, regardless of whether or not Wilson committed any crime. Crime scene, scene of the incident, scene of the shooting all seem to be pretty commonly used. I don't think it is unnecessarily POV; we should use whatever the sources use. [[User:Titanium Dragon|Titanium Dragon]] ([[User talk:Titanium Dragon|talk]]) 02:21, 11 December 2014 (UTC)
+
+== Incident reports ==
+
+I changed the incident report section. The complaints are really examples of journalists writing about how they think people should do their jobs; if this incident report isn't different than a normal one ''about the same thing'', then it's not lacking in information.
+
+The reason why the incident reports have very few details is that they are admissible in court. Filling in only basic information is a normal thing to do in a case like this, because the incident report is just the beginning of an investigation. In most cases, such as a collision involving a police vehicle, the incident report is a full description of the event because nothing more ever needs to be said about it. These incident reports are not the official story of the police department, they're the individual account of the person who might have to go to trial. Journalists should have known better than to speculate that details were being omitted improperly.
+
+Something was made of the date of the report (ten days after the shooting); this is the time the report was ''entered.'' The date it was ''submitted'' isn't there. The times of day must also not mean what they appear to mean, since other accounts have police arriving at the scene in much less than 40 minutes.
+
+[[User:Roches|Roches]] ([[User talk:Roches|talk]]) 18:12, 6 December 2014 (UTC)
+
+: No, no, and no. You are not here to decide what journalists should do or not do, or what they should report or not report. If you find a source that describes your opinion, by all means add it. But '''do not delete material just because you think the journalists are doing a poor job.''' Who cares what you (or I) think? We report what sources say. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:19, 6 December 2014 (UTC)
+::According to a spokesman for the St. Louis County police department, it's normal practice not to give out the details and that under the Missouri State “Sunshine” Law, the department was not required to release the information during a pending investigation.[http://time.com/3159680/ferguson-michael-brown-shooting-police-report/] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:31, 7 December 2014 (UTC)
+::: Then report that, alongside the critique from other media sources, even if unfounded. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 01:03, 7 December 2014 (UTC)
+
+Please don't tell me how Wikipedia works, even if it's using WP:article links to things that are not policy. I changed the section to describe the level of detail on the forms, and mentioned that Wilson sought legal advice about completing them. I kept the ACLU statement, because it is important to convey that people objected to the way the forms were completed, but I didn't keep the paraphrased list of things the HuffPo author thought were missing.
+
+Reporting the Huffington Post author's opinion of how police departments should fill out incident reporting forms is not NPOV. That's an opinion of one journalist at one source; the ACLU's public statement is a much better, and entirely sufficient, way to report objections to the way the forms were completed.. See [[WP:ONUS]]. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 04:37, 7 December 2014 (UTC) (Added policy link to post at 4:30.)
+
+:: we report opinions and attribute opinions to those that hold them. That is our work as editors, and not pass judgement. I will remove these edits and expect you to follow [[WP:BRD]], as there is an implicit consensus on material that has been in the article for a while. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:18, 7 December 2014 (UTC)
+:::If the opinion isn't found anywhere other than HuffPo, it's probably not notable. Notice also this was published in August and never followed up on. Not exactly quality sourcing. [[User:Factchecker_atyourservice|Centrify <small>(f / k / a FCAYS)</small>]] [[User_talk:Factchecker_atyourservice|(talk)]] [[Special:Contributions/Factchecker_atyourservice|(contribs)]] 15:51, 7 December 2014 (UTC)
+
+I started looking over the current version of the section [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637070981#Incident_reporting_forms Incident reporting forms] and there was a problem with verifying the first two sentences.
+:"[[MSNBC]]'s [[Lawrence O'Donnell]] reported on {{nowrap|August 21}} that Wilson did not complete an incident report about the shooting, after being advised by a union lawyer not to do so.<sup>[68]</sup> According to O'Donnell, Wilson did file a report, but not until ten days after the shooting, and the report contained no information other than his name and the date.<sup>[68]</sup>
+
+:<small>68. {{cite episode |first=Lawrence |last=O'Donnell |title=Ferguson PD didn't file report after shooting |date=August 21, 2014 |accessdate=August 26, 2014 |series=The Last Word |network=MSNBC |url=http://www.msnbc.com/the-last-word}}</small>
+
+The link for the source doesn't go to the page where the info is, so I wasn’t able to verify the material using the citation. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 23:01, 7 December 2014 (UTC)
+:: Searching for the title of the source in the ref, yields this: http://www.msnbc.com/the-last-word-with-lawrence-odonnell/watch/ferguson-pd-didnt-file-report-after-shooting-320755267999 - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:07, 7 December 2014 (UTC)
+:::{{fixed}} &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:18, 7 December 2014 (UTC)
+:::On the other hand, that link is to a 1:16 clip, apparently the intro to the episode. I can't figure out how to get the whole thing. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:31, 7 December 2014 (UTC)
+
+So who is correct, the prosecutor's office, O'Donnel, the ACLU? Was or was not an incident report filed? Because they did release the reports when pressed to do so. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:51, 7 December 2014 (UTC)
+:Cwobeel, The current issue is verifying those two sentences. The link you just gave is insufficient. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:01, 8 December 2014 (UTC)
+:: Well, it was the when I sourced it, but it seems that it is gone. I will see if I can find it in the wayback machine. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:05, 8 December 2014 (UTC)
+
+The full episode may be on this page, but I am not 100% sure: [http://www.msnbc.com/msnbc/aclu-michael-brown-incident-report-lacks-key-details], OTOH, this is a good source that could be used: [http://www.thewire.com/national/2014/08/ferguson-police-waited-10-days-to-review-michael-brown-incidents-report/378972/] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 00:12, 8 December 2014 (UTC)
+
+Here's a relevant excerpt from a Nov 24 Newsweek source.[http://www.newsweek.com/no-charges-ferguson-michael-brown-shooting-case-285976 ]
+:"The official incident report filed by St. Louis county police 10 days after the shooting contains few hard details about the encounter, other than the fact that Brown was unarmed."
+--[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:24, 8 December 2014 (UTC)
+
+I made some edits involving the second and third sentences of the first paragraph, which currently is:[https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637098637#Incident_reporting_forms]
+
+:"[[MSNBC]]'s [[Lawrence O'Donnell]] reported on {{nowrap|August 21}} that Wilson did not complete an incident report about the shooting, after being advised by a union lawyer not to do so.<ref name=MSNBC.File/> According to the {{nowrap|St. Louis}} County Prosecutor's Office, the Ferguson police didn’t file an incident report on the shooting because the case was turned over to the county police almost immediately.<ref name=NBC.Why/><ref name=MSNBC.Details/><ref name=ACLU.FPDReport/> The St. Louis county police filed an incident report 10 days after the shooting with little information about what happened.<ref name=Newsweek.After/>"
+
+{{reflist-talk}}
+
+The first sentence is not supported by its source. The only thing it adds is the part about the lawyer. The rest is covered in the second sentence. I think we should delete it for now and consider restoring the lawyer info when there is a suitable source for it. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 01:23, 8 December 2014 (UTC) Deleted. [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637128797&oldid=637122667] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 14:44, 8 December 2014 (UTC)
+
+: Unfortunately the source is no longer online. In any case I think what we have there is covers this quote well. I have re-ordered the sentences for a narrative that makes sense. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 14:50, 8 December 2014 (UTC)
+::I don't think that was an improvement. I noticed that another editor reverted the re-ordering. [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637174390&oldid=637172965] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 16:40, 8 December 2014 (UTC)
+
+::: The version reverted to does not make sense. It starts by describing the reasons why a report was not filed, only to say in the following paragraphs that reports were indeed filed. when you removed the O'Donnell reference, the section came out of whack. I am still trying to find the original source from O'Donnell. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:07, 8 December 2014 (UTC)
+::::I think the lead paragraph is OK and shouldn't be touched for now. I've been working on the rest of the section to get it into better shape. After I complete that, I'll revisit the lead paragraph. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:25, 8 December 2014 (UTC)
+
+OK Found it. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:16, 8 December 2014 (UTC)
+
+{{talkquote|We have breaking news tonight in the killing of Michael Brown. St. Louis County prosecutors told NBC News today that the Ferguson Police Department has no incident report of the shooting of Michael Brown. Darren Wilson, the officer who shot and killed Michael Brown, did not write an incident report contrary to standard police procedure. […] Yesterday, in response to a lawsuit from the ACLU, the St. Louis County police released an incident report that says, in effect, nothing other than the time and proximate location of a homicide and the victim`s name, Michael Brown. That incident report indicates that it was not filed until possibly 10 days after the killing of Michael Brown. […] In the decades I`ve been studying these cases, most of them involve incident reports written by the officers involved with the shooting. In recent years, it has become customary for the police lawyer to run in, police union lawyer usually, and prevent the shooter from giving any kind of comment or writing any sort of incident report whatsoever. <ref>{{cite web |url=http://www.nbcnews.com/id/55915749/ns/msnbc/t/last-word-lawrence-odonnell-thursday-august-st/#.VIXbR6YqjoA|title= The Last word with Lawrence O'Donnell August 21, 2014|publisher=NBC News|accessdate=8 December 2014}}</ref> }}
+{{reflist-talk}}
+
+:The excerpt you gave doesn't say that Wilson was advised by a union lawyer not to complete an incident report. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 17:31, 8 December 2014 (UTC)
+:: See my edit, which attributes that opinion to O'Donnell. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:45, 8 December 2014 (UTC)
+:::I moved it from the article to here for discussion.
+
+::::"[[MSNBC]]'s [[Lawrence O'Donnell]] reported on {{nowrap|August 21}} that St. Louis County prosecutors told NBC News that they do not have an incident report from the shooting, contrary to standard police procedure, and described a pattern in which police union lawyers prevent shooters from commenting to filing incident reports.<ref>{{cite web |url=http://www.nbcnews.com/id/55915749/ns/msnbc/t/last-word-lawrence-odonnell-thursday-august-st/#.VIXbR6YqjoA|title= The Last Word with Laurence O'Donnell - August 21, 2014|publisher=NBC News|accessdate=8 December 2014}}</ref>"
+{{reflist-talk}}
+
+:::This Aug 21 item became obsolete when the police interview of Wilson, the day after the shooting, was released to the public. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:15, 8 December 2014 (UTC)
+::::: Really? Can you provide a source that describes the police interview that was released? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 18:25, 8 December 2014 (UTC)
+::::::Here's a link from a [http://edition.cnn.com/interactive/2014/11/us/ferguson-grand-jury-docs/index.html CNN webpage] to the interview. [https://www.documentcloud.org/documents/1370928-interview-po-darren-wilson.html] --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:55, 8 December 2014 (UTC)
+::::: {{yo|Bob K31416}}I see what you mean. But you are confusing two things. What O'Donnell is referring to is an incident report. What you are refrring to is an interview with Wilson. These are two different things. Please restore that edit, as this section is all about incident reports and not interviews. - - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 18:31, 8 December 2014 (UTC)
+:::::<small>{{yo|Cwobeel}} - You have to add the ping (yo) and your sig in the same edit, or there is no notification. I learned that the hard way. {{yo|Bob K31416}} &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 18:50, 8 December 2014 (UTC) </small>
+::::::O'Donnell said, "any kind of comment or writing any sort of incident report whatsoever.” --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 18:55, 8 December 2014 (UTC)
+::::::: So what? The fact is that Wilson did not file an incident report. That is undisputed. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:39, 8 December 2014 (UTC)
+
+=== Break1 Incident reports ===
+{{yo|Bob K31416}} I added additional commentary from legal and law enforcement analysts. I also re-ordered the sentences to follow the chronology. I think I got it right, but please change it if it is not correct. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:58, 8 December 2014 (UTC)
+
+:(Here’s a link to the version after Cwobeel's recent edits [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637213737#Incident_reporting_forms] and a link to the version before [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637210952#Incident_reporting_forms] .)
+
+:[[User:Cwobeel|Cwobeel]], Here’s some comments on your recent edits of the section.
+
+::1) The first sentence of your version misstated the source. O'Donnell was referring to only the Ferguson incident report. The info was already in the first sentence that you moved.
+
+::2) The second sentence of your version about Lisa Bloom’s opinion misstates the source. Lisa Bloom didn’t say that Wilson refused to file a report.
+
+::3) Re the 3rd sentence of your version about Jim Cavanaugh’s comment — The info was already covered in the first and second sentences of the original version.
+
+::4) The 4th sentence of your version about the Ferguson police not filing an incident report was the original 1st sentence.
+
+::5) The 5th and last sentence of the lead paragraph of your version was about a use-of-force report and was formerly the last sentence of the section. I hadn’t worked on the placement or content of this sentence yet.
+
+::6) The 2nd and 3rd paragraphs of your version were obtained by switching the 2nd and 3rd paragraphs of the original version. I hadn’t worked on the content or placement of the material in these paragraphs yet.
+
+::7) The 4th and last paragraph of your version was the second sentence of the lead paragraph of the original version.
+
+:Before I try to edit the section again, could you list here in our discussion, in chronological order, the events that you are trying to portray in chronological order? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 01:33, 9 December 2014 (UTC)
+
+:: I cheeked again this evening and this is the correct chronology, my last edit was not correct:
+::* August 19 - (10 days after shooting) incident report filed by St. Louis county police
+::* August 21 - O'Donnel's reporting, commentary from Lisa Bloom and Jim Cavanaugh
+::* August 22 - St. Louis County Prosecutor's Office says that Ferguson police did not file a report because the case was assigned to county police
+::* August 26 - ACLU releases the report they received after their FOIA request
+::* August 26 - HuffPo reports on commentary by ACLU's Gupta
+::* Sept 25 - Yahoo News reports that key report does not exist
+:: Regarding Bloom and Cavanaugh:
+::* Lisa Bloom: ''And if he refuses to follow standard operating procedure in preparing a report about the taking of the human life, he should be fired."
+::* Jim Cavanaugh: That is an expert opinion that should be presented.
+:: I <s>will attempt again to correct</s> corrected the chronology. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:37, 9 December 2014 (UTC)
+
+:: {{yo|:Bob K31416}} feel free to copyedit my rendition of Bloom and Cavanugh's comments, if you can make it better and closer to the source. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 03:42, 9 December 2014 (UTC)
+:::[[User:Cwobeel|Cwobeel]], On giving the section another look, I noticed that it is about not releasing information that has now been released. It’s obsolete and a digression from the topic of the article, the shooting of Michael Brown. We could summarize the incident report issue in a couple of sentences and merge it with the Police section. Thoughts? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 00:48, 10 December 2014 (UTC)
+
+== Wholesale deletion of relevant material ==
+
+{{yo|Roches}} Why are you deleting perfectly good material without any discussion[https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=636909177&oldid=636903538]. I welcome your contributions, but you need to show some respect to the hard work from others. Deleting material that has been in the article for quite a while, and which represents an existing consensus is not acceptable - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:15, 6 December 2014 (UTC)
+
+And when you are it, explain this edit [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=636903538&oldid=636894100] in which you removed several key pieces of reporting. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:21, 6 December 2014 (UTC)
+
+I mean, how blatant can you be? You removed a key piece: {{talkquote|. Brown stumbled, stopped, put his hands up and said "OK, OK, OK, OK, OK." The worker believed Brown had been wounded. With his hands up, Brown began walking toward the officer, at which point Wilson began firing at Brown and backing away.}} - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:23, 6 December 2014 (UTC)
+
+:It's difficult to contribute anything at all if every aspect of every edit has to be justified. The fact that somebody said that something happened is not necessarily worth reporting here, and it does not remain worth reporting here. Editing material that was written some time ago is not destructive, it's just changing the article to represent the importance of that particular account ''as of right now.''
+
+:The construction worker's account describes Brown being hit from behind after being shot by one of three police officers. I thought it was acceptable to keep the broader details of the account. I did not remove all of the details in the "key piece" above. I only removed what the otherwise-unreliable account said Brown was saying. There's a reason for that. If someone reported that Brown said "I'm gonna kill you," then that conveys to readers the idea that Brown may have said that. Similarly, including a quotation from a possibly unreliable account, a quotation that other accounts don't include, can alter the opinions of readers in a different way than a retelling of what the worker said the people did. The edited account still conveys the worker's contention that Brown was trying to surrender, it just doesn't quote Brown in the retelling.
+
+:If that content represented an existing consensus between, say, ten editors, it no longer represents a consensus. I'm strongly opposed to it, I think it should be removed, so there isn't a consensus anymore. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 04:09, 7 December 2014 (UTC)
+
+::No comment on the rest, but I'll go out on a limb and challenge your last sentence based on the second sentence of [[WP:CONSENSUS]]: ''Consensus on Wikipedia does not mean unanimity (which, although an ideal result, is not always achievable)...''. In other words, consensus doesn't vanish the moment someone comes along and disagrees with it. It was rarely unanimous to begin with, as indicated in the quoted passage. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 04:39, 7 December 2014 (UTC)
+:::The part about hands up was removed. It was significant because it was supported by the following, which was also removed, "In a cellphone video obtained by CNN on {{nowrap|September 11}}, which captured the reaction of the construction worker and a colleague, one of them can be heard saying, "He had his fuckin' hands up." Does anyone know where the corresponding grand jury testimony is, volume, page number? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 05:04, 7 December 2014 (UTC)
+:::: I have restored the material that was deleted. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:28, 7 December 2014 (UTC)
+
+{{yo|Roches}}: ''It's difficult to contribute anything at all if every aspect of every edit has to be justified.'' Welcome to editing contentious articles in Wikipedia. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:30, 7 December 2014 (UTC)
+
+And a good reminder [[WP:NOTTRUTH]] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:32, 7 December 2014 (UTC)
+:Cwobeel, From the essay [[WP:NOTTRUTH]] that you referred to is the following, "The phrase 'the threshold for inclusion is verifiability, not truth' meant that verifiability is a necessary condition (a minimum requirement) for the inclusion of material, though it is not a sufficient condition (it may not be enough)." --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 05:45, 7 December 2014 (UTC)
+:: I agree with you in that context. I was referring to this section: [[WP:!TRUTHFINDERS]] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:50, 7 December 2014 (UTC)
+:::::[[User:Cwobeel|Cwobeel]], I don't think that part of the essay means that verifiability guarantees the inclusion of questionable material. Also, please note the statement at the top of that essay's page, "Essays are ''not'' [[Wikipedia:Policies and guidelines|Wikipedia policies or guidelines]]." Wikipedia policy says that [https://en.wikipedia.org/w/index.php?title=Wikipedia:Verifiability&oldid=634377638#Verifiability_does_not_guarantee_inclusion verifiability does not guarantee inclusion]. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 06:50, 7 December 2014 (UTC)
+:::::: I am fully aware that an essay is not policy. But the point made in that essay is a good one. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:24, 7 December 2014 (UTC)
+:::::::And what point is that? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 16:42, 7 December 2014 (UTC)
+
+::::From the St. Louis Post-Dispatch, talking about the construction worker's testimony to the grand jury - [http://www.stltoday.com/news/local/crime-and-courts/in-grand-jury-testimony-passion-but-little-agreement-from-witnesses/article_f2fc0e21-dc59-59bf-82bc-c0f35fd40572.html A landscape worker who lives in Jefferson County gave grand jurors one of the oddest accounts of the moments leading up to Brown's death. The man said he encountered Brown that morning. He was trying to cut through some tree roots and cursing at the difficulties of the job. Brown told him that Jesus would help him with his anger problem. A few minutes later, the man said, he heard gunshots. He looked up and saw Brown running. '''He said three officers were chasing Brown''', but only one of them was shooting. Brown appeared to have been shot as he fled, the worker said. Then Brown turned around, put his hands up and started yelling “OK.” "And within a couple of seconds the '''three officers came up''', and one just pulled up and shot him," the worker said.]--[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 05:36, 7 December 2014 (UTC)
+::::: Sure, but this article is not just about the testimony to the grand jury. This and other witnesses provided their accounts before that, such as in here [http://www.stltoday.com/news/local/crime-and-courts/workers-who-were-witnesses-provide-new-perspective-on-michael-brown/article_14a3e5f8-6c6a-5deb-92fe-87fcee622c29.html], the source used in that section. You are welcome to add his testimony to the grand jury for completeness. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:44, 7 December 2014 (UTC)
+
+::Restoring the original version reminded me of why I edited it. I'm not going to dissect the content line by line, feign outrage, or welcome you to Wikipedia. I especially do not like the last of these things, and I don't like when you tell me or other editors that we are free to add content to some section of the article, but not to another.
+
+::What I tried to do wasn't perfect, but if that content represents the hard work of many individuals working towards a consensus, the result was surprisingly awkward and difficult to read. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 06:22, 7 December 2014 (UTC)
+::: Fair enough. If you can improve content by copy editing, that would be most welcome. But there is a difference in making something more readable, and deleting content wholesale as you did. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 06:30, 7 December 2014 (UTC)
+
+== Fair use photos of Michael Brown and Darren Wilson ==
+
+I'm wondering about grabbing some photos of Brown and Wilson and uploading them as fair use. I have in mind these... [http://media4.s-nbcnews.com/i/newscms/2014_33/614086/140812-michael-brown-1338_8c5ad41dd423c28ed02e37e39222844e.jpg Brown],[http://i97.photobucket.com/albums/l217/Shockwave_73/Album%202/Darren-Wilson_zps70a1888c.jpg Wilson], and using them in a manner similar to the ones in [[Shooting of Trayvon Martin]]. Brown is dead so "historic portrait" applies, unless someone wants to argue that anyone who owns a photo of Brown ''could'' conceivably upload it here under some sort of free license. Wilson is still around, but I think the chances someone will upload a free picture of him anytime soon is pretty slim. And even if 30 years from now someone finally does, it won't do us much good in the meantime plus he won't look anything like he did during the event... which sort of kills the encyclopedic value. I think that since this a historic event (historic meaning this particular event happened at only one time in history), contemporary photos of the main participants are fair use. Thoughts on the validity of "fair-use" here? Thoughts on using the images in general? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:44, 8 December 2014 (UTC)
+:For Brown, we get one (and and only one) "fair use" photo under the "dead, no future free photos available" bits of [[WP:NFCC]]. So if consensus can be built on which photo to use, then we can go with it.
+:For Wilson, as he is living, we do not get such exceptions. I already uploaded a pic of Wilson's face injury under the NFCC for a non-reproduceable historical photo that is discussed in the article (the degree of injury or not). Having just an "What does Wilson look like" photo is not going to survive the fair use discussion tho.
+:The Trayvon Martin article is working under slightly different rules, because Florida does not allow state agencies to keep copyrights and so all of the evidence stuff is in the public domain. Missouri specifically does allow state agencies to keep copyright. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:52, 8 December 2014 (UTC)
+::That fair use can indeed encompass "what does a main participant look like?" in a very notable "moment in time" event is an incorrect belief? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 17:30, 8 December 2014 (UTC)
+:::Generally only if there is some specific thing that is being commented on significantly in the article that the "moment in time" captures. For example injuries, or "iconic" status. "Here is a random snapshot of Wilson" won't qualify. You can always try of course, but I've seen hundreds of photos trying that argument get deleted. The relevant criteria are [[Wikipedia:Non-free_content#UULP]]. In our case a hypothetical free replacement would let us see the general ID of Wilson just fine (As opposed to the injury photos, which cannot be replaced ever in the future). More detail can be found at [[Wikipedia:Replaceability_of_fair-use_images#Living_people]] [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:58, 8 December 2014 (UTC)
+::::I'm familiar with the guidelines, just wondering how far they can be stretched in this context. We could argue that not only is this hypothetical future free image of Wilson unlikely to materialize, but it may very well not capture him as he looked during the event. No doubt he'll probably lay low for the forseeable future, he may grow a beard, etc. So one way to look at it is that Wilson, as he was during the event, is in fact a not reasonably replacable historic image. Compare this context with say a movie star with a career that spans many years. If we don't get a picture of him today, he's likely to be out and about still making movies and appearing at events in the future, not to mention his notability is not tied to one particular moment in time. Very different context than Wilson here. I'm not looking for a "you can always try it and see how it goes". I'm looking for a consensus that a "what he looks like" image of Wilson is a valid application of fair-use and while stretching WP guidelines, doesn't necessarily run afoul of them.&ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 18:55, 8 December 2014 (UTC)
+:::::Actually, a re-read of [[Wikipedia:Replaceability_of_fair-use_images#Living_people]] (thank-you Gaijin42) makes me think a photo of Wilson is well within the guidelines simply as a "not reasonably replaceable image of a living person". Add to that the idea of his notability being tied to one moment in time, and it's starting to look like a pretty solid case. No? Again, I'm looking for a consensus on that point rather than a "try it and see how it goes". &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 19:25, 8 December 2014 (UTC)
+
+: I disagree with that choice of Michael Brown's photo, for several reasons. One reason is that is only shows his face. In the context of this article, I believe it is important to see his physical size (i.e., his body/frame/physique). Thanks. [[User:Joseph A. Spadaro|Joseph A. Spadaro]] ([[User talk:Joseph A. Spadaro|talk]]) 19:22, 8 December 2014 (UTC)
+::Can you point to any images you would prefer? &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 19:28, 8 December 2014 (UTC)
+
+::: No, I don't have any access to such photos. And I don't particularly understand (or follow) all of the intricacies of the copyright/fair use rules, etc., as discussed above. Nonetheless, I disagree with this particular proposed photo. For the reason stated above, and for other reasons as well. I am sure that I have seen many photos of Brown in the news and on the internet, etc., over the past few months. I will see if I can point one out in particular. Thanks. [[User:Joseph A. Spadaro|Joseph A. Spadaro]] ([[User talk:Joseph A. Spadaro|talk]]) 19:32, 8 December 2014 (UTC)
+
+:::: Here is one photo: [http://www.bing.com/images/search?q=michael%20brown%20missouri%20&qs=n&form=QBIR&pq=michael%20brown%20missouri%20&sc=8-23&sp=-1&sk=#view=detail&id=70EF2F07F28C8C3A728820D8683ACDAB3256EB25&selectedIndex=3]. And I thought that I had seen this photo in a not-cropped version, showing his full-length body shot. [[User:Joseph A. Spadaro|Joseph A. Spadaro]] ([[User talk:Joseph A. Spadaro|talk]]) 19:37, 8 December 2014 (UTC)
+:::::Even if you have a full body shot, unless he's standing next to someone much smaller, you probably won't get a true sense of his size. And even if you did get such a photo, people will come out of the woodwork screaming that we're trying to portray him as a "big black monster". I'm thinking maybe it should be a neutral sort of image that no one has much of a problem with. Then again, he was a big dude and that certainly plays a part in the narrative. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 19:55, 8 December 2014 (UTC)
+::::::People can visualize 6'4" 300 lbs. without a photo. Unless we feel it useful to show that his build was more that of a lineman than a linebacker (I don't, particularly). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:02, 8 December 2014 (UTC)
+:::::: I think the proposed photo by JBarta is just fine, as it is the one that was used by most sources. Go head and add it. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:36, 8 December 2014 (UTC)
+:::::: To counteract Spadaro's comment, we are not showing a full body shot of Wilson who is 6' 4" either. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:38, 8 December 2014 (UTC)
+
+{{u|JBarta}} Regarding your question above about Wilson and replacability, I do not think the photo serves any purpose in the article that qualifies under NFCC. What he looked like in general is not a subject that is discussed in this article. Relative sizes between Brown and Wilson may be relevant, but the photos in question do not show that. Your proposed justification would basically apply to any photo of any person for almost any article, it renders the restriction meaningless. If NFCC had an exception for "this photo has been widely used by news media for this story" I would support that, and would perhaps support a change to NFCC to create such an exception, but as the policy currently stands, I think its pretty clear generic photos of Wilson do not make the cut. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 20:45, 8 December 2014 (UTC)
+: Agree. The photo showing the redness on the face, relates specifically to the investigation and thus it can squeeze through (hardly,IMO) under NFCC. A generic photo of Wilson would not. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:48, 8 December 2014 (UTC)
+::"What he looked like in general isn't important" could be similarly argued for ''any'' person who is dead, yet has a fair use photo in their article. By my reading of the guidelines, it's not the importance that is important, but whether the photo is reasonably replaceable. If one agrees that a photo of Darren Wilson (especially capturing him at this moment in time) is not reasonably replaceable to an extent similar to a person who has died, then I would think the guideline would apply to Wilson as well as a person who has died. It's not like Wilson is going to be out posing for photos at the next Fergson Community Days or anything. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 21:00, 8 December 2014 (UTC)
+:::Wikipedia works in hypotheticals quite often. [[WP:V]] has [[WP:V#Access_to_sources]] for example. (Its in a physical library in Peru in a village only accessible by foot. Doesn't mean it isn't verifiable. ) There is a zero percent chance of free photos of Brown being taken in the future. I can come up with many ways we could have photos of Wilson in the future. (someone catches him in public, federal evidence released, federal charges, cspan testimony) etc. The main point that its tripping you up on replacability is that you have not stated how a photograph of him at the time is of particular encyclopedic value to justify the copyright issues vs a hypothetical image of him from the future. What does his "look" at that moment in time illustrate for the article? His skin tone? his physical fitness? We discuss none of this in the article, therefore illustrating it is not adding anything. In any case, the general policy won't get changed here. As I said feel free to try, but I have seen literally hundreds of photos go down in flames on the same type of reasoning. And fair warning I would !vote as I have indicated here (although I certainly don't make the consensus alone). [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 21:09, 8 December 2014 (UTC)
+
+::::On the issue of having a photo of him at this time and its replacabiliy. Imagine for a minute an article about a famous fight between two boxers back in the 1970's. You show each boxer... one a contemporaneous photo, the other forty years later all crippled up hunched over a cane because we can't find a free image of that boxer from back in the 1970s. The article is about the fight in the 1970's. The recent image of the one fighter arguably has little to do with the fight. It's not the same person that was in the fight. The same replacabilty concern exists with Darren Wilson, only the circumstances are less extreme and we're at the beginning of not having an image of him rather than far down the road. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 21:33, 8 December 2014 (UTC)
+
+:::Per NPOV I don't see how we could justify a photo of one without a photo of the other. A photo would serve no purpose other than to personalize the subject for the reader. If you think we've seen battles here to date, just make the popcorn and add Brown without Wilson. We have the shot of Wilson's cheek, but that's not equivalent to a full face shot, with eye contact, in the subject's bio section (which I presume is where Brown's photo would go). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:19, 8 December 2014 (UTC)
+
+* [[User:Jbarta]] asked me to comment here.
+: Wilson: This person is still alive. Jbarta seems to be concerned that Wilson may look very different when a free image is created. However, I note that the event took place only four months ago. It is therefore obvious that the person ''currently'' looks more or less the same as he did when this event took place. There is a potential that someone might take a photo of him tomorrow, next week or in January, and that photograph would then serve as a free replacement. It is important to note that [[WP:NFCC#1]] disallows non-free content if free content ''can be created'', and it is perfectly possible to take photos of him for the moment. The image is therefore replaceable, at least for the moment. If, after 40 years, it turns out that there is still no one who has taken a free photo of him, things may be different and he may look a lot different. [[WP:NFCC#1]] allows non-free images in some situations if the person has changed a lot from the time when he became famous, but non-free images are not allowed in all such situations. It may be useful to point out that a similar situation (a child actor active in the 1990s) currently is being discussed at [[Wikipedia:Deletion review/Log/2014 December 3|deletion review]].
+: Brown: This person is dead, so non-free images of him are not replaceable. The image proposed by Jbarta, [http://media4.s-nbcnews.com/i/newscms/2014_33/614086/140812-michael-brown-1338_8c5ad41dd423c28ed02e37e39222844e.jpg], looks like an image of children at an amusement park or some similar kind of place. It looks as if Brown could easily be at about the same age as the children in the background. However, it says that he was 18 at the time of his death. Is this a 10-year-old photo or something? If Jbarta is concerned that the photo of Wilson must be contemporary, then why does {{gender:Jbarta|he|she}} think that the photo of Brown doesn't need to be contemporary? I suspect that this photograph isn't suitable for the article. However, I don't know what other photographs, if any, would be suitable. I am also not sure if it is necessary to include a photograph of him in this article per [[WP:NFCC#8]]. I believe that there have been other discussions about murdered people at FFD, but I don't remember the outcome.
+: [[Shooting of Trayvon Martin]]: Jbarta mentioned this article because this article also contains non-free pictures. This article seems to have problems, see [[Wikipedia:Files for deletion/{{#time:Y F j|00:19, 10 December 2014 (UTC)}}#Pictures of Trayvon Martin]]. --[[User:Stefan2|Stefan2]] ([[User talk:Stefan2|talk]]) 00:19, 10 December 2014 (UTC)
+::On the topic of Brown's age in [http://media4.s-nbcnews.com/i/newscms/2014_33/614086/140812-michael-brown-1338_8c5ad41dd423c28ed02e37e39222844e.jpg this] photo you'll notice the bit of beard on his chin. It's the same as [http://www.google.com/imgres?imgurl=http%3A%2F%2Fbloximages.newyork1.vip.townnews.com%2Fstltoday.com%2Fcontent%2Ftncms%2Fassets%2Fv3%2Feditorial%2Ff%2Fed%2Ffed5e621-f0a8-5baa-a11a-c748e5dc65cd%2F5407e41926d2b.preview-620.jpg&imgrefurl=http%3A%2F%2Fwww.stltoday.com%2Fnews%2Flocal%2Fcrime-and-courts%2Fofficial-autopsy-shows-michael-brown-had-close-range-wound-to%2Farticle_e98a4ce0-c284-57c9-9882-3fb7df75fef6.html&h=501&w=620&tbnid=-nkr8uIvwcLzZM%3A&zoom=1&docid=HhK_zehdqKbgJM&ei=2JWHVJWjKYKqgwTdwIGACA&tbm=isch&ved=0CDUQMygCMAI&iact=rc&uact=3&dur=3358&page=1&start=0&ndsp=14 this] photo where I assume he's graduating high school. I think the photo I chose isn't more than a year or so old. At any rate, I'm not firmly fixed on any photo. It doesn't entirely matter to me. No matter what photo is chosen there will be those who see some sort of suspicious reason for the choice.
+::And while it's "possible" someone could snap an image of Wilson in the near future and upload free it here, I'd say it's highly unlikely. I'd also like to point out again that Wilson fits ''precisely'' the criteria set out in the 'May not be reasonably replaceable' section of [[Wikipedia:Replaceability_of_fair-use_images#Living_people]]. He's the poster boy for not likely to get a free picture of him anytime soon. The ''only'' thing he's likely to show himself for is a possible lawsuit from Brown's family... but I suspect he won' be out front signing autographs. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 00:51, 10 December 2014 (UTC)
+:::I just noticed [[Wikipedia:Replaceability_of_fair-use_images]] is a failed proposal. It carries zero weight. My argument just took a shit. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 01:17, 10 December 2014 (UTC)
+::::Yes, [[WP:REFU]] appears to be a failed proposal. I obviously overlooked the beard on the photograph. --[[User:Stefan2|Stefan2]] ([[User talk:Stefan2|talk]]) 23:06, 10 December 2014 (UTC)
+::{{re|Stefan2}} You probably missed the goatee, Brown doesn't look 8 years old in that photo. Judging by the [http://documents.latimes.com/federal-autopsy-michael-brown/ federal autopsy report's description], the photo is probably recent, although it could use a bit of cropping. Trayvon Martin's photos aren't relevant to the discussion; as of when I wrote this there hasn't been any consensus regarding those images. That leaves Wilson's images. It's possible that a photo of Wilson might be released publicly, so NFCC#1 probably doesn't work here. The only nonfree image that's irreplaceable is that of Wilson's injuries, except they're probably not appropriate for the short biography. Those are better suited for descriptions of the shooting. I think that posting only an image of Brown with the biographies would violate [[WP:IMPARTIAL|impartiality]], so I don't think their photos should be posted in the article. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 02:00, 10 December 2014 (UTC)
+
+== "baseline position" on diagram ==
+
+{{u|Cwobeel}} I think it may be helpful to include a spot on the diagram for the "baseline" position where all the measurements are from. Note that this point is not a [[WP:SYNTH]] issue derived by us from the witness testimony/sources, this is the "zero" point for the diagram measurements, per the crime scene photographers/investigators, and that point is explicitly marked on the original diagram.
+
+As an aside, the quotes below has bearing on the "Crime Scene" discussion above, as we have the police specifically referring to this location as a crime scene.
+
+* [http://www.washingtonpost.com/news/volokh-conspiracy/wp/2014/12/08/the-overlooked-audiotape-of-the-michael-brown-shooting/] (See figure 2 cone photo)
+
+* https://s3.amazonaws.com/s3.documentcloud.org/documents/1370513/grand-jury-volume-24.txt
+**And why is it that this cone was placed at that location on Canfield Drive? A As best we could tell based off of witness accounts, that would have been the furthest point east that Michael Brown would have went to. So that intersection of roughly Coppercreek Court and Canfield Drive. or Canfield Road? [...]That was the point that they had made reference to and so we used that as the furthest eastern point to go to.
+**In terms of on August 9th, one of our crime scene detective's jobs was to '''take various measurements of items of evidence at the scene. And he used what starts as a baseline at Coppercreek Court and Canfield Court, and used this baseline here and measured items during the entire, I should say, within the entire crime scene and those items were documented in a diagram that he completed with specific measurements, feet down to inches.''' So when we went back out there to take those 360 degree panoramic shots, we based, obviously, Coppercreek Court and Canfield Drive is subjective in the sense that we are basing that off of where, again, witnesses were telling us is the furthest point east that Michael Brown would have went So that is a subjective point that we use that intersection, northwest corner of that intersection right there.
+* Witness 14 http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/interviews/interview-witness-14-01.pdf
+** "the boy was still standing on the, on the, on the partially on the parking lot and on the grass. 'Cause he had ran that way. The officer came out came around got into his stance. And he said ?stop.? Because the boy looked up at him and he took two steps, about two or three steps.
+** When [Brown] turned around he had about one foot on the grass and one on the driveway.
+* Dorian
+** [Brown] was barely on the sidewalk, he was barely on the sidewalk to the parking lot. He was going towards this building. I presume that’s the way he was running. He wasn’t really all the way on the driveway when the . . . shot went off, and he turned around, and he was in the street
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:48, 8 December 2014 (UTC)
+
+Do we have the exact position of the baseline cone? I don't see it on the police report diagram. Is it on the legend list? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:40, 8 December 2014 (UTC)
+::{{u|Cwobeel}} It is at 0 feet 0 inches for both directions. on the diagram (text at bottom right corner saying "Baseline starting at 0'0" ) with a line pointing to the corner. On the legend the very bottom says "baseline runs east to west on north side of canfield with 0'0" starting at copper creek ct." The testimony indicates why they chose that spot as the baseline, and that the cone in the photograph is that point. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 20:58, 8 December 2014 (UTC)
+::: Added baseline as suggested. Also added the cross street Copper Creek Ct. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:45, 8 December 2014 (UTC)
+::::Nice. Suggestions: 1. Extend the bottom curb to the right edge of the image, to show that Copper Creek does not cross Canfield. 2. Is there a little too much space between the C and T in CT., or is that just more flaky rendering? 3. If there is any way to establish the distance between the left edge and the baseline, I can use that to fine-tune our coordinates, using the distance measuring tool in Google Maps. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:55, 8 December 2014 (UTC)
+::::: {{Done}} . Thanks for the feedback. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:36, 8 December 2014 (UTC)
+
+:::::{{u|Mandruss}} The legend of the original diagram includes the exact distance in feet and inches to every other item from the baseline, so just pick the furthest left item? (looks like its one of the casings by the car) [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:15, 8 December 2014 (UTC)
+::::::Ok, I tweaked the coords to a position halfway between items 4 and 20, or about 105 ft NW of the baseline (they moved about 20 ft SE). &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 22:28, 8 December 2014 (UTC)
+::::::Obsessively checking my work, I came up with 118 ft NW of the baseline, and the coords were already correct. I could be taking this accuracy thing too far, or perhaps someone as anal as I am would care to check my work. Item 4: 210' from baseline. Item 20: 26'7" from baseline. 26'7" = roughly 26.6 ft. ((210 - 26.6) / 2)) + 26.6 = 118.3. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 22:56, 8 December 2014 (UTC)
+::::::I vote accuracy too far. A few feet certainly won't matter for the purposes of the infobox. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:59, 8 December 2014 (UTC)
+:::::::Thought so. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:01, 8 December 2014 (UTC)
+
+As for the other witnesses narratives, that would be a good addition, as it explains the position of the casings and other evidence when the final shots were fired. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:46, 8 December 2014 (UTC)
+
+{{u|Cwobeel}} How are you making the SVG? Are you just eyeballing positions, or do you have it gridded out so you can convert from the actual feet/inches to the right pixels in some deterministic way? [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 22:10, 8 December 2014 (UTC)
+: Neither. I used the diagram of one of the media sources as an underlay, and positioned the evidence items accordingly. As the media sources did not have the baseline cone, that one I added by eyeballing. If we want to be scientific about it, I will have to re-do the position of each item using the measurements and converting the positions to the XY grid in Omnigraffle. Pretty laborious I'd say. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 22:29, 8 December 2014 (UTC)
+
+Can you explain how this is not original research or synthesis? You're converting a not-to-scale diagram to a scale diagram using information from two different primary sources. The article is in poor condition, with many outdated sections, far too many references, and duplicate information in several places. There are also far, far too many statements of the type "A B of XYZ News stated on August 21 that..."
+
+For comparison, [[2014 Grozny clashes]] has a better balance of opinion and fact, and an appropriate use of citations. That's just a random news article that I like the style of.
+
+Does this article require mediation? I haven't done that before, but I think there are issues that need to be addressed. I mean ownership, if it's not clear. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 05:06, 9 December 2014 (UTC)
+
+:From [[WP:Citing sources]]: ''Wikipedia's Verifiability policy requires inline citations for any material challenged or likely to be challenged, and for all quotations, anywhere in article space. However, editors are advised to provide citations for all material added to Wikipedia; any unsourced material risks being unexpectedly challenged or eventually removed.''
+
+:Based on the above, your concerns about too many references are unfounded and clearly unsupported by WP content guidelines.
+
+:I honestly don't see where you're getting the ownership claim, but please be specific and back it up.
+
+:I'll let others respond to your concerns about the diagram. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 05:14, 9 December 2014 (UTC)
+::I don't think Roches was referring to there being too many citations, but rather too many in-text attributions.
+::Regarding ownership, I think it's more a matter of there being some very active editors. This can result in there being misinformation and bias that would take more time than most have to correct it, but I don't see how that can be avoided, considering there is open editing. All I can say is to hang in there and do what you can.
+::Regarding the scale of the diagram, it looks like the same scale as the diagram in this source [http://www.stltoday.com/map-the-michael-brown-shooting-scene/html_0c861d0f-9a56-5769-8c16-d4b137af96e1.html]. In fact, the identifications and placement of the individual pieces of evidence look about the same too. If something is added to the diagram that is not supported by a reliable source, or it highlights something that is not specifically mentioned in a reliable source, then that might be a problem. So far I don't know of that happening here. Items that are the result of calculations can be questioned, but then there is the policy [[WP:CALC]] that allows some, and whether or not it is suitable for an article can be determined by consensus. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 13:01, 9 December 2014 (UTC)
+::On second thought it doesn't look like the same scale. [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637281752#Shooting_scene_evidence our article] [http://www.stltoday.com/map-the-michael-brown-shooting-scene/html_0c861d0f-9a56-5769-8c16-d4b137af96e1.html source] Maybe we need take out a ruler and check it and then add a note to the diagram, "not to scale", or redraw the diagram, using the source's diagram as a model for the scale. I notice that the source's diagram uses an actual picture of the street and surroundings on which it overlays the items in the crime scene. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 13:57, 9 December 2014 (UTC)
+::Update: I just now added the above source to the diagram. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 14:10, 9 December 2014 (UTC)
+:::My understanding is that the plotting of all points in the diagram used in the article was down to the inches from the baseline point based on the data published in that measurement table. If the scale in the diagram is questionable, it may be good for us to add a scale bar with 10-foot increment along the bottom part of the diagram. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 14:23, 9 December 2014 (UTC)
+
+:::Bob, I disagree that we need to inform the reader that the scale of our diagram is a little different from that of the source, for the sake of improved readability. All that matters is that the distance ''proportions'' are the same, and a "not to scale" statement could easily be interpreted as meaning that they are not. I think we're better off without it. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:51, 10 December 2014 (UTC)
+
+:About the diagram, as per [[WP:OI]], "Original images created by a Wikipedian are not considered original research, so long as they do not illustrate or introduce unpublished ideas or arguments, the core reason behind the NOR policy." This diagram was created from published data [http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/picture2.png here] and [http://graphics8.nytimes.com/newsgraphics/2014/11/24/ferguson-evidence/assets/ferguson/photos/2014-43984/photos-7/capture.png here], same document. There is no unpublished ideas or arguments included in the diagram, so it is not an original research, but it is just an original image. Also it is not synthesis because it is largely based on that same source. Other references listed next to the diagram were to show that same idea/argument has been published by multiple reliable sources. [[User:Z22|Z22]] ([[User talk:Z22|talk]]) 13:32, 9 December 2014 (UTC)
+
+Per the arguments above by Z22 and others, the diagram is not OR. Can it be improved? Sure, there is always that possibility. As for the state of the article referred to by Roches, same applies. It can always be improved, but generalizations don't help here. If there are specific things that you want addressed, join in and do the [[WP:EDITING|hard work]]. You may get reverted and challenged, but that is the way of this land. Collaborative editing is hard work and requires patience. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 8:39 am, Today (UTC−6)
+
+== Collaborating, OR, and inline attributions==
+Cwobeel, you have mentioned [[WP:OR]] three times since the talk page was last archived, and none of those instances were legitimately original research. I don't think the diagram is OR, actually, but it seemed inconsistent, for example, that you'd estimate the position of the baseline.
+
+I'd like to contribute in a collaborative and positive way, but that will require the active editors to assume competency on my part. I would use fewer in-line citations, I would use primary sources to some extent, and I would have to remove existing content in the process of editing it. I can't justify every change I make, but all the changes I make are justifiable. So, if I remove content, replace it, and if I make a change that needs justification, please ask for justification. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 15:46, 9 December 2014 (UTC)
+
+:Again, you call for fewer inline citations, but this time you're doing it without responding to the guideline excerpt that clearly says you're wrong on that. If you're in fact referring only to in-text attributions, as Bob said, then please use the correct term and say so.
+
+:If you want to work collaboratively on this article like the rest of us, I don't think anyone here will oppose that. We can use all the collaborative help we can get. Doing things like asserting, quite incorrectly, that your disagreement voids a consensus is not collaborative. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 17:26, 9 December 2014 (UTC)
+
+:: I second Mandruss comments about consensus. {{yo|Roches}} What I am puzzled about is your assertion that you want to {{tq|use primary sources to some extent}}. Can you clarify what do you mean by that? As discussed in [[Wikipedia_talk:Identifying_reliable_sources#Source_bombing]], while primary sources are not forbidden, most materials in articles are expected to be drawn from secondary sources. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:12, 9 December 2014 (UTC)
+
+:: A point about in-text attributions. These are needed in ''each and every case'' in which an opinion is expressed. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 19:15, 9 December 2014 (UTC)
+
+I'm referring to [[WP:BUNDLING]], not to any removal of inline citations or in-text attributions that are required. It didn't occur to me that there was even a possibility of someone thinking I meant removing references that needed to be there.
+
+About consensus: That was in reply to an assertion that I was deliberately removing content. The idea was that it had been there for a long time, and so it should stay. I thought that it needed to be updated, and that's all. If I was really trying to do something incorrect there, I would have undid the revert, and I didn't.
+
+About using primary sources to some extent: I really just meant what I said here (and everywhere else, for that matter). There are aspects of this case where primary sources are the best ones. An example would be the autopsy report, which is the work of a medical professional and makes all of the appropriate conclusions (and none of the inappropriate ones), as opposed to an article about the autopsy.
+
+In general: I don't have a lot of Wikipedia edits, but I've been using the site almost since the beginning. I've written and edited a substantial amount of scientific text, some of which is published. This does not mean I'm better than anyone else, but it's difficult for me to understand the hostility towards my comments here. (I don't mean replies to things that were already hostile.) It's even more difficult to understand the hostility I got when I tried to edit the article.
+
+I have posted to the admin noticeboards incident section. I tried to resolve this with the last post, but all that happened is that I got told I wasn't being collaborative. I can't see any reason why I was being uncollaborative that does not involve altering someone's content.
+
+[[User:Roches|Roches]] ([[User talk:Roches|talk]]) 20:35, 9 December 2014 (UTC)
+
+: I can understand your frustration. Expert editors sometimes have difficulties adapting to the realities of Wikipedia editing. A couple of good essay on the subject are [[WP:EXPERT]] and [[WP:EXR]] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:46, 9 December 2014 (UTC)
+
+The problem with [[WP:PRIMARY]] sources is that they can only be used for "straightforward, descriptive statements of facts that can be verified by any educated person with access to the primary source but without further, specialized knowledge" and "Any interpretation of primary source material requires a reliable secondary source for that interpretation". As can be seen in the "shell casing pattern" discussion above, deciding what is or isn't analysis vs objective fact is often itself controversial per your statement "''Objective facts from a primary source are not original research, and synthesis of objective facts when only one conclusion is possible is not speculation''". Clearly there is disagreement about how many conclusions are possible for almost all the facts of this case both on wiki and in the real world. Further, your specific example for wanting primary sources is itself problematic "''An example would be the autopsy report, which is the work of a medical professional and makes all of the appropriate conclusions (and none of the inappropriate ones), as opposed to an article about the autopsy''" By definition you are stating that your analysis of the primary source disagrees with the secondary source analysis of that same source. You may be right, you may be wrong, but policy prohibits any such analysis all together. There are plenty of places all of us disagree with various secondary sources, and think they got it wrong. The answer to that is to find an equally reliable secondary source that you think got it right and put it in, not just delete what we disagree with, or put in our own analysis. To some degree those restrictions are less ''on the talk page'' where we can briefly discuss why we think a particular fact or analsysis is relevant and worthy for inclusion in the article. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 21:06, 9 December 2014 (UTC)
+: I couldn't have argued it better. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 21:29, 9 December 2014 (UTC)
+
+Please don't be offended by the admin noticeboard post, at least not to a great extent. Things were gradually building up, and I held back from resorting to the admins for a while.
+
+The autopsy report may not be the best example, because that section is okay. I wouldn't analyze a primary source; there is always a need and a place for secondary sources. I just don't think secondary sources are necessarily better. Maybe a witness account is a better example; it could be quoted directly ''and supported by secondary sources'' rather than using several sources to write the account. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 23:14, 9 December 2014 (UTC)
+
+== Two witnesses found dead? ==
+
+According to this source, two witnesses, Shawn Gray, and DeAndre Joshua were found dead under suspicious circumstance. No idea if the source is reliable, but I doubt this is a made up story. [http://www.telesurtv.net/english/news/Another-Witness-in-Michael-Brown-Shooting-Found-Dead-20141208-0044.html]. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:33, 8 December 2014 (UTC)
+: After digging in a bit, it seems that there is a conspiracy theory garnering steam on the interwebs, that witnesses are being targeted. But reports I am seeing about the death of Shawn Gray, do not say anything about him being an witness in Brown's case. [http://www.stltoday.com/news/local/crime-and-courts/death-of-man-found-in-river-des-peres-in-st/article_f2e9ab3d-a536-573a-b85f-9d7cac03ed17.html] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:38, 8 December 2014 (UTC)
+
+::Joshua was the one found in the burned car. We have him in the unrest article with no connection to this case other than location. I don't see any reason to include random Internet conspiracy theories. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 23:45, 8 December 2014 (UTC)
+::: Neither do I. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:49, 8 December 2014 (UTC)
+
+== Anonymous released wrong name ==
+
+All right, here's a tricky issue.
+
+I went and tracked down the purportedly-[[Anonymous (group)]]-affiliated Twitter account's release of a police officer's name [[Shooting_of_Michael_Brown#Third_parties|mentioned in the article]], no doubt getting myself on all kinds of governmental watchlists in the process. It's not easy to find, but the name they released was '''not''' that of Darren Wilson. (Nobody type it here!) This fact seems inclusion-worthy despite (or, per [[WP:Recent]], particularly because) being out of the headlines, but the only RS I can find who have reported on this error mention the released incorrect name themselves, and it would be unethical and probably prohibited by [[WP:BLP]] to link to them.
+
+Should we just let this info fade into the Net? People will want to check the record next time Anonymous [[doxing|doxes]] someone in a high-profile situation like this, but maybe that's not our problem.
+
+Apologies for not posting links to what I'm talking about, but I shouldn't for obvious reasons. [[User:FourViolas|FourViolas]] ([[User talk:FourViolas|talk]]) 01:14, 9 December 2014 (UTC)
+
+:Are you talking about [[Shooting_of_Michael_Brown#Third_parties|this (fifth bullet, next-to-last sentence)]]? &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 01:17, 9 December 2014 (UTC)
+
+::That's the section I'm talking about, but not the citation. That one is from before Wilson's name was released, so all it says is that the police denied the allegation. It might be good enough for this article, though, as it allows readers to infer from the absence of an update saying "...but the police were lying, and it '''was''' Officer [redacted] after all." [[User:FourViolas|FourViolas]] ([[User talk:FourViolas|talk]]) 01:28, 9 December 2014 (UTC)
+
+:::I get you now. And you haven't found a source that says the Anonymous ID was wrong, without reporting the name of the innocent party. In that case, I agree with leaving it at is. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 01:34, 9 December 2014 (UTC)
+
+== New documents released ==
+
+New material has been released by the prosecutor's office. As I will not have much time today to work on this, maybe others can take a look. [http://www.latimes.com/nation/nationnow/la-na-nn-more-grand-jury-documents-michael-brown-shooting-20141208-story.html] - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 20:18, 9 December 2014 (UTC)
+
+:So far the docs seem all over the place. A few supporting brown, a few supporting wilson, one completely off the wall "walk out" one that claimed to personally see Brown on his knees and Wilson shoot him in the head point blank, and then saw/heard 8 more shots into Brown while he was face down, who then stopped the interview when they were told what they were saying didn't match the evidence. Mostly they seem to be all followup interviews asking specific questions after the local interviews. On from the guy Brown was living with that week.[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 20:31, 9 December 2014 (UTC)
+
+:Added above source as LATimes.Documents. It includes a link to the federal autopsy report, and I added that report separately as LATimes.FederalAutopsy. Added mention of the release of the federal autopsy report. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:48, 9 December 2014 (UTC)
+
+== More terse summaries in the witness accounts ==
+
+As there are now a massive amount of witness statements available, I think we need to change how we are doing things in the accounts section. Obviously covering each account in the level of detail we currently have for dozens of additional accounts, and then criticisms of those accounts, would not be viable - it would be multiple standalone articles worth of content. Keeping things the way it is now represents an [[WP:NPOV]] issue as well. I suggest we move to a more [[WP:SUMMARY]] style overall bringing all of the media witnesses together under a [[WP:SUMMARY]] section (as they are mostly saying the same thing), and then a Grand Jury section that discusses the various testimonies again at a high level - Using sources such as the PBS comparison (even with its well known flaws) or the links that {{u|TParis}} pointed out in ANI.
+
+Perhaps the Police/Wilson and Johnson should keep standalone sections, as they are directly involved and therefore their statements have more importance, and have been scrutinized more carefully by the media and other analysts.
+[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:26, 9 December 2014 (UTC)
+
+I was saying this, thinking this, and in one case tried doing this, for several days before taking it to ANI. I don't like that I had to take it to ANI because of objections that it would destroy people's work or might constitute original research. There was no critical discussion of any witness that opposed Wilson, and much discussion of discrepancies and flaws in the few accounts that supported it.
+
+I've always thought there should be a section on Wilson's story and a section about the opposing views; I typed that a few days ago, though I'm not sure I posted it. I still think it's the best way to move forward. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 15:49, 10 December 2014 (UTC)
+
+==POV Issues Regarding Controversy Section==
+
+I pretty much agree with everything that TParis wrote at ani. This article has NPOV issues. The article relies too heavily on the opinions of non-notable commentators and their criticism. The article is also littered with weasel words and phrases like "some legal experts" and terms like "asserted" and "claimed", which are all discouraged by MOS. The controversy section for the grand jury hearing is a prime example of undue weight with the amount of criticism in that section. That table really needs to go too, what is the significance of having that, it's not even true. These jurors were a ''typical grand jury'' that were conducting ''typical'' grand jury business, doing exactly everything listed in the first column, before Wilson's case was given to them, there's no mention of that in the table. The criticism in Wilson's section has weasel phrases like "sources reported" and "other discrepancies" without defining who the sources are or what the other discrepancies are. It also provides no context at all either, like the fact that the grand jury was made aware of these inconsistencies before Wilson even testified. There just seems to be a lot of cherry-picking sources to negatively portray Wilson, law-enforcement officers, prosecutors and the grand jurors.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 02:10, 10 December 2014 (UTC)
+
+:I think the reason for at least one occurrence of "some legal experts" is that the source says "some legal experts". Obviously we can't say it in Wikipedia's voice, so are you suggesting it should be left out of the article because the source declined to identify the legal experts? I would disagree. As for "other discrepancies", if those were elaborated it would be attacked as undue weight, so it appears there's no way to include such material at all. It's either undue weight or weasel words. I'll abstain from discussion about the table for lack of competence in that area. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 02:28, 10 December 2014 (UTC)
+
+:First, this has almost nothing to do with {{u|Gaijin42}}'s post in [[#More terse summaries in the witness accounts]] and I've refactored it into a new section (if not, go ahead and undo it). I disagree that this article has NPOV issues. [[WP:NNC|Notability does not apply to content]], and we should instead be looking at due weight. In this case, it seems that the majority of opinions are biased against Wilson, the prosecution team and the grand jury, which is why it's reported so heavily in the article; unless it's out of proportion, there shouldn't be anything wrong with this. Sources that argue to the contrary are present; if there are others, they should be included to keep due weight. The "some legal experts" phrase is a leftover from the [http://www.latimes.com/nation/la-na-ferguson-da-analysis-20141126-story.html LA Times] article, which provided a number of legal opinions. While out of context it may seem like a weasel phrase, the rest of the section references by legal experts mentioned in the source by name, so it really isn't a weasel phrase. Assertions and claims are only weasel words when [[WP:ALLEGED|implying a point is inaccurate]], which is hardly the case here. The table is sourced to NYT, which is why we have it. I don't see what's the problem with having it here, maybe you could clarify? The other two instances are poorly paraphrased: the "sources reported" is actually the Huffington Post's analysis, but the analysis that went into their article was cut out of ours so that'll have to be reworked; there's only one discrepancy reported in the CNN article, so I went ahead and reworded that phrase. At any rate, there doesn't seem to be blatant cherry-picking of POVs as far as I can tell. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 03:01, 10 December 2014 (UTC)
+::Once you have summarized and presented information to the reader in an encyclopedic tone - following that up with an endless stream of cherry-picked opinions of non-notable commentators is undue piling on. I completely agree that the majority of the reporting is negative against Wilson and the other entities involved in this case, but that doesn't mean we pack as many negative opinions that we can into a section, or the article, and still claim it's NPOV, because that's not neutral. We should be summarizing and including the most notable opinions or academic opinions, instead of being a depository for negative opinions that don't really impart any encyclopedic information to the reader. The weasel phrases "some legal experts" and "sources reported" is exactly that - weasel phrasing - and should never be used in this article, especially when there are more than enough legal experts identified by name offering legal opinions.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 17:36, 10 December 2014 (UTC)
+:::I really don't think the opinions are cherry-picked unless we're missing pro-Wilson/prosecutor references, and notability really doesn't matter for sources. I took a closer look at the article though, and I noticed that we're quoting a lot of the opinions directly, which is probably compromising [[WP:IMPARTIAL|impartial tone]]. We should neutrally summarize the arguments instead of quoting them, and I think that should fix the POV problem. Btw, "some legal experts" isn't a [[WP:WEASEL|weasel phrase]] when used in the header or (especially) when the legal experts are clarified after the fact. Using that phrase should be ok. "Sources reported" is weasel phrasing, and I'll take the time to reword that sentence later today. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 19:33, 10 December 2014 (UTC)
+:::<s>P.S. And now my refactoring's a moot point. Whoops. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 19:37, 10 December 2014 (UTC)</s>
+I don't think there was blatant cherry-picking of POVs, but I think there was a desire to represent a greater variety of opinions than was necessary. There are so many opinions from so many sources that it would be much more helpful to avoid arguing why a given source is acceptable despite having issues like weasel words and unnamed sources. We could simply choose sources that don't do that.
+
+In general, I objected to the inclusion of journalists' opinions about the legal issues because there were also several published opinions from real lawyers about the legal issues. In the point where there was a formal statement from the ACLU and an analysis by the Huffington Post, the first source was a much better choice than the other. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 16:11, 10 December 2014 (UTC)
+
+== Differences between typical grand jury proceedings in Missouri and Wilson's case --should be removed or changed to reflect data and not opinion ==
+
+It should either compare this case with a low profile case or just give the facts of the case. It is copied almost word for word from the the NYT and is not fact but opinion. As there are no references to real data. <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Oceanisle2009|Oceanisle2009]] ([[User talk:Oceanisle2009|talk]] • [[Special:Contributions/Oceanisle2009|contribs]]) 03:12, 10 December 2014 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+:Which NYT source are you suggesting is an opinion piece? [[User:Dyrnych|Dyrnych]] ([[User talk:Dyrnych|talk]]) 03:17, 10 December 2014 (UTC)
+:In addition, if it reflects an analysis by (hence opinion of) a New York Times columnist or reporter, it should probably be adequate to simply make sure it is identified as such (inline attribution). Even opinion, when properly identified and attributed to a credible source, is fair content here. <span style="font-family: Gill Sans MT, Arial, Helvetica; font-weight:100;">[[User:Dwpaul|<font color="#006633">Dwpaul</font>]]</span> <sup>''[[User talk:Dwpaul|<font color="#000666">Talk </font>]] ''</sup> 04:20, 10 December 2014 (UTC)
+:: I have no problems with attributing the content to the NYT. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 05:12, 10 December 2014 (UTC)
+:::Well, that solves that. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 07:17, 10 December 2014 (UTC)
+::::If the text of the table was copied verbatim, is there a problem with copyright infringement? --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 11:01, 10 December 2014 (UTC)
+:::::: It was not copied verbatim. You can check and compare. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:08, 10 December 2014 (UTC)
+BTW, the [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637461101#Controversy Controversy section] that has the table is bloated and could use some summarizing. --[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 11:33, 10 December 2014 (UTC)
+
+The problem with the table is that it doesn't take into account what grand juries usually do, which is approving felony indictments that a prosecuting attorney's office has already decided to take to trial. The hearing in Wilson's case was intended to determine whether there was sufficient evidence for a trial. (A trial for second degree murder, since it was intentional but unplanned.)
+Now, I think this is the time when we got into why it's not up to us to decide when journalists are right or wrong. The table compares two very different things, and in so doing it misrepresents the purpose for the hearing in this case. I don't want to deal with opinions to any more of an extent than is absolutely necessary, but it's not right for Wikipedia to contain information that is factually wrong, or misrepresented, up to the point where one journalist discovers the error of another. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 16:03, 10 December 2014 (UTC)
+:I think your difference of purpose is the exact point of the criticism. The grand jury was not normal, and thats what the table points out. The prosecutors job is to prosecute, not decide if there is a crime. There is prosecutorial discretion, but if thats what was at play he should have just said so, and declined to prosecute. Having a show "trial" where he didn't actually prosecute did nothing except waste money and provide room for criticism. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 16:34, 10 December 2014 (UTC)
+::I disagree, in this specific instance, this was a "normal" grand jury conducting "normal" grand jury business, it just so happened in August that they were thrust into the spotlight and given an unusual case under unusual circumstances - and the table doesn't point that out. The table is confusing because it seems to imply that some kind of special grand jury was convened to hear this case, and that's not what happened. A ''typical'' grand jury had already been convened and were conducting ''typical'' grand jury business when they were suddenly tasked with an unusual and controversial case, that's what happened and that's what should be relayed to the reader in prose instead of a generic table that doesn't address the context in which this case was given to them.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 17:50, 10 December 2014 (UTC)
+::: Nothing is stopping you from adding other viewpoints about the grand jury process, besides the NYT's opinion and the other opinions already in the article. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 18:22, 10 December 2014 (UTC)
+:::Certainly the makeup and convening of the GJ was normal. But was the presentation of this case normal? The table is about the GJ proceedings, not the GJ itself. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 18:25, 10 December 2014 (UTC)
+::::From what I read from the bloated opinions in that section, it's the decision and the presentation of the case by the ''prosecutor McCulloch'' and the unusual way he used the grand jury - that is the controversy, at least that's what the overwhelming sources indicate and what and who they are specifically criticizing. If anything, there should be a table comparing "Similar cases handled by McCulloch" vs. "Wilsons case". The controversy/criticism revolves around McCulloch and the decisions he made. And I'd also point out that the table says that they met 25 days over 3 months, that was a decision that this specific GJ themselves elected to do, so that is specific to them and therefore makes it about "the GJ itself" and an apparent scheduling decision they made for convenience purposes. Gee, isn't that controversial? And I'd also make note of the fact that a "typical" grand jury does not meet for a day or less, it meets for a specific timeframe decided by a judge, and these grand jurors were originally appointed for a four-month term (and later extended).[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 22:44, 10 December 2014 (UTC)
+:::::FYI [[Grand juries in the United States|grand juries]] are not the same as [[Jury#Types of jury|trial juries]]. Trial juries are directed by judges; grand juries are directed by prosecutors. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 22:55, 10 December 2014 (UTC)
+{{od}} {{u|Isaidnoway}} You are completely misinterpreting the criticism Isaidnoway. Yes, the jury was convened for a set amount of time, but the amount of time they spent on a particular case was controlled by the prosecutor. This same GJ dealt with dozens of cases prior to this case, and most of them were less than a day. Probable cause is a really low standard. Did wilson shoot? Yes. Were there witnesses (that passed the initial "not obviously lying" test) that said Brown was surrendering? Yes. Ok, thats probable cause for a trial. Impeaching those witnesses, and showing the defensive evidence is the job of the defense, not the prosecutor. Self defense cases are tougher, because they need to show all the elements of the crime and one of those elements is "it wasn't justified" but its still a really low bar. I think there is no way they could get a conviction, but the criticism that the prosecutor would not be giving the random joe the same level of deference is absolutely correct. He used the GJ for political cover instead of just saying "I don't think there is a case here" Political cover is not one of the appropriate roles for a GJ.McCulloch essentially had a trial, where he was both the prosecution and the defense. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:01, 10 December 2014 (UTC)
+::The amount of time spent on a case is not controlled by a prosecutor, the time is controlled by the jurors themselves, as they are certainly allowed to ask questions of the witnesses and to individually examine the evidence as it suits them. And your explanation here on the talk page about how they dealt with dozens of cases with most of them being less than a day is great, but that explanation for the reader is absent from the table. The implication presently in the table is that a "typical" grand jury meets for a day or less, sans any explanation or context. Probable cause was never there for the prosecution, the physical evidence is in line with the officer's version of events.[[User:Isaidnoway|<font face="Times New Roman" color="blue"> '''''Isaidnoway''''' </font>]][[User talk:Isaidnoway|<font face="Times New Roman" color="blue">'''''(talk)'''''</font>]] 23:26, 10 December 2014 (UTC)
+:{{tq|" but it's not right for Wikipedia to contain information that is factually wrong"}} - Actually, the purpose of Wikipedia is to report what reliable sources say about a subject. If reliable source A said X, and X is factually incorrect because B says so, then we report what A said and what B said, and let our readers arrive to their own conclusions. But we can't avoid quoting A just because B said that A is factually incorrect. In addition, we can't use a primary source that contradicts A, unless the primary source refers to A's opinion. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 17:16, 10 December 2014 (UTC)
+::Policy doesn't say that we have to include questionable material. See the policy [https://en.wikipedia.org/w/index.php?title=Wikipedia:Verifiability&oldid=637531987#Verifiability_does_not_guarantee_inclusion Verifiability does not guarantee inclusion.]
+
+::There’s a false implication in the NYT table and ours that the prosecutor didn’t provide a range of charges. He provided five, from murder in the first degree to involuntary manslaughter.[http://abcnews.go.com/US/ferguson-grand-jury-indict-officer-darren-wilson-death/story?id=27146400][http://www.usatoday.com/story/news/nation/2014/11/24/ferguson-grand-jury-deliberations/19474907/]
+
+::In any case, I think we should summarize the information in the table with the following:
+:::According to ''The NY Times'', the grand jury proceedings were not typical of such proceedings in Missouri. They lasted much longer, the prosecutor did not recommend that the defendant be indicted, there was much more evidence presented, many more witnesses testified, the defendant testified, and all of the evidence and testimony was released to the public after the defendant was not indicted.
+::--[[User:Bob K31416|Bob K31416]] ([[User talk:Bob K31416|talk]]) 01:23, 11 December 2014 (UTC)
+::: Reverted per [[WP:BRD]]. I don't see any consensus emerging for this change. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:51, 11 December 2014 (UTC)
+::: Your summary is inaccurate, to say the least. Using generic terms such as "much longer" and "more evidence" when we have hard data that is measurable. I still believe the table is the best and easy to read and appreciate for our readers. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 15:54, 11 December 2014 (UTC)
+
+== On the issues raised on ANI ==
+
+I've posted replies under three sections that dealt with issues raised in the ANI discussion. Now, I'm going to voluntarily avoid this article and talk page for 48 hours, and after that I'll respond to any outstanding issues.
+
+For the editors who have worked on this article and who will be working on it, try to remember that this is one of the increasingly small number of places that people can go to even get a chance at not seeing news presented in the form of a top ten list. Your work is important, people read it, and it needs to be the best it can be. [[User:Roches|Roches]] ([[User talk:Roches|talk]]) 16:35, 10 December 2014 (UTC)
+
+== What gun was used? ==
+
+One of the key missing details is how the police officer's gun was wrested from him. I have tried to find the make and model gun used, as well as the make and model of holster. If this article was merely an overview, I could excuse it, but this article drills down to the level of "$48 worth of cigarillos." Not $47, not $49,but $48. I would like to see the same attention to detail for the gun issue.
+
+Was the gun a Glock, a Smith, etc.? Did the holster have a butt strap, or an internal locking device, etc.?
+
+Thanks for your attention. [[Special:Contributions/50.0.36.243|50.0.36.243]] ([[User talk:50.0.36.243|talk]]) 16:38, 10 December 2014 (UTC)
+
+:Not an answer to your question, but a while back I stumbled on this [https://www.youtube.com/watch?v=1PR9dAr9vDI YouTube video] that may be informative, or at the very least, interesting. (I'm not suggesting using it as a source nor suggesting the information contained is unimpeachable) &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 16:50, 10 December 2014 (UTC)
+
+:It was a .40 cal [[SIG_Sauer_P226#P229]]. Its a 12+1 gun, and Wilson had several spare mags. To my knowledge we do not know the type of holster he was using, but I don't think its relevant as there is no assertion that Brown went for the gun while it was in the holster - Wilson freely says he drew the gun from the holster himself. We don't talk about the gun much, because it has not been discussed much in reliable sources.
+
+:One interesting (to me, not covered in any sources I am aware of) discrepancy is that there were 12 cases found near the scene. Wilson states that after the shooting there was one round left in the magazine, which he removed. If there was a round in the magazine, there should also have been a round chambered. That there wasn't means that either there was a [[Firearm_malfunction#Failure_to_feed]] or the remaining bullet was not in the magazine but in the chamber, but wilson explicitly said "I lock the slide back, take the magazine out, take the one round that’s left in it out. I put it all in that bag, seal it with evidence tape and then sign it.".
+
+:http://listverse.com/2014/11/25/10-of-the-most-important-pieces-of-evidence-from-darren-wilson-testimony/ [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 17:04, 10 December 2014 (UTC)
+
+:: {{yo|Gaijin42}} There are 15 rounds on a P299 magazine, so 12 cases + 1 in the magazine according to Wilson, that leaves two rounds not accounted for? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:07, 10 December 2014 (UTC)
+:::{{yo|Cwobeel}} The .40 model uses 12-round magazines, it's the 9mm variant that has 15 rounds. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 23:11, 10 December 2014 (UTC)
+
+:::{{u|Cwobeel}}There are both 10, 12, and 14 round magazines for a 229.[http://shop.sigsauerguns.com/Magazines_2/P229-Magazines/] You can see Wilson's specific magazine in the photo at that listverse article I posted, and that it is a 12 round mag. The 14 round mag is longer (duh) so is more difficult to wear while seated. Some cops have the 14 rounders as their backup mags tho since you can move them around more easily than the holstered gun (Wilson said he had 2 additional mags, but their size was not released anywhere)[[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:14, 10 December 2014 (UTC)
+:::: In my time in the army (not in the US), we used to chamber an extra round in our small arms in addition to the mag. Is that not a practice in law enforcement the US? - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 23:36, 10 December 2014 (UTC)
+:::::Yes, that is standard practice here too. Its a 12+1 gun, so the +1 is the "extra". That chambered round would have been the first one fired in the car. Wilson fired 12 times, so the final round should have been chambered in the end, but it could have stayed in the magazine if there was a failure to feed. Per wilson's testimony he also had 2 failure to fires in the car during the time he says Brown's hand was on the gun (see the video posted above for a technical explanation of how his particular gun works in that regard) [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 01:37, 11 December 2014 (UTC)
+
+Also to add to my discrepancy above "locking the slide back" prior to removing the magazine would have loaded the round from the mag into the chamber. (This is why you ALWAYS REMOVE THE MAG FIRST WHEN UNLOADING A GUN) So my assumption is that what he meant to say was that he ejected the round from the chamber and removed the mag, but it was a sloppy way to talk, and I'm surprised nobody (rs) mentioned it, especially with how some sources (Shaun King etc) were saying he might have reloaded, and therefore exactly what happened to each round would be very relevant. [[User:Gaijin42|Gaijin42]] ([[User talk:Gaijin42|talk]]) 23:28, 10 December 2014 (UTC)
+
+== Use of See also ==
+
+Resolution of [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637514479&oldid=637511493 my edit] and its [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&diff=637517371&oldid=637514479 revert] by {{u|Likeminas}}. Reason for revert was ''All these killings have been discussed as an overall recent trend in news articles''. I don't think that justifies the revert. The killings are included in the umbrella list article. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:22, 10 December 2014 (UTC)
+:With the exception of the Travon Martin shooting, all these cases are discussed in news articles as a recent trend of police abuse of force. i.e. Police officers killing people under questionable circumstances. In fact, there's a good amount of sources that mention them all in the same article.
+:The killings in the [[List of killings by law enforcement officers in the United States]] does not single out cases that have produced extensive news coverage and massive national outcry.
+:These cases are related and should be listed under 'See also' for readers that are interested in reading the most notorious cases in recent history. [[User:Likeminas|Likeminas]] ([[User talk:Likeminas|talk]]) 20:36, 10 December 2014 (UTC)
+
+:{{editconflict}} Garner, Rice and Gurley are at least related by timing. Martin and Diallo less so, since they aren't part of this recent chain of events. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 20:40, 10 December 2014 (UTC)
+::Agreed. Feel free to remove them, if chose to. Thanks [[User:Likeminas|Likeminas]] ([[User talk:Likeminas|talk]]) 20:44, 10 December 2014 (UTC)
+:::{{editconflict}} Done. Btw, should we keep the "hands up, don't shoot" in see also? We already have it in the navbox, having it in see also seems superfluous. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 20:48, 10 December 2014 (UTC)
+:Wikipedia has multiple articles addressing that topic, including [[Police brutality in the United States]] and [[Police misconduct]]. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 20:46, 10 December 2014 (UTC)
+::True, but the three deaths that are still in there are related by timing: The grand jury trial against the officer who killed Garner ended in non-indictment last week, and Rice and Gurley's deaths coincided with the grand jury case against Wilson. Brown's shooting at the very least had an influence on the reactions to these, so including them in 'see also' wouldn't be a bad idea. --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 20:54, 10 December 2014 (UTC)
+
+== Common sense (wiki-linking Ferguson, Missouri) ==
+
+In the opening sentence, I [https://en.wikipedia.org/w/index.php?title=Shooting_of_Michael_Brown&oldid=637524325 linked] [[Missouri]], and unlinked "suburb" (edit summary: "some of us don't know where Missouri is; everyone knows what a suburb is"). I was reverted (twice), and instructed to "talk it to talk and stop edit warring". So, I leave it here for others to consider. Thanks. [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 21:15, 10 December 2014 (UTC)
+
+:This is two separate issues, which I will address separately. First, the Missouri linking. I don't know of a policy or guideline about this, but there is [[User:Tony1/Build_your_linking_skills|this essay]] by an editor very experienced with linking. I would encourage any editor to read all of it before becoming involved in any disputes about linking. It says, ''Uniqueness: Is the linked topic reachable—directly or indirectly—through another link in the vicinity? (If so, consider not linking.)'' In other words, [[Missouri]] is easily reachable via [[Ferguson, Missouri]], so it probably doesn't need to be linked here. The general idea is the concept of overlinking, which says that having fewer links increases the value of the remaining ones. That concept is covered in the essay as well as guidelines.
+
+:As to "suburb", I don't think it's all that clear that everyone knows what a suburb is, but I feel less strongly about that. I might even support unlinking suburb on overlinking grounds. Frankly I didn't even notice that was part of what I was reverting. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:27, 10 December 2014 (UTC)
+::The idea that it's "overlinking" because the link is available on another article is clearly wrong. (Incidentally, it's only available there because [https://en.wikipedia.org/w/index.php?title=Ferguson,_Missouri&oldid=637510044 I just added it].) You should always check what your reverting, before accusing editors of edit-warring, (and quoting irrelevant essays and policies). [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 21:35, 10 December 2014 (UTC)
+
+:::Please don't make statements about what's "clearly wrong" without some kind of backup; i.e., no matter how emphatically you present something as truth, that doesn't make it true. That's fundamental Wikipedia. And please don't lecture me about proper editing procedure while demonstrating complete ignorance of [[WP:BRD]]. The correct procedure was demonstrated in the dispute preceding this one. I was reverted once and I opened a talk discussion about it. You did not do that, instead re-reverting the revert, thereby starting an edit war. There is nothing gray or fuzzy about this area. &#8209;&#8209;[[User:Mandruss|<span style="color:#8E8278;">'''''Mandruss'''''</span>]]&nbsp;[[User talk:Mandruss|<span style="color:#AAA;">&#9742;</span>]] 21:42, 10 December 2014 (UTC)
+::::Firstly, I started this discussion, not you!
+::::Secondly, "overlinking" is best avoided for the reason that it draws attention away from the text. In this case, [[Ferguson, Missouri]] appeared entirely in blue, ie. identically to my edit, so this reason does not apply. And you apparently agree about "suburb". So, we are in agreement, then. [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 21:52, 10 December 2014 (UTC)
+::::And thirdly, to reiterate, you should always check what you're reverting ("fundamental Wikipedia"). [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 22:19, 10 December 2014 (UTC)
+
+I think [[Ferguson, Missouri]] is fine. No need to link the city and state separately. Regarding [[suburb]], I could go either way. I lean towards not linking it as relatively common knowledge. Then again, I'm from the U.S. If '"suburb" is not a commonly used term in oher English speaking countries then wikilink it. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 22:31, 10 December 2014 (UTC)
+:This will be my last comment. You failed to mention any reason why [[Ferguson, Missouri]] is better than [[Ferguson, Missouri|Ferguson]], [[Missouri]]. [[User:Signedzzz|zzz]] ([[User talk:Signedzzz|talk]]) 22:46, 10 December 2014 (UTC)
+::First, never say "this is my last comment" because it rarely is. There's really no need to... if you're done commenting, just don't comment any more. No need for a parting shot. And if (like so many do) you re-enter the discussion, you re-enter it looking a little silly. We all look silly sometimes accidentally. There's really no need to do it on purpose. At any rate, to answer your question, while I know of no policy that prefers one way or another, I see no need to offer two links where one will do. &ndash;&nbsp;[[User:Jbarta|JBarta]] ([[User talk:Jbarta#top|talk]]) 23:03, 10 December 2014 (UTC)
+
+== Washington Post Reception Source ==
+
+''The Boston Post'' source that was used in the reception section has a couple of problems. First, it's actually a repost of ''The Washington Post'', but ''The Washington Post'' doesn't allow the Internet Archive to preserve it. Should it still be sourced to Boston or to Washington? Second, it seems to be a lot of analysis that can't be summed up easily without trimming it out, and doesn't really fit with the reception section and should probably moved next to Wilson's testimony. Any suggestions? --[[User:RAN1|RAN1]] ([[User talk:RAN1|talk]]) 01:44, 11 December 2014 (UTC)
+
+== Grand jury no bill reception ==
+
+{{u|Bob K31416}} has started a process of summarizing that section, in a manner that I believe it to be counter productive. We have expert opinions from legal, law enforcement, politicians, and media outlets all of which are notable and informative. [[WP:NOTPAPER|Wikipedia is not paper]] – If the section is too long, the correct process to avoid losing good content that is well sources, is to create a sub-article with all the detail, and summarize here per [[WP:SUMMARY]]. But deleting useful and well sourced material, is not acceptable. We are here to build an encyclopedia. - [[User:Cwobeel|<span style="color:#339966">Cwobeel</span>]] [[User_talk:Cwobeel|<span style="font-size:80%">(talk)</span>]] 16:02, 11 December 2014 (UTC)
diff --git a/Echo/tests/phpunit/includes/revision_txt/646790570.txt b/Echo/tests/phpunit/includes/revision_txt/646790570.txt
new file mode 100644
index 00000000..5c4ee5ec
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/646790570.txt
@@ -0,0 +1,69 @@
+{{User:ClueBot III/ArchiveThis
+|age=2160
+|archiveprefix=User talk:PatHadley/Archive
+|numberstart=1
+|maxarchsize=100000
+|header={{Automatic archive navigator}}
+|minkeepthreads=4
+|minarchthreads=1
+|format= %%i
+}}
+{{archives}}
+{{Signpost-subscription|right}}
+
+
+==Site I mentioned==
+http://www.theverge.com/2013/8/9/4607240/fall-asleep-to-the-sound-of-wikipedia [[User:Shiningroad|Shiningroad]] ([[User talk:Shiningroad|talk]]) 11:31, 22 November 2014 (UTC)
+:Thanks! [[User:PatHadley|PatHadley]] ([[User talk:PatHadley#top|talk]]) 12:36, 22 November 2014 (UTC)
+
+== This is a demo! ==
+
+Demoing the user talk page [[User:PatHadley|PatHadley]] ([[User talk:PatHadley#top|talk]]) 11:44, 22 November 2014 (UTC)
+
+== Fortitude & Frailty: Reading the Human Condition Edit-a-Thon ==
+
+{| style="border: 1px solid gray; background-color: #fdffe7;"
+|rowspan="2" valign="middle" |{{#ifeq:alt|alt|[[File:SHUmanities Barnstar.png|100px]]|[[File:SHUmanities Barnstar.png|100px]]}}
+|rowspan="2" |
+|style="font-size: x-large; padding: 0; vertical-align: middle; height: 1.1em;" | '''SHUmanities Barnstar'''
+
+|-
+|style="vertical-align: middle; border-top: 1px solid gray;" | On behalf of Sheffield Hallam University's Humanities Department, thank you for your tireless efforts during the [[Wikipedia:Meetup/Sheffield_1|Fortitude and Frailty Edit-a-thon]]. Your contribution to the day, on and offline, was exemplary! &mdash; [[User:Mhbeals|Mhbeals]] ([[User talk:Mhbeals|talk]]) 13:16, 24 November 2014 (UTC)
+|}
+
+== ''Signpost'' ==
+
+Hey Pat, thanks for writing the ''Signpost'' article, and I apologize for not replying before. As you might be able to glean from my contribs, I've entered graduate school and unfortunately don't have much extra time for Wikipedia. I delayed [[Wikipedia:Wikipedia_Signpost/2014-12-10/Op-ed|your article]] by a week as we already had a feature for this week, but it will run next week. With it being an [[op-ed]], you could make it into the first person if you'd like (rather then referring to yourself by your username). [[User:The ed17|Ed]]&nbsp;<sup>[[User talk:The ed17|[talk]]]&nbsp;[[WP:OMT|[majestic titan]]]</sup> 21:38, 6 December 2014 (UTC)
+:Just saw the post - thanks, great piece. I'd like to explore opportunities to get the York Museums Trust involved with a Wikidata-focused research project, the proposal for which I am currently [[:d:Wikidata:WikiProject Wikidata for research|drafting]] (see [http://blog.wikimedia.de/2014/12/05/wikidata-for-research-a-grant-proposal-that-anyone-can-edit/ this blog post] for background). --<font style="font-family:Monotype Corsiva; font-size:15px;"> [[User:Daniel Mietchen|Daniel Mietchen]] ([[User talk:Daniel Mietchen|talk]]) </font> 05:22, 13 December 2014 (UTC)
+
+== Six degrees of separation ==
+
+Hello Pat. I was delighted to read the Signpost draft and realise that your work had touched on Sterne (whose lesser novel ''Travels'' inspired a C19 writer I'm fond of). I just love how Wikipedia joins up knowledge. [[User:Roberta Wedge (WMUK)|Roberta Wedge (WMUK)]] ([[User talk:Roberta Wedge (WMUK)|talk]]) 13:12, 9 December 2014 (UTC)
+
+==Yo Ho Ho==
+<div style="border-style:solid; border-color:blue; background-color:AliceBlue; border-width:1px; text-align:left; padding:8px;" class="plainlinks">[[File:Trialeti silver cup.JPG|250x100px|right]] [[File:Animal headed shallow bowl.jpg||150x100px|left]]
+
+''[[User:WereSpielChequers|<span style="color:DarkGreen">Ϣere</span>]][[User talk:WereSpielChequers|<span style="color:DarkRed">Spiel</span>]]<span style="color:#CC5500">Chequers''</span> is wishing you [[Wikipedia:WikiLove|Seasons Greetings]]! Whether you celebrate your hemisphere's [[Solstice]] or [[Christmas]], [[Diwali]], [[Hogmanay]], [[Hanukkah]], [[Lenaia]], [[Festivus]] or even the [[Saturnalia]], this is a special time of year for almost everyone! <br />
+
+<small>Spread the holiday cheer by adding {{[[WP:SUBST|subst]]:[[User:WereSpielChequers/Dec14c]]}} to your friends' talk pages</small>.
+{{clear}}
+</div>
+
+== Bradford request for volunteers ==
+Saw this via a BBC news item:-
+http://www.bradford.gov.uk/bmdc/government_politics_and_public_administration/news/volunteers_sought_for_museums
+
+Thought it might be within the GLAM sphere. [[User:ShakespeareFan00|ShakespeareFan00]] ([[User talk:ShakespeareFan00|talk]]) 12:26, 13 January 2015 (UTC)
+:Many thanks! I'll definitely follow it up. [[User:PatHadley|PatHadley]] ([[User talk:PatHadley#top|talk]]) 13:26, 13 January 2015 (UTC)
+
+== Thanks ==
+
+Many thanks for opening this new world for me [[User:HassanEbeid|HassanEbeid]] ([[User talk:HassanEbeid|talk]]) 15:03, 15 January 2015 (UTC)
+
+==York memorial==
+Yes, it's not that I worked on the image, though of course everyone hates to see their work lost. But I think I can overcome that twinge of pain. It was just that the image you added was rather "weird" to look at, as it had some very odd visual 'artefacts', especially at the right (streaks of unreadable shapes); and the base of the sculpture seemed to floating in a void, which gave it a distinctly eerie look. Yes the image was in one sense more useful. It had more visual ''information'' in it, but of course that's not the principal purpose the picture serves in the article. Thanks for the information on other images. [[User:Paul Barlow|Paul B]] ([[User talk:Paul Barlow|talk]]) 11:27, 23 January 2015 (UTC)
+
+==Wizardry required==
+Yo maestro, I cannot for the life of my figure out why my new and exciting [[Humber ware]] page auto alphabetises to being under 'Y' in Category:Medieval_Ceramics. Enlightenment? [[User:Zakhx150|Zakhx150]] ([[User talk:Zakhx150|talk]]) 12:34, 12 February 2015 (UTC)
+:{{talk page stalker}} {{ping|Zakhx150}} That would be because of the [[Template:DEFAULTSORT]] at the bottom of the page, which currently sorts the page as "York Glazed Ware". [[User:Samwalton9|'''S'''am '''W'''alton]] ([[User talk:Samwalton9|talk]]) 12:37, 12 February 2015 (UTC)
+:: {{ping|Samwalton9}} Ah the old 'copy and paste' fail. Cheers chief. Enlightenment acquired. [[User:Zakhx150|Zakhx150]] ([[User talk:Zakhx150|talk]]) 12:40, 12 February 2015 (UTC)
diff --git a/Echo/tests/phpunit/includes/revision_txt/646792804.txt b/Echo/tests/phpunit/includes/revision_txt/646792804.txt
new file mode 100644
index 00000000..ab91a79c
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/646792804.txt
@@ -0,0 +1,70 @@
+{{User:ClueBot III/ArchiveThis
+|age=2160
+|archiveprefix=User talk:PatHadley/Archive
+|numberstart=1
+|maxarchsize=100000
+|header={{Automatic archive navigator}}
+|minkeepthreads=4
+|minarchthreads=1
+|format= %%i
+}}
+{{archives}}
+{{Signpost-subscription|right}}
+
+
+==Site I mentioned==
+http://www.theverge.com/2013/8/9/4607240/fall-asleep-to-the-sound-of-wikipedia [[User:Shiningroad|Shiningroad]] ([[User talk:Shiningroad|talk]]) 11:31, 22 November 2014 (UTC)
+:Thanks! [[User:PatHadley|PatHadley]] ([[User talk:PatHadley#top|talk]]) 12:36, 22 November 2014 (UTC)
+
+== This is a demo! ==
+
+Demoing the user talk page [[User:PatHadley|PatHadley]] ([[User talk:PatHadley#top|talk]]) 11:44, 22 November 2014 (UTC)
+
+== Fortitude & Frailty: Reading the Human Condition Edit-a-Thon ==
+
+{| style="border: 1px solid gray; background-color: #fdffe7;"
+|rowspan="2" valign="middle" |{{#ifeq:alt|alt|[[File:SHUmanities Barnstar.png|100px]]|[[File:SHUmanities Barnstar.png|100px]]}}
+|rowspan="2" |
+|style="font-size: x-large; padding: 0; vertical-align: middle; height: 1.1em;" | '''SHUmanities Barnstar'''
+
+|-
+|style="vertical-align: middle; border-top: 1px solid gray;" | On behalf of Sheffield Hallam University's Humanities Department, thank you for your tireless efforts during the [[Wikipedia:Meetup/Sheffield_1|Fortitude and Frailty Edit-a-thon]]. Your contribution to the day, on and offline, was exemplary! &mdash; [[User:Mhbeals|Mhbeals]] ([[User talk:Mhbeals|talk]]) 13:16, 24 November 2014 (UTC)
+|}
+
+== ''Signpost'' ==
+
+Hey Pat, thanks for writing the ''Signpost'' article, and I apologize for not replying before. As you might be able to glean from my contribs, I've entered graduate school and unfortunately don't have much extra time for Wikipedia. I delayed [[Wikipedia:Wikipedia_Signpost/2014-12-10/Op-ed|your article]] by a week as we already had a feature for this week, but it will run next week. With it being an [[op-ed]], you could make it into the first person if you'd like (rather then referring to yourself by your username). [[User:The ed17|Ed]]&nbsp;<sup>[[User talk:The ed17|[talk]]]&nbsp;[[WP:OMT|[majestic titan]]]</sup> 21:38, 6 December 2014 (UTC)
+:Just saw the post - thanks, great piece. I'd like to explore opportunities to get the York Museums Trust involved with a Wikidata-focused research project, the proposal for which I am currently [[:d:Wikidata:WikiProject Wikidata for research|drafting]] (see [http://blog.wikimedia.de/2014/12/05/wikidata-for-research-a-grant-proposal-that-anyone-can-edit/ this blog post] for background). --<font style="font-family:Monotype Corsiva; font-size:15px;"> [[User:Daniel Mietchen|Daniel Mietchen]] ([[User talk:Daniel Mietchen|talk]]) </font> 05:22, 13 December 2014 (UTC)
+
+== Six degrees of separation ==
+
+Hello Pat. I was delighted to read the Signpost draft and realise that your work had touched on Sterne (whose lesser novel ''Travels'' inspired a C19 writer I'm fond of). I just love how Wikipedia joins up knowledge. [[User:Roberta Wedge (WMUK)|Roberta Wedge (WMUK)]] ([[User talk:Roberta Wedge (WMUK)|talk]]) 13:12, 9 December 2014 (UTC)
+
+==Yo Ho Ho==
+<div style="border-style:solid; border-color:blue; background-color:AliceBlue; border-width:1px; text-align:left; padding:8px;" class="plainlinks">[[File:Trialeti silver cup.JPG|250x100px|right]] [[File:Animal headed shallow bowl.jpg||150x100px|left]]
+
+''[[User:WereSpielChequers|<span style="color:DarkGreen">Ϣere</span>]][[User talk:WereSpielChequers|<span style="color:DarkRed">Spiel</span>]]<span style="color:#CC5500">Chequers''</span> is wishing you [[Wikipedia:WikiLove|Seasons Greetings]]! Whether you celebrate your hemisphere's [[Solstice]] or [[Christmas]], [[Diwali]], [[Hogmanay]], [[Hanukkah]], [[Lenaia]], [[Festivus]] or even the [[Saturnalia]], this is a special time of year for almost everyone! <br />
+
+<small>Spread the holiday cheer by adding {{[[WP:SUBST|subst]]:[[User:WereSpielChequers/Dec14c]]}} to your friends' talk pages</small>.
+{{clear}}
+</div>
+
+== Bradford request for volunteers ==
+Saw this via a BBC news item:-
+http://www.bradford.gov.uk/bmdc/government_politics_and_public_administration/news/volunteers_sought_for_museums
+
+Thought it might be within the GLAM sphere. [[User:ShakespeareFan00|ShakespeareFan00]] ([[User talk:ShakespeareFan00|talk]]) 12:26, 13 January 2015 (UTC)
+:Many thanks! I'll definitely follow it up. [[User:PatHadley|PatHadley]] ([[User talk:PatHadley#top|talk]]) 13:26, 13 January 2015 (UTC)
+
+== Thanks ==
+
+Many thanks for opening this new world for me [[User:HassanEbeid|HassanEbeid]] ([[User talk:HassanEbeid|talk]]) 15:03, 15 January 2015 (UTC)
+
+==York memorial==
+Yes, it's not that I worked on the image, though of course everyone hates to see their work lost. But I think I can overcome that twinge of pain. It was just that the image you added was rather "weird" to look at, as it had some very odd visual 'artefacts', especially at the right (streaks of unreadable shapes); and the base of the sculpture seemed to floating in a void, which gave it a distinctly eerie look. Yes the image was in one sense more useful. It had more visual ''information'' in it, but of course that's not the principal purpose the picture serves in the article. Thanks for the information on other images. [[User:Paul Barlow|Paul B]] ([[User talk:Paul Barlow|talk]]) 11:27, 23 January 2015 (UTC)
+
+==Wizardry required==
+Yo maestro, I cannot for the life of my figure out why my new and exciting [[Humber ware]] page auto alphabetises to being under 'Y' in Category:Medieval_Ceramics. Enlightenment? [[User:Zakhx150|Zakhx150]] ([[User talk:Zakhx150|talk]]) 12:34, 12 February 2015 (UTC)
+:{{talk page stalker}} {{ping|Zakhx150}} That would be because of the [[Template:DEFAULTSORT]] at the bottom of the page, which currently sorts the page as "York Glazed Ware". [[User:Samwalton9|'''S'''am '''W'''alton]] ([[User talk:Samwalton9|talk]]) 12:37, 12 February 2015 (UTC)
+:: {{ping|Samwalton9}} Ah the old 'copy and paste' fail. Cheers chief. Enlightenment acquired. [[User:Zakhx150|Zakhx150]] ([[User talk:Zakhx150|talk]]) 12:40, 12 February 2015 (UTC)
+:::Well that was a very relaxing way to sort out a query. :) Cheers {{ping|Samwalton9}}! [[User:PatHadley|PatHadley]] ([[User talk:PatHadley#top|talk]]) 13:08, 12 February 2015 (UTC)
diff --git a/Echo/tests/phpunit/includes/revision_txt/647258025.txt b/Echo/tests/phpunit/includes/revision_txt/647258025.txt
new file mode 100644
index 00000000..cfb39a8e
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/647258025.txt
@@ -0,0 +1,473 @@
+<div style="margin-bottom: 4.25em; position: absolute; bottom: -5em; right: 1em; "><div style="font-style: roman; background-color: #CBEBFF; font-weight:bold; border: 1px steelblue solid; color:black; padding:5px 5px">Please sign your message.</div></div>
+{{Statustop|offset=250}}
+{{administrator topicon|icon_nr=3}}
+{{Online Ambassador}}
+<!-- {{Attempting wikibreak|[[User:Kudpung|Kudpung]]| sometime|I}}
+ -->
+{{editnotice
+| header = Hi, welcome to my talk page!
+| headerstyle = font-size: 150%; color: #9900FF; font-family: 'Copperplate Gothic Light'
+| text =
+*I make plenty of errors - if you are here to complain about a tag, a warning, a deletion, or a block, please [[WP:AGF|'''assume good faith''']].
+*If I ''have'' erred, don't hesitate to tell me, but being '''rude''' will [[WP:BAIT|get you nowhere]].
+*If ''you'' have erred, chances are I'll help you get round it and over it, but [[WP:GAME|'''I don't suffer fools gladly''']] ;)
+*'''Please''' <span class="plainlinks">[http://en.wikipedia.org/w/index.php?title=User_talk:Kudpung&action=edit&section=new click here]</span> '''to leave a new message'''.
+[[Image:Crystal Clear app clock.svg|25px]] On line now? It is '''{{#time:g:i A|{{CURRENTHOUR}}:{{CURRENTMINUTE}} {{#if:{{{1|}}}|{{{1}}}|+7}} hours}}''' where this user lives near [[Udon Thani]], '''Thailand'''
+| textstyle = font-size: 100%; color: #555555; background-color: #DDDDDD
+| image = [[File:Nuvola apps edu languages.svg]]
+| textstyle = font-size: 100%; color: #555555; background-color: #DDDDDD
+| image = [[File:Nuvola apps edu languages.svg]]
+}}
+{{collapsetop|Archives}}
+{{archive box|auto=no|search=yes|style=background-color:lightBlue; border:1px solid black;|
+{{flatlist}}
+2006-2009
+*[[/Archive 1|Start - Jun 2009]]
+*[[/Archive 2|July-Aug]]
+*[[/Archive Aug 2009|Aug]]
+*[[/Archive Aug - Dec 2009|Sep - Dec]]
+*<hr>
+2010
+*[[/Archive Jan 2010|Jan]]
+*[[/Archive Feb 2010|Feb]]
+*[[/Archive Mar 2010|Mar]]
+*[[/Archive Apr 2010|Apr]]
+*[[/Archive May 2010|May]]
+*[[/Archive Jun 2010|Jun]]
+*[[/Archive July 2010|Jul]]
+*[[/Archive Aug (1) 2010|Aug]]
+*[[/Archive Sep 2010|Sep ]]
+*[[/Archive Oct 2010|Oct]]
+*[[/Archive Nov 2010|Nov]]
+*[[/Archive Dec 2010|Dec]]
+*<hr>
+2011
+*[[/Archive Jan 2011|Jan]]
+*[[/Archive Feb 2011|Feb]]
+*[[/Archive Mar 2011|Mar]]
+*[[/Archive Apr 2011|Apr]]
+*[[/Archive May 2011|May]]
+*[[/Archive Jun 2011|Jun]]
+*[[/Archive Jul 2011|Jul]]
+*[[/Archive Aug 2011|Aug]]
+*[[/Archive Sep 2011|Sep]]
+*[[/Archive 01-15 Oct 2011|01-14 Oct]] • [[/Archive 15-30 Oct 2011|15-30 Oct]]
+*[[/Archive Nov 2011|Nov]]
+*[[/Archive Dec 2011|Dec]]
+*<hr>
+2012
+*[[/Archive Jan 2012|Jan]]
+*[[/Archive Feb 2012|Feb]]
+*[[/Archive March-June 2012|Mar-Jun]]
+*[[/Archive Jul 2012|Jul]]
+*[[/Archive Aug 2012|Aug]]
+*[[/Archive Sep 2012|Sep]]
+*[[/Archive Oct 2012|Oct]]
+*[[/Archive Nov 2012|Nov]]
+*[[/Archive Dec 2012|Dec]]
+*<hr>
+2013
+*[[/Archive Jan 2013|Jan]]
+*[[/Archive Feb 2013|Feb]]
+*[[/Archive Mar 2013|Mar]]
+*[[/Archive Apr 2013|Apr]]
+*[[/Archive May 2013|May]]
+*[[/Archive Jun 2013|Jun]]
+*[[/Archive Jul 2013|Jul]]
+*[[/Archive Aug 2013|Aug]]
+*[[/Archive Sep 2013|Sep]]
+*[[/Archive Oct 2013|Oct]]
+*[[/Archive Nov 2013|Nov]]
+*[[/Archive Dec 2013|Dec]]
+*<hr>
+2014
+*[[/Archive Jan 2014|Jan]]
+*[[/Archive Feb, Mar, Apr, May 2014|Feb, Mar, Apr, May]]
+*[[/Archive Jun 2014|Jun]]
+*[[/Archive Jul 2014|Jul]]
+*[[/Archive Aug 2014|Aug]]
+*[[/Archive Sep 2014|Sep]]
+*[[/Archive Oct 2014|Oct]]
+*[[/Archive Nov 2014|Nov]]
+*[[/Archive Dec 2014|Dec]]
+*<hr>
+2015
+*[[/Archive Jan 2015|Jan]]
+{{endflatlist}}
+}}
+{{collapsebottom}}
+{{messagebox|'''NOT even in semi-retirement, but I am only very sporadically available for the time being. I may throw in the occasional edit, but I cannot for the moment get involved in issues that would require my undivided attention, or participation in anything over a number of consecutive days. Thanks.'''
+}}
+== Final warning on Awesomeninja's talk page ==
+
+Hi Kudpung,
+
+I noticed that you put a final warning for disruption on Awesomeninja's talk page. While I must admit that I vehemently despise "cool teen talk", it's my understanding that a final warning was only to be used ''after'' several warnings had been previously issued, ''or'' when a first instance of vandalism is so gross and severe that it deserves an almost immediate block. I don't see any previous warnings on Awesomeninja's talk page, and I hardly think that a NOTNOW RfA is such a severe offense to require a final warning right off the bat. --[[User:Biblioworm|<span style="color:#6F4E37;">'''''Biblio'''''</span>]][[User_talk:Biblioworm|<span style="color:#6F4E37;">'''''worm'''''</span>]] 15:36, 31 January 2015 (UTC)
+:That's your opinion, {{U|Biblioworm|}}. I have been around in life and on Wikipedia a long time and I use my judgement ''very'' carefully and do a lot of research before I do anything or criticise anyone's work or actions. I helped rewrite and develop many of the warning templates - I think I understand the guidelines for their use. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:23, 1 February 2015 (UTC)
+::Thanks for your reply, but it does not seem to directly address the point. This is the description for the level 4 template: "Assumes bad faith; strong cease and desist, last warning". How is a newbie (presumably unaware of what admins really are) filing a NOTNOW RfA editing in bad faith? Isn't it policy that users should [[WP:AGF|assume good faith]] unless there is a very good reason not to? Besides, three users (myself included) messaged the user in almost immediate succession after he transcluded his RfA. I think three rapid-fire messages and a speedy deletion notice was enough to get the point across. In any case, I have no desire to argue, so I won't say any more. --[[User:Biblioworm|<span style="color:#6F4E37;">'''''Biblio'''''</span>]][[User_talk:Biblioworm|<span style="color:#6F4E37;">'''''worm'''''</span>]] 00:51, 1 February 2015 (UTC)
+:::It does address the point because it states: ''do a lot of research before I do anything or criticise anyone's work or actions''. That's good advice for anyone, particularly users who have been around for only a relatively short time and start criticising the work of admins who, contrary to what you may have been led to believe, are ''not'' all bad, do ''not'' all misuse their tools, and do ''not'' all apply poor judgement. [[WP:IAR|Experience is the key]]. Now let's both get back to work, {{U|Biblioworm|}}. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:59, 1 February 2015 (UTC)
+
+== The RfC for AfC reviewer requirement ==
+
+Hey Kudpung, is there any new information on that? I don't think I was actually around when it happened (oops) but... yeah... where can I find the infos...? Thanks! <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 01:47, 1 February 2015 (UTC)
+
+Hi {{U|Kikichugirl}}. It was based on two RfC that I started. One was for a requirement for qualifications, followed up with one to establish the actual requirement and enact it. Both were carried by consensus. It's all history now.
+*[[Wikipedia:WikiProject Articles for creation/RfC Reviewer permission]]
+*[[Wikipedia:WikiProject Articles for creation/RfC for AfC reviewer permission criteria]]
+There was another one proposed by {{U|Anne Delong}} which was an attempt to get the imp;ementation sharpened up, but although I supported it, the RfC was not heavily subscribed:
+*[[Wikipedia:WikiProject Articles for creation/RfC for AfC reviewer permission implementation]]
+That said, we have reached the stage now where the technical implementation needs to be seriously reviewd, or to implement the consensus of April last year to scrap AfC and either replace it with a software package similar to that of NPP, or to merge the whole process to NPP entirely. I support both proposals wholeheartedly and the community just needs to decide which one they want. The problem we are currently faced with is that AfC has become a battleground for volunteer programmers vying for first place, and is fast turning into a walled garden. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 02:10, 1 February 2015 (UTC)
+:Thanks. I might be elitist or have high standards, but the dubious reviews I've seen today, from several users, make me want to quit the project and cry instead... we definitely need to fix up the criteria. <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 08:24, 1 February 2015 (UTC)
+::{{U|Kikichugirl}} check out the current discussion at [[WT:AFC]], and if you can, provide diffs for the poor reviews, something is going to break soon if DGG and I can convince the stone wallers at AfC that someting needs to be done. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:30, 1 February 2015 (UTC)
+:::I've seen it. My question is: Why is AfC so complicated? When I did NPP, I felt myself getting increasingly bitey (I'm increasingly lenient at AfC) but AfC is starting to seem like a mess of blah. If there's a bad patrol at NPP, you stick the CSD tag on right where someone else didn't see it. If there's a bad review, then you gotta revert the review, confuse the newbie, and badness all around. Ugh. <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 08:34, 1 February 2015 (UTC)
+::::{{tps}} - One particularly bad review I can think of is here: [[Brad Craddock]]. The reviewer declined it as "unnotable" when the topic clearly passes [[WP:ATHLETE]] and [[WP:GNG]]. It was written like an advertisement but extensive copyeditting turned it into a viable article. It's going to be shown on the Main Page (DYK) in a few days. AfC reviewers have a lot of power in their hands: In many cases, you can either uplift or destroy the spirit of a newbie and their willingness to contribute to Wikipedia. A bad review and a new editor may never want to come back or they get deep misconceptions about Wikipedia. To tell you the truth, the Brad Craddock, article made me rather sad. [[User talk:Wikifanman37#Brad Craddock article|I had to go into full damage control]]. --'''[[User:Ceradon|ceradon]]''' ([[User talk:Ceradon|<font color="#036">talk</font>]] • [[Special:Contributions/Ceradon|<font color="#036">contribs</font>]]) 08:42, 1 February 2015 (UTC)
+{{od}}{{U|Ceradon}}. {{U|Kikichugirl}}. I can only reiterate that AfC is only a very tiny project when compared with the workload at NPP which is a serious vetting process and not a cosy little hobby for some who want to save a handfull of crap articles every day. Sure, the quality of patrolling at NPP is lousy, and it will remain so until the community stops refusing to believe that we need some criteria of competency for patrollers . --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:52, 1 February 2015 (UTC)
+* {{Tps}} I support scrapping AfC and merging it into NPP or replacing it with and extension/guidedTour replacement as well. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 16:42, 1 February 2015 (UTC)
+::In which case {{U|Technical 13}}, you've done yourself and us a misfavour by voting as you did [[Wikipedia:WikiProject Articles for creation/RfC to physically restrict access to the Helper Script|here]]. Scrapping AfC is the obvious solution but before we get there we have to prove to the community that AfC is not working in its present concept. History has shown that on Wikipedia, little changes lead to bigger ones. This would have been a valuable stepping stone, and still can be if you would reconsider. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 17:58, 1 February 2015 (UTC)
+::* [[Special:Diff/645188517|Fair enough]]. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 18:11, 1 February 2015 (UTC)
+* I am not against ''merging'' the AfC and NPP processes, but the reason I have support AfC for now is, as Kudpung says, due to bad patrolling at NPP. Some NPPers (eg: Mr X, WikiDan61, RandyKitty, SL93) do good work, but there is still [[WP:BITE]]ing going on, so I really think that if we want to put up a hard barrier to reviewing new articles, we apply it consistently across the board. I have some shortcuts on my userpage to check articles nominated for CSD, particularly A7 and G11, and try and salvage anything that I can where possible. ([https://en.wikipedia.org/w/index.php?title=Köpenicker_Blues_und_Jazz_Festival&diff=645333548&oldid=645294851 example]) However, where I can't I consistently see confused newbies who don't understand why their work will be deleted. As long as a reasonable explanation is given, ideally suggesting another article or website where some of the content could go, is a better approach. Unfortunately it's a more time consuming one. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 18:04, 2 February 2015 (UTC)
+::I can't argue with that, {{U|Ritchie333|Ritchie}}. That's why it's a total paradox that NPPers don't require any qualifications at all. They refuse to read what instructions there are (the ones {{U|Scottywong}} and I wrote at [[WP:NPP]]), rarely make use of the handwritten note feature of the curation tool, and never move an article to Draft namespace. That said, in a way, AfC and NPP are almost identical processes with NPP being by far the most important of the two. Merging would be ideal if the regular experienced AfC reviewers would migrate with the move. That way, we would have the best of both worlds. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 23:09, 2 February 2015 (UTC)
+:::I'm going to start moving stuff to draft ([[Draft:Le Trouble (musician)|first example]]) and see if takes up. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 17:17, 3 February 2015 (UTC)
+
+== Buster7 ==
+
+Hello there. I would appreciate it of you could keep me informed of the case I buster7. I would appreciate it if there could be a sutiable warning for violation rules and his extra rights as a rollbacker. How could there be an accidental rollback? Thank you very much[[User:TheMagikCow|TheMagikCow]] ([[User talk:TheMagikCow|talk]]) 14:55, 1 February 2015 (UTC)
+
+:Hi {{U|TheMagikCow|Magic Cow}} It's a very strict rule that editors should not refactor, re-edit, or remove anything from other users' talk pages or user pages. It is in fact quite easy to click a Rollback button by mistake, that's why we're so strict about handing out Rollback rights. In view of the events of earlier today (or tonight according to wherever you are) {{U|Buster7}} could have every reason to take a swipe at one of my edits. It would be a huge coincidence if it were an accident, but I guess we have to stretch the rubber band of AGF and presume it was. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:14, 1 February 2015 (UTC)
+
+== RfC: AfC Helper Script access ==
+
+An RfC has been opened at [[Wikipedia:WikiProject Articles for creation/RfC to physically restrict access to the Helper Script|RfC to physically restrict access to the Helper Script]]. You are invited to comment. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 18:09, 1 February 2015 (UTC)
+
+== A barnstar for you! ==
+
+{| style="background-color: #fdffe7; border: 1px solid #fceb92;"
+|rowspan="2" style="vertical-align: middle; padding: 5px;" | [[File:Brilliant Idea Barnstar Hires.png|100px]]
+|style="font-size: x-large; padding: 3px 3px 0 3px; height: 1.5em;" | '''The Brilliant Idea Barnstar'''
+|-
+|style="vertical-align: middle; padding: 3px;" | For all your work with AfC reform. <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 00:02, 2 February 2015 (UTC)
+|}
+;Thank you ! --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:56, 2 February 2015 (UTC)
+
+== WP:ER ==
+
+You're always welcomed at [[WP:RETENTION]] -- [[User:GoodDay|GoodDay]] ([[User talk:GoodDay|talk]]) 03:18, 2 February 2015 (UTC)
+
+== Shane Ferguson ==
+
+Hello, could you please semi-protect [[Shane Ferguson]] as it's getting a lot of disruptive editors at the moment. Thanks, [[User:JMHamo|JMHamo]] ([[User talk:JMHamo|talk]]) 00:59, 3 February 2015 (UTC)
+:{{done}} --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 01:03, 3 February 2015 (UTC)
+
+== Paracommunications ==
+
+Hi Kudpung
+
+I don't understand your reasons for proposing deletion of my Paracommunications entry. Please would you explain, as this is my first entry to Wikipedia. What does dicdef mean? And, how should I edit this entry so it is not deleted. Thank you.
+
+David <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Batmanolan|Batmanolan]] ([[User talk:Batmanolan|talk]] • [[Special:Contributions/Batmanolan|contribs]]) 03:28, 3 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+:Hi {{U|Batmanolan|David}}. Well, Wikipedia is an encyclopedia and not a dictionary. There is a very big difference (dicdef = dictionary definition). That said, the page will not be suitable for Wikipedia at all, even the more so that the word is not to be found anywhere else. You could try publishing it at [[Wiktionary]] which is a Wikimedia web site., but although [[Wiktionary]] is in the same group, we here don't work there. Regards, --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]])
+
+Done, thanks for the tip. Please feel free to delete, now. <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Batmanolan|Batmanolan]] ([[User talk:Batmanolan|talk]] • [[Special:Contributions/Batmanolan|contribs]]) 03:52, 3 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+== Edit summary usage ==
+Hi Kudpung! I just need some advice. Is it okay to use words like "Fu*k off" in edit summaries when directing other users? Isn't it violates our core policy, [[WP:CIVILITY]]? Today, I came across an editor who often uses those words in edit summaries. See [[Special:Diff/645405716|this]]. When I asked him not to use such words, he said [[Special:MobileDiff/645410610|this]]. It is not the first time he is using profanity when talking about other fellow editors. [[Special:MobileDiff/642443657|Here]] some one warned him too when he said someone a "miserable shit". You will get to see more such things in his talk page history and elsewhere. I think it's time for an admin to step in and warn. What you think? '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 06:17, 3 February 2015 (UTC)
+
+:It's ''never'' alright to use such language either on edit summaries or anywhere else. But remember, I am very old fashioned and come from a British background where such language was never used. It might be more modern and more tolerated nowadays, but I don't really think it is, and it's certainly not the kind of language that should be used on Wikipedia. I looked at the edit history and it seems you may have done something wrong but I guess it wasn't intentional. I very much liked one comment of yours I came across (I seem to have seen something very similar before...), you should use it more often, but carefully of course, and only if you are sure that the person is a child (well, under 18 or so). I made myself a golden rule many years ago: always check out an editor's user page before you hit them with anything. If the page looks like a teenager's bedroom wall, chances ar that they are a teenager (or even younger), but on the other hand, while there are lots of children who act like mature adults on Wikipedia, there are lots of adults who behave like children ;) Keep up the good work, {{U|Jim Carter|Jim}}! --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 06:38, 3 February 2015 (UTC)--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 06:38, 3 February 2015 (UTC)
+::Yes, indeed. I strongly condemn the use of such language on Wikipedia. Actually, I don't know what exactly happened but I guess his comment was removed due to an edit conflict. His behavior was so childish that I didn't have to check his user page. Anyway, thank you. I'm just trying to follow your commands :) Cheers, '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 10:06, 3 February 2015 (UTC)
+
+:::{{u|Jim Carter|Jim}} - Your comment had gone from polite to and I quote "''This is not a playground for kids. You're here to build an encyclopedia, why don’t you just grow up and behave as if you are working on the world’s biggest single source of information? A huge number of users are much older than you might think. Try to give others respect in talk pages as well as in edit summaries'' - How do you expect me to react?,
+:::Had you left it at the section where you said you disagreed with my use of words I'd of been more than happy to apologize, As for my "miserable shit" comment elsewhere ... I realized I was wrong and had removed it[https://en.wikipedia.org/w/index.php?title=Wikipedia:Requests_for_adminship/Titodutta&diff=642463191&oldid=642449018] so it's not really relevant here<br>
+:::Sorry Kudpung for barging in here hope you don't mind :) –[[User:Davey2010|<span style="color: blue;">'''Davey'''</span><span style="color: orange;">'''2010'''</span>]]<sup>[[User talk:Davey2010|<span style="color: navy;">'''Talk'''</span>]]</sup> 10:31, 3 February 2015 (UTC)
+
+::::Hi {{U|Davey2010|Davey}}. I don't really mind - if it helps clear the air. However, '' "This is not a playground for kids. You're here to build an encyclopedia, why don’t you just grow up and behave as if you are working on the world’s biggest single source of information? A huge number of users are much older than you might think." '' is is a brilliant statement if used wisely and one I would recommend being used more often by young editors who are concerned about the crap and strife caused by other young editors. Someone like me though, and an admin to boot, would get shot down in flames as a child hater if we said it. Even the word ''children'' is considered taboo on Wikipedia - by the children of course. You're probably not aware of it yet, but as one of the most regular contrubutors to [[WP:WER]] I have retired from that project - namely due to the antics of some younger editors and three or four adults who behave like kids a lot of the time. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:48, 3 February 2015 (UTC)
+
+:::::Hiya Kudpung, I agree with the statement providing its used wisely, Everyone knows I'm the least patient/short tempered person here so It was obvious saying something like that would tick me off easily,
+:::::I've not really dealt with any kids really but then again you're alot more active in other areas like NPP etc :)
+:::::When you overwritten my comment twice, Being very confused and without thinking I simply asked myself "what I stated in the edit summary" ...
+:::::Anyway I apologize to both Kudpung and to {{u|Jim Carter|Jim}} if they were offended/upset - Despite it may not seem like it at times - It's never my intention to offend or upset anyone,
+:::::Life's too short to start arguments & all that :)
+:::::Anyway I admit I shouldn't of said it and I sincerely apologize,
+:::::Thanks –[[User:Davey2010|<span style="color: blue;">'''Davey'''</span><span style="color: orange;">'''2010'''</span>]]<sup>[[User talk:Davey2010|<span style="color: navy;">'''Talk'''</span>]]</sup> 13:08, 3 February 2015 (UTC)
+
+== Little experience ==
+
+She ([[Kristin Sutton]]) doesn't look like she needs a wiki page. And who said I had little experience? It sounds like you're saying I'm dumb. --[[User:Satouyoukun|Satouyoukun]] ([[User talk:Satouyoukun|talk]]) 13:54, 3 February 2015 (UTC)
+:{{U|Satouyoukun}}, I am saying that with only 182 edits to the encycolpedia pages and wthout having read and thoroughly understood our deletion policies, you are not ready to be doing such maintenance tasks. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 14:02, 3 February 2015 (UTC)
+
+== You mentioned HJ mitchen ==
+
+http://theralphretort.com/wikipedia-blocks-veteran-editor-for-being-pro-gamergate-off-site-1715/ Check this article please <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:IntelligenceMonkey|IntelligenceMonkey]] ([[User talk:IntelligenceMonkey|talk]] • [[Special:Contributions/IntelligenceMonkey|contribs]]) 14:13, 3 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+::So what? And who are you, if I may ask? I do not take any notice of any crap that is written about Wikipedia on other websites. Also I have every confidence in the adminstrative acts and decisions of {{U|HJ Mitchell}}. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 14:21, 3 February 2015 (UTC)
+::::Oh yes, the block was based completely on something he said somewhere else on the Internet and on a site I don't even read. It wouldn't have anything at all to do with the [[Special:Contributions/Xander756|series of nasty BLP violations and personal attacks]]! ;) [[User:HJ Mitchell|<font color="Teal" face="Tahoma">'''HJ&nbsp;Mitchell'''</font>]] &#124; [[User talk:HJ Mitchell|<font color="Navy" face= "Times New Roman">Penny for your thoughts? </font>]] 14:37, 3 February 2015 (UTC)
+
+== Problematic new page patroller ==
+
+Kudpung,
+
+You, I, and about five other editors have cautioned [[User:Kges1901|Kges1901]] that he or she is making serious mistakes patrolling and speedying new pages. I just noticed another incorrect speedy nom on [[Yashvardhan Shukla]] (I converted it to an AfD). Obviously the cautions have not gotten through—do you know what the next step should be?
+
+Thanks!—[[User:Neil P. Quinn|Neil P. Quinn]] ([[User talk:Neil P. Quinn|talk]]) 16:58, 3 February 2015 (UTC)
+
+Sorry, but wasn't the page previously deleted using the same cause because a nomination by me? and wasn't it also exactly the same content on the page? I tried my best after reading the cautions to not make any mistakes, but... [[User:Kges1901|Kges1901]] ([[User talk:Kges1901|talk]]) 21:18, 3 February 2015 (UTC)
+:{{ping|Neil P. Quinn}}. The problem with {{U|Kges1901}}'s patrolling is that he has been asked by an administrator to stop patrolling but in defiance of the request he is continuing to do so. It took me nearly an hour this morning to check his last 100 or so patrolls and while most of them are OK the accuracy rate is still too low. Thus the issue is not whether or not his patrols are accurate but the enormous work he is creating for admins and other editors in having to check his work. His editing history shows that he cannot normaly have accumulated sufficient experience for this type of work. The alternatives are that he either stops patrolling, or it will be discussed at ANI with a risk of him being blocked or at least T-banned from patrolling. Perhaps however, a couple more warnings may do the trick-. -[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:27, 4 February 2015 (UTC)
+
+* {{ping|Kges1901}} now that you mention it, I see that [[Yashvardhan Shukla]] [https://en.wikipedia.org/w/index.php?title=Special:Log&page=Yashvardhan+Shukla was speedy deleted before], but if the content was the same, I would also consider that deletion incorrect. The problem is that the criterion you used, [[WP:A7|A7]], is for pages that don't make a "[[WP:credible claim of significance|credible claim of significance]]." That page does: it claims that Shukla is significant because he published a novel at age 13, which is certainly credible (young authors ''do'' exist) and could theoretically make him notable (the author actually included a link to [http://www.outlookindia.com/news/article/13YrOld-Yashwardhan-Shukla-Pens-Gods-of-Antarctica/857080 a profile of him in a national magazine]). I around five minutes searching for other sources to check whether he was actually notable, and decided he wasn't—but I had to use [[Wikipedia:Articles for deletion|articles for deletion process]] because it didn't meet any of the speedy deletion criteria. There's a good reason for this—if it doesn't meet the criteria, it's worth using AfD, which takes more time but makes more sure that we didn't miss any reasons to keep the article.
+:Also, Kges, one of the reasons I was concerned was that you didn't seem interested in talking to any of the people who cautioned you so you could learn more about how to avoid mistakes. I feel a bit better since you responded here. I'd advise you to be '''much''' more careful, read the [[Wikipedia:Criteria for speedy deletion|guidelines for speedy deletion]] very carefully, and above all, ask someone like me or Kupung for advice if you have ''any'' doubts about whether an article can be speedy deleted. This will allow you to keep contributing to the encyclopedia without creating unnecessary work for other editors.—[[User:Neil P. Quinn|Neil P. Quinn]] ([[User talk:Neil P. Quinn|talk]]) 21:34, 4 February 2015 (UTC)
+::{{reply to|Neil P. Quinn}} - again apologies for barging in here. Just wanted to say something in regards to: "didn't seem interested in talking to any of the people who cautioned you". I am often accused of the same wiki-crime, so I am wondering if you may be interested in my perspective? [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:21, 6 February 2015 (UTC)
+Sorry for barging in. As someone who has lost countless articles to [[wp:CSD]]s, I always assumed that it is the admin's job to make sure that articles they are deleting are being deleted for the right reason. Is my assumption correct ? [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:05, 4 February 2015 (UTC)
+:In theory, yes. At least that's what *I* do - and willingly too because I like to catch those clueless patrollers and bend them over my knee. That said, even if some sloppy admins do not check what they are deleting, there's always Delrev where anything worth keeping is generally refunded without much fuss. More difficult of course if the deletion was on a community consensus at XfD. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 16:29, 4 February 2015 (UTC)
+::Thanks for responding, Kudpung. I am just wondering if there are statistics kept somewhere about the number of "sloppy admins do not check what they are deleting"? [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:25, 6 February 2015 (UTC)
+
+:::I doubt it, {{U|Ottawahitech}}. I can't see how it would be possible to extract suc a statistic. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:45, 6 February 2015 (UTC)
+
+:::: A good place to start would be on my own talkpage :-) [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:55, 7 February 2015 (UTC)
+
+== [[King's Norton Boys' School]] ==
+
+Hi,
+In response to the message you sent me the only thing I have added is the school logo change, and a picture of the head for the news sake. If these are against the rules that you sent me I will gladly change the box to meet the required expectations of a schools Wikipedia Page. The whole page has been restored, is there a huge problem with adding texts of information. I understand the quotes but why can't there be other history, details about the curriculum. Also the motto box was already there, so why is it removed.
+
+Thanks
+James Byford <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Ja5by101|Ja5by101]] ([[User talk:Ja5by101|talk]] • [[Special:Contributions/Ja5by101|contribs]]) 19:30, 4 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+:{{U|Ja5by101}} Hi James. I don't think the photo is appropriate, Wikipedia is not a news site and such content gets quickly out of date. It would be good if you could restore the original formal school logo. I have also removed some text from the article but I can't remember if it was added by you. You are most welcome to continue to expand the article but do check out [[WP:WPSCH]] first. I am the coordinator there so if you have any questions don't hesitate to contact me. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 19:41, 4 February 2015 (UTC)
+
+::Hi yes sorry for the inconvenience. I currently go to the school and they have changed the logo to the one I have put on there. The reason why I put the news on there is because I was planning on updating it. I will remove the content. Also the school motto, is that aloud to be put back up? I am really really sorry. Thanks for Your Help
+James <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Ja5by101|Ja5by101]] ([[User talk:Ja5by101|talk]] • [[Special:Contributions/Ja5by101|contribs]]) 19:44, 4 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+:::Don't worry James, I have restored everything the way it should be. By all means add the motto to the motto section in the infobox, but preferably don't add any content to the article body before asking me first if you are not sure. Do check out [[WP:WPSCH/AG]] too - you'll soon get the hang of things and you'll soon be improving other articles. Make yourself a user page too. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 20:13, 4 February 2015 (UTC)
+
+
+Thank you so much for your help, I actually really appreciate things and I am sincerely sorry for the inconvience I have caused for you! I will add the motto but I shall not add anything else as it does cause an inconvenience and I can understand why the changes were made now and I do appreciate it!
+
+Thank you so much again!
+James
+
+[[User:Ja5by101|Ja5by101]] ([[User talk:Ja5by101|talk]] • [[Special:Contributions/Ja5by101|contribs]]) 20:17, 4 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+==RAN==
+
+Actually, proxying Mr. Norton's new starts is permitted under terms of his original sanction, as I recall, so long as the person moving the start into mainspace accepts full responsibility for any possible copyright violation it contains. The logical and obvious solution for the betterment of the encyclopedia is to get rid of his punitive topic ban against direct new creations, of course, but as long as CCI is hot and bothered about 10 year old copyvios that nobody can or will ever fix, that doesn't seem too likely either. It's a stupid situation. [[User:Carrite|Carrite]] ([[User talk:Carrite|talk]]) 06:40, 5 February 2015 (UTC)
+
+== ''The Signpost'': 04 February 2015 ==
+
+<div lang="en" dir="ltr" class="mw-content-ltr"><div style="-moz-column-count:2; -webkit-column-count:2; column-count:2;">
+{{Wikipedia:Wikipedia Signpost/2015-02-04}}
+</div><!--Volume 11, Issue 5-->
+<div class="hlist" style="margin-top:10px; font-size:90%; padding-left:5px; font-family:Georgia, Palatino, Palatino Linotype, Times, Times New Roman, serif;">
+* '''[[Wikipedia:Wikipedia Signpost|Read this Signpost in full]]'''
+* [[Wikipedia:Signpost/Single/2015-02-04|Single-page]]
+* [[Wikipedia:Wikipedia Signpost/Subscribe|Unsubscribe]]
+* [[User:MediaWiki message delivery|MediaWiki message delivery]] ([[User talk:MediaWiki message delivery|talk]]) 00:43, 6 February 2015 (UTC)
+</div></div>
+<!-- Message sent by User:LivingBot@enwiki using the list at http://en.wikipedia.org/w/index.php?title=Wikipedia:Wikipedia_Signpost/Tools/Spamlist&oldid=645566867 -->
+
+== Bitey? ==
+
+How about you try not to be, eh? [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 12:21, 6 February 2015 (UTC)
+:{{ping|Squinge}} No, not in the slightest. A bit direct maybe, but only with those who should know better. I don't bite newcomers. If you are trying to do maintenance tasks you are hardly a newcomer, so how about you [[WP:NPP|reading the instructions]] before you do anything and perhaps also talk page headers. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:40, 6 February 2015 (UTC)
+::I'm not doing NPP - its not a <s>fucking</s> new page! [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 12:41, 6 February 2015 (UTC)
+:::{{ping|Squinge}} Nobody, just nobody, uses language like that on ''my'' talk page and never has in 9 years. Read the instructions, in particular [[WP:CIVIL|these too]] and do not come here again - under an circumstances. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:49, 6 February 2015 (UTC)
+::::Apologies for the rude word, I withdraw it and I've struck it now. If you'd like to discuss the fact that you were wrong about it being a new page then I'll be happy to do so, or I'll never post here again (other than when mandatory) as you wish - just let me know. [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 12:55, 6 February 2015 (UTC)
+{{talkback|Squinge}}
+{{ygm}}
+
+== Help understanding a chart ==
+
+The most recent vote concerning RfA at VPR included a chart, the first one at [[Wikipedia:Village_pump_(proposals)/Archive_115#Time to replace RfA]]. Can you help me interpret the numbers? Have they been updated? - Dank ([[User talk:Dank|push to talk]]) 13:33, 6 February 2015 (UTC)
+:Hi {{U|Dank}}, how are you doin'? Nice to see you. I'm still not quite sure which chart you mean, but all the graphs and tables are pretty accurate. The discussion was only 3 months ago so not much will have changed since. Reading through it, I still stand by all my comments which, summa sumarum, is that RfA is now as good as it's ever going to get, doesn't need any major changes except perhaps for more consequent removal of inapropriate questions, votes, and comments, but it's a start. RfA is actually doing a good job, demonstrated by one candidate whom I dragged kicking and screaming to the process and who then skipped through it like a lamb through a field of buttercups. If you are thinking of starting a new reform campaign, you'll probably have my support, but I think we need to give RfA time now for people to realise that it's no longer the horrible & brioken process that I and Wales suggested it was four years ago, and we need to make more publicity for it. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 13:56, 6 February 2015 (UTC)
+::Oh ... wasn't thinking of starting an RfA reform discussion, I've got something else in mind, a followup to the current RfC at VPR on user-rights. Not disputing that the chart is accurate ... I just don't know what the numbers mean. Here it is. - Dank ([[User talk:Dank|push to talk]]) 14:21, 6 February 2015 (UTC)
+
+{| class="wikitable"
+! !!2008!!2009!!2010!!2011!!2012!!2013!!2014 (projected)
+|-
+
+!Active admins
+||943||870||766||744||674||633||570
+|-
+
+!Admin promotions
+||201||121||78||52||28||34||21
+|-
+
+!Admin attrition (actual, not net)
+||<span style="color:Red">263</span>||<span style="color:Red">194</span>||<span style="color:Red">182</span>||<span style="color:Red">74</span>||<span style="color:Red">98</span>||<span style="color:Red">75</span>||<span style="color:Red">85</span>
+|}
+
+Dank, do you by any chance mean any of the graphs or charts I uploaded from my Excel spreadsheet? I'm pretty sure I still have that spreadsheet if you want me to email it to you or something, just let me know. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 14:35, 6 February 2015 (UTC)
+:Thanks for your work on that, but I think if I can find out what the numbers above represent, I'm good. (I get what the middle row means.) - Dank ([[User talk:Dank|push to talk]]) 14:47, 6 February 2015 (UTC)
+
+{{ec}} {{U|Dank}}, most of these charts are created and maintained by {{U|WereSpielChequers}}. I don't find the figures particularly difficult to understand. Active admins are those who by some some silly criterion (not created by WereSpielChequers) that gives a totally false picture. IMO the actual number of truly active admins is about one tenth of that. Promotions is of course the actual number who passed an fA, and attrition is the total number lost through all kinds of desysoping. The projected number for 2014 was pretty accurate, in fact the actual number was 22. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 14:50, 6 February 2015 (UTC)
+:Agreed that it would be nice to have numbers that are based on a higher bar for activity ... do either of you happen to have numbers that reflect that? I'll ask WSC too. - Dank ([[User talk:Dank|push to talk]]) 15:01, 6 February 2015 (UTC)
+::{{U|Dank}}, I don't but anyone who knows how to run a regex through the actual admin action logs can soon find out. I would suggest that a truly active admin should be based on the uses of the admin tools over the previous 60 days, plus the number of edits to ANI over the same period and then divide by 2. If the answer is 40 or greater, then I would consider them as active, {{U|Scottywong}} used to be brilliant at pulling stats but he's gone AWOL as far as I can see. He did most of the stats for us at [[WP:RFA2011]]. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:14, 6 February 2015 (UTC)
+:::Thanks, I've asked WSC if he has numbers. - Dank ([[User talk:Dank|push to talk]]) 15:19, 6 February 2015 (UTC)
+
+== AfC ==
+
+Hi. You removed me from Articles for Creation participants list because you thought I was too inexperienced. When do I know if I am experienced enough? When I reach 1000 edits? Thanks. [[User:William2001|William2001]] ([[User talk:William2001|talk]]) 04:01, 7 February 2015 (UTC)
+:Well, {{U|William2001|William}} that's something else which you have misunderstood. If you had read the page before putting your name on it and my comments on your talk page you would have seen that 500 edits / 90 days are only a starting point and that more important is having sufficient experience that can't simply be measured by an edit count. We are shorly going to change the system and reviewers will have to request an admin to include them on the list just as we do for PC Reviewer, Rollbacker, and AWB user. I suggest that you might like to do some less complex maintenance tasks until the new system is up and running and make a new application then. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 05:27, 7 February 2015 (UTC)
+::OK. Thank you. [[User:William2001|William2001]] ([[User talk:William2001|talk]]) 16:39, 7 February 2015 (UTC)
+
+== Recreated ==
+
+Hi just letting you know that I have recreated the pre-speedy tag. This is for purpose of demonstration for the discussion started '''[[Wikipedia:Village_pump_(proposals)#Pre-Speedy_Deletion_tag|here]].''' Please know that until the discussion has ended I will not use the tag. If a consensus is not reached I will tag it for deletion myself - Thanks. [[User:Unit388|Unit388]] ([[User talk:Unit388|talk]]) 05:31, 7 February 2015 (UTC)
+:Replied on your talk page.--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 05:55, 7 February 2015 (UTC)
+::Kudpung, you owe this user an apology. You already have 4 editors at criteria for speedy deletion who consider this deletion inappropriate. What's described at that page is not an ambiguous misrepresentation of policy (altho I can't speak for the template itself). Deleting a template so quickly while it's still under discussion at the appropriate page because you personally disagree is, in my opinion, a mis-use of administrator tools. [[User:Oiyarbepsy|Oiyarbepsy]] ([[User talk:Oiyarbepsy|talk]]) 07:16, 7 February 2015 (UTC)
+:::{{U|Oiyarbepsy}}, I don't really care for your opinion. It hasn't gone unnoticed by several editors that since you arrived at Wikipedia recently, you appear to have a disproportionate interest in policing the product to adding content to its articles. You are not likely to be an admin any time soon so if you don't understand our policies, kindly stay out of them. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:16, 7 February 2015 (UTC)
+
+== Something came in my mind ==
+Is it possible some how to physically hide [[Special:NewPages|this page]] from new editors. I mean restricting new editors (who have less than 200 mainspace) to visit that page. I was thinking maybe WMF can do this but we need consensus first. What you say? '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 06:28, 7 February 2015 (UTC)
+:{{U|Jim Carter| Hi Jim}}. Well, theoretically that old feed ought to be deprecated. If the new NPP system has been in operation for a full two years (and if it hasn't it will be soon) the best way would be to start a major RfC to get it deprecated. At the moment, paradoxically, there are no requirements of minimm experiemce to patrol new pages but if the RfC for AfC goes through in a few days I will be starting a similar one for NPP and that will be the one to ask the Foundation how they can deny access to the curation system for non privileged patrollers. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 06:39, 7 February 2015 (UTC)
+::Actually, I started drafting an RfC. Currently there are two ways to see the log of new pages. 1) [[Special:NewPages]] and 2) [[Special:NewPagesFeed]]. As there are no requirements of minimum experience so my proposal would be: an editor with a minimum of 500 mainspace edits, account 90 days old will be able to view those two pages. The old feed cannot be shut down because older browsers are not able to open [[Special:NewPagesFeed]] page as the curation system uses JavaScript. So my RfC will ask the Foundation to set a filter such that users with less experience than the requirement will not be able access that page. I will be setting the RfC by tomorrow. I will inform you before it goes live. Cheers, '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 09:34, 7 February 2015 (UTC)
+
+== .js page ==
+
+Hello. When you need to put a template on a javascript page please put two slashes '''//''' before the template so that the browser does no try to interpret it as code. The slashed tell the interpreter what follows is a comment and not code. Remember when you edit another persons javascript page you are effecting the code ran on their browser, given the shear number of browsers and their idiosyncratic interpretation of javascript it can be problematic. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 07:19, 7 February 2015 (UTC)
+
+:Hi. I have no idea what you are talking about except that I know that two slashes signifies a comment that is not part of the code. All the js sripts in my vector.js page have been copied and pasted as is and I have not tried to modify them. If you see something there that is not correct I would appreciate a hint rather than a vague message. Thanks. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:28, 7 February 2015 (UTC)
+
+::I may have communicated poorly, I was referring to [https://en.wikipedia.org/w/index.php?title=Special:Undelete&target=User%3AUnit388%2Ftwinklespeedy.js&timestamp=20150207060549&diff=prev this edit]. To put it simply pages that end in .js have the potential to run code on the users browsers. While administrators are able to edit these pages they should only do so if they understand javascript enough to not screw things up. The tip about putting the slashes in front of the template was my 5 cent lesson on not messing up scripts.
+
+::When a javascript interpreter sees '''<nowiki>{{mfd}}</nowiki>''' it goes '''SYNTAX ERROR''' and depending on the browser various difficult to predict symptoms can arise. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 07:39, 7 February 2015 (UTC)
+
+:::Sorry, {{U|Chillum}}, but I still have no idea what you are talking about. I followed the link but it did not provide any clues that I understand either. Perhaps the Twinkle MfD script is not working correctly but that is nothing to do with me, and I'm too old to be learning javascript - I am a common or garden admin, and nothing about adminship (and believe me, I know says sysops have to be computer programmers to get the mop. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:50, 7 February 2015 (UTC)
+
+::::You don't have to learn javascript, but you are responsible for the edits you make with javascript tools like twinkle. Tools like twinkle save a lot of time but they aren't perfect. I cannot explain it any simpler than this: you made an edit to another users javascript page that would result in the script crashing on their browser, if you don't understand javascript then do not edit those pages.
+
+::::As I said the only reason you were able to edit it at all is because you are an admin and admins have been given special access to other users javascript pages. If it is a problem with twinkle then you may wish to report a bug, stop using it, or audit the edits it makes for you. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 07:57, 7 February 2015 (UTC)
+
+:::::{{U|Chillum}}, You are not being very helpful. Are you suggesting that I am in someway in misuse of my admin tools for innocently using a broken Twinkle script available to anyone that I had not edited? If all you come here to do is to continue to stalk my work, I suggest you start worrying about your own admin attitude. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:05, 7 February 2015 (UTC)
+::::::He actually is being helpful, Kudpung. Don't add non-code stuff to any .js page without sticking // in front of it, or else you can break the code and weird things can happen. - Dank ([[User talk:Dank|push to talk]]) 14:53, 7 February 2015 (UTC)
+:::::::{{tps}As I see it, Kudpung '''did not''' add non-code stuff to a .js page, he simply nominated a .js page for deletion using Twinkle and '''Twinkle''' edited the .js page to add stuff to it - that's hardly Kudpung's fault! People, try talking '''to''' each other and not '''past''' each other, eh? [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 14:58, 7 February 2015 (UTC)
+
+You don't have to learn javascript, but you are responsible for the edits you make with javascript tools like twinkle. Tools like twinkle save a lot of time but they aren't perfect. I cannot explain it any simpler than this: you made an edit to another users javascript page that would result in the script crashing on their browser, if you don't understand javascript then do not edit those pages.
+
+As I said the only reason you were able to edit it at all is because you are an admin and admins have been given special access to other users javascript pages. If it is a problem with twinkle then you may wish to report a bug, stop using it, or audit the edits it makes for you}
+* {{Tps}} Kudpung, I understand what chillium was attempting to relay to you from the start as a JavaScript capable person, and I can entirely see why you were missing what was attempting to be relayed. I can't see the deleted edit, but based on this discussion I have a fairly good understanding of the core issue here. I'm away from home until next Tuesday or Wednesday but will test and work on a fix then as I get home. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 16:27, 7 February 2015 (UTC)
+
+Jesus Kudpung I am not accusing you of anything much less you abusing your admin tools. The only reason I mentioned admin tools was that if you were not an admin you would have been prevented from editing that page. I understand and accept that you did not do it on purpose and it was the result of a tool you used. All I am asking is the you either do not change other users javascript pages or that you put '''//''' before your change. This is a reasonable request, not some sort of attack on you. I am asking this of you for technical reasons not because I think you have done something wrong. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 18:03, 7 February 2015 (UTC)
+
+Regardless it is not my intent to carry on about this matter, it is minor. Please just use more care in the future when it comes to javascript pages or avoid them altogether. I have notified the maintainers of twinkle here: [[Wikipedia_talk:Twinkle#Javascript_pages_and_admins]]. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 18:11, 7 February 2015 (UTC)
+:{{tps}}Hi Chillum, I hope you don't mind a comment from me here. It's not what was said, but the way it was said that's caused the aggravation here, I think. Perhaps something like "''You might not be aware of it, but when you nominated X for deletion Twinkle did something wrong''" rather than just the "''It's your responsibility...''" approach might have worked better? [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 18:32, 7 February 2015 (UTC)
+
+== CSD Criteria ==
+
+What would a page like [[Aswin mukundan]] qualify for deletion under? I'm not sure. --[[User:Kges1901|Kges1901]] ([[User talk:Kges1901|talk]]) 08:57, 7 February 2015 (UTC)
+:{{U|Kges1901}} Both A7 ''and'' G11. Take a look at the article now while it's still there. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 09:00, 7 February 2015 (UTC)
+
+== Righto ==
+
+:better start earning my pay and start digging into some NPP. I still have the tool and full guidance. I think I've only ever done about 12, but there were no disasters generated as I recall. Keep a subtle eye out if you would be so kind. I assume you have the tools which give you a general overview of the day's or week's NPP output. Regards, Simon. [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 14:32, 7 February 2015 (UTC)
+
+== February 2015 GOCE newsletter ==
+
+{| style="position: relative; margin-left: 2em; margin-right: 2em; padding: 0.5em 1em; background-color: #dfeff3; border: 2px solid #bddff2; border-color: rgba( 109, 193, 240, 0.75 ); {{border-radius}} {{box-shadow|8px|8px|12px|rgba( 0, 0, 0, 0.7 )}}"
+
+| <span style="font-size: 110%;">'''[[WP:GOCE|Guild of Copy Editors]] February 2015 Newsletter</span>
+
+<div style="float:right; width: 75px; height: 60px;"></div>
+<div style="position: absolute; top: -20px; right: -12px;">[[File:Writing Magnifying.PNG|100px|link=]]</div>
+<hr style="border-bottom: 1px solid rgba( 109, 193, 240, 0.75 );" />
+[[File:Copyeditors progress.png|right|thumb]]
+
+'''Drive:''' Thanks to everyone who participated in [[Wikipedia:WikiProject Guild of Copy Editors/Backlog elimination drives/January 2015|'''January's Backlog Elimination Drive''']]. Of the 38 people who signed up for this drive, 21 copyedited at least one article. Final results, including barnstars awarded, are available [[Wikipedia:WikiProject Guild of Copy Editors/Backlog elimination drives/January 2015/Barnstars|'''here''']].
+
+'''Progress report:''' We were able to remove August 2013 from the general copyediting backlog and November 2014 from the request-page backlog. Many thanks, everyone!
+
+'''Blitz''': The [[Wikipedia:WikiProject Guild of Copy Editors/Blitzes/February 2015|'''February Blitz''']] will run from February 15–21 and again focuses on the [[WP:GOCE/REQ|requests page]]. Awards will be given to everyone who copyedits at least one request article. [[Wikipedia:WikiProject_Guild_of_Copy_Editors/Blitzes/February_2015#Signing_up|'''Sign up here''']]!
+
+Thank you all again for your participation; we wouldn't be able to achieve what we have without you! Cheers from your GOCE coordinators {{noping|Miniapolis}}, {{noping|Jonesey95}}, {{noping|Biblioworm}} and {{noping|Philg88}}.
+
+{{center
+| <small>To discontinue receiving GOCE newsletters, please remove your name from [[Wikipedia:WikiProject Guild of Copy Editors/Mailing List|our mailing list]].</small>
+}}
+|}
+[[User:MediaWiki message delivery|MediaWiki message delivery]] ([[User talk:MediaWiki message delivery|talk]]) 15:52, 7 February 2015 (UTC)
+<!-- Message sent by User:Miniapolis@enwiki using the list at http://en.wikipedia.org/w/index.php?title=Wikipedia:WikiProject_Guild_of_Copy_Editors/Mailing_List&oldid=645586491 -->
+
+==Talkback==
+{{talkback|Jim Carter|ts=10:44, 8 February 2015 (UTC)}}
+'''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="border:1px solid White; border-radius:99px; background-color:Black"><span style="color:White">Car</span></span><span style="color:#FF0000">ter</span>]]''' 10:44, 8 February 2015 (UTC)
+
+== Please can you check my NPP quality ==
+
+Hi Kudpung. Dunno if you in bed, or busy, but if you have a minute, could you please give a brief glance at my NPP efforts so far? There are not many of them so It should not take long. I am very aware that there are some powerful tools available to the NPP'er, and I just want to know if my basic "feel" and methodology is acceptable. I am very aware of the responsibilities and potential to do inadvertant damage, so I just need some reassurance really. You can be as blunt as you wish. Regards Simon aka [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 19:19, 8 February 2015 (UTC)
+:I've looked at some of your more recent patrols. As usual for most new patrollers you have a tendency to over-tag. This is both a negative ''and'' a positive criticism: it shows tha you are seeing what is wrong with the articles and it shows that you know what tags are available for use. Don't tag relatively harmless articles to soon, but of course any which are blatantly toxic must be tagged as quickly as possible for deletion to rapidly attract the attention of admins. If you are working from the back of the queue remember that some articles may be months or even years old - do check their histories very carefully. Here ae some things that you might like to look at again which illustrate some of my comments:
+*[[Tooker & Marsh]] tage for CSD A7 if you can't find sources
+*[[Nicholas Irving]] Overtagging - tagging the blatantly obvious. Good though because it caught the creator online
+*[[Hitler Stalingrad Speech]] older article. Probably not worth tagging at all. Seems to be factually accurate.
+*[[Under Electric Clouds]] Overtagging - tagging the blatantly obvious.
+:Be sure to make use of the 'message to the creator' feature (this may have less effect on older articles where the creator was an SPA who will probably never return, but do it nevertheless. You are on the right track - keep up the good work. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:46, 9 February 2015 (UTC)
+::Noted and much appreciated. S. [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 14:41, 9 February 2015 (UTC)
+::I am noting some peculiar phenomena as I work from the back of the queue. A proposal for deletion on a long-dormant unworked on article will suddenly provoke a flurry of activity. The original creator suddenly beginning to add cites, or otherwise begin work on the article. This process can be measured in minutes. Odd, but rather encouraging. I am closely following Jim's NPP proposals and the debate being generated from that by the way. I shall be commenting. I feel it is the article creation, rather than the patrollers that may be the issue. Just initial thoughts. Will be revisiting the patrolled examples you highlighted above. I am becoming much lighter on the tagging. Regards as always. S [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 21:29, 9 February 2015 (UTC)
+:::{{U|Irondome|Simon}}, you are right about the flurries of activity - it happens at AfC too when drafts get tagged G13 for not having been edited for 6 months. Nevetheless, check that the improvements are relevant and if the creator has simply fremoved maintenance tags (which often happens) simply restore them.
+:::The problem with NPP is most certainly the patrollers. I've been researching and patrolling the patrollers for 5 years. That said, although I favour a set of criteria of competency for users to be allowed to patrol new pages, it is too soon to be launching that proposal. I wish people wouldn't jump the gun but that's also what enthusiastic newcomers often do. They may not be entirely wrong but they will probably not be aware of what is already being done. A substandard RfC can set its own goals back ''years''. Before anything can be done with NPP it is essential that we get consensus to disband AfC and that could take at least another year. AfC has a terrible 'ownership' syndrome to be conquered first. Yes, being lighter on the tagging, especially when the faults in the articles and stubs are evident is a good idea. Keep reading [[WP:NPP]] over and over again, you'll always find you missed something. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 21:45, 9 February 2015 (UTC)
+::::Of course, {{U|Kudpung|Chris}}. I have completed overlooked the rather bizarre entity that is AfC, which I am now belatedly researching. I see nowhere where it actually fits into the grand scheme, if you will. Certainly a minimum skills set in patrollers can only be a positive, but I fully endorse your policy of gradualism. A premature RfC can be literally devastating for an otherwise good attempt to improve the project, and can set back months of intensive (and unpaid!) research and diplomacy to naught. I am beginning to notice instances of premature RfC's in my brief tenure that have gone horribly wrong. A poorly planned RfC seems to have a strange "souring" effect on the community, where the merits of the proposal are sublimated by an irritation that the case has not been competely or thouroughly presented. Much like a jury. This prejudice can last years in contributors to these tainted RfCs'. A similar thing to the old grudges issue in the RfA process. I am beginning to join the dots, and to begin to appreciate how bloody hard it is and how subtle and patient one has to be to actually get things done. Your encouragement on my modest patrolling efforts is greatly appreciated Chris. I hope we all can meet up in London some time and have a doubtless very interesting conversation. Be good to meet Harry too! Simon. [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 22:05, 9 February 2015 (UTC)
+
+Hi Kudpung, I was going to start a new thread but this related to the above conversation. I agree that AfC has got too over-complicated and empirical evidence has now shown me that, far from being kinder and more compassionate as I had assumed, an AfC decline seems to be just as [[WP:BITE]]y for newbies as a PROD or CSD tag, though I'd be interested to see some statistics of how many "one decline" AfC drafts get abandoned and deleted per G13. I still review the odd AfC submission, but nowadays take each one as a cue to improve it and pass it.
+
+Anyway, I was discussing with [[User:Rhondamerrick|my other half]] why Wikipedia can still appear hostile to newcomers, and the consensus came back, once again, to badly called CSDs. I'm thinking specifically of [[The Mariposa Trust]] and [[Le QuecumBar]], which were both quickly tagged for A7 (multiple times in the case of the Mariposa Trust), but where a simple search for the article's title on Google News returned more than one page of hits, easily allowing me to expand these articles with proper referencing. Would it be possible to change Twinkle (where the majority of CSDs get called from) to bring up a message along the lines of "STOP! Have you followed [[WP:BEFORE]]" as some sort of edit notice if a Google News or Books search on the article's title returns, say, more than 10 hits. The problem with the scenarios above is that looking from hindsight it seems poor from the newcomer's point of view to be slapped about, and when they read up on policies, conclude they shouldn't have been. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 12:27, 10 February 2015 (UTC)
+
+:Maybe the instructions at the top of [[WP:NPP]] could be changed to emphasise the importance of [[WP:BEFORE]]? I've lost count of the number of times I've caught pages which have been tagged, usually as A7, where a quick google search would either establish notability or at least make it iffy enough for the page to go for more scrutiny at [[WP:AFD]] instead. I also think there's a case for making pages ineligible for A7 until about 30-45 minutes have passed, to give creators enough time to add their content, though people opposing could probably point to pages like [[Karim Badie|this]] though. Unless the page is obviously problematic, vandalism, attack pages etc, there's nothing to be lost by watchlisting the page and returning to it later to see if it has improved or not. Unfortunately, a lot of patrollers seem to be in a rush to get there first (I was guilty of those mistakes myself in my early days of NPP) when a little more digging would be more productive for all concerned. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 15:15, 10 February 2015 (UTC)
+
+::I like that idea, and if there's traction it would be nice to make it into a guideline, I have a [https://en.wikipedia.org/w/index.php?title=Special%3AWhatLinksHere&target=Template%3ADb-a7&namespace=0 link to active A7s] that I use all the time, hoping I can spot one that is salvageable. Of the two examples I gave, in both cases I was unsure if they would survive an AfD until I'd expanded up to about 7-8 sources, which was about half an hour's worth of work, and I know what I'm doing. I don't see anything wrong with taking some A7s to AfD, as they do not cause immediate harm to Wikipedia by existing, unlike attack pages and copyvios, a week's grace won't hurt us. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 16:16, 10 February 2015 (UTC)
+
+:::{{U| Ritchie333}}. {{U|Valenciano}}, I spend several ''hours'' every week patrolling the patrollers and I've been doing this for around 4 years. There is so much poor tagging nowadays that I only bother now to contact the patrollers whom I really have to ask to stop patrolling and deven that is far, far too many. I would hesitate to say that the majority of patrollers arfe still working from the old feed. The New pages Feed and the Curation tool have been running now for around two years, so I'm going to make a move soon to get the old feed cdeprecated - to do any good anywhere on Wikipedia, one needs to get maintenance workers singing from the same page and applying the same judgement and criteria.
+:::NPP is not an article hospital or the ARSollers should ''not'' be taking the time to improve or repair artic les. If they do the backlog will be even longer than the current 30,000. Indeed, they should do a 'before' before tagging, but if they find refs they should tell the creator that there are refs out there so would they pleazse add them or have their article slated for deletion. What ever Wikipedia guidelines say, there are very definitely moments when we have to be cruel to be kind, gthe most important thing is to avoid being blunt and bitey when we do it. I could go on and on and on about NPP, but I'm slowly getting totally fed up with say ing the same thing to 20 users a week. This is the kind of thing that one day will cause me to retire for good from Wikipedia. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:23, 11 February 2015 (UTC)
+:::BTW getting A7 delayed for 40 minutes won't wash. It's been suggested before. People who propose such ideas may need somewhat more experience with patrolling and won't have noticed that that the majority of A7 are articles that ''must'' be deleted almost as quickly as spam or attach pages - or are you really going to make a mockery of the process by allowing : '' 'I am Johm Doe and me and Jim are the students in Grade 7 at Mrs Bingo's class' stand for an hour before hammering it - and its creator - into the floor? --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:34, 11 February 2015 (UTC)
+::::I don't agree with that sentiment, I'm afraid. What do you mean by "hammering its creator into the floor"? The spam folder on my Gmail account has a grace period of 30 days, I don't think there's a single message I want to read, and that's just one account out of 425 million, that's about a hundred times as many articles on Wikipedia. Google does not generally bring Wikipedia articles to the top of search results until about a week, based on my tracking of [[pink cat]], which despite being created nearly a month ago and having 12 hours linked off the main page via a DYK, does not appear in the first page of hits on a Google Search. These type of articles (which from my experience are more likely to be things like "Advanced Solutions inc is an Indian derivitives analysis company founded in January 2015" or "Bringers of Darkness is a doom metal band from Boise, Idaho") cause no legal harm to the WMF by existing, unlike attack pages or copyvios, and is unlikely to be linked from anywhere in the hour or two it may exist. So my evidence suggests that hastily deleting these types of articles has no obvious benefit, and should not be necessary. [[WP:DEADLINE|Why the rush]]? [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 09:49, 11 February 2015 (UTC)
+:::Overall it's a fine line. We need new contributors and new articles and some of the creators of the latter do get scared away by over hasty tagging, but on the other hand sloppy articles about some "up and coming" band that the creator plays bongos for do create work which takes regulars' time away from adding content and it's often for the sake of an SPA that has no other interest in Wikipedia. There are two issues, firstly, there does need to be more guidance for those new here and submitting the first articles and AFC doesn't seem to have fulfilled that. That could come in the form of technical tweaks to give more advice and guidance when new users are submitting their first articles. Secondly, NPPatrollers need to understand that speedy deletion doesn't necessarily mean nominating pages as quickly as possible, it means that the article deletion process, which would normally take 7-10 days through PROD and AFD, can be done in a matter of hours. The latter could be done by changing the instructions at the top of NPP. You're right regarding the A7 issue and I did acknowledge that above, but I also believe that a lot of A7s could do with a bit more time. The "Danny X is the coolest kid in my class" ones can be nuked fairly quickly, but the ones like "company X is a famous travel agent in India" can be given a little more time just in case there are offline sources covering the company's services or products. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 08:20, 11 February 2015 (UTC)
+::::{{U| Ritchie333}}. {{U|Valenciano}}. Valenciano, have you lived and worked in India? I have. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:04, 11 February 2015 (UTC)
+::::{{U| Ritchie333}}. {{U|Valenciano}}. With all due respect, what it boils down to is that neither of you have properly read what I wrote above. That will of course teach me not to TL;DR... --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:07, 11 February 2015 (UTC)
+:::::I did read what you wrote, but I simply do not agree with your views. There is no reason to disparage anyone with terms such as "trash" or "trolls". I think our conversation is done, and I fear we will continue to lose editors, which is a shame. Happy editing. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 10:31, 11 February 2015 (UTC)
+::::Also, I fail to understand the value pf providing links to deleted G3s when we're disscussing A7. I have aqccess to deleted material, and take it from me, I've been here long enoigh to know the difference between a blatant vandalism and an A7 for an article that stands absolutely no chance whatsoever and should be flagged for deketion as soon as a patroller sees it. It doesn't matter if the creator might have stayed around to create a proper article about something else (let's not kid ourselves, the VAST majority of them don't), what NPP is for is to do a triage of articles, not to read the creator's mind or assess hi/her position and maturity in RL. We are an encyclopedioa, not a psychological counselling service (unless one is here for the pure social networking, but I am not - I'm here to build an encyclopedia and keep it free of trash and trolls, and actually I'm very much an inclusionist). --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:16, 11 February 2015 (UTC)
+:::::I read everything you wrote and agree with some, but not all of it, I don't get your point about India. However, there does remain the issue of editor retention and the need to have new blood coming through. You don't throw the baby out with the trash and sometimes that is what NP patrollers are doing, as yes there will be cases, especially in the A7 area, where naive newbies will have posted a worthy topic but will have failed to reference it adequately. Incidentally, if the redlink you are speaking about is [[Karim Badie]], that was an A7 when I posted it as an example and was indeed deleted as such. The fact that a subsequent version was deleted as G3 doesn't change that or the fact that I specifically highlighted that as an example of an article which didn't deserve to stick around. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 14:25, 11 February 2015 (UTC)
+::::::I think things have got a little at cross-purposes. [[The Mariposa Trust]] was a good result. Have a look at [[User talk:Charliallpress|the creator's talk page]]. Couple of cliched bitey twinkle tags, a few ''really'' bitey block warnings, I go in, add 6 reliable sources, everyone says "oops, sorry" and things calm down. That's the stuff I'm talking about. I maybe need to get some metrics of "CSD saves", but it can't be that many (I would guess about 70% - 90% of A7s are generally impossible for me to salvage) and most I do salvage go to BLP prod or AfD. Certainly there were about 20 articles tagged for A7 this morning that I thought "clear cut A7; bin now". But, going back to my original point that seems to have been lost a bit, a script would almost certainly (I haven't checked) report 0 or few news hits for all of those, giving the tagger a "clean" bill of health to CSD it. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 14:50, 11 February 2015 (UTC)
+
+{{od}}The first tagging was A7. It was blatant trolling and could have been tagged as hoax/vandalism, or even with just a tiny stretch of imagination as an attack page. Some of us admins would accord 2% AGF and delete it as a test page to save the creator's face -in which case however an L1 warning about creating inappropriate pages might be conceivable.
+
+The second tagging (on recreation) of the same content by {{U|J man708}} as G3 was perfectly accurate. In both instances the tagging took place within 5 mins or so of creation - and most rightly so - even a raw newbie patroller would know (well, mostly) that you are not going to make a regular Wikipedian out of that author. Sorry to continue to be a damp squid for anyone advocating a delay for tagging of articles that are pure nonense.--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 18:58, 11 February 2015 (UTC)
+
+:As I'm not an admin I can't view the page in question, so will take your word for it, but as I cited that as a specific example of a page which *should* be quickly nuked I'm not sure what point you're trying to make. No one is advocating a delay for nonsense articles. I nominate quite a few myself as soon as I see them and those should quickly go, but there are pages on other topics such as companies which are less obviously problematic, could theoretically have coverage not immediately obvious from google searches like offline sources or through paywalls and articles like that don't need to bite the dust so quickly. How to gain a little more time for those is one of several issues I see at NPP along with the [[WP:BEFORE]] issue of people not even bothering to check for sources. We do need a wider discussion on it. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 19:26, 11 February 2015 (UTC)
+
+''All'' new articles are referenced and cached by Google within seconds of being posted on Wikipedia - that's part of the deal for Google's $1 mio donation, so that Internet searches ''always'' return Wikipedia articles at the top of the list. Your Gmail content is not referenced at all so I fail totally to see what it has to do with our problems at NPP. Fortunately, when I got the Draft namespace (yes, another of my proposals) created, we stipulated hat drafts will be 'no index, no follow'. That's what should have been included for new pages at NPP until they had been 'patrolled' but somehow the devs failed to do it and now it's an uphil battle to get it done in retro. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 18:58, 11 February 2015 (UTC)
+: I'm sure we're not talking about the same articles. Anyway, WP articles ''used'' to be the top Google search hit, but recently I've found that's not the case so much, they take a while to catch up. [http://www.google.co.uk/search?client=safari&rls=en&q=%22pink+cat%22&ie=UTF-8&oe=UTF-8&gfe_rd=cr&ei=0rrbVJGnNILFaNv1gIAK pink cat] isn't on the first page. [http://www.google.co.uk/search?client=safari&rls=en&q=mariposa+trust&ie=UTF-8&oe=UTF-8&gfe_rd=cr&ei=87rbVMGSC8-DaID3gNgN The Mariposa Trust] is hit #6. I created [[Tape op]] (the term, not the magazine) yesterday and while the magazine might drown that out, I've just been through [http://www.google.com/search?q=%22tape+op%22&client=safari&rls=en&oq=&gs_l= five pages of Google] and not found it. So something has changed somewhere, but as Google never release pagerank algorithms, who knows. Maybe it now takes page views into the equation; obviously older articles will have had lots of views anyway because of their prominence, so will self-weight towards the top. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 20:33, 11 February 2015 (UTC)
+::{{U| Ritchie333}}. {{U|Valenciano}}, [[The Mariposa Trust]] was tagged A7 by {{U|Harry the Dirty Dog}} in '''less than a minute''' of its creation. The patroller, around since 2007 with an EC of 13,569, should have known better than to tag so quickly and should have applied other maintenance tags and made use of the message feature. Contrary to policy, the creator {{U|Charliallpress}} almost instantly removed the CSD themself and within less than a minute the tag was restored, again by {{U|Harry the Dirty Dog}} - this should have been an alert to the patroller who seems to patrol with a vengeance. However, the first and second pages of Google did not return any RS, and that's all a patroller is expected to as a ''Before'', apart from checking for COPYVIO. I would therefore probably have tagged ''that'' page for A7 but certainly not within less than 20 minutes. I click to add such pages to my watchlist and go back to then after 20 minutes or so. I will soon find out later if it is still a blue link and if it is I will look to see why.
+
+::The fiasco of a discussion on the creator’s talk page starts of being rather bitey and only after a lot of kerfuffle does it start to get any nicer. Admittedly it pays to remember that Charliallpress is not here to become a regular Wikipedia contributor but nevertheless their article was neither a hoax/vandalism or otherwise toxic and they deserved to be treated in GF. Lessons to be learned all round (except {{U|MelanieN}} who I recently [[Wikipedia:Requests for adminship/MelanieN|turned into an admin|| and will be one of the best we have).
+
+::This article and its creator are classic examples of the Foundation’s mammoth failure after all these years to address the lack of a proper landing page for new users - I believe this to be a WMF mandate even more than the creation of the new page feed and it curation thing. Indeed,development of the Article Creation Flow began but when things cooled down it was swept under the carpet. Follow up talks every 6 - 12 months have received vague promises but still nothing has been done. While the WMF will refuse, even with overwhelming community consensus, to introduce any mechanism to restrict creation of articles to [[WP:Autoconfirmed|auto confirmed]] users, there is nothing in that policy that says we cannot force all new users to build their first article through the [[Article Wizard]] - and that’s what IMO should be done. What needs to be done is:
+:::*Significantly improve the quality of NPP and either introduce a technically imposed qualification for doing it or significantly step up the control of those who patrol.
+:::*Create a proper landing page for new users, trolls, spammers, SPa, and who ever else, so that they have a clearer idea of what an [[encyclopedia]] is.
+:::*''Force'' at least all non confirmed users to choose to create either through the Article Wizard or to create a Draft first for submission to AfC (bearing in mind that there is a growing movement to migrate AfC to NPP and not without reason.
+:::*Maintain the new quality of voting at RfA and continue our campaign to get users of the right calibre to run for adminship.
+:::*Get regular editors more involved in the RfA voting process.
+:::*Make it much quicker and easier to desysop the admins (probably pre-2007 promotions) who have a pattern of abusing their mandate.
+::None of the above is impossible and I can't see anyone seriously disagreeing. Just needs aforethought and some careful planning. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 02:27, 12 February 2015 (UTC)
+
+== Thai user ==
+
+Hi Kudpung, not sure how much Thai you speak, but we have a bit of an issue with a Thai user. {{u|RKC Vakwai}} is uploading a lot of Thai football club logos, which in and of itself is not the issue, if they were properly licenced. The user is claiming they are the creator, and copyright holder, which is obviously not the case, having a look at their talk page, you can see the mass amount of messages, warnings, etc. that he/she has received. There was even a not so in depth discussion at AN/I a year ago which, really only resulted in a short message by another user. I dropped the last one, with a stop sign (presuming English as not a first language, visuals are good), saying don't upload anything without the correct licence. I am sure the actual message got lost in translation, but the concept is understood, based on [https://en.wikipedia.org/w/index.php?title=User%3AKelapstick&diff=646825765&oldid=643405902 this edit] on my talk page. If you do know any Thai (or someone who does), could you explain the concept of fair use logos to this user? Really we can save a lot of time, work, and hassle if they just upload the images as fair use, but I personally cannot explain that in a way they will understand (my rather stern warning was really just to get them to stop uploading temporarily, lest they actually get blocked). Ta, --[[User:kelapstick|kelapstick]]<sup>([[User talk:Kelapstick#top|bainuu]]) </sup> 21:01, 12 February 2015 (UTC)
+:Also you seem to have a fan - {{noping|Reptiles Birds Exotic AnimalsYes Bad UsersNo}}... --[[User:kelapstick|kelapstick]]<sup>([[User talk:Kelapstick#top|bainuu]]) </sup> 21:14, 12 February 2015 (UTC)
+
+:Hi {{U|kelapstick}}. sorry to disappoint you but while I ''speak'' relatively fluent Thai, and can read it just a tiny bit, it's worlds away from discussing anything in that language with anyone on Wikipedia.--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:54, 13 February 2015 (UTC)
+::No worries, thanks anyway Kudpung. --[[User:kelapstick|kelapstick]]<sup>([[User talk:Kelapstick#top|bainuu]]) </sup> 13:03, 13 February 2015 (UTC)
+
+== Valentine Greets!!! ==
+{| style="background-color: #FA8072; border: 4px solid #DC143C;"
+|rowspan="2" style="vertical-align: middle; padding: 1px;" | [[File:Wikilove2 new.png|211px]]
+|style="font-size: x-large; padding: 2px 2px 0 2px; height: 1.5em;" | '''Valentine Greets!!!'''
+|-
+|style="vertical-align: middle; padding: 3px;" |
+----
+'''Hello Kudpung, [[love]] is the language of hearts and is the feeling that joins two souls and brings two hearts together in a bond. Taking love to the level of [[Wikipedia]], spread the [[Wikipedia:WikiLove|WikiLove]] by wishing each other [[Valentine's Day|Happy Valentine's Day]], whether it be someone you have had disagreements with in the past, a good friend, or just some random person.<br />
+Sending you a heartfelt and warm love on the eve, <br>
+Happy editing,<br>
+&nbsp;-&nbsp;[[User:The Herald|'''T H''']] ([[User talk:The Herald|''here I am'']]) 12:08, 13 February 2015 (UTC)
+
+''{{resize|96%|Spread the love by adding {{tls|Valentine Greetings}} to other user talk pages.}}''
+|}
+== Me? ==
+[[Special:Diff/647199277|<s>Is</s> Are you]] referring me among those unhelpful editors? '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 15:01, 15 February 2015 (UTC)
+:{{U|Jim Carter|Jim}}, It's not 'Is you' it's 'Are you', and I'm referring to users who have been around since long before you joined Wikipedia, and who have a particularly nasty disposition - remember some of us have been around here for 10 years or more. Stop being so paranoid. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:10, 15 February 2015 (UTC)
+::Oh! I started this thread with "Is" as I wanted to say something else but later changed it but forgot to change that word. Don't count my grammatical mistakes, I make plenty; though I'm able to write two GAs and a FL. I'm asking you because I'm a bit confused as your comment there didn't made it clear to whom you're referring. Best, '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 16:05, 15 February 2015 (UTC)
diff --git a/Echo/tests/phpunit/includes/revision_txt/647260329.txt b/Echo/tests/phpunit/includes/revision_txt/647260329.txt
new file mode 100644
index 00000000..d7b7c21f
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/647260329.txt
@@ -0,0 +1,474 @@
+<div style="margin-bottom: 4.25em; position: absolute; bottom: -5em; right: 1em; "><div style="font-style: roman; background-color: #CBEBFF; font-weight:bold; border: 1px steelblue solid; color:black; padding:5px 5px">Please sign your message.</div></div>
+{{Statustop|offset=250}}
+{{administrator topicon|icon_nr=3}}
+{{Online Ambassador}}
+<!-- {{Attempting wikibreak|[[User:Kudpung|Kudpung]]| sometime|I}}
+ -->
+{{editnotice
+| header = Hi, welcome to my talk page!
+| headerstyle = font-size: 150%; color: #9900FF; font-family: 'Copperplate Gothic Light'
+| text =
+*I make plenty of errors - if you are here to complain about a tag, a warning, a deletion, or a block, please [[WP:AGF|'''assume good faith''']].
+*If I ''have'' erred, don't hesitate to tell me, but being '''rude''' will [[WP:BAIT|get you nowhere]].
+*If ''you'' have erred, chances are I'll help you get round it and over it, but [[WP:GAME|'''I don't suffer fools gladly''']] ;)
+*'''Please''' <span class="plainlinks">[http://en.wikipedia.org/w/index.php?title=User_talk:Kudpung&action=edit&section=new click here]</span> '''to leave a new message'''.
+[[Image:Crystal Clear app clock.svg|25px]] On line now? It is '''{{#time:g:i A|{{CURRENTHOUR}}:{{CURRENTMINUTE}} {{#if:{{{1|}}}|{{{1}}}|+7}} hours}}''' where this user lives near [[Udon Thani]], '''Thailand'''
+| textstyle = font-size: 100%; color: #555555; background-color: #DDDDDD
+| image = [[File:Nuvola apps edu languages.svg]]
+| textstyle = font-size: 100%; color: #555555; background-color: #DDDDDD
+| image = [[File:Nuvola apps edu languages.svg]]
+}}
+{{collapsetop|Archives}}
+{{archive box|auto=no|search=yes|style=background-color:lightBlue; border:1px solid black;|
+{{flatlist}}
+2006-2009
+*[[/Archive 1|Start - Jun 2009]]
+*[[/Archive 2|July-Aug]]
+*[[/Archive Aug 2009|Aug]]
+*[[/Archive Aug - Dec 2009|Sep - Dec]]
+*<hr>
+2010
+*[[/Archive Jan 2010|Jan]]
+*[[/Archive Feb 2010|Feb]]
+*[[/Archive Mar 2010|Mar]]
+*[[/Archive Apr 2010|Apr]]
+*[[/Archive May 2010|May]]
+*[[/Archive Jun 2010|Jun]]
+*[[/Archive July 2010|Jul]]
+*[[/Archive Aug (1) 2010|Aug]]
+*[[/Archive Sep 2010|Sep ]]
+*[[/Archive Oct 2010|Oct]]
+*[[/Archive Nov 2010|Nov]]
+*[[/Archive Dec 2010|Dec]]
+*<hr>
+2011
+*[[/Archive Jan 2011|Jan]]
+*[[/Archive Feb 2011|Feb]]
+*[[/Archive Mar 2011|Mar]]
+*[[/Archive Apr 2011|Apr]]
+*[[/Archive May 2011|May]]
+*[[/Archive Jun 2011|Jun]]
+*[[/Archive Jul 2011|Jul]]
+*[[/Archive Aug 2011|Aug]]
+*[[/Archive Sep 2011|Sep]]
+*[[/Archive 01-15 Oct 2011|01-14 Oct]] • [[/Archive 15-30 Oct 2011|15-30 Oct]]
+*[[/Archive Nov 2011|Nov]]
+*[[/Archive Dec 2011|Dec]]
+*<hr>
+2012
+*[[/Archive Jan 2012|Jan]]
+*[[/Archive Feb 2012|Feb]]
+*[[/Archive March-June 2012|Mar-Jun]]
+*[[/Archive Jul 2012|Jul]]
+*[[/Archive Aug 2012|Aug]]
+*[[/Archive Sep 2012|Sep]]
+*[[/Archive Oct 2012|Oct]]
+*[[/Archive Nov 2012|Nov]]
+*[[/Archive Dec 2012|Dec]]
+*<hr>
+2013
+*[[/Archive Jan 2013|Jan]]
+*[[/Archive Feb 2013|Feb]]
+*[[/Archive Mar 2013|Mar]]
+*[[/Archive Apr 2013|Apr]]
+*[[/Archive May 2013|May]]
+*[[/Archive Jun 2013|Jun]]
+*[[/Archive Jul 2013|Jul]]
+*[[/Archive Aug 2013|Aug]]
+*[[/Archive Sep 2013|Sep]]
+*[[/Archive Oct 2013|Oct]]
+*[[/Archive Nov 2013|Nov]]
+*[[/Archive Dec 2013|Dec]]
+*<hr>
+2014
+*[[/Archive Jan 2014|Jan]]
+*[[/Archive Feb, Mar, Apr, May 2014|Feb, Mar, Apr, May]]
+*[[/Archive Jun 2014|Jun]]
+*[[/Archive Jul 2014|Jul]]
+*[[/Archive Aug 2014|Aug]]
+*[[/Archive Sep 2014|Sep]]
+*[[/Archive Oct 2014|Oct]]
+*[[/Archive Nov 2014|Nov]]
+*[[/Archive Dec 2014|Dec]]
+*<hr>
+2015
+*[[/Archive Jan 2015|Jan]]
+{{endflatlist}}
+}}
+{{collapsebottom}}
+{{messagebox|'''NOT even in semi-retirement, but I am only very sporadically available for the time being. I may throw in the occasional edit, but I cannot for the moment get involved in issues that would require my undivided attention, or participation in anything over a number of consecutive days. Thanks.'''
+}}
+== Final warning on Awesomeninja's talk page ==
+
+Hi Kudpung,
+
+I noticed that you put a final warning for disruption on Awesomeninja's talk page. While I must admit that I vehemently despise "cool teen talk", it's my understanding that a final warning was only to be used ''after'' several warnings had been previously issued, ''or'' when a first instance of vandalism is so gross and severe that it deserves an almost immediate block. I don't see any previous warnings on Awesomeninja's talk page, and I hardly think that a NOTNOW RfA is such a severe offense to require a final warning right off the bat. --[[User:Biblioworm|<span style="color:#6F4E37;">'''''Biblio'''''</span>]][[User_talk:Biblioworm|<span style="color:#6F4E37;">'''''worm'''''</span>]] 15:36, 31 January 2015 (UTC)
+:That's your opinion, {{U|Biblioworm|}}. I have been around in life and on Wikipedia a long time and I use my judgement ''very'' carefully and do a lot of research before I do anything or criticise anyone's work or actions. I helped rewrite and develop many of the warning templates - I think I understand the guidelines for their use. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:23, 1 February 2015 (UTC)
+::Thanks for your reply, but it does not seem to directly address the point. This is the description for the level 4 template: "Assumes bad faith; strong cease and desist, last warning". How is a newbie (presumably unaware of what admins really are) filing a NOTNOW RfA editing in bad faith? Isn't it policy that users should [[WP:AGF|assume good faith]] unless there is a very good reason not to? Besides, three users (myself included) messaged the user in almost immediate succession after he transcluded his RfA. I think three rapid-fire messages and a speedy deletion notice was enough to get the point across. In any case, I have no desire to argue, so I won't say any more. --[[User:Biblioworm|<span style="color:#6F4E37;">'''''Biblio'''''</span>]][[User_talk:Biblioworm|<span style="color:#6F4E37;">'''''worm'''''</span>]] 00:51, 1 February 2015 (UTC)
+:::It does address the point because it states: ''do a lot of research before I do anything or criticise anyone's work or actions''. That's good advice for anyone, particularly users who have been around for only a relatively short time and start criticising the work of admins who, contrary to what you may have been led to believe, are ''not'' all bad, do ''not'' all misuse their tools, and do ''not'' all apply poor judgement. [[WP:IAR|Experience is the key]]. Now let's both get back to work, {{U|Biblioworm|}}. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:59, 1 February 2015 (UTC)
+
+== The RfC for AfC reviewer requirement ==
+
+Hey Kudpung, is there any new information on that? I don't think I was actually around when it happened (oops) but... yeah... where can I find the infos...? Thanks! <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 01:47, 1 February 2015 (UTC)
+
+Hi {{U|Kikichugirl}}. It was based on two RfC that I started. One was for a requirement for qualifications, followed up with one to establish the actual requirement and enact it. Both were carried by consensus. It's all history now.
+*[[Wikipedia:WikiProject Articles for creation/RfC Reviewer permission]]
+*[[Wikipedia:WikiProject Articles for creation/RfC for AfC reviewer permission criteria]]
+There was another one proposed by {{U|Anne Delong}} which was an attempt to get the imp;ementation sharpened up, but although I supported it, the RfC was not heavily subscribed:
+*[[Wikipedia:WikiProject Articles for creation/RfC for AfC reviewer permission implementation]]
+That said, we have reached the stage now where the technical implementation needs to be seriously reviewd, or to implement the consensus of April last year to scrap AfC and either replace it with a software package similar to that of NPP, or to merge the whole process to NPP entirely. I support both proposals wholeheartedly and the community just needs to decide which one they want. The problem we are currently faced with is that AfC has become a battleground for volunteer programmers vying for first place, and is fast turning into a walled garden. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 02:10, 1 February 2015 (UTC)
+:Thanks. I might be elitist or have high standards, but the dubious reviews I've seen today, from several users, make me want to quit the project and cry instead... we definitely need to fix up the criteria. <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 08:24, 1 February 2015 (UTC)
+::{{U|Kikichugirl}} check out the current discussion at [[WT:AFC]], and if you can, provide diffs for the poor reviews, something is going to break soon if DGG and I can convince the stone wallers at AfC that someting needs to be done. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:30, 1 February 2015 (UTC)
+:::I've seen it. My question is: Why is AfC so complicated? When I did NPP, I felt myself getting increasingly bitey (I'm increasingly lenient at AfC) but AfC is starting to seem like a mess of blah. If there's a bad patrol at NPP, you stick the CSD tag on right where someone else didn't see it. If there's a bad review, then you gotta revert the review, confuse the newbie, and badness all around. Ugh. <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 08:34, 1 February 2015 (UTC)
+::::{{tps}} - One particularly bad review I can think of is here: [[Brad Craddock]]. The reviewer declined it as "unnotable" when the topic clearly passes [[WP:ATHLETE]] and [[WP:GNG]]. It was written like an advertisement but extensive copyeditting turned it into a viable article. It's going to be shown on the Main Page (DYK) in a few days. AfC reviewers have a lot of power in their hands: In many cases, you can either uplift or destroy the spirit of a newbie and their willingness to contribute to Wikipedia. A bad review and a new editor may never want to come back or they get deep misconceptions about Wikipedia. To tell you the truth, the Brad Craddock, article made me rather sad. [[User talk:Wikifanman37#Brad Craddock article|I had to go into full damage control]]. --'''[[User:Ceradon|ceradon]]''' ([[User talk:Ceradon|<font color="#036">talk</font>]] • [[Special:Contributions/Ceradon|<font color="#036">contribs</font>]]) 08:42, 1 February 2015 (UTC)
+{{od}}{{U|Ceradon}}. {{U|Kikichugirl}}. I can only reiterate that AfC is only a very tiny project when compared with the workload at NPP which is a serious vetting process and not a cosy little hobby for some who want to save a handfull of crap articles every day. Sure, the quality of patrolling at NPP is lousy, and it will remain so until the community stops refusing to believe that we need some criteria of competency for patrollers . --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:52, 1 February 2015 (UTC)
+* {{Tps}} I support scrapping AfC and merging it into NPP or replacing it with and extension/guidedTour replacement as well. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 16:42, 1 February 2015 (UTC)
+::In which case {{U|Technical 13}}, you've done yourself and us a misfavour by voting as you did [[Wikipedia:WikiProject Articles for creation/RfC to physically restrict access to the Helper Script|here]]. Scrapping AfC is the obvious solution but before we get there we have to prove to the community that AfC is not working in its present concept. History has shown that on Wikipedia, little changes lead to bigger ones. This would have been a valuable stepping stone, and still can be if you would reconsider. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 17:58, 1 February 2015 (UTC)
+::* [[Special:Diff/645188517|Fair enough]]. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 18:11, 1 February 2015 (UTC)
+* I am not against ''merging'' the AfC and NPP processes, but the reason I have support AfC for now is, as Kudpung says, due to bad patrolling at NPP. Some NPPers (eg: Mr X, WikiDan61, RandyKitty, SL93) do good work, but there is still [[WP:BITE]]ing going on, so I really think that if we want to put up a hard barrier to reviewing new articles, we apply it consistently across the board. I have some shortcuts on my userpage to check articles nominated for CSD, particularly A7 and G11, and try and salvage anything that I can where possible. ([https://en.wikipedia.org/w/index.php?title=Köpenicker_Blues_und_Jazz_Festival&diff=645333548&oldid=645294851 example]) However, where I can't I consistently see confused newbies who don't understand why their work will be deleted. As long as a reasonable explanation is given, ideally suggesting another article or website where some of the content could go, is a better approach. Unfortunately it's a more time consuming one. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 18:04, 2 February 2015 (UTC)
+::I can't argue with that, {{U|Ritchie333|Ritchie}}. That's why it's a total paradox that NPPers don't require any qualifications at all. They refuse to read what instructions there are (the ones {{U|Scottywong}} and I wrote at [[WP:NPP]]), rarely make use of the handwritten note feature of the curation tool, and never move an article to Draft namespace. That said, in a way, AfC and NPP are almost identical processes with NPP being by far the most important of the two. Merging would be ideal if the regular experienced AfC reviewers would migrate with the move. That way, we would have the best of both worlds. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 23:09, 2 February 2015 (UTC)
+:::I'm going to start moving stuff to draft ([[Draft:Le Trouble (musician)|first example]]) and see if takes up. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 17:17, 3 February 2015 (UTC)
+
+== Buster7 ==
+
+Hello there. I would appreciate it of you could keep me informed of the case I buster7. I would appreciate it if there could be a sutiable warning for violation rules and his extra rights as a rollbacker. How could there be an accidental rollback? Thank you very much[[User:TheMagikCow|TheMagikCow]] ([[User talk:TheMagikCow|talk]]) 14:55, 1 February 2015 (UTC)
+
+:Hi {{U|TheMagikCow|Magic Cow}} It's a very strict rule that editors should not refactor, re-edit, or remove anything from other users' talk pages or user pages. It is in fact quite easy to click a Rollback button by mistake, that's why we're so strict about handing out Rollback rights. In view of the events of earlier today (or tonight according to wherever you are) {{U|Buster7}} could have every reason to take a swipe at one of my edits. It would be a huge coincidence if it were an accident, but I guess we have to stretch the rubber band of AGF and presume it was. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:14, 1 February 2015 (UTC)
+
+== RfC: AfC Helper Script access ==
+
+An RfC has been opened at [[Wikipedia:WikiProject Articles for creation/RfC to physically restrict access to the Helper Script|RfC to physically restrict access to the Helper Script]]. You are invited to comment. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 18:09, 1 February 2015 (UTC)
+
+== A barnstar for you! ==
+
+{| style="background-color: #fdffe7; border: 1px solid #fceb92;"
+|rowspan="2" style="vertical-align: middle; padding: 5px;" | [[File:Brilliant Idea Barnstar Hires.png|100px]]
+|style="font-size: x-large; padding: 3px 3px 0 3px; height: 1.5em;" | '''The Brilliant Idea Barnstar'''
+|-
+|style="vertical-align: middle; padding: 3px;" | For all your work with AfC reform. <span style="text-shadow:#A2E1FC 2px -2px 9px;">&mdash;&nbsp;[[User:Kikichugirl|<font face="Georgia" color="#000000">kikichugirl</font>]]&nbsp;<sup>[[User talk:Kikichugirl|<font color="#8A37F0">speak&nbsp;up!</font>]]</sup></span> 00:02, 2 February 2015 (UTC)
+|}
+;Thank you ! --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:56, 2 February 2015 (UTC)
+
+== WP:ER ==
+
+You're always welcomed at [[WP:RETENTION]] -- [[User:GoodDay|GoodDay]] ([[User talk:GoodDay|talk]]) 03:18, 2 February 2015 (UTC)
+
+== Shane Ferguson ==
+
+Hello, could you please semi-protect [[Shane Ferguson]] as it's getting a lot of disruptive editors at the moment. Thanks, [[User:JMHamo|JMHamo]] ([[User talk:JMHamo|talk]]) 00:59, 3 February 2015 (UTC)
+:{{done}} --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 01:03, 3 February 2015 (UTC)
+
+== Paracommunications ==
+
+Hi Kudpung
+
+I don't understand your reasons for proposing deletion of my Paracommunications entry. Please would you explain, as this is my first entry to Wikipedia. What does dicdef mean? And, how should I edit this entry so it is not deleted. Thank you.
+
+David <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Batmanolan|Batmanolan]] ([[User talk:Batmanolan|talk]] • [[Special:Contributions/Batmanolan|contribs]]) 03:28, 3 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+:Hi {{U|Batmanolan|David}}. Well, Wikipedia is an encyclopedia and not a dictionary. There is a very big difference (dicdef = dictionary definition). That said, the page will not be suitable for Wikipedia at all, even the more so that the word is not to be found anywhere else. You could try publishing it at [[Wiktionary]] which is a Wikimedia web site., but although [[Wiktionary]] is in the same group, we here don't work there. Regards, --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]])
+
+Done, thanks for the tip. Please feel free to delete, now. <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Batmanolan|Batmanolan]] ([[User talk:Batmanolan|talk]] • [[Special:Contributions/Batmanolan|contribs]]) 03:52, 3 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+== Edit summary usage ==
+Hi Kudpung! I just need some advice. Is it okay to use words like "Fu*k off" in edit summaries when directing other users? Isn't it violates our core policy, [[WP:CIVILITY]]? Today, I came across an editor who often uses those words in edit summaries. See [[Special:Diff/645405716|this]]. When I asked him not to use such words, he said [[Special:MobileDiff/645410610|this]]. It is not the first time he is using profanity when talking about other fellow editors. [[Special:MobileDiff/642443657|Here]] some one warned him too when he said someone a "miserable shit". You will get to see more such things in his talk page history and elsewhere. I think it's time for an admin to step in and warn. What you think? '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 06:17, 3 February 2015 (UTC)
+
+:It's ''never'' alright to use such language either on edit summaries or anywhere else. But remember, I am very old fashioned and come from a British background where such language was never used. It might be more modern and more tolerated nowadays, but I don't really think it is, and it's certainly not the kind of language that should be used on Wikipedia. I looked at the edit history and it seems you may have done something wrong but I guess it wasn't intentional. I very much liked one comment of yours I came across (I seem to have seen something very similar before...), you should use it more often, but carefully of course, and only if you are sure that the person is a child (well, under 18 or so). I made myself a golden rule many years ago: always check out an editor's user page before you hit them with anything. If the page looks like a teenager's bedroom wall, chances ar that they are a teenager (or even younger), but on the other hand, while there are lots of children who act like mature adults on Wikipedia, there are lots of adults who behave like children ;) Keep up the good work, {{U|Jim Carter|Jim}}! --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 06:38, 3 February 2015 (UTC)--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 06:38, 3 February 2015 (UTC)
+::Yes, indeed. I strongly condemn the use of such language on Wikipedia. Actually, I don't know what exactly happened but I guess his comment was removed due to an edit conflict. His behavior was so childish that I didn't have to check his user page. Anyway, thank you. I'm just trying to follow your commands :) Cheers, '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 10:06, 3 February 2015 (UTC)
+
+:::{{u|Jim Carter|Jim}} - Your comment had gone from polite to and I quote "''This is not a playground for kids. You're here to build an encyclopedia, why don’t you just grow up and behave as if you are working on the world’s biggest single source of information? A huge number of users are much older than you might think. Try to give others respect in talk pages as well as in edit summaries'' - How do you expect me to react?,
+:::Had you left it at the section where you said you disagreed with my use of words I'd of been more than happy to apologize, As for my "miserable shit" comment elsewhere ... I realized I was wrong and had removed it[https://en.wikipedia.org/w/index.php?title=Wikipedia:Requests_for_adminship/Titodutta&diff=642463191&oldid=642449018] so it's not really relevant here<br>
+:::Sorry Kudpung for barging in here hope you don't mind :) –[[User:Davey2010|<span style="color: blue;">'''Davey'''</span><span style="color: orange;">'''2010'''</span>]]<sup>[[User talk:Davey2010|<span style="color: navy;">'''Talk'''</span>]]</sup> 10:31, 3 February 2015 (UTC)
+
+::::Hi {{U|Davey2010|Davey}}. I don't really mind - if it helps clear the air. However, '' "This is not a playground for kids. You're here to build an encyclopedia, why don’t you just grow up and behave as if you are working on the world’s biggest single source of information? A huge number of users are much older than you might think." '' is is a brilliant statement if used wisely and one I would recommend being used more often by young editors who are concerned about the crap and strife caused by other young editors. Someone like me though, and an admin to boot, would get shot down in flames as a child hater if we said it. Even the word ''children'' is considered taboo on Wikipedia - by the children of course. You're probably not aware of it yet, but as one of the most regular contrubutors to [[WP:WER]] I have retired from that project - namely due to the antics of some younger editors and three or four adults who behave like kids a lot of the time. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:48, 3 February 2015 (UTC)
+
+:::::Hiya Kudpung, I agree with the statement providing its used wisely, Everyone knows I'm the least patient/short tempered person here so It was obvious saying something like that would tick me off easily,
+:::::I've not really dealt with any kids really but then again you're alot more active in other areas like NPP etc :)
+:::::When you overwritten my comment twice, Being very confused and without thinking I simply asked myself "what I stated in the edit summary" ...
+:::::Anyway I apologize to both Kudpung and to {{u|Jim Carter|Jim}} if they were offended/upset - Despite it may not seem like it at times - It's never my intention to offend or upset anyone,
+:::::Life's too short to start arguments & all that :)
+:::::Anyway I admit I shouldn't of said it and I sincerely apologize,
+:::::Thanks –[[User:Davey2010|<span style="color: blue;">'''Davey'''</span><span style="color: orange;">'''2010'''</span>]]<sup>[[User talk:Davey2010|<span style="color: navy;">'''Talk'''</span>]]</sup> 13:08, 3 February 2015 (UTC)
+
+== Little experience ==
+
+She ([[Kristin Sutton]]) doesn't look like she needs a wiki page. And who said I had little experience? It sounds like you're saying I'm dumb. --[[User:Satouyoukun|Satouyoukun]] ([[User talk:Satouyoukun|talk]]) 13:54, 3 February 2015 (UTC)
+:{{U|Satouyoukun}}, I am saying that with only 182 edits to the encycolpedia pages and wthout having read and thoroughly understood our deletion policies, you are not ready to be doing such maintenance tasks. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 14:02, 3 February 2015 (UTC)
+
+== You mentioned HJ mitchen ==
+
+http://theralphretort.com/wikipedia-blocks-veteran-editor-for-being-pro-gamergate-off-site-1715/ Check this article please <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:IntelligenceMonkey|IntelligenceMonkey]] ([[User talk:IntelligenceMonkey|talk]] • [[Special:Contributions/IntelligenceMonkey|contribs]]) 14:13, 3 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+::So what? And who are you, if I may ask? I do not take any notice of any crap that is written about Wikipedia on other websites. Also I have every confidence in the adminstrative acts and decisions of {{U|HJ Mitchell}}. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 14:21, 3 February 2015 (UTC)
+::::Oh yes, the block was based completely on something he said somewhere else on the Internet and on a site I don't even read. It wouldn't have anything at all to do with the [[Special:Contributions/Xander756|series of nasty BLP violations and personal attacks]]! ;) [[User:HJ Mitchell|<font color="Teal" face="Tahoma">'''HJ&nbsp;Mitchell'''</font>]] &#124; [[User talk:HJ Mitchell|<font color="Navy" face= "Times New Roman">Penny for your thoughts? </font>]] 14:37, 3 February 2015 (UTC)
+
+== Problematic new page patroller ==
+
+Kudpung,
+
+You, I, and about five other editors have cautioned [[User:Kges1901|Kges1901]] that he or she is making serious mistakes patrolling and speedying new pages. I just noticed another incorrect speedy nom on [[Yashvardhan Shukla]] (I converted it to an AfD). Obviously the cautions have not gotten through—do you know what the next step should be?
+
+Thanks!—[[User:Neil P. Quinn|Neil P. Quinn]] ([[User talk:Neil P. Quinn|talk]]) 16:58, 3 February 2015 (UTC)
+
+Sorry, but wasn't the page previously deleted using the same cause because a nomination by me? and wasn't it also exactly the same content on the page? I tried my best after reading the cautions to not make any mistakes, but... [[User:Kges1901|Kges1901]] ([[User talk:Kges1901|talk]]) 21:18, 3 February 2015 (UTC)
+:{{ping|Neil P. Quinn}}. The problem with {{U|Kges1901}}'s patrolling is that he has been asked by an administrator to stop patrolling but in defiance of the request he is continuing to do so. It took me nearly an hour this morning to check his last 100 or so patrolls and while most of them are OK the accuracy rate is still too low. Thus the issue is not whether or not his patrols are accurate but the enormous work he is creating for admins and other editors in having to check his work. His editing history shows that he cannot normaly have accumulated sufficient experience for this type of work. The alternatives are that he either stops patrolling, or it will be discussed at ANI with a risk of him being blocked or at least T-banned from patrolling. Perhaps however, a couple more warnings may do the trick-. -[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 00:27, 4 February 2015 (UTC)
+
+* {{ping|Kges1901}} now that you mention it, I see that [[Yashvardhan Shukla]] [https://en.wikipedia.org/w/index.php?title=Special:Log&page=Yashvardhan+Shukla was speedy deleted before], but if the content was the same, I would also consider that deletion incorrect. The problem is that the criterion you used, [[WP:A7|A7]], is for pages that don't make a "[[WP:credible claim of significance|credible claim of significance]]." That page does: it claims that Shukla is significant because he published a novel at age 13, which is certainly credible (young authors ''do'' exist) and could theoretically make him notable (the author actually included a link to [http://www.outlookindia.com/news/article/13YrOld-Yashwardhan-Shukla-Pens-Gods-of-Antarctica/857080 a profile of him in a national magazine]). I around five minutes searching for other sources to check whether he was actually notable, and decided he wasn't—but I had to use [[Wikipedia:Articles for deletion|articles for deletion process]] because it didn't meet any of the speedy deletion criteria. There's a good reason for this—if it doesn't meet the criteria, it's worth using AfD, which takes more time but makes more sure that we didn't miss any reasons to keep the article.
+:Also, Kges, one of the reasons I was concerned was that you didn't seem interested in talking to any of the people who cautioned you so you could learn more about how to avoid mistakes. I feel a bit better since you responded here. I'd advise you to be '''much''' more careful, read the [[Wikipedia:Criteria for speedy deletion|guidelines for speedy deletion]] very carefully, and above all, ask someone like me or Kupung for advice if you have ''any'' doubts about whether an article can be speedy deleted. This will allow you to keep contributing to the encyclopedia without creating unnecessary work for other editors.—[[User:Neil P. Quinn|Neil P. Quinn]] ([[User talk:Neil P. Quinn|talk]]) 21:34, 4 February 2015 (UTC)
+::{{reply to|Neil P. Quinn}} - again apologies for barging in here. Just wanted to say something in regards to: "didn't seem interested in talking to any of the people who cautioned you". I am often accused of the same wiki-crime, so I am wondering if you may be interested in my perspective? [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:21, 6 February 2015 (UTC)
+Sorry for barging in. As someone who has lost countless articles to [[wp:CSD]]s, I always assumed that it is the admin's job to make sure that articles they are deleting are being deleted for the right reason. Is my assumption correct ? [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:05, 4 February 2015 (UTC)
+:In theory, yes. At least that's what *I* do - and willingly too because I like to catch those clueless patrollers and bend them over my knee. That said, even if some sloppy admins do not check what they are deleting, there's always Delrev where anything worth keeping is generally refunded without much fuss. More difficult of course if the deletion was on a community consensus at XfD. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 16:29, 4 February 2015 (UTC)
+::Thanks for responding, Kudpung. I am just wondering if there are statistics kept somewhere about the number of "sloppy admins do not check what they are deleting"? [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:25, 6 February 2015 (UTC)
+
+:::I doubt it, {{U|Ottawahitech}}. I can't see how it would be possible to extract suc a statistic. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:45, 6 February 2015 (UTC)
+
+:::: A good place to start would be on my own talkpage :-) [[User:Ottawahitech|Ottawahitech]] ([[User talk:Ottawahitech|talk]]) 15:55, 7 February 2015 (UTC)
+
+== [[King's Norton Boys' School]] ==
+
+Hi,
+In response to the message you sent me the only thing I have added is the school logo change, and a picture of the head for the news sake. If these are against the rules that you sent me I will gladly change the box to meet the required expectations of a schools Wikipedia Page. The whole page has been restored, is there a huge problem with adding texts of information. I understand the quotes but why can't there be other history, details about the curriculum. Also the motto box was already there, so why is it removed.
+
+Thanks
+James Byford <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Ja5by101|Ja5by101]] ([[User talk:Ja5by101|talk]] • [[Special:Contributions/Ja5by101|contribs]]) 19:30, 4 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+:{{U|Ja5by101}} Hi James. I don't think the photo is appropriate, Wikipedia is not a news site and such content gets quickly out of date. It would be good if you could restore the original formal school logo. I have also removed some text from the article but I can't remember if it was added by you. You are most welcome to continue to expand the article but do check out [[WP:WPSCH]] first. I am the coordinator there so if you have any questions don't hesitate to contact me. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 19:41, 4 February 2015 (UTC)
+
+::Hi yes sorry for the inconvenience. I currently go to the school and they have changed the logo to the one I have put on there. The reason why I put the news on there is because I was planning on updating it. I will remove the content. Also the school motto, is that aloud to be put back up? I am really really sorry. Thanks for Your Help
+James <small><span class="autosigned">—&nbsp;Preceding [[Wikipedia:Signatures|unsigned]] comment added by [[User:Ja5by101|Ja5by101]] ([[User talk:Ja5by101|talk]] • [[Special:Contributions/Ja5by101|contribs]]) 19:44, 4 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+:::Don't worry James, I have restored everything the way it should be. By all means add the motto to the motto section in the infobox, but preferably don't add any content to the article body before asking me first if you are not sure. Do check out [[WP:WPSCH/AG]] too - you'll soon get the hang of things and you'll soon be improving other articles. Make yourself a user page too. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 20:13, 4 February 2015 (UTC)
+
+
+Thank you so much for your help, I actually really appreciate things and I am sincerely sorry for the inconvience I have caused for you! I will add the motto but I shall not add anything else as it does cause an inconvenience and I can understand why the changes were made now and I do appreciate it!
+
+Thank you so much again!
+James
+
+[[User:Ja5by101|Ja5by101]] ([[User talk:Ja5by101|talk]] • [[Special:Contributions/Ja5by101|contribs]]) 20:17, 4 February 2015 (UTC)</span></small><!-- Template:Unsigned --> <!--Autosigned by SineBot-->
+
+==RAN==
+
+Actually, proxying Mr. Norton's new starts is permitted under terms of his original sanction, as I recall, so long as the person moving the start into mainspace accepts full responsibility for any possible copyright violation it contains. The logical and obvious solution for the betterment of the encyclopedia is to get rid of his punitive topic ban against direct new creations, of course, but as long as CCI is hot and bothered about 10 year old copyvios that nobody can or will ever fix, that doesn't seem too likely either. It's a stupid situation. [[User:Carrite|Carrite]] ([[User talk:Carrite|talk]]) 06:40, 5 February 2015 (UTC)
+
+== ''The Signpost'': 04 February 2015 ==
+
+<div lang="en" dir="ltr" class="mw-content-ltr"><div style="-moz-column-count:2; -webkit-column-count:2; column-count:2;">
+{{Wikipedia:Wikipedia Signpost/2015-02-04}}
+</div><!--Volume 11, Issue 5-->
+<div class="hlist" style="margin-top:10px; font-size:90%; padding-left:5px; font-family:Georgia, Palatino, Palatino Linotype, Times, Times New Roman, serif;">
+* '''[[Wikipedia:Wikipedia Signpost|Read this Signpost in full]]'''
+* [[Wikipedia:Signpost/Single/2015-02-04|Single-page]]
+* [[Wikipedia:Wikipedia Signpost/Subscribe|Unsubscribe]]
+* [[User:MediaWiki message delivery|MediaWiki message delivery]] ([[User talk:MediaWiki message delivery|talk]]) 00:43, 6 February 2015 (UTC)
+</div></div>
+<!-- Message sent by User:LivingBot@enwiki using the list at http://en.wikipedia.org/w/index.php?title=Wikipedia:Wikipedia_Signpost/Tools/Spamlist&oldid=645566867 -->
+
+== Bitey? ==
+
+How about you try not to be, eh? [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 12:21, 6 February 2015 (UTC)
+:{{ping|Squinge}} No, not in the slightest. A bit direct maybe, but only with those who should know better. I don't bite newcomers. If you are trying to do maintenance tasks you are hardly a newcomer, so how about you [[WP:NPP|reading the instructions]] before you do anything and perhaps also talk page headers. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:40, 6 February 2015 (UTC)
+::I'm not doing NPP - its not a <s>fucking</s> new page! [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 12:41, 6 February 2015 (UTC)
+:::{{ping|Squinge}} Nobody, just nobody, uses language like that on ''my'' talk page and never has in 9 years. Read the instructions, in particular [[WP:CIVIL|these too]] and do not come here again - under an circumstances. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:49, 6 February 2015 (UTC)
+::::Apologies for the rude word, I withdraw it and I've struck it now. If you'd like to discuss the fact that you were wrong about it being a new page then I'll be happy to do so, or I'll never post here again (other than when mandatory) as you wish - just let me know. [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 12:55, 6 February 2015 (UTC)
+{{talkback|Squinge}}
+{{ygm}}
+
+== Help understanding a chart ==
+
+The most recent vote concerning RfA at VPR included a chart, the first one at [[Wikipedia:Village_pump_(proposals)/Archive_115#Time to replace RfA]]. Can you help me interpret the numbers? Have they been updated? - Dank ([[User talk:Dank|push to talk]]) 13:33, 6 February 2015 (UTC)
+:Hi {{U|Dank}}, how are you doin'? Nice to see you. I'm still not quite sure which chart you mean, but all the graphs and tables are pretty accurate. The discussion was only 3 months ago so not much will have changed since. Reading through it, I still stand by all my comments which, summa sumarum, is that RfA is now as good as it's ever going to get, doesn't need any major changes except perhaps for more consequent removal of inapropriate questions, votes, and comments, but it's a start. RfA is actually doing a good job, demonstrated by one candidate whom I dragged kicking and screaming to the process and who then skipped through it like a lamb through a field of buttercups. If you are thinking of starting a new reform campaign, you'll probably have my support, but I think we need to give RfA time now for people to realise that it's no longer the horrible & brioken process that I and Wales suggested it was four years ago, and we need to make more publicity for it. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 13:56, 6 February 2015 (UTC)
+::Oh ... wasn't thinking of starting an RfA reform discussion, I've got something else in mind, a followup to the current RfC at VPR on user-rights. Not disputing that the chart is accurate ... I just don't know what the numbers mean. Here it is. - Dank ([[User talk:Dank|push to talk]]) 14:21, 6 February 2015 (UTC)
+
+{| class="wikitable"
+! !!2008!!2009!!2010!!2011!!2012!!2013!!2014 (projected)
+|-
+
+!Active admins
+||943||870||766||744||674||633||570
+|-
+
+!Admin promotions
+||201||121||78||52||28||34||21
+|-
+
+!Admin attrition (actual, not net)
+||<span style="color:Red">263</span>||<span style="color:Red">194</span>||<span style="color:Red">182</span>||<span style="color:Red">74</span>||<span style="color:Red">98</span>||<span style="color:Red">75</span>||<span style="color:Red">85</span>
+|}
+
+Dank, do you by any chance mean any of the graphs or charts I uploaded from my Excel spreadsheet? I'm pretty sure I still have that spreadsheet if you want me to email it to you or something, just let me know. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 14:35, 6 February 2015 (UTC)
+:Thanks for your work on that, but I think if I can find out what the numbers above represent, I'm good. (I get what the middle row means.) - Dank ([[User talk:Dank|push to talk]]) 14:47, 6 February 2015 (UTC)
+
+{{ec}} {{U|Dank}}, most of these charts are created and maintained by {{U|WereSpielChequers}}. I don't find the figures particularly difficult to understand. Active admins are those who by some some silly criterion (not created by WereSpielChequers) that gives a totally false picture. IMO the actual number of truly active admins is about one tenth of that. Promotions is of course the actual number who passed an fA, and attrition is the total number lost through all kinds of desysoping. The projected number for 2014 was pretty accurate, in fact the actual number was 22. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 14:50, 6 February 2015 (UTC)
+:Agreed that it would be nice to have numbers that are based on a higher bar for activity ... do either of you happen to have numbers that reflect that? I'll ask WSC too. - Dank ([[User talk:Dank|push to talk]]) 15:01, 6 February 2015 (UTC)
+::{{U|Dank}}, I don't but anyone who knows how to run a regex through the actual admin action logs can soon find out. I would suggest that a truly active admin should be based on the uses of the admin tools over the previous 60 days, plus the number of edits to ANI over the same period and then divide by 2. If the answer is 40 or greater, then I would consider them as active, {{U|Scottywong}} used to be brilliant at pulling stats but he's gone AWOL as far as I can see. He did most of the stats for us at [[WP:RFA2011]]. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:14, 6 February 2015 (UTC)
+:::Thanks, I've asked WSC if he has numbers. - Dank ([[User talk:Dank|push to talk]]) 15:19, 6 February 2015 (UTC)
+
+== AfC ==
+
+Hi. You removed me from Articles for Creation participants list because you thought I was too inexperienced. When do I know if I am experienced enough? When I reach 1000 edits? Thanks. [[User:William2001|William2001]] ([[User talk:William2001|talk]]) 04:01, 7 February 2015 (UTC)
+:Well, {{U|William2001|William}} that's something else which you have misunderstood. If you had read the page before putting your name on it and my comments on your talk page you would have seen that 500 edits / 90 days are only a starting point and that more important is having sufficient experience that can't simply be measured by an edit count. We are shorly going to change the system and reviewers will have to request an admin to include them on the list just as we do for PC Reviewer, Rollbacker, and AWB user. I suggest that you might like to do some less complex maintenance tasks until the new system is up and running and make a new application then. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 05:27, 7 February 2015 (UTC)
+::OK. Thank you. [[User:William2001|William2001]] ([[User talk:William2001|talk]]) 16:39, 7 February 2015 (UTC)
+
+== Recreated ==
+
+Hi just letting you know that I have recreated the pre-speedy tag. This is for purpose of demonstration for the discussion started '''[[Wikipedia:Village_pump_(proposals)#Pre-Speedy_Deletion_tag|here]].''' Please know that until the discussion has ended I will not use the tag. If a consensus is not reached I will tag it for deletion myself - Thanks. [[User:Unit388|Unit388]] ([[User talk:Unit388|talk]]) 05:31, 7 February 2015 (UTC)
+:Replied on your talk page.--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 05:55, 7 February 2015 (UTC)
+::Kudpung, you owe this user an apology. You already have 4 editors at criteria for speedy deletion who consider this deletion inappropriate. What's described at that page is not an ambiguous misrepresentation of policy (altho I can't speak for the template itself). Deleting a template so quickly while it's still under discussion at the appropriate page because you personally disagree is, in my opinion, a mis-use of administrator tools. [[User:Oiyarbepsy|Oiyarbepsy]] ([[User talk:Oiyarbepsy|talk]]) 07:16, 7 February 2015 (UTC)
+:::{{U|Oiyarbepsy}}, I don't really care for your opinion. It hasn't gone unnoticed by several editors that since you arrived at Wikipedia recently, you appear to have a disproportionate interest in policing the product to adding content to its articles. You are not likely to be an admin any time soon so if you don't understand our policies, kindly stay out of them. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:16, 7 February 2015 (UTC)
+
+== Something came in my mind ==
+Is it possible some how to physically hide [[Special:NewPages|this page]] from new editors. I mean restricting new editors (who have less than 200 mainspace) to visit that page. I was thinking maybe WMF can do this but we need consensus first. What you say? '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 06:28, 7 February 2015 (UTC)
+:{{U|Jim Carter| Hi Jim}}. Well, theoretically that old feed ought to be deprecated. If the new NPP system has been in operation for a full two years (and if it hasn't it will be soon) the best way would be to start a major RfC to get it deprecated. At the moment, paradoxically, there are no requirements of minimm experiemce to patrol new pages but if the RfC for AfC goes through in a few days I will be starting a similar one for NPP and that will be the one to ask the Foundation how they can deny access to the curation system for non privileged patrollers. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 06:39, 7 February 2015 (UTC)
+::Actually, I started drafting an RfC. Currently there are two ways to see the log of new pages. 1) [[Special:NewPages]] and 2) [[Special:NewPagesFeed]]. As there are no requirements of minimum experience so my proposal would be: an editor with a minimum of 500 mainspace edits, account 90 days old will be able to view those two pages. The old feed cannot be shut down because older browsers are not able to open [[Special:NewPagesFeed]] page as the curation system uses JavaScript. So my RfC will ask the Foundation to set a filter such that users with less experience than the requirement will not be able access that page. I will be setting the RfC by tomorrow. I will inform you before it goes live. Cheers, '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 09:34, 7 February 2015 (UTC)
+
+== .js page ==
+
+Hello. When you need to put a template on a javascript page please put two slashes '''//''' before the template so that the browser does no try to interpret it as code. The slashed tell the interpreter what follows is a comment and not code. Remember when you edit another persons javascript page you are effecting the code ran on their browser, given the shear number of browsers and their idiosyncratic interpretation of javascript it can be problematic. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 07:19, 7 February 2015 (UTC)
+
+:Hi. I have no idea what you are talking about except that I know that two slashes signifies a comment that is not part of the code. All the js sripts in my vector.js page have been copied and pasted as is and I have not tried to modify them. If you see something there that is not correct I would appreciate a hint rather than a vague message. Thanks. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:28, 7 February 2015 (UTC)
+
+::I may have communicated poorly, I was referring to [https://en.wikipedia.org/w/index.php?title=Special:Undelete&target=User%3AUnit388%2Ftwinklespeedy.js&timestamp=20150207060549&diff=prev this edit]. To put it simply pages that end in .js have the potential to run code on the users browsers. While administrators are able to edit these pages they should only do so if they understand javascript enough to not screw things up. The tip about putting the slashes in front of the template was my 5 cent lesson on not messing up scripts.
+
+::When a javascript interpreter sees '''<nowiki>{{mfd}}</nowiki>''' it goes '''SYNTAX ERROR''' and depending on the browser various difficult to predict symptoms can arise. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 07:39, 7 February 2015 (UTC)
+
+:::Sorry, {{U|Chillum}}, but I still have no idea what you are talking about. I followed the link but it did not provide any clues that I understand either. Perhaps the Twinkle MfD script is not working correctly but that is nothing to do with me, and I'm too old to be learning javascript - I am a common or garden admin, and nothing about adminship (and believe me, I know says sysops have to be computer programmers to get the mop. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:50, 7 February 2015 (UTC)
+
+::::You don't have to learn javascript, but you are responsible for the edits you make with javascript tools like twinkle. Tools like twinkle save a lot of time but they aren't perfect. I cannot explain it any simpler than this: you made an edit to another users javascript page that would result in the script crashing on their browser, if you don't understand javascript then do not edit those pages.
+
+::::As I said the only reason you were able to edit it at all is because you are an admin and admins have been given special access to other users javascript pages. If it is a problem with twinkle then you may wish to report a bug, stop using it, or audit the edits it makes for you. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 07:57, 7 February 2015 (UTC)
+
+:::::{{U|Chillum}}, You are not being very helpful. Are you suggesting that I am in someway in misuse of my admin tools for innocently using a broken Twinkle script available to anyone that I had not edited? If all you come here to do is to continue to stalk my work, I suggest you start worrying about your own admin attitude. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 08:05, 7 February 2015 (UTC)
+::::::He actually is being helpful, Kudpung. Don't add non-code stuff to any .js page without sticking // in front of it, or else you can break the code and weird things can happen. - Dank ([[User talk:Dank|push to talk]]) 14:53, 7 February 2015 (UTC)
+:::::::{{tps}As I see it, Kudpung '''did not''' add non-code stuff to a .js page, he simply nominated a .js page for deletion using Twinkle and '''Twinkle''' edited the .js page to add stuff to it - that's hardly Kudpung's fault! People, try talking '''to''' each other and not '''past''' each other, eh? [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 14:58, 7 February 2015 (UTC)
+
+You don't have to learn javascript, but you are responsible for the edits you make with javascript tools like twinkle. Tools like twinkle save a lot of time but they aren't perfect. I cannot explain it any simpler than this: you made an edit to another users javascript page that would result in the script crashing on their browser, if you don't understand javascript then do not edit those pages.
+
+As I said the only reason you were able to edit it at all is because you are an admin and admins have been given special access to other users javascript pages. If it is a problem with twinkle then you may wish to report a bug, stop using it, or audit the edits it makes for you}
+* {{Tps}} Kudpung, I understand what chillium was attempting to relay to you from the start as a JavaScript capable person, and I can entirely see why you were missing what was attempting to be relayed. I can't see the deleted edit, but based on this discussion I have a fairly good understanding of the core issue here. I'm away from home until next Tuesday or Wednesday but will test and work on a fix then as I get home. — <code class="nowrap">&#123;&#123;U&#124;[[User:Technical 13|Technical 13]]&#125;&#125; <sup>([[Special:EmailUser/Technical 13|e]] • [[User talk:Technical 13|t]] • [[Special:Contribs/Technical 13|c]])</sup></code> 16:27, 7 February 2015 (UTC)
+
+Jesus Kudpung I am not accusing you of anything much less you abusing your admin tools. The only reason I mentioned admin tools was that if you were not an admin you would have been prevented from editing that page. I understand and accept that you did not do it on purpose and it was the result of a tool you used. All I am asking is the you either do not change other users javascript pages or that you put '''//''' before your change. This is a reasonable request, not some sort of attack on you. I am asking this of you for technical reasons not because I think you have done something wrong. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 18:03, 7 February 2015 (UTC)
+
+Regardless it is not my intent to carry on about this matter, it is minor. Please just use more care in the future when it comes to javascript pages or avoid them altogether. I have notified the maintainers of twinkle here: [[Wikipedia_talk:Twinkle#Javascript_pages_and_admins]]. [[User talk:Chillum|<b style="color:DarkRed">Chillum</b>]] 18:11, 7 February 2015 (UTC)
+:{{tps}}Hi Chillum, I hope you don't mind a comment from me here. It's not what was said, but the way it was said that's caused the aggravation here, I think. Perhaps something like "''You might not be aware of it, but when you nominated X for deletion Twinkle did something wrong''" rather than just the "''It's your responsibility...''" approach might have worked better? [[User:Squinge|Squinge]] ([[User talk:Squinge|talk]]) 18:32, 7 February 2015 (UTC)
+
+== CSD Criteria ==
+
+What would a page like [[Aswin mukundan]] qualify for deletion under? I'm not sure. --[[User:Kges1901|Kges1901]] ([[User talk:Kges1901|talk]]) 08:57, 7 February 2015 (UTC)
+:{{U|Kges1901}} Both A7 ''and'' G11. Take a look at the article now while it's still there. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 09:00, 7 February 2015 (UTC)
+
+== Righto ==
+
+:better start earning my pay and start digging into some NPP. I still have the tool and full guidance. I think I've only ever done about 12, but there were no disasters generated as I recall. Keep a subtle eye out if you would be so kind. I assume you have the tools which give you a general overview of the day's or week's NPP output. Regards, Simon. [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 14:32, 7 February 2015 (UTC)
+
+== February 2015 GOCE newsletter ==
+
+{| style="position: relative; margin-left: 2em; margin-right: 2em; padding: 0.5em 1em; background-color: #dfeff3; border: 2px solid #bddff2; border-color: rgba( 109, 193, 240, 0.75 ); {{border-radius}} {{box-shadow|8px|8px|12px|rgba( 0, 0, 0, 0.7 )}}"
+
+| <span style="font-size: 110%;">'''[[WP:GOCE|Guild of Copy Editors]] February 2015 Newsletter</span>
+
+<div style="float:right; width: 75px; height: 60px;"></div>
+<div style="position: absolute; top: -20px; right: -12px;">[[File:Writing Magnifying.PNG|100px|link=]]</div>
+<hr style="border-bottom: 1px solid rgba( 109, 193, 240, 0.75 );" />
+[[File:Copyeditors progress.png|right|thumb]]
+
+'''Drive:''' Thanks to everyone who participated in [[Wikipedia:WikiProject Guild of Copy Editors/Backlog elimination drives/January 2015|'''January's Backlog Elimination Drive''']]. Of the 38 people who signed up for this drive, 21 copyedited at least one article. Final results, including barnstars awarded, are available [[Wikipedia:WikiProject Guild of Copy Editors/Backlog elimination drives/January 2015/Barnstars|'''here''']].
+
+'''Progress report:''' We were able to remove August 2013 from the general copyediting backlog and November 2014 from the request-page backlog. Many thanks, everyone!
+
+'''Blitz''': The [[Wikipedia:WikiProject Guild of Copy Editors/Blitzes/February 2015|'''February Blitz''']] will run from February 15–21 and again focuses on the [[WP:GOCE/REQ|requests page]]. Awards will be given to everyone who copyedits at least one request article. [[Wikipedia:WikiProject_Guild_of_Copy_Editors/Blitzes/February_2015#Signing_up|'''Sign up here''']]!
+
+Thank you all again for your participation; we wouldn't be able to achieve what we have without you! Cheers from your GOCE coordinators {{noping|Miniapolis}}, {{noping|Jonesey95}}, {{noping|Biblioworm}} and {{noping|Philg88}}.
+
+{{center
+| <small>To discontinue receiving GOCE newsletters, please remove your name from [[Wikipedia:WikiProject Guild of Copy Editors/Mailing List|our mailing list]].</small>
+}}
+|}
+[[User:MediaWiki message delivery|MediaWiki message delivery]] ([[User talk:MediaWiki message delivery|talk]]) 15:52, 7 February 2015 (UTC)
+<!-- Message sent by User:Miniapolis@enwiki using the list at http://en.wikipedia.org/w/index.php?title=Wikipedia:WikiProject_Guild_of_Copy_Editors/Mailing_List&oldid=645586491 -->
+
+==Talkback==
+{{talkback|Jim Carter|ts=10:44, 8 February 2015 (UTC)}}
+'''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="border:1px solid White; border-radius:99px; background-color:Black"><span style="color:White">Car</span></span><span style="color:#FF0000">ter</span>]]''' 10:44, 8 February 2015 (UTC)
+
+== Please can you check my NPP quality ==
+
+Hi Kudpung. Dunno if you in bed, or busy, but if you have a minute, could you please give a brief glance at my NPP efforts so far? There are not many of them so It should not take long. I am very aware that there are some powerful tools available to the NPP'er, and I just want to know if my basic "feel" and methodology is acceptable. I am very aware of the responsibilities and potential to do inadvertant damage, so I just need some reassurance really. You can be as blunt as you wish. Regards Simon aka [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 19:19, 8 February 2015 (UTC)
+:I've looked at some of your more recent patrols. As usual for most new patrollers you have a tendency to over-tag. This is both a negative ''and'' a positive criticism: it shows tha you are seeing what is wrong with the articles and it shows that you know what tags are available for use. Don't tag relatively harmless articles to soon, but of course any which are blatantly toxic must be tagged as quickly as possible for deletion to rapidly attract the attention of admins. If you are working from the back of the queue remember that some articles may be months or even years old - do check their histories very carefully. Here ae some things that you might like to look at again which illustrate some of my comments:
+*[[Tooker & Marsh]] tage for CSD A7 if you can't find sources
+*[[Nicholas Irving]] Overtagging - tagging the blatantly obvious. Good though because it caught the creator online
+*[[Hitler Stalingrad Speech]] older article. Probably not worth tagging at all. Seems to be factually accurate.
+*[[Under Electric Clouds]] Overtagging - tagging the blatantly obvious.
+:Be sure to make use of the 'message to the creator' feature (this may have less effect on older articles where the creator was an SPA who will probably never return, but do it nevertheless. You are on the right track - keep up the good work. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:46, 9 February 2015 (UTC)
+::Noted and much appreciated. S. [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 14:41, 9 February 2015 (UTC)
+::I am noting some peculiar phenomena as I work from the back of the queue. A proposal for deletion on a long-dormant unworked on article will suddenly provoke a flurry of activity. The original creator suddenly beginning to add cites, or otherwise begin work on the article. This process can be measured in minutes. Odd, but rather encouraging. I am closely following Jim's NPP proposals and the debate being generated from that by the way. I shall be commenting. I feel it is the article creation, rather than the patrollers that may be the issue. Just initial thoughts. Will be revisiting the patrolled examples you highlighted above. I am becoming much lighter on the tagging. Regards as always. S [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 21:29, 9 February 2015 (UTC)
+:::{{U|Irondome|Simon}}, you are right about the flurries of activity - it happens at AfC too when drafts get tagged G13 for not having been edited for 6 months. Nevetheless, check that the improvements are relevant and if the creator has simply fremoved maintenance tags (which often happens) simply restore them.
+:::The problem with NPP is most certainly the patrollers. I've been researching and patrolling the patrollers for 5 years. That said, although I favour a set of criteria of competency for users to be allowed to patrol new pages, it is too soon to be launching that proposal. I wish people wouldn't jump the gun but that's also what enthusiastic newcomers often do. They may not be entirely wrong but they will probably not be aware of what is already being done. A substandard RfC can set its own goals back ''years''. Before anything can be done with NPP it is essential that we get consensus to disband AfC and that could take at least another year. AfC has a terrible 'ownership' syndrome to be conquered first. Yes, being lighter on the tagging, especially when the faults in the articles and stubs are evident is a good idea. Keep reading [[WP:NPP]] over and over again, you'll always find you missed something. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 21:45, 9 February 2015 (UTC)
+::::Of course, {{U|Kudpung|Chris}}. I have completed overlooked the rather bizarre entity that is AfC, which I am now belatedly researching. I see nowhere where it actually fits into the grand scheme, if you will. Certainly a minimum skills set in patrollers can only be a positive, but I fully endorse your policy of gradualism. A premature RfC can be literally devastating for an otherwise good attempt to improve the project, and can set back months of intensive (and unpaid!) research and diplomacy to naught. I am beginning to notice instances of premature RfC's in my brief tenure that have gone horribly wrong. A poorly planned RfC seems to have a strange "souring" effect on the community, where the merits of the proposal are sublimated by an irritation that the case has not been competely or thouroughly presented. Much like a jury. This prejudice can last years in contributors to these tainted RfCs'. A similar thing to the old grudges issue in the RfA process. I am beginning to join the dots, and to begin to appreciate how bloody hard it is and how subtle and patient one has to be to actually get things done. Your encouragement on my modest patrolling efforts is greatly appreciated Chris. I hope we all can meet up in London some time and have a doubtless very interesting conversation. Be good to meet Harry too! Simon. [[User:Irondome|Irondome]] ([[User talk:Irondome|talk]]) 22:05, 9 February 2015 (UTC)
+
+Hi Kudpung, I was going to start a new thread but this related to the above conversation. I agree that AfC has got too over-complicated and empirical evidence has now shown me that, far from being kinder and more compassionate as I had assumed, an AfC decline seems to be just as [[WP:BITE]]y for newbies as a PROD or CSD tag, though I'd be interested to see some statistics of how many "one decline" AfC drafts get abandoned and deleted per G13. I still review the odd AfC submission, but nowadays take each one as a cue to improve it and pass it.
+
+Anyway, I was discussing with [[User:Rhondamerrick|my other half]] why Wikipedia can still appear hostile to newcomers, and the consensus came back, once again, to badly called CSDs. I'm thinking specifically of [[The Mariposa Trust]] and [[Le QuecumBar]], which were both quickly tagged for A7 (multiple times in the case of the Mariposa Trust), but where a simple search for the article's title on Google News returned more than one page of hits, easily allowing me to expand these articles with proper referencing. Would it be possible to change Twinkle (where the majority of CSDs get called from) to bring up a message along the lines of "STOP! Have you followed [[WP:BEFORE]]" as some sort of edit notice if a Google News or Books search on the article's title returns, say, more than 10 hits. The problem with the scenarios above is that looking from hindsight it seems poor from the newcomer's point of view to be slapped about, and when they read up on policies, conclude they shouldn't have been. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 12:27, 10 February 2015 (UTC)
+
+:Maybe the instructions at the top of [[WP:NPP]] could be changed to emphasise the importance of [[WP:BEFORE]]? I've lost count of the number of times I've caught pages which have been tagged, usually as A7, where a quick google search would either establish notability or at least make it iffy enough for the page to go for more scrutiny at [[WP:AFD]] instead. I also think there's a case for making pages ineligible for A7 until about 30-45 minutes have passed, to give creators enough time to add their content, though people opposing could probably point to pages like [[Karim Badie|this]] though. Unless the page is obviously problematic, vandalism, attack pages etc, there's nothing to be lost by watchlisting the page and returning to it later to see if it has improved or not. Unfortunately, a lot of patrollers seem to be in a rush to get there first (I was guilty of those mistakes myself in my early days of NPP) when a little more digging would be more productive for all concerned. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 15:15, 10 February 2015 (UTC)
+
+::I like that idea, and if there's traction it would be nice to make it into a guideline, I have a [https://en.wikipedia.org/w/index.php?title=Special%3AWhatLinksHere&target=Template%3ADb-a7&namespace=0 link to active A7s] that I use all the time, hoping I can spot one that is salvageable. Of the two examples I gave, in both cases I was unsure if they would survive an AfD until I'd expanded up to about 7-8 sources, which was about half an hour's worth of work, and I know what I'm doing. I don't see anything wrong with taking some A7s to AfD, as they do not cause immediate harm to Wikipedia by existing, unlike attack pages and copyvios, a week's grace won't hurt us. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 16:16, 10 February 2015 (UTC)
+
+:::{{U| Ritchie333}}. {{U|Valenciano}}, I spend several ''hours'' every week patrolling the patrollers and I've been doing this for around 4 years. There is so much poor tagging nowadays that I only bother now to contact the patrollers whom I really have to ask to stop patrolling and deven that is far, far too many. I would hesitate to say that the majority of patrollers arfe still working from the old feed. The New pages Feed and the Curation tool have been running now for around two years, so I'm going to make a move soon to get the old feed cdeprecated - to do any good anywhere on Wikipedia, one needs to get maintenance workers singing from the same page and applying the same judgement and criteria.
+:::NPP is not an article hospital or the ARSollers should ''not'' be taking the time to improve or repair artic les. If they do the backlog will be even longer than the current 30,000. Indeed, they should do a 'before' before tagging, but if they find refs they should tell the creator that there are refs out there so would they pleazse add them or have their article slated for deletion. What ever Wikipedia guidelines say, there are very definitely moments when we have to be cruel to be kind, gthe most important thing is to avoid being blunt and bitey when we do it. I could go on and on and on about NPP, but I'm slowly getting totally fed up with say ing the same thing to 20 users a week. This is the kind of thing that one day will cause me to retire for good from Wikipedia. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:23, 11 February 2015 (UTC)
+:::BTW getting A7 delayed for 40 minutes won't wash. It's been suggested before. People who propose such ideas may need somewhat more experience with patrolling and won't have noticed that that the majority of A7 are articles that ''must'' be deleted almost as quickly as spam or attach pages - or are you really going to make a mockery of the process by allowing : '' 'I am Johm Doe and me and Jim are the students in Grade 7 at Mrs Bingo's class' stand for an hour before hammering it - and its creator - into the floor? --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 07:34, 11 February 2015 (UTC)
+::::I don't agree with that sentiment, I'm afraid. What do you mean by "hammering its creator into the floor"? The spam folder on my Gmail account has a grace period of 30 days, I don't think there's a single message I want to read, and that's just one account out of 425 million, that's about a hundred times as many articles on Wikipedia. Google does not generally bring Wikipedia articles to the top of search results until about a week, based on my tracking of [[pink cat]], which despite being created nearly a month ago and having 12 hours linked off the main page via a DYK, does not appear in the first page of hits on a Google Search. These type of articles (which from my experience are more likely to be things like "Advanced Solutions inc is an Indian derivitives analysis company founded in January 2015" or "Bringers of Darkness is a doom metal band from Boise, Idaho") cause no legal harm to the WMF by existing, unlike attack pages or copyvios, and is unlikely to be linked from anywhere in the hour or two it may exist. So my evidence suggests that hastily deleting these types of articles has no obvious benefit, and should not be necessary. [[WP:DEADLINE|Why the rush]]? [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 09:49, 11 February 2015 (UTC)
+:::Overall it's a fine line. We need new contributors and new articles and some of the creators of the latter do get scared away by over hasty tagging, but on the other hand sloppy articles about some "up and coming" band that the creator plays bongos for do create work which takes regulars' time away from adding content and it's often for the sake of an SPA that has no other interest in Wikipedia. There are two issues, firstly, there does need to be more guidance for those new here and submitting the first articles and AFC doesn't seem to have fulfilled that. That could come in the form of technical tweaks to give more advice and guidance when new users are submitting their first articles. Secondly, NPPatrollers need to understand that speedy deletion doesn't necessarily mean nominating pages as quickly as possible, it means that the article deletion process, which would normally take 7-10 days through PROD and AFD, can be done in a matter of hours. The latter could be done by changing the instructions at the top of NPP. You're right regarding the A7 issue and I did acknowledge that above, but I also believe that a lot of A7s could do with a bit more time. The "Danny X is the coolest kid in my class" ones can be nuked fairly quickly, but the ones like "company X is a famous travel agent in India" can be given a little more time just in case there are offline sources covering the company's services or products. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 08:20, 11 February 2015 (UTC)
+::::{{U| Ritchie333}}. {{U|Valenciano}}. Valenciano, have you lived and worked in India? I have. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:04, 11 February 2015 (UTC)
+::::{{U| Ritchie333}}. {{U|Valenciano}}. With all due respect, what it boils down to is that neither of you have properly read what I wrote above. That will of course teach me not to TL;DR... --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:07, 11 February 2015 (UTC)
+:::::I did read what you wrote, but I simply do not agree with your views. There is no reason to disparage anyone with terms such as "trash" or "trolls". I think our conversation is done, and I fear we will continue to lose editors, which is a shame. Happy editing. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 10:31, 11 February 2015 (UTC)
+::::Also, I fail to understand the value pf providing links to deleted G3s when we're disscussing A7. I have aqccess to deleted material, and take it from me, I've been here long enoigh to know the difference between a blatant vandalism and an A7 for an article that stands absolutely no chance whatsoever and should be flagged for deketion as soon as a patroller sees it. It doesn't matter if the creator might have stayed around to create a proper article about something else (let's not kid ourselves, the VAST majority of them don't), what NPP is for is to do a triage of articles, not to read the creator's mind or assess hi/her position and maturity in RL. We are an encyclopedioa, not a psychological counselling service (unless one is here for the pure social networking, but I am not - I'm here to build an encyclopedia and keep it free of trash and trolls, and actually I'm very much an inclusionist). --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 10:16, 11 February 2015 (UTC)
+:::::I read everything you wrote and agree with some, but not all of it, I don't get your point about India. However, there does remain the issue of editor retention and the need to have new blood coming through. You don't throw the baby out with the trash and sometimes that is what NP patrollers are doing, as yes there will be cases, especially in the A7 area, where naive newbies will have posted a worthy topic but will have failed to reference it adequately. Incidentally, if the redlink you are speaking about is [[Karim Badie]], that was an A7 when I posted it as an example and was indeed deleted as such. The fact that a subsequent version was deleted as G3 doesn't change that or the fact that I specifically highlighted that as an example of an article which didn't deserve to stick around. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 14:25, 11 February 2015 (UTC)
+::::::I think things have got a little at cross-purposes. [[The Mariposa Trust]] was a good result. Have a look at [[User talk:Charliallpress|the creator's talk page]]. Couple of cliched bitey twinkle tags, a few ''really'' bitey block warnings, I go in, add 6 reliable sources, everyone says "oops, sorry" and things calm down. That's the stuff I'm talking about. I maybe need to get some metrics of "CSD saves", but it can't be that many (I would guess about 70% - 90% of A7s are generally impossible for me to salvage) and most I do salvage go to BLP prod or AfD. Certainly there were about 20 articles tagged for A7 this morning that I thought "clear cut A7; bin now". But, going back to my original point that seems to have been lost a bit, a script would almost certainly (I haven't checked) report 0 or few news hits for all of those, giving the tagger a "clean" bill of health to CSD it. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 14:50, 11 February 2015 (UTC)
+
+{{od}}The first tagging was A7. It was blatant trolling and could have been tagged as hoax/vandalism, or even with just a tiny stretch of imagination as an attack page. Some of us admins would accord 2% AGF and delete it as a test page to save the creator's face -in which case however an L1 warning about creating inappropriate pages might be conceivable.
+
+The second tagging (on recreation) of the same content by {{U|J man708}} as G3 was perfectly accurate. In both instances the tagging took place within 5 mins or so of creation - and most rightly so - even a raw newbie patroller would know (well, mostly) that you are not going to make a regular Wikipedian out of that author. Sorry to continue to be a damp squid for anyone advocating a delay for tagging of articles that are pure nonense.--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 18:58, 11 February 2015 (UTC)
+
+:As I'm not an admin I can't view the page in question, so will take your word for it, but as I cited that as a specific example of a page which *should* be quickly nuked I'm not sure what point you're trying to make. No one is advocating a delay for nonsense articles. I nominate quite a few myself as soon as I see them and those should quickly go, but there are pages on other topics such as companies which are less obviously problematic, could theoretically have coverage not immediately obvious from google searches like offline sources or through paywalls and articles like that don't need to bite the dust so quickly. How to gain a little more time for those is one of several issues I see at NPP along with the [[WP:BEFORE]] issue of people not even bothering to check for sources. We do need a wider discussion on it. [[User:Valenciano|Valenciano]] ([[User talk:Valenciano|talk]]) 19:26, 11 February 2015 (UTC)
+
+''All'' new articles are referenced and cached by Google within seconds of being posted on Wikipedia - that's part of the deal for Google's $1 mio donation, so that Internet searches ''always'' return Wikipedia articles at the top of the list. Your Gmail content is not referenced at all so I fail totally to see what it has to do with our problems at NPP. Fortunately, when I got the Draft namespace (yes, another of my proposals) created, we stipulated hat drafts will be 'no index, no follow'. That's what should have been included for new pages at NPP until they had been 'patrolled' but somehow the devs failed to do it and now it's an uphil battle to get it done in retro. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 18:58, 11 February 2015 (UTC)
+: I'm sure we're not talking about the same articles. Anyway, WP articles ''used'' to be the top Google search hit, but recently I've found that's not the case so much, they take a while to catch up. [http://www.google.co.uk/search?client=safari&rls=en&q=%22pink+cat%22&ie=UTF-8&oe=UTF-8&gfe_rd=cr&ei=0rrbVJGnNILFaNv1gIAK pink cat] isn't on the first page. [http://www.google.co.uk/search?client=safari&rls=en&q=mariposa+trust&ie=UTF-8&oe=UTF-8&gfe_rd=cr&ei=87rbVMGSC8-DaID3gNgN The Mariposa Trust] is hit #6. I created [[Tape op]] (the term, not the magazine) yesterday and while the magazine might drown that out, I've just been through [http://www.google.com/search?q=%22tape+op%22&client=safari&rls=en&oq=&gs_l= five pages of Google] and not found it. So something has changed somewhere, but as Google never release pagerank algorithms, who knows. Maybe it now takes page views into the equation; obviously older articles will have had lots of views anyway because of their prominence, so will self-weight towards the top. [[User:Ritchie333|<b style="color:#7F007F">Ritchie333</b>]] [[User talk:Ritchie333|<sup style="color:#7F007F">(talk)</sup>]] [[Special:Contributions/Ritchie333|<sup style="color:#7F007F">(cont)</sup>]] 20:33, 11 February 2015 (UTC)
+::{{U| Ritchie333}}. {{U|Valenciano}}, [[The Mariposa Trust]] was tagged A7 by {{U|Harry the Dirty Dog}} in '''less than a minute''' of its creation. The patroller, around since 2007 with an EC of 13,569, should have known better than to tag so quickly and should have applied other maintenance tags and made use of the message feature. Contrary to policy, the creator {{U|Charliallpress}} almost instantly removed the CSD themself and within less than a minute the tag was restored, again by {{U|Harry the Dirty Dog}} - this should have been an alert to the patroller who seems to patrol with a vengeance. However, the first and second pages of Google did not return any RS, and that's all a patroller is expected to as a ''Before'', apart from checking for COPYVIO. I would therefore probably have tagged ''that'' page for A7 but certainly not within less than 20 minutes. I click to add such pages to my watchlist and go back to then after 20 minutes or so. I will soon find out later if it is still a blue link and if it is I will look to see why.
+
+::The fiasco of a discussion on the creator’s talk page starts of being rather bitey and only after a lot of kerfuffle does it start to get any nicer. Admittedly it pays to remember that Charliallpress is not here to become a regular Wikipedia contributor but nevertheless their article was neither a hoax/vandalism or otherwise toxic and they deserved to be treated in GF. Lessons to be learned all round (except {{U|MelanieN}} who I recently [[Wikipedia:Requests for adminship/MelanieN|turned into an admin|| and will be one of the best we have).
+
+::This article and its creator are classic examples of the Foundation’s mammoth failure after all these years to address the lack of a proper landing page for new users - I believe this to be a WMF mandate even more than the creation of the new page feed and it curation thing. Indeed,development of the Article Creation Flow began but when things cooled down it was swept under the carpet. Follow up talks every 6 - 12 months have received vague promises but still nothing has been done. While the WMF will refuse, even with overwhelming community consensus, to introduce any mechanism to restrict creation of articles to [[WP:Autoconfirmed|auto confirmed]] users, there is nothing in that policy that says we cannot force all new users to build their first article through the [[Article Wizard]] - and that’s what IMO should be done. What needs to be done is:
+:::*Significantly improve the quality of NPP and either introduce a technically imposed qualification for doing it or significantly step up the control of those who patrol.
+:::*Create a proper landing page for new users, trolls, spammers, SPa, and who ever else, so that they have a clearer idea of what an [[encyclopedia]] is.
+:::*''Force'' at least all non confirmed users to choose to create either through the Article Wizard or to create a Draft first for submission to AfC (bearing in mind that there is a growing movement to migrate AfC to NPP and not without reason.
+:::*Maintain the new quality of voting at RfA and continue our campaign to get users of the right calibre to run for adminship.
+:::*Get regular editors more involved in the RfA voting process.
+:::*Make it much quicker and easier to desysop the admins (probably pre-2007 promotions) who have a pattern of abusing their mandate.
+::None of the above is impossible and I can't see anyone seriously disagreeing. Just needs aforethought and some careful planning. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 02:27, 12 February 2015 (UTC)
+
+== Thai user ==
+
+Hi Kudpung, not sure how much Thai you speak, but we have a bit of an issue with a Thai user. {{u|RKC Vakwai}} is uploading a lot of Thai football club logos, which in and of itself is not the issue, if they were properly licenced. The user is claiming they are the creator, and copyright holder, which is obviously not the case, having a look at their talk page, you can see the mass amount of messages, warnings, etc. that he/she has received. There was even a not so in depth discussion at AN/I a year ago which, really only resulted in a short message by another user. I dropped the last one, with a stop sign (presuming English as not a first language, visuals are good), saying don't upload anything without the correct licence. I am sure the actual message got lost in translation, but the concept is understood, based on [https://en.wikipedia.org/w/index.php?title=User%3AKelapstick&diff=646825765&oldid=643405902 this edit] on my talk page. If you do know any Thai (or someone who does), could you explain the concept of fair use logos to this user? Really we can save a lot of time, work, and hassle if they just upload the images as fair use, but I personally cannot explain that in a way they will understand (my rather stern warning was really just to get them to stop uploading temporarily, lest they actually get blocked). Ta, --[[User:kelapstick|kelapstick]]<sup>([[User talk:Kelapstick#top|bainuu]]) </sup> 21:01, 12 February 2015 (UTC)
+:Also you seem to have a fan - {{noping|Reptiles Birds Exotic AnimalsYes Bad UsersNo}}... --[[User:kelapstick|kelapstick]]<sup>([[User talk:Kelapstick#top|bainuu]]) </sup> 21:14, 12 February 2015 (UTC)
+
+:Hi {{U|kelapstick}}. sorry to disappoint you but while I ''speak'' relatively fluent Thai, and can read it just a tiny bit, it's worlds away from discussing anything in that language with anyone on Wikipedia.--[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 12:54, 13 February 2015 (UTC)
+::No worries, thanks anyway Kudpung. --[[User:kelapstick|kelapstick]]<sup>([[User talk:Kelapstick#top|bainuu]]) </sup> 13:03, 13 February 2015 (UTC)
+
+== Valentine Greets!!! ==
+{| style="background-color: #FA8072; border: 4px solid #DC143C;"
+|rowspan="2" style="vertical-align: middle; padding: 1px;" | [[File:Wikilove2 new.png|211px]]
+|style="font-size: x-large; padding: 2px 2px 0 2px; height: 1.5em;" | '''Valentine Greets!!!'''
+|-
+|style="vertical-align: middle; padding: 3px;" |
+----
+'''Hello Kudpung, [[love]] is the language of hearts and is the feeling that joins two souls and brings two hearts together in a bond. Taking love to the level of [[Wikipedia]], spread the [[Wikipedia:WikiLove|WikiLove]] by wishing each other [[Valentine's Day|Happy Valentine's Day]], whether it be someone you have had disagreements with in the past, a good friend, or just some random person.<br />
+Sending you a heartfelt and warm love on the eve, <br>
+Happy editing,<br>
+&nbsp;-&nbsp;[[User:The Herald|'''T H''']] ([[User talk:The Herald|''here I am'']]) 12:08, 13 February 2015 (UTC)
+
+''{{resize|96%|Spread the love by adding {{tls|Valentine Greetings}} to other user talk pages.}}''
+|}
+== Me? ==
+[[Special:Diff/647199277|<s>Is</s> Are you]] referring me among those unhelpful editors? '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 15:01, 15 February 2015 (UTC)
+:{{U|Jim Carter|Jim}}, It's not 'Is you' it's 'Are you', and I'm referring to users who have been around since long before you joined Wikipedia, and who have a particularly nasty disposition - remember some of us have been around here for 10 years or more. Stop being so paranoid. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 15:10, 15 February 2015 (UTC)
+::Oh! I started this thread with "Is" as I wanted to say something else but later changed it but forgot to change that word. Don't count my grammatical mistakes, I make plenty; though I'm able to write two GAs and a FL. I'm asking you because I'm a bit confused as your comment there didn't made it clear to whom you're referring. Best, '''[[User:Jim Carter|<span style="color:#000000">Jim</span> <span style="color:#FF0000">Car</span><span style="color:#FFCC00">ter</span>]]''' 16:05, 15 February 2015 (UTC)
+:::Well, {{U|Jim Carter|Jim}}, you need to follow that thread some more, because {{U|Buster7}} has been doling some math. Wikipedia rules forbid me from naming manes or even making comments through which such individuals can be instantly identified. It's a very 'knife-edge' thing where some are concerned who are bent on destroying the editing pleasure of other volunteers. Some of them are now on a very short leash and will probably be banned before the year's out, and others will follow soon - some admins have been been oiling the mechanisms of their block buttons. --[[User:Kudpung|Kudpung กุดผึ้ง]] ([[User talk:Kudpung#top|talk]]) 16:26, 15 February 2015 (UTC)
diff --git a/Echo/tests/phpunit/includes/revision_txt/README b/Echo/tests/phpunit/includes/revision_txt/README
new file mode 100644
index 00000000..9a483aee
--- /dev/null
+++ b/Echo/tests/phpunit/includes/revision_txt/README
@@ -0,0 +1,4 @@
+This folder holds wikitext revision excerpts that are used in
+phpunit/includes/DiscussionParserTest.php
+
+It just seemed a bit overkill to include the entire content in the PHP code ;)
diff --git a/Echo/tests/phpunit/maintenance/SupressionMaintenanceTest.php b/Echo/tests/phpunit/maintenance/SupressionMaintenanceTest.php
new file mode 100644
index 00000000..5547e384
--- /dev/null
+++ b/Echo/tests/phpunit/maintenance/SupressionMaintenanceTest.php
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @group Echo
+ */
+class SuppressionMaintenanceTest extends MediaWikiTestCase {
+
+ public static function provider_updateRow() {
+ $input = array(
+ 'event_id' => 2,
+ 'event_type' => 'mention',
+ 'event_variant' => null,
+ 'event_agent_id' => 3,
+ 'event_agent_ip' => null,
+ 'event_page_title' => '',
+ 'event_page_namespace' => 0,
+ 'event_page_extra' => null,
+ 'event_extra' => null,
+ 'event_page_id' => null,
+ );
+ return array(
+ array( 'Unrelated row must result in no update', array(), $input ),
+
+ array(
+ 'Page title and namespace for non-existant page must move into event_extra',
+ array( // expected update
+ 'event_extra' => serialize( array(
+ 'page_title' => 'Yabba Dabba Do',
+ 'page_namespace' => NS_MAIN
+ ) ),
+ ),
+ array( // input row
+ 'event_page_title' => 'Yabba Dabba Do',
+ 'event_page_namespace' => NS_MAIN,
+ ) + $input,
+ ),
+
+ array(
+ 'Page title and namespace for existing page must be result in update to event_page_id',
+ array( // expected update
+ 'event_page_id' => 42,
+ ),
+ array( // input row
+ 'event_page_title' => 'Mount Rushmore',
+ 'event_page_namespace' => NS_MAIN,
+ ) + $input,
+ self::attachTitleFor( 42, 'Mount Rushmore', NS_MAIN )
+ ),
+
+ array(
+ 'When updating non-existant page must keep old extra data',
+ array( // expected update
+ 'event_extra' => serialize( array(
+ 'foo' => 'bar',
+ 'page_title' => 'Yabba Dabba Do',
+ 'page_namespace' => NS_MAIN
+ ) ),
+ ),
+ array( // input row
+ 'event_page_title' => 'Yabba Dabba Do',
+ 'event_page_namespace' => NS_MAIN,
+ 'event_extra' => serialize( array( 'foo' => 'bar' ) ),
+ ) + $input,
+ ),
+
+ array(
+ 'Must update link-from-title/namespace to link-from-page-id for page-linked events',
+ array( // expected update
+ 'event_extra' => serialize( array( 'link-from-page-id' => 99 ) ),
+ ),
+ array( //input row
+ 'event_type' => 'page-linked',
+ 'event_extra' => serialize( array(
+ 'link-from-title' => 'Horse',
+ 'link-from-namespace' => NS_USER_TALK
+ ) ),
+ ) + $input,
+ self::attachTitleFor( 99, 'Horse', NS_USER_TALK )
+ ),
+
+ array(
+ 'Must perform both generic update and page-linked update at same time',
+ array( // expected update
+ 'event_extra' => serialize( array( 'link-from-page-id' => 8675309 ) ),
+ 'event_page_id' => 8675309,
+ ),
+ array( //input row
+ 'event_type' => 'page-linked',
+ 'event_extra' => serialize( array(
+ 'link-from-title' => 'Jenny',
+ 'link-from-namespace' => NS_MAIN,
+ ) ),
+ 'event_page_title' => 'Jenny',
+ 'event_page_namespace' => NS_MAIN,
+ ) + $input,
+ self::attachTitleFor( 8675309, 'Jenny', NS_MAIN ),
+ ),
+ );
+ }
+
+ protected static function attachTitleFor( $id, $providedText, $providedNamespace ) {
+ return function( $test, $gen ) use ( $id, $providedText, $providedNamespace ) {
+ $title = $test->getMock( 'Title' );
+ $title->expects( $test->any() )
+ ->method( 'getArticleId' )
+ ->will( $test->returnValue( $id ) );
+
+ $titles = array( $providedNamespace => array( $providedText => $title ) );
+
+ $gen->setNewTitleFromText( function( $text, $defaultNamespace ) use( $titles ) {
+ if ( isset( $titles[$defaultNamespace][$text] ) ) {
+ return $titles[$defaultNamespace][$text];
+ }
+ return Title::newFromText( $text, $defaultNamespace );
+ } );
+ };
+ }
+
+ /**
+ * @dataProvider provider_updateRow
+ */
+ public function testUpdateRow( $message, $expected, $input, $callable = null ) {
+ $gen = new EchoSuppressionRowUpdateGenerator;
+ if ( $callable ) {
+ call_user_func( $callable, $this, $gen );
+ }
+ $update = $gen->update( (object) $input );
+ $this->assertEquals( $expected, $update, $message );
+ }
+}
diff --git a/Echo/tests/phpunit/model/NotificationTest.php b/Echo/tests/phpunit/model/NotificationTest.php
new file mode 100644
index 00000000..267bd25a
--- /dev/null
+++ b/Echo/tests/phpunit/model/NotificationTest.php
@@ -0,0 +1,88 @@
+<?php
+
+class EchoNotificationTest extends MediaWikiTestCase {
+
+ public function testNewFromRow() {
+ $row = $this->mockNotificationRow() + $this->mockEventRow();
+
+ $notif = EchoNotification::newFromRow( (object)$row );
+ $this->assertInstanceOf( 'EchoNotification', $notif );
+ // getReadTimestamp() should return null
+ $this->assertNull( $notif->getReadTimestamp() );
+ $this->assertEquals(
+ $notif->getTimestamp(),
+ wfTimestamp( TS_MW, $row['notification_timestamp'] )
+ );
+ $this->assertInstanceOf( 'EchoEvent', $notif->getEvent() );
+ $this->assertNull( $notif->getTargetPages() );
+
+ // Provide a read timestamp
+ $row['notification_read_timestamp'] = time() + 1000;
+ $notif = EchoNotification::newFromRow( (object)$row );
+ // getReadTimestamp() should return the timestamp in MW format
+ $this->assertEquals(
+ $notif->getReadTimestamp(),
+ wfTimestamp( TS_MW, $row['notification_read_timestamp'] )
+ );
+
+ $notif = EchoNotification::newFromRow( (object)$row, array(
+ EchoTargetPage::newFromRow( (object)$this->mockTargetPageRow() )
+ ) );
+ $this->assertGreaterThan( 0, count( $notif->getTargetPages() ) );
+ foreach ( $notif->getTargetPages() as $targetPage ) {
+ $this->assertInstanceOf( 'EchoTargetPage', $targetPage );
+ }
+ }
+
+ /**
+ * @expectedException MWException
+ */
+ public function testNewFromRowWithException() {
+ $row = $this->mockNotificationRow();
+ // Provide an invalid event id
+ $row['notification_event'] = -1;
+ $noitf = EchoNotification::newFromRow( (object)$row );
+ }
+
+ /**
+ * Mock a notification row from database
+ */
+ protected function mockNotificationRow() {
+ return array (
+ 'notification_user' => 1,
+ 'notification_event' => 1,
+ 'notification_timestamp' => time(),
+ 'notification_read_timestamp' => '',
+ 'notification_bundle_base' => 1,
+ 'notification_bundle_hash' => 'testhash',
+ 'notification_bundle_display_hash' => 'testdisplayhash'
+ );
+ }
+
+ /**
+ * Mock an event row from database
+ */
+ protected function mockEventRow() {
+ return array (
+ 'event_id' => 1,
+ 'event_type' => 'test_event',
+ 'event_variant' => '',
+ 'event_extra' => '',
+ 'event_page_id' => '',
+ 'event_agent_id' => '',
+ 'event_agent_ip' => ''
+ );
+ }
+
+ /**
+ * Mock a target page row
+ */
+ protected function mockTargetPageRow() {
+ return array (
+ 'etp_user' => 1,
+ 'etp_page' => 2,
+ 'etp_event' => 1
+ );
+ }
+
+}
diff --git a/Echo/tests/phpunit/model/TargetPageTest.php b/Echo/tests/phpunit/model/TargetPageTest.php
new file mode 100644
index 00000000..29670ff7
--- /dev/null
+++ b/Echo/tests/phpunit/model/TargetPageTest.php
@@ -0,0 +1,99 @@
+<?php
+
+class EchoTargetPageTest extends MediaWikiTestCase {
+
+ public function testCreate() {
+ $this->assertNull(
+ EchoTargetPage::create(
+ User::newFromId( 0 ),
+ $this->mockTitle( 1 ),
+ $this->mockEchoEvent()
+ )
+ );
+
+ $this->assertNull(
+ EchoTargetPage::create(
+ User::newFromId( 1 ),
+ $this->mockTitle( 0 ),
+ $this->mockEchoEvent()
+ )
+ );
+
+ $this->assertNull(
+ EchoTargetPage::create(
+ User::newFromId( 0 ),
+ $this->mockTitle( 0 ),
+ $this->mockEchoEvent()
+ )
+ );
+
+ $this->assertInstanceOf(
+ 'EchoTargetPage',
+ EchoTargetPage::create(
+ User::newFromId( 1 ),
+ $this->mockTitle( 1 ),
+ $this->mockEchoEvent()
+ )
+ );
+ }
+
+ public function testNewFromRow() {
+ $row = (object) array (
+ 'etp_user' => 1,
+ 'etp_page' => 2,
+ 'etp_event' => 3
+ );
+ $obj = EchoTargetPage::newFromRow( $row );
+ $this->assertInstanceOf( 'EchoTargetPage', $obj );
+ return $obj;
+ }
+
+ /**
+ * @expectedException MWException
+ */
+ public function testNewFromRowWithException() {
+ $row = (object) array (
+ 'etp_page' => 2,
+ 'etp_event' => 3
+ );
+ $this->assertInstanceOf( 'EchoTargetPage', EchoTargetPage::newFromRow( $row ) );
+ }
+
+ /**
+ * @depends testNewFromRow
+ */
+ public function testToDbArray( $obj ) {
+ $row = $obj->toDbArray();
+ $this->assertTrue( is_array( $row ) );
+ $this->assertArrayHasKey( 'etp_user', $row );
+ $this->assertArrayHasKey( 'etp_page', $row );
+ $this->assertArrayHasKey( 'etp_event', $row );
+ }
+
+ /**
+ * Mock object of Title
+ */
+ protected function mockTitle( $pageId ) {
+ $event = $this->getMockBuilder( 'Title' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getArticleID' )
+ ->will( $this->returnValue( $pageId ) );
+ return $event;
+ }
+
+ /**
+ * Mock object of EchoEvent
+ */
+ protected function mockEchoEvent( $eventId = 1 ) {
+ $event = $this->getMockBuilder( 'EchoEvent' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects( $this->any() )
+ ->method( 'getId' )
+ ->will( $this->returnValue( $eventId ) );
+ return $event;
+ }
+
+}
diff --git a/Echo/tests/qunit/overlay/test_ext.echo.overlay.js b/Echo/tests/qunit/overlay/test_ext.echo.overlay.js
new file mode 100644
index 00000000..7f456b6b
--- /dev/null
+++ b/Echo/tests/qunit/overlay/test_ext.echo.overlay.js
@@ -0,0 +1,307 @@
+( function( $, mw ) {
+ QUnit.module( 'ext.echo.overlay', {
+ setup: function() {
+ this.$badge = $( '<a class="mw-echo-notifications-badge mw-echo-unread-notifications">1</a>' );
+ this.sandbox.stub( mw.echo, 'getBadge' ).returns( this.$badge );
+ // Kill any existing overlays to avoid clashing with other tests
+ $( '.mw-echo-overlay' ).remove();
+
+ var ApiStub = function( mode, numberUnreadMessages ) {
+ this.mode = mode;
+ this.numberUnreadMessages = numberUnreadMessages || 7;
+ };
+ ApiStub.prototype = {
+ post: function( data ) {
+ return new $.Deferred().resolve( this.getNewNotificationCountData( data,
+ this.mode === 'with-new-messages' ) );
+ },
+ get: function() {
+ var i, id,
+ index = [], listObj = {},
+ data = this.getData();
+ // a response which contains 0 unread messages and 1 unread alert
+ if ( this.mode === 'no-new-messages' ) {
+ data.query.notifications.message = {
+ index: [ 100 ],
+ list: {
+ 100: {
+ '*': 'Jon sent you a message on the Flow board Talk:XYZ',
+ read: '20140805211446',
+ category: 'message',
+ id: 100,
+ type: 'message'
+ }
+ },
+ rawcount: 0,
+ count: '0'
+ };
+ // a response which contains 8 unread messages and 1 unread alert
+ } else if ( this.mode === 'with-new-messages' ) {
+ for ( i = 0; i < 7; i++ ) {
+ id = 500 + i;
+ index.push( id );
+ listObj[id] = { '*': '!', category: 'message', id: id, type: 'message' };
+ }
+ data.query.notifications.message = {
+ index: index,
+ list: listObj,
+ rawcount: this.numberUnreadMessages,
+ count: '' + this.numberUnreadMessages
+ };
+ // Total number is number of messages + number of alerts (1)
+ data.query.notifications.count = this.numberUnreadMessages + 1;
+ data.query.notifications.rawcount = this.numberUnreadMessages + 1;
+ }
+ return $.Deferred().resolve( data );
+ },
+ getNewNotificationCountData: function( data, hasNewMessages ) {
+ var alertCount, messageCount,
+ rawCount = 0,
+ count = 0;
+
+ messageCount = {
+ count: '0',
+ rawcount: 0
+ };
+ alertCount = {
+ count: '0',
+ rawcount: 0
+ };
+ if ( data.list === '100' ) {
+ alertCount = {
+ count: '0',
+ rawcount: 0
+ };
+ count = 1;
+ rawCount = 1;
+ }
+
+ if ( hasNewMessages && data.sections === 'alert' ) {
+ messageCount = {
+ count: '7',
+ rawcount: 7
+ };
+ rawCount = 7;
+ count = 7;
+ }
+
+ if ( data.list === 500 ) {
+ messageCount = {
+ count: '6',
+ rawcount: 6
+ };
+ rawCount = 6;
+ count = 6;
+ }
+
+ data = {
+ query: {
+ echomarkread: {
+ alert: alertCount,
+ message: messageCount,
+ rawcount: rawCount,
+ count: count
+ }
+ }
+ };
+ return data;
+ },
+ getData: function() {
+ return {
+ query: {
+ notifications: {
+ count: '1',
+ rawcount: 1,
+ message: {
+ rawcount: 0,
+ count: '0',
+ index: [],
+ list: {}
+ },
+ alert: {
+ rawcount: 1,
+ count: '1',
+ index: [ 70, 71 ],
+ list: {
+ 70: {
+ '*': 'Jon mentioned you.',
+ agent: { id: 212, name: 'Jon' },
+ category: 'mention',
+ id: 70,
+ read: '20140805211446',
+ timestamp: {
+ unix: '1407273276'
+ },
+ title: {
+ full: 'Spiders'
+ },
+ type: 'mention'
+ },
+ 71: {
+ '*': 'X talked to you.',
+ category: 'edit-user-talk',
+ id: 71,
+ type: 'edit-user-talk'
+ }
+ }
+ }
+ }
+ }
+ };
+ }
+ };
+ this.ApiStub = ApiStub;
+ }
+ } );
+
+ QUnit.test( 'mw.echo.overlay.buildOverlay', 7, function( assert ) {
+ var $overlay;
+ this.sandbox.stub( mw.echo.overlay, 'api', new this.ApiStub() );
+ mw.echo.overlay.buildOverlay( function( $o ) {
+ $overlay = $o;
+ } );
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title ul li' ).length, 1, 'Only one tab in header' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications' ).length, 1, 'Overlay contains a list of notifications.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications li' ).length, 2, 'There are two notifications.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-unread' ).length, 1, 'There is one unread notification.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-footer a' ).length, 2,
+ 'There is a footer with 2 links to preferences and all notifications.' );
+ assert.strictEqual( this.$badge.text(),
+ '0', 'The alerts are marked as read once opened.' );
+ assert.strictEqual( this.$badge.hasClass( 'mw-echo-unread-notifications' ),
+ false, 'The badge no longer indicates new messages.' );
+ } );
+
+ QUnit.test( 'mw.echo.overlay.buildOverlay with messages', 5, function( assert ) {
+ var $overlay;
+ this.sandbox.stub( mw.echo.overlay, 'api', new this.ApiStub( 'no-new-messages' ) );
+ mw.echo.overlay.buildOverlay( function( $o ) {
+ $overlay = $o;
+ } );
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title ul li' ).length, 2, 'There are two tabs in header' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications' ).length, 2, 'Overlay contains 2 lists of notifications.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title a' ).eq( 0 ).hasClass( 'mw-ui-quiet' ),
+ true, 'First tab is the selected tab upon opening.' );
+ assert.strictEqual( this.$badge.text(),
+ '0', 'The label updates to 0 as alerts tab is default and now alerts have been read.' );
+ assert.strictEqual( this.$badge.hasClass( 'mw-echo-unread-notifications' ),
+ false, 'The notification button class is updated with the default switch to alert tab.' );
+ } );
+
+ QUnit.test( 'Switch tabs on overlay. 1 unread alert, no unread messages.', 7, function( assert ) {
+ var $overlay, $tabs;
+
+ this.sandbox.stub( mw.echo.overlay, 'api', new this.ApiStub( 'no-new-messages' ) );
+ mw.echo.overlay.buildOverlay( function( $o ) {
+ $overlay = $o;
+ // switch to 1st tab (alerts)
+ $overlay.find( '.mw-echo-overlay-title li a' ).eq( 0 ).trigger( 'click' );
+ } );
+
+ $tabs = $overlay.find( '.mw-echo-overlay-title li a' );
+
+ assert.strictEqual( $tabs.eq( 0 ).hasClass( 'mw-ui-quiet' ),
+ true, 'First tab is now the selected tab.' );
+ assert.strictEqual( $tabs.eq( 1 ).hasClass( 'mw-ui-quiet' ),
+ false, 'Second tab is not the selected tab.' );
+ assert.strictEqual( this.$badge.text(),
+ '0', 'The label is now set to 0.' );
+ assert.strictEqual( this.$badge.hasClass( 'mw-echo-unread-notifications' ),
+ false, 'There are now zero unread notifications.' );
+
+ assert.strictEqual( $tabs.eq( 0 ).text(), 'Alerts (0)', 'Check the label has a count in it.' );
+ assert.strictEqual( $tabs.eq( 1 ).text(), 'Messages (0)', 'Check the label has an updated count in it.' );
+ assert.strictEqual( $tabs.eq( 1 ).hasClass( 'mw-ui-active' ),
+ true, 'Second tab has active class .as it is the only clickable tab' );
+ } );
+
+ QUnit.test( 'Unread message behaviour', 5, function( assert ) {
+ var $overlay;
+
+ this.sandbox.stub( mw.echo.overlay, 'api', new this.ApiStub( 'with-new-messages' ) );
+ mw.echo.overlay.buildOverlay( function( $o ) {
+ $overlay = $o;
+ } );
+
+ // Test initial state
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title li a' ).eq( 1 ).text(), 'Messages (7)',
+ 'Check the label has a count in it and it is not automatically reset when tab is open.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-unread' ).length, 8, 'There are 8 unread notifications.' );
+
+ // Click mark as read
+ $overlay.find( '.mw-echo-notifications > button' ).eq( 0 ).trigger( 'click' );
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title li a' ).eq( 1 ).text(), 'Messages (0)',
+ 'Check all the notifications (even those outside overlay) have been marked as read.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications ' ).eq( 1 ).find( '.mw-echo-unread' ).length,
+ 0, 'There are now no unread notifications in this tab.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications > button' ).length, 0,
+ 'There are no notifications now so no need for button.' );
+ } );
+
+ QUnit.test( 'Mark as read.', 8, function( assert ) {
+ var $overlay;
+ this.$badge.text( '8' );
+ this.sandbox.stub( mw.echo.overlay, 'api', new this.ApiStub( 'with-new-messages' ) );
+ mw.echo.overlay.buildOverlay( function( $o ) {
+ $overlay = $o;
+ } );
+
+ // Test initial state
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title li a' ).eq( 1 ).text(), 'Messages (7)',
+ 'Check the label has a count in it and it is not automatically reset when tab is open.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-unread' ).length, 8,
+ 'There are 7 unread message notifications and although the alert is marked as read on server is displays as unread in overlay.' );
+ assert.strictEqual( this.$badge.text(), '7', '7 unread notifications in badge (alerts get marked automatically).' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications li button' ).length, 7,
+ 'There are 7 mark as read button.' );
+
+ // Click first mark as read
+ $overlay.find( '.mw-echo-notifications li button' ).eq( 0 ).trigger( 'click' );
+
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title li a' ).eq( 1 ).text(), 'Messages (6)',
+ 'Check the notification was marked as read.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-unread' ).length, 7,
+ 'There are now 6 unread message notifications in UI and 1 unread alert.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications li button' ).length, 6,
+ 'There are now 6 mark as read buttons.' );
+ assert.strictEqual( this.$badge.text(), '6', 'Now 6 unread notifications.' );
+ } );
+
+ QUnit.test( 'Tabs when there is overflow.', 2, function( assert ) {
+ var $overlay;
+ this.sandbox.stub( mw.echo.overlay, 'api', new this.ApiStub( 'with-new-messages', 50 ) );
+ mw.echo.overlay.buildOverlay( function( $o ) {
+ $overlay = $o;
+ } );
+
+ // Test initial state
+ assert.strictEqual( $overlay.find( '.mw-echo-overlay-title li a' ).eq( 1 ).text(), 'Messages (50)',
+ 'Check the label has a count in it and reflects the total unread and not the shown unread' );
+ assert.strictEqual( $overlay.find( '.mw-echo-unread' ).length, 8, 'There are 8 unread notifications.' );
+ } );
+
+ QUnit.test( 'Switching tabs visibility', 4, function( assert ) {
+ var $overlay;
+
+ this.sandbox.stub( mw.echo.overlay, 'api', new this.ApiStub( 'with-new-messages' ) );
+ mw.echo.overlay.buildOverlay( function( $o ) {
+ // put in dom so we can do visibility tests
+ $overlay = $o.appendTo( '#qunit-fixture' );
+ } );
+
+ // Test initial state
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications' ).eq( 0 ).is( ':visible' ),
+ true, 'First tab (alerts) starts visible.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications' ).eq( 1 ).is( ':visible' ),
+ false, 'Second tab (messages) starts hidden.' );
+
+ // Switch to second tab
+ $overlay.find( '.mw-echo-overlay-title li a' ).eq( 1 ).trigger( 'click' );
+
+ // check new tab visibility
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications' ).eq( 0 ).is( ':visible' ),
+ false, 'First tab is now hidden.' );
+ assert.strictEqual( $overlay.find( '.mw-echo-notifications' ).eq( 1 ).is( ':visible' ),
+ true, 'Second tab is now visible.' );
+ } );
+}( jQuery, mediaWiki ) );
diff --git a/Echo/version b/Echo/version
new file mode 100644
index 00000000..bea66132
--- /dev/null
+++ b/Echo/version
@@ -0,0 +1,4 @@
+Echo: REL1_25
+2015-06-16T21:06:07
+
+995570a