Compare commits

...
232 Commits
Author SHA1 Message Date
Kim Gardner 1575b15e36 Merge pull request #2374 from leeeandroo/german-translations
Added missing German translations.
2019-06-21 15:32:55 +01:00
Kim Gardner 7da9126a76 Merge branch 'master' into german-translations 2019-06-21 15:24:17 +01:00
Kim Gardner 9453d207f5 Merge pull request #2373 from leeeandroo/featured-tooltip-breakword
Break headline on featured comments plugin
2019-06-21 15:23:18 +01:00
Leandro Vasco da Rocha 869c760a8b Grammatical changes on German wording 2019-06-20 14:44:52 +02:00
Leandro Vasco da Rocha b283595c97 Break headline on featured comments plugin.
If a headline is too long, we need to break it to fit the tooltip
content box.
2019-06-20 13:24:05 +02:00
Leandro Vasco da Rocha d672af63f9 Added missing german translations. 2019-06-18 15:53:27 +02:00
Kim Gardner b4ad78fd65 Bump version 4.9.1 (#2361) 2019-06-14 15:28:26 +00:00
Kim Gardner 713de46c2a Merge pull request #2359 from coralproject/corl-427
[CORL-427] AddEmailAddressDialog should appear at the top
2019-06-14 14:53:46 +01:00
Chi Vinh Le fc1e51ed62 fix: Position Add Email Address Dialog to the top 2019-06-14 00:08:37 +02:00
Etienne Martin 4eef6f4218 Added missing translations (#2357) 2019-06-13 19:06:41 +00:00
Kim Gardner c8cfd7c0f8 Merge pull request #2345 from coralproject/bump-4-9-0
Bump version 4.9.0
2019-06-06 20:11:11 +01:00
Kim Gardner 0e4cbf5f44 Bump version 4.9.0 2019-06-06 19:59:58 +01:00
Kim Gardner 448b988281 Merge pull request #2327 from coralproject/next-amp-docs
AMP docs
2019-06-05 20:55:40 +01:00
Kim Gardner 7a688495f2 Merge branch 'master' into next-amp-docs 2019-05-29 13:29:57 +01:00
Kim Gardner b9cf7084eb Merge pull request #2326 from Sentynel/master
Don't crash on email address lookup failure
2019-05-29 13:29:34 +01:00
Kim Gardner b99161f0cb Merge branch 'master' into next-amp-docs 2019-05-29 12:59:22 +01:00
Kim Gardner 6faa4862de Merge branch 'master' into master 2019-05-29 12:58:57 +01:00
Aram Zucker-Scharff eff3f1dfd8 Small correction of a spelling error (#2325) 2019-05-28 16:36:17 +00:00
immber 73aa77d7da CORL-380 | DOCS | Updates pre-launch checklist, asset scraping (#2317)
* updated asset scraping docs

* added note about setting close date

* added close window setting details
2019-05-27 17:58:18 +02:00
Chi Vinh Le 5580ab385f fix: remove margin from amp body 2019-05-27 17:20:07 +02:00
Chi Vinh Le 40eb0e97ec docs: add amp docs 2019-05-27 17:19:05 +02:00
Sam Lade b7e1ce0205 Don't crash on email address lookup failure
If for whatever reason an email job gets queued for a user with no
email, an exception is thrown on the getEmailAddress() step. This
exception was never handled and therefore the app crashed. Handle it and
log instead..
2019-05-27 14:12:14 +01:00
Kiwi bfde9bf8c7 [CORL-373] Experimental AMP Support (#2324)
* feat: support amp

* fix: support a custom PORT for amp development
2019-05-23 20:42:58 +02:00
Gerardo Gálvez 54f9b28086 Show/hide a comment's edit history from Moderation and User Detail. (#2299)
* Show/Hide comment edit history in moderation queues and user detail.

* Add spanish translations

* Place timestamp and comment body on separate lines

* Remove padding between timestamp and comment
2019-05-15 19:57:21 +02:00
immber 03a5eb7f9b Merge pull request #2307 from coralproject/fbdocs
DOCS | Update fb app creation steps
2019-05-09 15:51:51 -07:00
immber 43e60e6544 Merge branch 'master' into fbdocs 2019-05-09 15:37:24 -07:00
Jessie Rushing ebd16666e6 Merge branch 'fbdocs' of https://github.com/coralproject/talk into fbdocs 2019-05-09 15:36:37 -07:00
Jessie Rushing f2129082a9 added note about location of live button 2019-05-09 15:35:41 -07:00
Kim Gardner 1098c068f2 Merge pull request #2310 from coralproject/bump-version-4-8-7
Bump version 4.8.7
2019-05-09 23:19:10 +01:00
Kim Gardner f0c95d0044 Update package.json 2019-05-09 23:12:14 +01:00
immber 74226aa6fc Merge branch 'master' into fbdocs 2019-05-09 15:08:59 -07:00
Jessie Rushing b6ed5b792b updated Fb dev steps 2019-05-09 15:07:40 -07:00
Kim Gardner d31969592c Remove quotes from Featured Comments (#2309) 2019-05-09 23:50:43 +02:00
Kiwi 794487b1a9 fix: bug where erasing the edit RTE content would respawn the original content (#2308) 2019-05-09 23:22:14 +02:00
Jessie Rushing 39e45c30ba added callback url 2019-05-08 16:05:13 -07:00
Jessie Rushing ed734ebb08 update fb app creation steps 2019-05-08 15:42:06 -07:00
Kim Gardner 9f059e0c4a Docs typo (#2303) 2019-05-07 21:59:25 +00:00
Kim Gardner 7d369f2d35 Merge pull request #2279 from type-face/admin-ui-custom-css
apply custom CSS to admin panel
2019-05-07 19:40:18 +01:00
type_face 5fb5240f89 Merge branch 'master' into admin-ui-custom-css 2019-05-02 12:28:59 -07:00
Wyatt Johnson 976931135c fix: added username config (#2295) 2019-05-02 16:07:42 +00:00
Wyatt Johnson 1e3d47eb87 Tags Permissions (#2291)
* fix: fixed a bug that exposed tags

* chore: bumped versions
2019-04-29 22:28:49 +02:00
Kim Gardner 2d804d783b Merge pull request #2283 from coralproject/docs
Removed Old Roadmap
2019-04-26 14:48:49 +01:00
type_face 3404578ecc Merge branch 'master' into admin-ui-custom-css 2019-04-24 15:54:12 -07:00
Rob Ring 48c5355a5b apply custom CSS to admin panel 2019-04-24 15:50:29 -07:00
Wyatt Johnson e3a300c643 fix: removed roadmap from sidebar 2019-04-24 13:00:58 -06:00
Andrew Losowsky a6653152e4 added info box (#2281)
* added info box

* fix: styles
2019-04-23 22:08:48 +00:00
Kim Gardner 441422542c Fix broken links and update info (#2277) 2019-04-22 23:41:34 +00:00
Kim Gardner 1d1822c086 Bump version 4.8.4 (#2266) 2019-04-17 16:54:58 +00:00
Kim Gardner 1c2ff7d2ae Update default plugins and docs (#2265)
* Update default plugins

* Update plugin docs with missing plugin

* Fixed broken link in docs

* Update Code of Conduct in docs

* Fix mixup that both plugins are moderation-actions

* fix: adapt server tests to use the rich text plugin

* fix: e2e

* fix: sync docs
2019-04-16 20:54:44 +02:00
Kim Gardner 9319bb4e1f Remove unnecessary Talk branding (#2271)
* Remove Talk copy from Login view

* Remove favicon from base template and only use it for admin view
2019-04-15 11:06:09 +02:00
Kim Gardner 6611f8b636 Fix email copy typo (#2267) 2019-04-11 17:50:10 +02:00
cpoonolly 738542ab99 Cherry seeing if he can fix stuff! (#2254) 2019-04-11 17:42:17 +02:00
Kim Gardner cd4ae47958 [Docs] Initial list of events you can track from Talk (#2262)
* Initial list of events you can track from Talk

* Remove duplicates

* Remove more duplicates
2019-04-08 19:01:42 +02:00
Wyatt Johnson 2ec66007d9 feat: added docs for featured comments tab (#2259) 2019-04-05 21:42:17 +00:00
immber ea34c936d0 DOCS || CORL-290 || Add Custom SSO Plugin Recipe (#2249)
* updated auth strategies

* added custom auth plugin recipe

* fixed format on TALK_SMTP_FROM_ADDRESS

* cleaned up formatting a bit

* added CDN to checklist

* Update docs/source/01-05-pre-launch-checklist.md

Co-Authored-By: immber <jessiekrushing@gmail.com>

* Update docs/source/integrating/authentication.md

Co-Authored-By: immber <jessiekrushing@gmail.com>

* added links to plugins
2019-04-01 22:23:22 +00:00
Mendel Konikov ef1fd9c159 Clarify that Reliable commenter is also not yet in use (#2253) 2019-04-01 21:14:04 +00:00
Andrew Losowsky c7ccf03132 Updated Vox Media Logo on Documentation (#2244)
* added Vox Media logo

* fix: added logo

* fix: cleanup
2019-03-27 22:34:58 -06:00
Andrew Losowsky 8015098305 Changed 'Mozilla' to 'Vox Media' in the sidebar (#2245)
* Changed 'Mozilla' to 'Vox Media' in the sidebar

* Delete moz-logo-bw-rgb.svg
2019-03-27 22:43:12 +00:00
Kim Gardner c85a2703f9 Merge pull request #2241 from coralproject/CORL-290
DOCS | CORL-290 | Documentation updates
2019-03-26 13:24:06 +00:00
Jessie Rushing 9aec6b026c updated event tracking page 2019-03-22 13:25:40 -07:00
immber b2ca9dba40 Merge pull request #2227 from coralproject/CORL-308
update tokenUserNotFound docs
2019-03-20 11:43:16 -07:00
immber 9186c73fff Merge branch 'master' into CORL-308 2019-03-20 11:07:20 -07:00
immber 86d55fa2de Merge pull request #2232 from GlynnPhillips/slack-doc-update
Update the slack config name in the docs
2019-03-20 11:02:56 -07:00
Wyatt Johnson 12c4cfbbf6 feat: improved server api docs 2019-03-19 16:24:32 -06:00
Jessie Rushing c875a8d9ed added note about subdomain whitelisting 2019-03-19 16:24:32 -06:00
Jessie Rushing 4d082165aa update tokenUserNotFound docs 2019-03-19 16:24:31 -06:00
Glynn Phillips 08c01981ac Update the slack config name in the docs
The documentation for the slack notification plugin referenced the wrong
environment variable name.
2019-03-19 14:16:07 +00:00
Wyatt Johnson cd01aae76c fix: fixed incorrect users lookup (#2229) 2019-03-18 12:06:29 -06:00
Andrew Losowsky 53367eeaac Updated text to include our pricing page (#2221)
A few updates plus corrections.
2019-03-11 22:58:50 +00:00
Wyatt Johnson 32962aa1e8 External User Fix (#2220)
* fix: fixed bug with user upserting

* chore: version bump
2019-03-11 19:35:22 +00:00
Kim Gardner 049357a09c Bump version 4.8.1 (#2218) 2019-03-07 16:00:18 +00:00
Wyatt Johnson 5e7fe7cf5a fix: upgrade passport-google-oauth2 (#2217)
- Fixes #2215
2019-03-07 01:12:08 +00:00
Kim Gardner 6243fcba91 Merge pull request #2212 from vittoboa/italian-translation
Italian translation
2019-03-04 11:53:41 -05:00
vittoboa 805825e5d2 Fix typo 2019-03-02 22:42:13 +01:00
vittoboa a40e721a68 Fix typo 2019-03-02 22:38:16 +01:00
vittoboa 1dd8d0a706 Add italian translation for plugins 2019-03-02 22:33:52 +01:00
Leandro da1a8bb539 Remove duplicate placeholder proptype. (#2211) 2019-03-01 19:34:24 +01:00
Kim Gardner 18add4cdea Merge pull request #2210 from sanoma/feature/talk_470_dutch_translations
Feature/talk 470 dutch translations
2019-02-28 12:28:17 -05:00
Kim Gardner de5de26c82 Merge branch 'master' into feature/talk_470_dutch_translations 2019-02-28 11:09:19 -05:00
Besma 934e4b4754 Replace email with e-mail for Dutch translation consistency 2019-02-27 10:11:39 +01:00
Kim Gardner 049658508c Merge pull request #2206 from coralproject/bump-version-4-8-0
v4.8.0
2019-02-26 17:03:38 -05:00
Kim Gardner f0ead66f68 v4.8.0 2019-02-26 14:30:35 -05:00
David Burke 14f1343930 Additional Replies Increment (#2203)
* added ADDTL_REPLIES_ON_LOAD_MORE variable

* feat: added docs and onbuild ref
2019-02-26 16:18:55 +00:00
Besma b21845b963 Update translations 2019-02-26 09:39:54 +01:00
Kim Gardner 0ff20bed5e Merge pull request #2201 from mazzi/fix/issue-2141
Suspended vs. Banned  translations and typos in Spanish fixed
2019-02-25 17:33:27 -05:00
Besma 0bb2d4cbca Add Dutch translation 2019-02-25 16:18:33 +01:00
Lautaro Mazzitelli 927a34a579 ci: quotation not needed 2019-02-22 17:37:38 -03:00
Lautaro Mazzitelli 75f2f05534 fix: Suspended vs. Banned. Fixed in spanish translations. 2019-02-22 17:21:56 -03:00
Lautaro Mazzitelli 2998db46ad fix: three different typos were fixed on spanish translation file. 2019-02-22 16:21:02 -03:00
Gerardo Gálvez 8163b52301 Flag users as "Always premoderate" (#2145)
* Flag users as "Always premoderate"

Status can be set using the action dropdown in the People tab and in User Details.
Users flagged as "Always premoderate" will have their comments sent to the premod queue.
Users can be filtered with the Always Premoderate status.
Include Always Premoderate status changes in User History.
Add spanish translations.

* Reorder CSS as per cvle's suggestion

* Address second comment
2019-02-13 20:08:22 +01:00
Kim Gardner 19b425dc1a Merge pull request #2182 from mkonikov/snackbar-improvements
Snackbar improvements
2019-02-13 13:57:35 -05:00
Kim Gardner be81ced2f5 Merge branch 'master' into snackbar-improvements 2019-02-13 11:42:57 -05:00
Kim Gardner f6e5f24722 Merge pull request #2189 from javierbarriosafonso/master
Spanish (es) translations for talk notifications plugins
2019-02-13 11:42:48 -05:00
Kim Gardner 2c1dc9c118 Merge branch 'master' into master 2019-02-13 11:34:21 -05:00
Steven 657bf388cf fix: rename devToolsExtension (#2192)
Note that starting from v2.7, window.devToolsExtension was renamed to window.__REDUX_DEVTOOLS_EXTENSION__ / window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__.
2019-02-12 17:12:29 +01:00
Javier Barrios b3412a46cf Spanish (es) translations for talk notifications plugins 2019-02-11 14:08:31 -03:00
Mendel Konikov c6ee54c2f5 Rename classes to match id 2019-02-08 10:46:32 -05:00
Mendel Konikov 174a80c377 Reorder style as previous 2019-02-08 10:34:40 -05:00
Mendel Konikov 17a05059d9 Add working close button and style 2019-02-08 10:31:57 -05:00
Mendel Konikov 8c53c25a89 Merge branch 'master' of github.com:mkonikov/talk into snackbar-improvements 2019-02-08 09:15:07 -05:00
Mendel Konikov 1928a7b02e Create Moderation actions notification plugin (#2175)
* Create Moderation actions plugin

* Clarify env var in readme

* Reword log message

* Update with suggestion from Wyatt

* Whitelist notification types

* Update messaging

* Rename unpublished to pending
2019-02-07 15:20:44 +01:00
immber 5173af2a27 talk-plugin-toxic-comments - ADD MODEL VARIABLE TO TOXIC COMMENTS (#2178)
* updated readme

* added config var TALK_PERSPECTIVE_MODEL

* fixed duplication on readme

* fixed link on readme

* fix: applied some changes
2019-02-07 00:22:10 +00:00
Kim Gardner 9077f31872 Merge pull request #2179 from mkonikov/patch-1
Break word on long description
2019-02-06 18:14:51 -05:00
Mendel Konikov 51e8035533 Break word on long description
Also fix font size
2019-02-06 11:40:51 -05:00
Wyatt Johnson 94786c2711 fix: repairs poor performance for assets (#2174)
- fixes #2158
2019-02-05 22:06:05 +01:00
Nacho Toledo 456abaf862 Update appropriate <section> class in Profile section (#2170)
* Update appropriate <section> class in user profile section

Download my comment history has `talk-plugin-ignore-user-section` class. Should be `talk-plugin-profile-data--download-my-comment-history` (couldn't figure out the proper naming convention used).

* Fix linting error

* Fix lint second try
2019-02-05 16:49:25 +01:00
Kim Gardner fe9f92d3fc Merge pull request #2165 from mkonikov/hebrew
Add Hebrew Language Support
2019-02-04 17:37:46 -05:00
Kim Gardner a49fbf2d05 Yml fix 2019-02-04 17:16:15 -05:00
Kim Gardner 51bb158446 Merge branch 'master' into hebrew 2019-02-04 15:52:14 -05:00
Kim Gardner d601bd1466 Merge pull request #2177 from coralproject/remove-pt-link
Update Readme
2019-02-04 15:51:53 -05:00
immber 8eb8294987 Merge branch 'master' into remove-pt-link 2019-02-04 12:08:11 -08:00
Kim Gardner 99332323a8 Merge branch 'master' into hebrew 2019-02-04 14:52:29 -05:00
Kim Gardner 1a23cc1fa7 Merge pull request #2159 from mkonikov/fix-ios-copy
Fix Permalink copy on iOS
2019-02-04 19:48:38 +00:00
Kim Gardner 798f55ed79 Merge branch 'master' into hebrew 2019-02-04 19:47:24 +00:00
Kim Gardner 6897c0e18d Merge branch 'master' into fix-ios-copy 2019-02-04 19:34:31 +00:00
Kim Gardner 9d7b9a91cd Merge pull request #2153 from ljubar/master
sr_ME translations (Montenegrin version of Serbian language, Latin letters)
2019-02-04 19:32:56 +00:00
Kim Gardner 51a62b8c26 Merge branch 'master' into master 2019-02-04 19:28:23 +00:00
Kim Gardner f11a51ebfc Update Readme 2019-02-04 12:56:50 -05:00
Kim Gardner dbdf38af73 Merge branch 'master' into hebrew 2019-02-04 17:30:32 +00:00
Mendel Konikov abc1664ef7 WIP: Snackbar close 2019-01-31 09:59:58 -05:00
immber c16514502c Update recommended release version to link (#2168)
* Update recommended release version to 4.7

* update release link on readme!
2019-01-29 20:41:26 +00:00
Mendel Konikov 9d3e3ce45d Add additional Hebrew translations 2019-01-27 21:59:38 -05:00
Mendel Konikov f6bfef3fb5 Sort Translations ABC, Add missing Hebrew 2019-01-27 21:31:51 -05:00
Mendel Konikov 9b0173e6bf Add few more translations 2019-01-26 21:41:02 -05:00
Mendel Konikov 43219eed4b Replace quote marks 2019-01-24 22:32:50 -05:00
Mendel Konikov 9300359ed1 Merge branch 'master' of github.com:coralproject/talk into hebrew 2019-01-24 22:31:15 -05:00
Mendel Konikov 80c3367259 Merge branch 'master' into fix-ios-copy 2019-01-24 13:58:22 -05:00
Andrew Losowsky ef731f719d added Vox Media link (#2161) 2019-01-24 18:11:04 +00:00
Kim Gardner 9c09509a08 Merge pull request #2163 from mkonikov/fix-typo
Fix typo for Asset URL translation
2019-01-23 20:10:58 +00:00
Mendel Konikov 313310a097 Fix typo 2019-01-23 00:55:23 -05:00
Mendel Konikov fa42c028df Fix quotes 2019-01-23 00:45:31 -05:00
Mendel Konikov 905e43e745 Remove deleted plugin 2019-01-23 00:41:29 -05:00
Mendel Konikov 6cc0c60ade Add Final hebrew translations 2019-01-23 00:38:53 -05:00
Mendel Konikov ca44588095 Add Hebrew profile translations - server 2019-01-22 23:38:10 -05:00
Mendel Konikov 9a49044030 Add client profile translations 2019-01-22 23:30:39 -05:00
Mendel Konikov 02963dc5ac Fix translation 2019-01-22 23:18:18 -05:00
Mendel Konikov 5ad90e00cb Add Hebrew to profile plugin 2019-01-22 23:16:09 -05:00
Mendel Konikov 1dfc4b83c7 Remove unnecessary diffs 2019-01-22 23:11:25 -05:00
Mendel Konikov d522a72d42 Add additional hebrew 2019-01-22 23:09:30 -05:00
Mendel Konikov d1a22f9dc8 Remove merge comments 2019-01-22 22:10:53 -05:00
Mendel Konikov 5ac3910687 Fix lint 2019-01-22 22:08:29 -05:00
Mendel Konikov d007c2295e Fix Permalink copy on iOS 2019-01-21 17:15:16 -05:00
Kim Gardner 7ebcc4c793 Merge pull request #2157 from coralproject/docs-update
added native comments pdf
2019-01-18 19:41:19 +00:00
immber 582d45bb21 moved pdf to wp and updated copy 2019-01-17 09:56:55 -08:00
immber 6ef5c3a42f added link to sidebar 2019-01-16 14:29:35 -08:00
immber 00883a3739 added link to sidebar 2019-01-16 14:25:52 -08:00
immber d7fb0056be added native comments pdf 2019-01-16 14:16:04 -08:00
Kim Gardner ad55d715f6 Merge branch 'master' into master 2019-01-16 21:24:52 +00:00
Kim Gardner 0a855cd3d4 Merge pull request #2154 from coralproject/losowsky-patch-1
Fixed blog url
2019-01-16 21:24:18 +00:00
Andrew Losowsky c02d2b9b4e Fixed blog url 2019-01-16 10:46:49 -05:00
Kim Gardner 68255bec70 Merge branch 'master' into master 2019-01-16 14:44:51 +00:00
immber 28edd98ff1 Merge pull request #2151 from coralproject/docs-update
added TALK_CONCURRENCY to adv config
2019-01-14 13:53:12 -08:00
immber d1b5409e44 Merge branch 'master' into docs-update 2019-01-14 13:46:43 -08:00
Wyatt Johnsonandimmber df5e863cc4 updated default phrasing to be consistent
Co-Authored-By: immber <jessiekrushing@gmail.com>
2019-01-14 13:45:28 -08:00
immber acc83e27ce added TALK_CONCURRENCY to adv config 2019-01-14 10:37:36 -08:00
Kim Gardner ca13fde87d Merge pull request #2148 from coralproject/docs-update
Docs update
2019-01-11 15:46:35 +00:00
immber f69a9c826d removed link to community from faq 2019-01-10 17:04:22 -08:00
immber 76ef0f7d52 pulled community link from readme 2019-01-10 10:55:20 -08:00
immber 8f54c1d3c3 fixed md typo 2019-01-09 12:38:33 -08:00
immber 83379b58a7 em that can not be opted out of 2019-01-08 16:46:49 -08:00
immber b0b5807c8b added scaling talk 2019-01-08 16:39:06 -08:00
immber c98d227411 updated notifications page 2019-01-08 15:12:44 -08:00
immber 83819df922 added talk-plugin-comment-count to plugins directory 2019-01-08 13:27:08 -08:00
immber db5bf9a676 added twitter faq 2019-01-08 10:04:39 -08:00
immber ba31dbbdf9 added logout wait time 2019-01-08 09:53:46 -08:00
immber 8f633fbe78 added comment count to checklist 2019-01-04 17:20:49 -08:00
immber 886222260d fb requires ssl 2019-01-04 16:55:56 -08:00
immber 2c3589cdac added cert to auth section 2019-01-04 16:49:16 -08:00
Ljuba Rankovic ed953b5e7e Change translation 2018-12-24 15:41:05 +01:00
Ljuba Rankovic 79d1f059c2 fixes 2018-12-22 16:34:16 +01:00
Ljuba Rankovic 282db6847a locale sr added 2018-12-15 09:40:53 +01:00
Mendel Konikov 63400a455f Merge https://github.com/coralproject/talk 2018-05-10 20:53:41 -04:00
Mendel Konikov b7d8fb950b Merge master 2018-05-01 20:25:05 -04:00
Mendel Konikov 3915ffc4e0 Merge master 2018-04-10 20:10:21 -04:00
Mendel Konikov ac9899406a Merge 2018-03-07 12:02:01 -05:00
Mendel Konikov 13e1b288b3 Add more translations 2018-03-07 12:00:38 -05:00
Mendel Konikov 8c8f5d8fee Fix apostrophes 2018-03-07 12:00:38 -05:00
Mendel Konikov 35cf694b60 Add More hebrew translations 2018-03-07 12:00:38 -05:00
Mendel Konikov fa4dbfe9d0 Trigger build 2018-03-07 12:00:38 -05:00
Mendel Konikov 0ea08ccc9c Remove extra space 2018-03-07 12:00:38 -05:00
Mendel Konikov fd5bbe0234 Viewing options Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov b43f657c8d Toxic comments Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 9456c79bad Most respected Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 0cd18a458d More Hebrew translations 2018-03-07 12:00:38 -05:00
Mendel Konikov fdcd1404ef Most loved Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 741d5000dd Most liked Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 8f413852d9 Settings Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 420fc6daa7 Off-top Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov ad69086888 Moderation actions Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov f18c51dc68 Member since Hebrew Translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 8e1822af21 Google Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 5d3e8f3fb6 Flag Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 71288f543e Featured comments Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov a1890a0bfe Facebook Auth translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 1f17d71a76 Ignore user hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov fc8b9c3547 Like hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov 8ebb90c160 Subscriber hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov b0c230a1df Akismet Hebrew translations 2018-03-07 12:00:38 -05:00
Mendel Konikov be15734c77 Respect hebrew translations 2018-03-07 12:00:38 -05:00
Mendel Konikov 4478ced205 Auth Hebrew translations 2018-03-07 12:00:38 -05:00
Mendel Konikov 769437c8fb Add more translations 2018-03-07 12:00:38 -05:00
Mendel Konikov 5fde3235ad Add Hebrew template to all translation files 2018-03-07 12:00:38 -05:00
Mendel Konikov 2a8975711a Begin adding Hebrew translation 2018-03-07 12:00:38 -05:00
Mendel Konikov da56cd5b18 Add more translations 2018-03-06 13:02:03 -05:00
Mendel Konikov 90424b4766 Fix apostrophes 2018-02-26 16:39:28 -05:00
Mendel Konikov cf23bdba12 Add More hebrew translations 2018-02-26 16:37:40 -05:00
Mendel Konikov 0f983109e1 Trigger build 2018-02-26 16:14:16 -05:00
Mendel Konikov 8f7edde93f Remove extra space 2018-02-24 21:38:07 -05:00
Mendel Konikov 1946d023cd Viewing options Hebrew translation 2018-02-24 21:27:31 -05:00
Mendel Konikov 1e5f5848b2 Toxic comments Hebrew translation 2018-02-24 21:25:58 -05:00
Mendel Konikov 3cbf5fef07 Most respected Hebrew translation 2018-02-24 21:21:02 -05:00
Mendel Konikov 4f276ed944 More Hebrew translations 2018-02-24 21:19:43 -05:00
Mendel Konikov e69afc4e76 Most loved Hebrew translation 2018-02-24 21:17:02 -05:00
Mendel Konikov c4b46c28fe Most liked Hebrew translation 2018-02-24 21:15:51 -05:00
Mendel Konikov dac823f9c4 Settings Hebrew translation 2018-02-24 21:14:00 -05:00
Mendel Konikov 65deb1cfbe Off-top Hebrew translation 2018-02-24 21:12:04 -05:00
Mendel Konikov 828f200eb6 Moderation actions Hebrew translation 2018-02-24 21:10:23 -05:00
Mendel Konikov fe5c95c27a Member since Hebrew Translation 2018-02-24 21:06:24 -05:00
Mendel Konikov c7fad00b66 Google Hebrew translation 2018-02-24 21:05:14 -05:00
Mendel Konikov 5165d06d64 Flag Hebrew translation 2018-02-24 21:03:10 -05:00
Mendel Konikov e15275666e Featured comments Hebrew translation 2018-02-24 21:01:25 -05:00
Mendel Konikov 1dc8df4189 Facebook Auth translation 2018-02-24 20:43:18 -05:00
Mendel Konikov ffe83452cd Ignore user hebrew translation 2018-02-24 20:41:22 -05:00
Mendel Konikov 3c3603ee08 Like hebrew translation 2018-02-24 20:34:22 -05:00
Mendel Konikov f6e94b0cc2 Subscriber hebrew translation 2018-02-24 20:30:34 -05:00
Mendel Konikov c3f92e8c8d Akismet Hebrew translations 2018-02-24 20:27:52 -05:00
Mendel Konikov 84a121a1d9 Respect hebrew translations 2018-02-24 20:22:12 -05:00
Mendel Konikov f55f1341e1 Auth Hebrew translations 2018-02-24 20:19:20 -05:00
Mendel Konikov cccac6a8bc Add more translations 2018-02-23 12:17:13 -05:00
Mendel Konikov e775a9f092 Add Hebrew template to all translation files 2018-02-23 12:00:01 -05:00
Mendel Konikov 76237f42da Begin adding Hebrew translation 2018-02-23 11:29:28 -05:00
Mendel Konikov 6e942a1121 Fix typos in comments 2018-02-23 11:11:41 -05:00
192 changed files with 5749 additions and 1295 deletions
+1
View File
@@ -45,6 +45,7 @@ plugins/*
!plugins/talk-plugin-moderation-actions
!plugins/talk-plugin-notifications
!plugins/talk-plugin-notifications-category-featured
!plugins/talk-plugin-notifications-category-moderation-actions
!plugins/talk-plugin-notifications-category-reply
!plugins/talk-plugin-notifications-category-staff
!plugins/talk-plugin-notifications-digest-daily
+5 -4
View File
@@ -1,6 +1,7 @@
# Mozilla Community Participation Guidelines
# Vox Media Code of Conduct
## Version 2.3 - Updated May 16, 2017
## Introduction
The heart of Mozilla is people. We put people first and do our best to recognize, appreciate and respect the diversity of our global contributors. The Mozilla Project welcomes contributions from everyone who shares our goals and wants to contribute in a healthy and constructive manner within our community. As such, we have adopted this code of conduct and require all those who participate to agree and adhere to these Community Participation Guidelines in order to help us create a safe and positive community experience for all.
https://www.mozilla.org/en-US/about/governance/policies/participation/
This code of conduct governs the environment of the Vox Product team. We created it not because we anticipate bad behavior, but because we believe that articulating our values and obligations to one another reinforces the already exceptional level of respect among the team and because having a code provides us with clear avenues to correct our culture should it ever stray from that course. We make this code public in the hopes of contributing to the ongoing conversation about inclusion in the tech, design, and media communities and encourage other teams to fork it and make it their own. To our team, we commit to enforce and evolve this code as our team grows.
Read the rest here: http://code-of-conduct.voxmedia.com/
+3 -23
View File
@@ -18,7 +18,7 @@ There are at least three ways to contribute to Talk:
Conversation surrounding contributions begins in [issues](https://github.com/coralproject/talk/issues).
### When should I Create an Issue?
### When should I create an issue?
File an issue as soon as you have an idea of something you'd like to contribute. We would love to hear what you're thinking and help refine the idea to make it into the Talk ecosystem.
@@ -30,9 +30,9 @@ Please file issues if:
### What should I include?
Coral has adopted an iterative, agile development philosophy. All contributions that make it into the Talk repository should start with a story or this form:
Coral has adopted an iterative, agile development philosophy. All contributions that make it into the Talk repository should start with a user story in this form:
> As a [type of person] I'd like to be able to [do something] so that I can [get some result].
> As a [type of Coral user] I'd like to [do something] so that I can [get some result/value].
This exercise does two things:
@@ -71,23 +71,3 @@ If you'd like to discuss a contribution, please [file an issue](https://github.c
Talk's translations are stored in `.yml` files [here](https://github.com/coralproject/talk/tree/master/locales).
Translations can be submitted via pull request. If you do not use github, you can use 'en.yml' as a template and [email](https://coralproject.net/contact) the translations to us. We can import it into the repository.
## I want to contribute but I'm not sure what to do!
If you want to contribute but don't have a clear idea of exactly what that may be, here are some resources that may help:
### Product Roadmap
Please visit our product roadmap here: https://www.pivotaltracker.com/n/projects/1863625. If you'd like to take on any of our scheduled tasks we'd be forever grateful!
### Discussion Forum
If you'd like to discuss what we're up to, please visit or [community](https://community.coralproject.net/) or [contact us](https://coralproject.net/contact).
### Integrations
Have a favorite analytics engine? Data science service? CMS? Auth platform? Deployment platform or pipeline? Pet project? Consider building a plugin to integrate them!
### Favorite Features?
Do you have a favorite feature of an existing platform that's not yet been done in Talk? Sounds like Talk needs that feature.
+1
View File
@@ -4,6 +4,7 @@ FROM coralproject/talk:latest
ONBUILD ARG TALK_ADDTL_COMMENTS_ON_LOAD_MORE=10
ONBUILD ARG TALK_ASSET_COMMENTS_LOAD_DEPTH=10
ONBUILD ARG TALK_REPLY_COMMENTS_LOAD_DEPTH=3
ONBUILD ARG TALK_ADDTL_REPLIES_ON_LOAD_MORE=999999
ONBUILD ARG TALK_THREADING_LEVEL=3
ONBUILD ARG TALK_DEFAULT_STREAM_TAB=all
ONBUILD ARG TALK_DISABLE_EMBED_POLYFILL=FALSE
+3 -5
View File
@@ -2,7 +2,7 @@
Online comments are broken. Our open-source commenting platform, Talk, rethinks how moderation, comment display, and conversation function, creating the opportunity for safer, smarter discussions around your work. [Read more about Talk here](https://coralproject.net/talk).
Built with <3 by The Coral Project.
Built with <3 by The Coral Project, a part of [Vox Media](https://www.voxmedia.com/).
## Getting Started
@@ -22,13 +22,11 @@ For advanced configuration and usage of Talk, check out our [Configuration](http
## Versions & Upgrading
The current recommended release version is v4.5.0. ^4.5 (and all future even-numbered versions) are considered stable LTS versions. We recommend ^4.5 for use in production environments.
Check our Releases page for the latest recommended release version. [Releases](https://github.com/coralproject/talk/releases) All future even-numbered versions are considered stable LTS versions. We recommend the latest verified release for use in production environments.
## More Resources
- [Talk Product Roadmap](https://www.pivotaltracker.com/n/projects/1863625)
- [Our Blog](https://blog.coralproject.net/)
- [Community Forums](https://community.coralproject.net/)
- [Our Blog](https://coralproject.net/blog)
- [Community Guides for Journalism](https://guides.coralproject.net/)
- [More About Us](https://coralproject.net/)
+2 -1
View File
@@ -105,7 +105,8 @@ function printUserAsTable(user) {
Suspension: user.suspended
? `Until ${user.status.suspension.until}`
: false,
}
},
{ 'Always premod comments': user.alwaysPremod }
);
console.log(table.toString());
@@ -0,0 +1,14 @@
import {
SHOW_ALWAYS_PREMOD_USER_DIALOG,
HIDE_ALWAYS_PREMOD_USER_DIALOG,
} from '../constants/alwaysPremodUserDialog.js';
export const showAlwaysPremodUserDialog = ({ userId, username }) => ({
type: SHOW_ALWAYS_PREMOD_USER_DIALOG,
userId,
username,
});
export const hideAlwaysPremodUserDialog = () => ({
type: HIDE_ALWAYS_PREMOD_USER_DIALOG,
});
@@ -9,6 +9,8 @@ import {
SET_SEARCH_VALUE,
SHOW_BANUSER_DIALOG,
HIDE_BANUSER_DIALOG,
SHOW_ALWAYS_PREMOD_USER_DIALOG,
HIDE_ALWAYS_PREMOD_USER_DIALOG,
SHOW_REJECT_USERNAME_DIALOG,
HIDE_REJECT_USERNAME_DIALOG,
SET_INDICATOR_TRACK,
@@ -61,6 +63,15 @@ export const setSearchValue = value => ({
export const showBanUserDialog = user => ({ type: SHOW_BANUSER_DIALOG, user });
export const hideBanUserDialog = () => ({ type: HIDE_BANUSER_DIALOG });
// Always premod User Dialog
export const showAlwaysPremodUserDialog = user => ({
type: SHOW_ALWAYS_PREMOD_USER_DIALOG,
user,
});
export const hideAlwaysPremodUserDialog = () => ({
type: HIDE_ALWAYS_PREMOD_USER_DIALOG,
});
// Reject Username Dialog
export const showRejectUsernameDialog = user => ({
type: SHOW_REJECT_USERNAME_DIALOG,
@@ -0,0 +1,29 @@
.dialog {
border: none;
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
width: 400px;
top: 50%;
transform: translateY(-50%);
padding: 20px;
border-radius: 4px;
}
.header {
color: black;
font-size: 1.5em;
font-weight: 500;
margin: 0 0 8px 0;
}
.subheader {
color: black;
font-size: 1.3em;
font-weight: 500;
margin: 0 0 8px 0;
}
.buttons {
margin-top: 8px;
margin-bottom: 6px;
text-align: right;
}
@@ -0,0 +1,68 @@
import React from 'react';
import cn from 'classnames';
import PropTypes from 'prop-types';
import { Dialog } from 'coral-ui';
import styles from './AlwaysPremodUserDialog.css';
import Button from 'coral-ui/components/Button';
import t from 'coral-framework/services/i18n';
class AlwaysPremodUserDialog extends React.Component {
handlePerform = () => {
this.props.onPerform();
};
render() {
const { open, onCancel, username, info } = this.props;
return (
<Dialog
className={cn(styles.dialog, 'talk-always-premod-user-dialog')}
id="alwaysPremodUserDialog"
open={open}
onCancel={onCancel}
title={t('alwayspremoddialog.always_premod_user')}
>
<span className={styles.close} onClick={onCancel}>
×
</span>
<section>
<h2 className={styles.header}>
{t('alwayspremoddialog.always_premod_user')}
</h2>
<h3 className={styles.subheader}>
{t('alwayspremoddialog.are_you_sure', username)}
</h3>
<p className={styles.description}>{info}</p>
<div className={styles.buttons}>
<Button
className={cn('talk-always-premod-user-dialog-button-cancel')}
cStyle="white"
onClick={onCancel}
raised
>
{t('alwayspremoddialog.cancel')}
</Button>
<Button
className={cn('talk-always-premod-user-dialog-button-confirm')}
cStyle="black"
onClick={this.handlePerform}
raised
>
{t('alwayspremoddialog.yes_always_premod_user')}
</Button>
</div>
</section>
</Dialog>
);
}
}
AlwaysPremodUserDialog.propTypes = {
open: PropTypes.bool,
onPerform: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
username: PropTypes.string,
info: PropTypes.string,
};
export default AlwaysPremodUserDialog;
@@ -137,6 +137,12 @@
display: inline-block;
}
.actionsMenuAlwaysPremod {
background-color: #F0B50B;
border-color: #F0B50B;
color: white;
}
.actionsMenuSuspended {
background-color: #F29336;
border-color: #F29336;
@@ -12,6 +12,7 @@ import {
isUsernameRejected,
isUsernameChanged,
isBanned,
isAlwaysPremod,
getKarma,
} from 'coral-framework/utils/user';
@@ -45,6 +46,7 @@ function getUserStatusArray(user) {
const statusMap = {
suspended: isSuspended,
banned: isBanned,
alwaysPremod: isAlwaysPremod,
usernameRejected: isUsernameRejected,
usernameChanged: isUsernameChanged,
};
@@ -68,6 +70,12 @@ class UserDetail extends React.Component {
username: this.props.root.user.username,
});
showAlwaysPremodUserDialog = () =>
this.props.showAlwaysPremodUserDialog({
userId: this.props.root.user.id,
username: this.props.root.user.username,
});
showRejectUsernameDialog = () =>
this.props.showRejectUsernameDialog({
userId: this.props.root.user.id,
@@ -107,6 +115,8 @@ class UserDetail extends React.Component {
return t('user_detail.suspended');
case 'banned':
return t('user_detail.banned');
case 'alwaysPremod':
return t('user_detail.always_premoded');
case 'usernameRejected':
return (
<span>
@@ -153,6 +163,7 @@ class UserDetail extends React.Component {
toggleSelectAll,
unbanUser,
unsuspendUser,
removeAlwaysPremodUser,
modal,
acceptComment,
rejectComment,
@@ -169,6 +180,7 @@ class UserDetail extends React.Component {
const banned = isBanned(user);
const suspended = isSuspended(user);
const alwaysPremod = isAlwaysPremod(user);
const usernameRejected = isUsernameRejected(user);
const usernameChanged = isUsernameChanged(user);
@@ -200,6 +212,7 @@ class UserDetail extends React.Component {
{
[styles.actionsMenuSuspended]: suspended,
[styles.actionsMenuBanned]: banned,
[styles.actionsMenuAlwaysPremod]: alwaysPremod,
},
'talk-admin-user-detail-actions-button'
)}
@@ -231,6 +244,21 @@ class UserDetail extends React.Component {
</ActionsMenuItem>
)}
{alwaysPremod ? (
<ActionsMenuItem
onClick={() => removeAlwaysPremodUser({ id: user.id })}
>
{t('user_detail.remove_always_premod')}
</ActionsMenuItem>
) : (
<ActionsMenuItem
disabled={me.id === user.id}
onClick={this.showAlwaysPremodUserDialog}
>
{t('user_detail.always_premod')}
</ActionsMenuItem>
)}
{usernameChanged && (
<ActionsMenuItem onClick={this.goToReportedUsernames}>
{t('user_detail.username_needs_approval')}
@@ -476,8 +504,10 @@ UserDetail.propTypes = {
showRejectUsernameDialog: PropTypes.func,
showSuspendUserDialog: PropTypes.func,
showBanUserDialog: PropTypes.func,
showAlwaysPremodUserDialog: PropTypes.func,
unbanUser: PropTypes.func.isRequired,
unsuspendUser: PropTypes.func.isRequired,
removeAlwaysPremodUser: PropTypes.func.isRequired,
modal: PropTypes.bool,
rejectUsername: PropTypes.func.isRequired,
};
@@ -34,7 +34,7 @@
color: #063b9a;
text-decoration: none;
font-weight: 500;
letter-spacing: .5px;
letter-spacing: 0.5px;
margin-left: 10px;
font-size: 13px;
margin-left: 5px;
@@ -109,7 +109,7 @@
}
.external {
font-size: .7em;
font-size: 0.7em;
text-decoration: none;
color: #063b9a;
cursor: pointer;
@@ -119,7 +119,7 @@
&:hover {
text-decoration: underline;
opacity: .9;
opacity: 0.9;
}
> i {
@@ -139,3 +139,25 @@
margin-right: 5px;
}
}
.bodyHistoryToggle {
color: #666;
font-size: 12px;
line-height: 1px;
font-weight: 300;
text-decoration: underline;
&:hover {
cursor: pointer;
}
}
.editedCommentBody {
padding: 0 5px 5px 5px;
}
.editedComment {
margin-top: 6px;
font-weight: 300;
font-size: 16px;
overflow-wrap: break-word;
}
@@ -19,6 +19,8 @@ import TimeAgo from 'coral-framework/components/TimeAgo';
import t from 'coral-framework/services/i18n';
class UserDetailComment extends React.Component {
state = { showingEditHistory: false };
approve = () =>
this.props.comment.status === 'ACCEPTED'
? null
@@ -29,6 +31,29 @@ class UserDetailComment extends React.Component {
? null
: this.props.rejectComment({ commentId: this.props.comment.id });
getBodyHistory = () => {
const bodyHistory = [];
const comment = this.props.comment;
for (let i = 0; i < comment.body_history.length - 1; i++) {
bodyHistory.push(
<div key={i} className={styles.editedComment}>
<div>
<TimeAgo className={styles.created} datetime={comment.created_at} />
</div>
<div className={styles.editedCommentBody}>
{comment.body_history[i].body}
</div>
</div>
);
}
return bodyHistory;
};
toggleEditHistory = () => {
this.setState({ showingEditHistory: !this.state.showingEditHistory });
};
render() {
const {
comment,
@@ -81,6 +106,14 @@ class UserDetailComment extends React.Component {
&nbsp;<span className={styles.editedMarker}>
({t('comment.edited')})
</span>
&nbsp;<span
className={styles.bodyHistoryToggle}
onClick={this.toggleEditHistory}
>
{this.state.showingEditHistory
? t('comment.hide_edit_history')
: t('comment.show_edit_history')}
</span>
</span>
) : null}
@@ -142,6 +175,14 @@ class UserDetailComment extends React.Component {
</div>
</CommentAnimatedEdit>
</div>
{this.state.showingEditHistory ? (
<div className={styles.container}>
{t('comment.edit_history')}
{this.getBodyHistory()}
</div>
) : null}
<CommentDetails root={root} comment={comment} />
</li>
);
@@ -48,6 +48,10 @@ const buildActionResponse = (typename, created_at, until, status) => {
return status
? t('user_history.user_banned')
: t('user_history.ban_removed');
case 'AlwaysPremodStatusHistory':
return status
? t('user_history.user_always_premoded')
: t('user_history.always_premod_removed');
case 'SuspensionStatusHistory':
return until
? t('user_history.suspended', readableDuration(created_at, until))
@@ -0,0 +1,2 @@
export const SHOW_ALWAYS_PREMOD_USER_DIALOG = 'SHOW_ALWAYS_PREMOD_USER_DIALOG';
export const HIDE_ALWAYS_PREMOD_USER_DIALOG = 'HIDE_ALWAYS_PREMOD_USER_DIALOG';
@@ -14,6 +14,9 @@ export const FETCH_FLAGGED_COMMENTERS_FAILURE = `${prefix}_FETCH_FLAGGED_COMMENT
export const SHOW_BANUSER_DIALOG = `${prefix}_SHOW_BANUSER_DIALOG`;
export const HIDE_BANUSER_DIALOG = `${prefix}_HIDE_BANUSER_DIALOG`;
export const SHOW_ALWAYS_PREMOD_USER_DIALOG = `${prefix}_SHOW_ALWAYS_PREMOD_USER_DIALOG`;
export const HIDE_ALWAYS_PREMOD_USER_DIALOG = `${prefix}_HIDE_ALWAYS_PREMOD_USER_DIALOG`;
export const SHOW_REJECT_USERNAME_DIALOG = `${prefix}_SHOW_REJECT_USERNAME_DIALOG`;
export const HIDE_REJECT_USERNAME_DIALOG = `${prefix}_HIDE_REJECT_USERNAME_DIALOG`;
@@ -0,0 +1,66 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import AlwaysPremodUserDialog from '../components/AlwaysPremodUserDialog';
import { hideAlwaysPremodUserDialog } from '../actions/alwaysPremodUserDialog';
import { withAlwaysPremodUser } from 'coral-framework/graphql/mutations';
import { compose } from 'react-apollo';
import t from 'coral-framework/services/i18n';
class AlwaysPremodUserDialogContainer extends Component {
alwaysPremodUser = async () => {
const { userId, alwaysPremodUser, hideAlwaysPremodUserDialog } = this.props;
await alwaysPremodUser({ id: userId });
hideAlwaysPremodUserDialog();
};
getInfo() {
let note = t('alwayspremoddialog.note_always_premod_user');
return t('alwayspremoddialog.note', note);
}
render() {
return (
<AlwaysPremodUserDialog
open={this.props.open}
onPerform={this.alwaysPremodUser}
onCancel={this.props.hideAlwaysPremodUserDialog}
username={this.props.username}
info={this.getInfo()}
/>
);
}
}
AlwaysPremodUserDialogContainer.propTypes = {
alwaysPremodUser: PropTypes.func.isRequired,
hideAlwaysPremodUserDialog: PropTypes.func,
open: PropTypes.bool,
username: PropTypes.string,
};
const mapStateToProps = ({
alwaysPremodUserDialog: { open, userId, username },
}) => ({
open,
userId,
username,
});
const mapDispatchToProps = dispatch => ({
...bindActionCreators(
{
hideAlwaysPremodUserDialog,
},
dispatch
),
});
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
),
withAlwaysPremodUser
)(AlwaysPremodUserDialogContainer);
@@ -5,6 +5,7 @@ import Layout from '../components/Layout';
import Login from '../containers/Login';
import { FullLoading } from '../components/FullLoading';
import BanUserDialog from './BanUserDialog';
import AlwaysPremodUserDialog from './AlwaysPremodUserDialog';
import SuspendUserDialog from './SuspendUserDialog';
import RejectUsernameDialog from './RejectUsernameDialog';
import { toggleModal as toggleShortcutModal } from '../actions/moderation';
@@ -40,6 +41,7 @@ class LayoutContainer extends React.Component {
toggleShortcutModal={toggleShortcutModal}
currentUser={this.props.currentUser}
>
<AlwaysPremodUserDialog />
<BanUserDialog />
<SuspendUserDialog />
<RejectUsernameDialog />
@@ -22,12 +22,14 @@ import {
withSetCommentStatus,
withUnbanUser,
withUnsuspendUser,
withRemoveAlwaysPremodUser,
withRejectUsername,
withPostFlag,
} from 'coral-framework/graphql/mutations';
import UserDetailComment from './UserDetailComment';
import update from 'immutability-helper';
import { showBanUserDialog } from 'actions/banUserDialog';
import { showAlwaysPremodUserDialog } from 'actions/alwaysPremodUserDialog';
import { showSuspendUserDialog } from 'actions/suspendUserDialog';
import { showRejectUsernameDialog } from 'actions/rejectUsernameDialog';
@@ -153,6 +155,7 @@ UserDetailContainer.propTypes = {
selectedCommentIds: PropTypes.array,
unbanUser: PropTypes.func.isRequired,
unsuspendUser: PropTypes.func.isRequired,
removeAlwaysPremodUser: PropTypes.func.isRequired,
rejectUsername: PropTypes.func.isRequired,
userId: PropTypes.string,
};
@@ -218,6 +221,17 @@ export const withUserDetailQuery = withQuery(
created_at
}
}
alwaysPremod {
status
history {
status
assigned_by {
id
username
}
created_at
}
},
username {
status
history {
@@ -280,6 +294,7 @@ const mapDispatchToProps = dispatch => ({
...bindActionCreators(
{
showBanUserDialog,
showAlwaysPremodUserDialog,
showSuspendUserDialog,
showRejectUsernameDialog,
changeTab,
@@ -302,6 +317,7 @@ export default compose(
withSetCommentStatus,
withUnbanUser,
withUnsuspendUser,
withRemoveAlwaysPremodUser,
withRejectUsername,
withPostFlag,
withRouter
@@ -42,6 +42,10 @@ export default withFragments({
status_history {
type
}
body_history {
body
created_at
}
${getSlotFragmentSpreads(slots, 'comment')}
...${getDefinitionName(CommentLabels.fragments.comment)}
...${getDefinitionName(CommentDetails.fragments.comment)}
+78
View File
@@ -10,6 +10,9 @@ const userStatusFragment = gql`
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -125,6 +128,64 @@ export default {
});
},
}),
AlwaysPremodUser: ({
variables: {
input: { id },
},
}) => ({
update: proxy => {
const fragmentId = `User_${id}`;
const data = proxy.readFragment({
fragment: userStatusFragment,
id: fragmentId,
});
const updated = update(data, {
state: {
status: {
alwaysPremod: {
status: { $set: true },
},
},
},
});
proxy.writeFragment({
fragment: userStatusFragment,
id: fragmentId,
data: updated,
});
},
}),
RemoveAlwaysPremodUser: ({
variables: {
input: { id },
},
}) => ({
update: proxy => {
const fragmentId = `User_${id}`;
const data = proxy.readFragment({
fragment: userStatusFragment,
id: fragmentId,
});
const updated = update(data, {
state: {
status: {
alwaysPremod: {
status: { $set: false },
},
},
},
});
proxy.writeFragment({
fragment: userStatusFragment,
id: fragmentId,
data: updated,
});
},
}),
BanUser: ({
variables: {
input: { id },
@@ -154,6 +215,23 @@ export default {
});
},
}),
SetUserAlwaysPremodStatus: ({ variables: { status, id } }) => ({
updateQueries: {
TalkAdmin_Community: prev => {
if (!status) {
return prev;
}
const updated = update(prev, {
users: {
nodes: {
$apply: nodes => nodes.filter(node => node.id !== id),
},
},
});
return updated;
},
},
}),
UnbanUser: ({
variables: {
input: { id },
@@ -0,0 +1,29 @@
import {
SHOW_ALWAYS_PREMOD_USER_DIALOG,
HIDE_ALWAYS_PREMOD_USER_DIALOG,
} from '../constants/alwaysPremodUserDialog';
const initialState = {
open: false,
userId: null,
username: '',
};
export default function alwaysPremodUserDialog(state = initialState, action) {
switch (action.type) {
case SHOW_ALWAYS_PREMOD_USER_DIALOG:
return {
...state,
open: true,
userId: action.userId,
username: action.username,
};
case HIDE_ALWAYS_PREMOD_USER_DIALOG:
return {
...state,
open: false,
};
default:
return state;
}
}
+2
View File
@@ -5,6 +5,7 @@ import moderation from './moderation';
import install from './install';
import banUserDialog from './banUserDialog';
import suspendUserDialog from './suspendUserDialog';
import alwaysPremodUserDialog from './alwaysPremodUserDialog';
import rejectUsernameDialog from './rejectUsernameDialog';
import userDetail from './userDetail';
import ui from './ui';
@@ -14,6 +15,7 @@ export default {
banUserDialog,
configure,
suspendUserDialog,
alwaysPremodUserDialog,
userDetail,
stories,
community,
@@ -11,6 +11,7 @@ const initialState = {
criteria: {
asc: 'false',
filter: 'all',
limit: 20,
},
};
+14
View File
@@ -6,6 +6,10 @@ import {
SHOW_SUSPEND_USER_DIALOG,
HIDE_SUSPEND_USER_DIALOG,
} from '../constants/suspendUserDialog';
import {
SHOW_ALWAYS_PREMOD_USER_DIALOG,
HIDE_ALWAYS_PREMOD_USER_DIALOG,
} from '../constants/alwaysPremodUserDialog';
const initialState = {
modal: false,
@@ -23,6 +27,11 @@ export default function config(state = initialState, action) {
...state,
modal: true,
};
case SHOW_ALWAYS_PREMOD_USER_DIALOG:
return {
...state,
modal: true,
};
case HIDE_BAN_USER_DIALOG:
return {
...state,
@@ -33,6 +42,11 @@ export default function config(state = initialState, action) {
...state,
modal: false,
};
case HIDE_ALWAYS_PREMOD_USER_DIALOG:
return {
...state,
modal: false,
};
default:
return state;
}
@@ -78,9 +78,10 @@
}
.flaggedByReason {
font-size: 1tpx;
font-size: 14px;
margin: 0px;
line-height: 1.4;
word-break: break-word;
}
@@ -130,6 +130,12 @@ th.header:nth-child(2), th.header:nth-child(3) {
font-size: 0.98em;
}
.actionsMenuAlwaysPremod {
background-color: #F0B50B;
border-color: #F0B50B;
color: white;
}
.actionsMenuSuspended {
background-color: #F29336;
border-color: #F29336;
@@ -8,7 +8,11 @@ import LoadMore from '../../../components/LoadMore';
import PropTypes from 'prop-types';
import ActionsMenu from 'coral-admin/src/components/ActionsMenu';
import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem';
import { isSuspended, isBanned } from 'coral-framework/utils/user';
import {
isSuspended,
isBanned,
isAlwaysPremod,
} from 'coral-framework/utils/user';
import { RadioGroup, Radio } from 'react-mdl';
import moment from 'moment';
import {
@@ -43,6 +47,8 @@ class People extends React.Component {
return 'Banned';
} else if (isSuspended(user)) {
return 'Suspended';
} else if (isAlwaysPremod(user)) {
return 'Always premoderated';
}
return '';
};
@@ -55,6 +61,10 @@ class People extends React.Component {
this.props.unbanUser(input);
};
removeAlwaysPremodUser = input => {
this.props.removeAlwaysPremodUser(input);
};
showBanUserDialog = input => {
this.props.showBanUserDialog(input);
};
@@ -63,6 +73,10 @@ class People extends React.Component {
this.props.showSuspendUserDialog(input);
};
showAlwaysPremodUserDialog = input => {
this.props.showAlwaysPremodUserDialog(input);
};
render() {
const {
onFilterChange,
@@ -109,6 +123,7 @@ class People extends React.Component {
<Radio value="active">{t('community.active')}</Radio>
<Radio value="suspended">{t('community.suspended')}</Radio>
<Radio value="banned">{t('community.banned')}</Radio>
<Radio value="alwaysPremod">{t('community.always_premod')}</Radio>
</RadioGroup>
<div className={styles.filterDetail}>
{t('community.filter_role')}
@@ -188,6 +203,9 @@ class People extends React.Component {
user
),
[styles.actionsMenuBanned]: isBanned(user),
[styles.actionsMenuAlwaysPremod]: isAlwaysPremod(
user
),
},
'talk-admin-user-detail-actions-button'
)}
@@ -232,6 +250,27 @@ class People extends React.Component {
{t('modqueue.ban_user_actions')}
</ActionsMenuItem>
)}
{isAlwaysPremod(user) ? (
<ActionsMenuItem
onClick={() =>
this.removeAlwaysPremodUser({ id: user.id })
}
>
Remove Always Premoderate
</ActionsMenuItem>
) : (
<ActionsMenuItem
onClick={() =>
this.showAlwaysPremodUserDialog({
userId: user.id,
username: user.username,
})
}
>
{t('modqueue.always_premod_user_actions')}
</ActionsMenuItem>
)}
</ActionsMenu>
</td>
<td className="mdl-data-table__cell--non-numeric">
@@ -294,8 +333,10 @@ People.propTypes = {
viewUserDetail: PropTypes.func.isRequired,
unbanUser: PropTypes.func.isRequired,
unsuspendUser: PropTypes.func.isRequired,
removeAlwaysPremodUser: PropTypes.func.isRequired,
showSuspendUserDialog: PropTypes.func,
showBanUserDialog: PropTypes.func,
showAlwaysPremodUserDialog: PropTypes.func,
loadMore: PropTypes.func.isRequired,
};
@@ -8,9 +8,11 @@ import {
withUnbanUser,
withUnsuspendUser,
withSetUserRole,
withRemoveAlwaysPremodUser,
} from 'coral-framework/graphql/mutations';
import { showBanUserDialog } from 'actions/banUserDialog';
import { showSuspendUserDialog } from 'actions/suspendUserDialog';
import { showAlwaysPremodUserDialog } from 'actions/alwaysPremodUserDialog';
import { viewUserDetail } from '../../../actions/userDetail';
import { appendNewNodes } from 'plugin-api/beta/client/utils';
import update from 'immutability-helper';
@@ -30,6 +32,7 @@ class PeopleContainer extends React.PureComponent {
active: { suspended: false, banned: false },
suspended: { suspended: true },
banned: { banned: true },
alwaysPremod: { alwaysPremod: true },
};
onFilterChange = filter => e =>
@@ -40,7 +43,6 @@ class PeopleContainer extends React.PureComponent {
getFilterState = () => {
const { role, status } = this.state;
return {
status: this.statusToQuery[status] || null,
role: role || null,
@@ -106,8 +108,10 @@ class PeopleContainer extends React.PureComponent {
setUserRole={this.props.setUserRole}
showSuspendUserDialog={this.props.showSuspendUserDialog}
showBanUserDialog={this.props.showBanUserDialog}
showAlwaysPremodUserDialog={this.props.showAlwaysPremodUserDialog}
unbanUser={this.props.unbanUser}
unsuspendUser={this.props.unsuspendUser}
removeAlwaysPremodUser={this.props.removeAlwaysPremodUser}
data={this.props.data}
root={this.props.root}
users={this.props.root.users}
@@ -122,9 +126,11 @@ PeopleContainer.propTypes = {
setUserRole: PropTypes.func.isRequired,
unbanUser: PropTypes.func.isRequired,
unsuspendUser: PropTypes.func.isRequired,
removeAlwaysPremodUser: PropTypes.func.isRequired,
viewUserDetail: PropTypes.func.isRequired,
showSuspendUserDialog: PropTypes.func,
showBanUserDialog: PropTypes.func,
showAlwaysPremodUserDialog: PropTypes.func,
data: PropTypes.object,
root: PropTypes.object,
};
@@ -134,8 +140,11 @@ const LOAD_MORE_QUERY = gql`
$limit: Int
$cursor: Cursor
$value: String
$state: UserStateInput
) {
users(query: { value: $value, limit: $limit, cursor: $cursor }) {
users(
query: { value: $value, limit: $limit, cursor: $cursor, state: $state }
) {
hasNextPage
endCursor
nodes {
@@ -153,6 +162,9 @@ const LOAD_MORE_QUERY = gql`
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -187,6 +199,9 @@ const FILTER_QUERY = gql`
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -203,6 +218,7 @@ const mapDispatchToProps = dispatch =>
viewUserDetail,
showSuspendUserDialog,
showBanUserDialog,
showAlwaysPremodUserDialog,
},
dispatch
);
@@ -215,6 +231,7 @@ export default compose(
withSetUserRole,
withUnsuspendUser,
withUnbanUser,
withRemoveAlwaysPremodUser,
withQuery(
gql`
query TalkAdmin_Community_People {
@@ -236,6 +253,9 @@ export default compose(
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -14,6 +14,11 @@ class TechSettings extends React.Component {
this.props.updatePending({ updater });
};
updateCustomAdminCssUrl = event => {
const updater = { customAdminCssUrl: { $set: event.target.value } };
this.props.updatePending({ updater });
};
updateDomainlist = (listName, list) => {
this.props.updatePending({
updater: {
@@ -50,6 +55,14 @@ class TechSettings extends React.Component {
onChange={this.updateCustomCssUrl}
/>
</ConfigureCard>
<ConfigureCard title={t('configure.custom_admin_css_url')}>
<p>{t('configure.custom_admin_css_url_desc')}</p>
<input
className={styles.customCSSInput}
value={settings.customAdminCssUrl}
onChange={this.updateCustomAdminCssUrl}
/>
</ConfigureCard>
<Slot fill="adminTechSettings" passthrough={slotPassthrough} />
</ConfigurePage>
);
@@ -32,6 +32,7 @@ export default compose(
settings: gql`
fragment TalkAdmin_TechSettings_settings on Settings {
customCssUrl
customAdminCssUrl
domains {
whitelist
}
@@ -62,7 +62,7 @@
font-weight: 300;
margin-bottom: 8px;
overflow-wrap: break-word;
word-break:break-word;
word-break: break-word;
}
.body {
@@ -103,7 +103,7 @@
color: #063b9a;
text-decoration: none;
font-weight: 500;
letter-spacing: .5px;
letter-spacing: 0.5px;
margin-left: 10px;
font-size: 13px;
margin-left: 5px;
@@ -111,14 +111,14 @@
border-bottom: solid 1px;
line-height: 16px;
&:hover {
opacity: .9;
opacity: 0.9;
cursor: pointer;
}
}
}
.username {
color: #393B44;
color: #393b44;
text-decoration: none;
cursor: pointer;
font-weight: 600;
@@ -127,12 +127,12 @@
margin-left: -5px;
transition: background-color 200ms ease;
&:hover {
background-color: #E0E0E0;
background-color: #e0e0e0;
}
}
.external {
font-size: .7em;
font-size: 0.7em;
text-decoration: none;
color: #063b9a;
cursor: pointer;
@@ -140,7 +140,7 @@
white-space: nowrap;
&:hover {
text-decoration: underline;
opacity: .9;
opacity: 0.9;
}
i {
font-size: 12px;
@@ -196,3 +196,25 @@
.commentContentFooter {
flex: 1;
}
.bodyHistoryToggle {
color: #666;
font-size: 12px;
line-height: 1px;
font-weight: 300;
text-decoration: underline;
&:hover {
cursor: pointer;
}
}
.editedCommentBody {
padding: 0 5px 5px 5px;
}
.editedComment {
margin-top: 6px;
font-weight: 300;
font-size: 16px;
overflow-wrap: break-word;
}
@@ -22,6 +22,8 @@ import t from 'coral-framework/services/i18n';
class Comment extends React.Component {
ref = null;
state = { showingEditHistory: false };
handleRef = ref => (this.ref = ref);
handleFocusOrClick = () => {
@@ -45,6 +47,30 @@ class Comment extends React.Component {
? null
: this.props.rejectComment({ commentId: this.props.comment.id });
getBodyHistory = () => {
const bodyHistory = [];
const comment = this.props.comment;
for (let i = 0; i < comment.body_history.length - 1; i++) {
bodyHistory.push(
<div key={i} className={styles.editedComment}>
<div>
<TimeAgo className={styles.created} datetime={comment.created_at} />
</div>
<div className={styles.editedCommentBody}>
{comment.body_history[i].body}
</div>
</div>
);
}
return bodyHistory;
};
toggleEditHistory = () => {
this.setState({ showingEditHistory: !this.state.showingEditHistory });
this.props.clearHeightCache && this.props.clearHeightCache();
};
componentDidUpdate(prev) {
if (!prev.selected && this.props.selected) {
this.ref.focus();
@@ -137,6 +163,14 @@ class Comment extends React.Component {
&nbsp;<span className={styles.editedMarker}>
({t('comment.edited')})
</span>
&nbsp;<span
className={styles.bodyHistoryToggle}
onClick={this.toggleEditHistory}
>
{this.state.showingEditHistory
? t('comment.hide_edit_history')
: t('comment.show_edit_history')}
</span>
</span>
) : null}
<div className={styles.adminCommentInfoBar}>
@@ -201,6 +235,14 @@ class Comment extends React.Component {
</div>
</CommentAnimatedEdit>
</div>
{this.state.showingEditHistory ? (
<div className={styles.container}>
{t('comment.edit_history')}
{this.getBodyHistory()}
</div>
) : null}
<CommentDetails
root={root}
comment={comment}
@@ -52,6 +52,10 @@ export default withFragments({
status_history {
type
}
body_history {
body
created_at
}
hasParent
${getSlotFragmentSpreads(slots, 'comment')}
...${getDefinitionName(CommentLabels.fragments.comment)}
@@ -5,6 +5,9 @@ const prefix = 'TALK_EMBED_STREAM';
export const ADDTL_COMMENTS_ON_LOAD_MORE = parseInt(
defaultTo(process.env.TALK_ADDTL_COMMENTS_ON_LOAD_MORE, '10')
);
export const ADDTL_REPLIES_ON_LOAD_MORE = parseInt(
defaultTo(process.env.TALK_ADDTL_REPLIES_ON_LOAD_MORE, '999999')
);
export const ASSET_COMMENTS_LOAD_DEPTH = parseInt(
defaultTo(process.env.TALK_ASSET_COMMENTS_LOAD_DEPTH, '10')
);
@@ -175,6 +175,9 @@ const USER_BANNED_SUBSCRIPTION = gql`
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -196,6 +199,9 @@ const USER_SUSPENDED_SUBSCRIPTION = gql`
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -217,6 +223,9 @@ const USERNAME_REJECTED_SUBSCRIPTION = gql`
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -253,6 +262,9 @@ const EMBED_QUERY = gql`
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
@@ -6,6 +6,7 @@ import { bindActionCreators } from 'redux';
import {
ADDTL_COMMENTS_ON_LOAD_MORE,
ASSET_COMMENTS_LOAD_DEPTH,
ADDTL_REPLIES_ON_LOAD_MORE,
THREADING_LEVEL,
} from '../../../constants/stream';
import {
@@ -152,7 +153,9 @@ class StreamContainer extends React.Component {
return this.props.data.fetchMore({
query: LOAD_MORE_QUERY,
variables: {
limit: parent_id ? 999999 : ADDTL_COMMENTS_ON_LOAD_MORE,
limit: parent_id
? ADDTL_REPLIES_ON_LOAD_MORE
: ADDTL_COMMENTS_ON_LOAD_MORE,
cursor: comment.replies.endCursor,
parent_id,
asset_id: this.props.asset.id,
@@ -398,6 +401,9 @@ const fragments = {
banned {
status
}
alwaysPremod {
status
}
suspension {
until
}
+41 -6
View File
@@ -3,6 +3,7 @@ import URLSearchParams from '@ungap/url-search-params';
import pym from 'pym.js';
import EventEmitter from 'eventemitter2';
import { buildUrl } from 'coral-framework/utils/url';
import SnackBar from './SnackBar';
import onIntersect from './onIntersect';
import {
@@ -92,6 +93,21 @@ function viewportDimensions() {
};
}
function parseAMPHash(opts) {
const result = { ...opts };
const query = window.location.hash.length && window.location.hash.substr(1);
if (query) {
const parsed = queryString.parse(query);
if (parsed.asset_url && !result.asset_url) {
result.asset_url = parsed.asset_url;
}
if (parsed.asset_id && !result.asset_id) {
result.asset_id = parsed.asset_id;
}
}
return result;
}
export default class Bridge {
constructor(
element,
@@ -110,19 +126,23 @@ export default class Bridge {
lazy = process.env.TALK_DEFAULT_LAZY_RENDER === 'TRUE',
// Any additional options are extracted to be sent to the embed via the
// pym bridge.
amp,
...opts
}
) {
this.pym = null;
this.element = element;
this.opts = opts;
this.amp = amp;
this.lazy = !amp && lazy;
// Parse amp hash.
this.opts = amp ? parseAMPHash(opts) : opts;
this.query = buildQuery(this.opts);
this.emitter = new EventEmitter({ wildcard: true });
this.snackBar = new SnackBar(snackBarStyles || {});
this.snackBar = amp ? null : new SnackBar(snackBarStyles || {});
this.onAuthChanged = onAuthChanged;
this.talkBaseUrl = ensureEndSlash(talkBaseUrl);
this.talkStaticUrl = ensureEndSlash(talkStaticUrl);
this.lazy = lazy;
// Store queued operations in a queue that can be processed once the stream
// is rendered.
@@ -179,6 +199,16 @@ export default class Bridge {
if (height !== cachedHeight) {
this.pym.el.firstChild.style.height = `${height}px`;
cachedHeight = height;
if (this.amp) {
window.parent.postMessage(
{
sentinel: 'amp',
type: 'embed-size',
height,
},
'*'
);
}
}
});
@@ -267,8 +297,10 @@ export default class Bridge {
// Setup Pym.
this.setupPym();
// Attach the snackBar to the pym parent and to the body of the page.
this.snackBar.attach(window.document.body, this.pym);
if (this.snackBar) {
// Attach the snackBar to the pym parent and to the body of the page.
this.snackBar.attach(window.document.body, this.pym);
}
// If the user clicks outside the embed, then tell the embed.
document.addEventListener('click', this.handleClick.bind(this), true);
@@ -315,7 +347,10 @@ export default class Bridge {
this.emitter.removeAllListeners();
// Remove the snackbar.
this.snackBar.remove();
if (this.snackBar) {
this.snackBar.remove();
this.snackBar = null;
}
// Remove the pym parent.
this.pym.remove();
+31 -6
View File
@@ -7,17 +7,25 @@ const DEFAULT_STYLE = {
willChange: 'transform, opacity',
transition: 'transform .35s cubic-bezier(.55,0,.1,1), opacity .35s',
pointerEvents: 'none',
padding: '12px 18px',
padding: '12px 18px 0',
color: '#fff',
borderRadius: '3px 3px 0 0',
textAlign: 'center',
borderRadius: '4px',
maxWidth: '400px',
left: '50%',
opacity: 0,
transform: 'translate(-50%, 20px)',
bottom: 0,
bottom: '20px',
boxSizing: 'border-box',
fontFamily: 'Helvetica, "Helvetica Neue", Verdana, sans-serif',
display: 'flex',
};
const CLOSE_STYLE = {
fontSize: '20px',
cursor: 'pointer',
marginLeft: '10px',
position: 'relative',
top: '-4px',
};
export default class Snackbar {
@@ -26,6 +34,20 @@ export default class Snackbar {
this.el = document.createElement('div');
this.el.id = 'coral-notif';
const closeButton = document.createElement('div');
closeButton.className = 'coral-notif-close';
for (let key in CLOSE_STYLE) {
closeButton.style[key] = CLOSE_STYLE[key];
}
closeButton.textContent = '×';
closeButton.onclick = () => this.clear();
this.snackbarText = document.createElement('div');
this.snackbarText.className = 'coral-notif-text';
this.snackbarText.style.paddingBottom = '12px';
this.el.appendChild(this.snackbarText);
this.el.appendChild(closeButton);
// Apply custom styles to the snackbar.
const style = Object.assign({}, DEFAULT_STYLE, customStyle);
for (let key in style) {
@@ -35,6 +57,7 @@ export default class Snackbar {
clear() {
this.el.style.opacity = 0;
this.el.style.pointerEvents = 'none';
}
alert(message) {
@@ -42,7 +65,7 @@ export default class Snackbar {
this.el.style.transform = 'translate(-50%, 20px)';
this.el.style.opacity = 0;
this.el.className = `coral-notif-${type}`;
this.el.textContent = text;
this.snackbarText.textContent = text;
if (this.timeout) {
clearTimeout(this.timeout);
@@ -51,10 +74,12 @@ export default class Snackbar {
this.timeout = setTimeout(() => {
this.el.style.transform = 'translate(-50%, 0)';
this.el.style.opacity = 1;
this.el.style.pointerEvents = 'auto';
this.timeout = setTimeout(() => {
this.el.style.opacity = 0;
}, 7000);
this.el.style.pointerEvents = 'none';
}, 15000);
}, 0);
}
+1
View File
@@ -56,6 +56,7 @@ export const Talk = {
* @param {String} [config.auth_token] - (optional) A jwt representing the session
* @param {String} [config.lazy] - (optional) If set the stream will only render lazily
* @param {String} [config.talkStaticUrl] - (optional) Static URL used to serve Talk
* @param {Boolean} [config.amp] - (optional) Run Talk in AMP mode
* @return {Object}
*/
render: (element, config) => {
@@ -3,6 +3,7 @@ import { createDefaultResponseFragments } from '../utils';
// fragments defined here are automatically registered.
export default {
...createDefaultResponseFragments(
'AlwaysPremodUserResponse',
'BanUsersResponse',
'ChangeUsernameResponse',
'CloseAssetResponse',
@@ -14,6 +15,7 @@ export default {
'IgnoreUserResponse',
'ModifyTagResponse',
'PostFlagResponse',
'RemoveAlwaysPremodUserResponse',
'SetCommentStatusResponse',
'SetUsernameResponse',
'SetUsernameStatusResponse',
@@ -412,6 +412,48 @@ export const withSetUsername = withMutation(
}
);
export const withAlwaysPremodUser = withMutation(
gql`
mutation AlwaysPremodUser($input: AlwaysPremodUserInput!) {
alwaysPremodUser(input: $input) {
...AlwaysPremodUserResponse
}
}
`,
{
props: ({ mutate }) => ({
alwaysPremodUser: input => {
return mutate({
variables: {
input,
},
});
},
}),
}
);
export const withRemoveAlwaysPremodUser = withMutation(
gql`
mutation RemoveAlwaysPremodUser($input: RemoveAlwaysPremodUserInput!) {
removeAlwaysPremodUser(input: $input) {
...RemoveAlwaysPremodUserResponse
}
}
`,
{
props: ({ mutate }) => ({
removeAlwaysPremodUser: input => {
return mutate({
variables: {
input,
},
});
},
}),
}
);
export const withBanUser = withMutation(
gql`
mutation BanUser($input: BanUserInput!) {
+5
View File
@@ -12,6 +12,7 @@ import 'moment/locale/da';
import 'moment/locale/de';
import 'moment/locale/es';
import 'moment/locale/fr';
import 'moment/locale/he';
import 'moment/locale/it';
import 'moment/locale/nl';
import 'moment/locale/pt-br';
@@ -23,6 +24,7 @@ import daTA from 'timeago.js/locales/da';
import deTA from 'timeago.js/locales/de';
import esTA from 'timeago.js/locales/es';
import frTA from 'timeago.js/locales/fr';
import heTA from 'timeago.js/locales/he';
import itTA from 'timeago.js/locales/it';
import nlTA from 'timeago.js/locales/nl';
import pt_BRTA from 'timeago.js/locales/pt_BR';
@@ -36,6 +38,7 @@ import da from '../../../locales/da.yml';
import de from '../../../locales/de.yml';
import es from '../../../locales/es.yml';
import fr from '../../../locales/fr.yml';
import he from '../../../locales/he.yml';
import it from '../../../locales/it.yml';
import nl_NL from '../../../locales/nl_NL.yml';
import pt_BR from '../../../locales/pt_BR.yml';
@@ -64,6 +67,7 @@ export const translations = {
...de,
...es,
...fr,
...he,
...it,
...nl_NL,
...pt_BR,
@@ -110,6 +114,7 @@ export function setupTranslations() {
ta.register('da', daTA);
ta.register('de', deTA);
ta.register('fr', frTA);
ta.register('he', heTA);
ta.register('it', itTA);
ta.register('nl_NL', nlTA);
ta.register('pt_BR', pt_BRTA);
+2 -2
View File
@@ -14,9 +14,9 @@ import {
export function createStore(reducers, middlewares = []) {
const enhancers = [applyMiddleware(...middlewares)];
if (window.devToolsExtension) {
if (window.__REDUX_DEVTOOLS_EXTENSION__) {
// we can't have the last argument of compose() be undefined
enhancers.push(window.devToolsExtension());
enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__());
}
return reduxCreateStore(combineReducers(reducers), {}, compose(...enhancers));
+9
View File
@@ -35,6 +35,15 @@ export const isBanned = user => {
return get(user, 'state.status.banned.status');
};
/**
* isAlwaysPremod
* retrieves boolean based on the user premod status
*/
export const isAlwaysPremod = user => {
return get(user, 'state.status.alwaysPremod.status');
};
/**
* isUsernameRejected
* retrieves boolean based on the username status
+10 -2
View File
@@ -16,7 +16,8 @@
text-align: center;
vertical-align: middle;
line-height: 30px;
width: 30px;
min-width: 30px;
padding: 5px;
user-select: none;
}
@@ -24,7 +25,14 @@
font-size: 1.8em;
}
.active {
.page:hover {
background-color: #ababab;
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
a {
color: white;
}
}
.active, .active:hover {
background-color: #696969;
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
a {
+26
View File
@@ -43,6 +43,32 @@ const CONFIG = {
process.env.TALK_WHITELISTED_LANGUAGES &&
process.env.TALK_WHITELISTED_LANGUAGES.split(',').map(l => l.trim()),
// USERNAME_CAST_REGEXP defiles the regex expression that will be used to
// strip characters from a username during a username cast operation.
USERNAME_CAST_REGEXP: new RegExp(
process.env.USERNAME_CAST_REGEXP || '[^a-zA-Z_]',
'g'
),
// USERNAME_REPLACEMENT_CAST_REGEXP defiles the regex expression that will be
// used to replace characters with the replacement character during a username
// cast operation. First duplicates will be replaced, then
USERNAME_REPLACEMENT_CAST_REGEXP: new RegExp(
process.env.USERNAME_REPLACEMENT_CAST_REGEXP || ' +',
'g'
),
// USERNAME_REPLACEMENT_CHARACTER is the character used to replace other
// characters matching the USERNAME_REPLACEMENT_CAST_REGEXP.
USERNAME_REPLACEMENT_CHARACTER:
process.env.USERNAME_REPLACEMENT_CHARACTER || '_',
// USERNAME_VALIDATION_REGEX defines the allowed characters for a username in
// Talk.
USERNAME_VALIDATION_REGEX: new RegExp(
process.env.USERNAME_VALIDATION_REGEX || '^[A-Za-z0-9_]+$'
),
// When TRUE, it ensures that database indexes created in core will not add
// indexes.
CREATE_MONGO_INDEXES: process.env.DISABLE_CREATE_MONGO_INDEXES !== 'TRUE',
+5 -3
View File
@@ -76,9 +76,7 @@ sidebar:
- title: GitHub
url: https://github.com/coralproject/
- title: Docker
url: https://hub.docker.com/r/coralproject/
- title: Roadmap
url: https://www.pivotaltracker.com/n/projects/1863625
url: https://hub.docker.com/r/coralproject/talk/
side:
- title: Installation
children:
@@ -122,6 +120,8 @@ sidebar:
url: /integrating/translations-i18n/
- title: GDPR Compliance
url: /integrating/gdpr/
- title: Accelerated Mobile Page
url: /integrating/amp/
- title: Product Guide
children:
- title: How Talk Works
@@ -166,6 +166,8 @@ sidebar:
url: /customizing-plugins-coral-ui/
- title: When You've Installed Talk
url: /when-youve-installed-talk/
- title: Embedding Talk in Native Mobile Apps
url: /embedding-in-native-mobile-apps/
- title: Migrating
children:
- title: Migrating from v3.x.x
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"hexo": {
"version": "3.7.1"
"version": "3.8.0"
},
"scripts": {
"start": "hexo serve",
+13 -4
View File
@@ -5,9 +5,18 @@ permalink: /
Online comments are broken. Our open-source Talk tool rethinks how moderation,
comment display, and conversation function, creating the opportunity for safer,
smarter discussions around your work. Read more about our product features and
goals [here](https://coralproject.net/talk). The
documentation available here is pertaining to the technical details for
smarter discussions around your work.
More than 60 newsrooms use Talk to run their on-site communities, including the Washington Post, the Wall Street Journal, and IGN.
[Read more about our product features and
goals here](https://coralproject.net/talk).
<div class="callout">
We offer hosting and support packages for Talk. [Contact us for more information.](https://coralproject.net/pricing/)
</div>
The documentation available here is pertaining to the technical details for
installing, configuring, and deploying Talk.
Talk is a [Node](https://nodejs.org/) application with
@@ -46,7 +55,7 @@ Start by making a new directory and create a file called `docker-compose.yml` an
version: '2'
services:
talk:
image: coralproject/talk:4.5
image: coralproject/talk:4
restart: always
ports:
- "3000:3000"
@@ -43,7 +43,7 @@ be used to setup Talk:
version: '2'
services:
talk:
image: coralproject/talk:4.5
image: coralproject/talk:4
restart: always
ports:
- "3000:3000"
@@ -121,7 +121,7 @@ base installation with additional custom plugins. Images can be created with the
most basic of `Dockerfile`'s:
```docker
FROM coralproject/talk:4.5-onbuild
FROM coralproject/talk:4-onbuild
```
And running the following to build the docker image:
@@ -153,7 +153,7 @@ your containerized infrastructure. The versioning of our Docker tags as well
lets you do something like:
```docker
FROM coralproject/talk:4.5-onbuild
FROM coralproject/talk:4-onbuild
```
Which would pin your image to `4.5.x release's.
Which would pin your image to `4.x.x release's.
@@ -19,3 +19,40 @@ Application servers: c4.xlarge (16 VM nginx + Talk VM machine pairs)
Mongo nodes: 3x c3.medium (large db cluster, 1 master, 2 read replicas)
If you need help with Talk performance or want custom scaling help or recommendations, let us know by logging a ticket and one of our engineers will get in touch with you: https://support.coralproject.net
## How to Scale Talk Components
### Scaling the Talk Application
In addition to scaling by adding additional app servers, Talk as a server component can flex to various roles. Depending on the desired configuration the roles can be split up to ensure high availability, and best matching to underlying host resources.
There are three components to the Talk application that can be served independently or in combination on a single thread: API Server, WebSockets, and Jobs
![ServerArchitectureDiagram](/talk/images/ServerArch.png)
In the diagram we see the difference between a Typical configuration (which just adds additional Talk application instances) vs the Split configuration where different Talk components could be spread across different machine resources to optimize infrastructure utilization.
See [Serving the Application](/talk/configuration-cli-tools/#serving-the-application)
### Scaling Redis
Redis serves as a general cache and pub/sub broker. We treat all the data stored in Redis as ephemeral, so using as a cache serves us well for Talk to synchronize expensive query caches. It also serves as our pub/sub broker for use with live updates as propagated through the GraphQL subscription system. For this reason it is not recommended to implement multiple instances of Redis.
### Scaling MongoDB
MongoDB is treated as our general store for persisted data. Talk supports the most common strategies for scaling MongoDB instances including replicas and/or sharding. Depending on your specific data use cases, refer to MongoDBs documentation for more information about scaling https://www.mongodb.com/mongodb-scale.
### Load Balancer
While this subject lives outside the Talk ecosystem, it is critical for application delivery. For websockets to work correctly, a load balancer must be selected that can support long lived connections that are required for websockets to work.
## Running Talk in Production
When you are ready to launch your production instance of Talk update your NODE_ENV environment variable from `development` to `production` mode.
Then launch talk with `yarn start` or with the command `NODE_ENV=production ./bin/cli-serve -j -w`
By default Talk will run on a single thread, but you can also run multiple Talk threads on a single application instance by setting the environment variable `TALK_CONCURRENCY`. [See Advanced Configuration](/talk/advanced-configuration/#talk-concurrency)
+11 -4
View File
@@ -13,6 +13,9 @@ permalink: /pre-launch-checklist/
- [ ] Do you have a domain name for Talk?
- **Recommended**: You should host Talk on a subdomain on your main site (e.g. if your site is mysitefornews.org, you should serve Talk from a subdomain like talk.mysitefornews.org) to avoid issues with third-party cookie sharing.
- [ ] Do you have a Content Delivery Network (CDN) to improve performance and reduce load on your Talk servers?
- [ ] Do you have a MongoDB instance?
- A MongoDB [Docker instance](/talk/installation-from-docker/) hosted alongside Talk?
@@ -28,9 +31,11 @@ permalink: /pre-launch-checklist/
- [ ] Do you want to provide single sign-on (SSO) by integrating with an external auth system?
- See [Authenticating with Talk](/talk/integrating/authentication/)
- [ ] Do you want to integrate Talk with your CMS to automate embedding Talk Comment Stream into your site?
- See [CMS Integration](/talk/integrating/cms-integration/)
- [ ] Do you want to use Social sign-on?
- Facebook
- Install [talk-plugin-facebook-auth](/talk/plugin/talk-plugin-facebook-auth/)
@@ -58,9 +63,10 @@ permalink: /pre-launch-checklist/
- Install [talk-plugin-rich-text](/talk/plugin/talk-plugin-rich-text)
- [ ] Do you want to display comment counts?
- Use the GraphQL [CommentCountQuery](https://docs.coralproject.net/talk/api/graphql/#CommentCountQuery)
- Install [talk-plugin-deep-reply-count](/talk/plugin/talk-plugin-deep-reply-count) if necessary.
- [ ] Do you want to display comment counts on your embed stream or on a homepage with dozens of articles?
- Install [talk-plugin-comment-count](https://github.com/coralproject/talk-plugin-comment-count) for summary counts on multiple articles
- Install [talk-plugin-deep-reply-count](/talk/plugin/talk-plugin-deep-reply-count) to add counts to the embed stream
- Or use the GraphQL [CommentCountQuery](https://docs.coralproject.net/talk/api/graphql/#CommentCountQuery)
- [ ] Do you want to translate Talk to a different language?
@@ -71,7 +77,8 @@ permalink: /pre-launch-checklist/
- See [our blog for more information](https://coralproject.net/blog/slacking-on/)
- [ ] Has your community team configured Talk to match your community strategy?
- [ ] Have you configured Talks admin settings and determined your community strategy?
- See [our tutorial for more information](https://docs.coralproject.net/talk/when-youve-installed-talk/)
- See [Configuring Talk](/talk/configuring-talk/)
+26 -5
View File
@@ -23,6 +23,10 @@ otherwise the application will fail to start.
Configure the duration for which comment counts are cached for, parsed by
[ms](https://www.npmjs.com/package/ms). (Default `1hr`)
## TALK_CONCURRENCY
This environment variable allows multiple worker processes to be spawned to handle traffic. (Default `1`)
## TALK_DEFAULT_LANG
This is a **Build Variable** and must be consumed during build. If using the
@@ -412,13 +416,19 @@ cannot. You would use this option in the latter situation.
## TALK_SMTP_FROM_ADDRESS
The email address to send emails from using the SMTP provider in the format:
The email address to send emails from using the SMTP provider. You can include the name and email address or only provide the email.
```plain
TALK_SMTP_FROM_ADDRESS="The Coral Project" <support@coralproject.net>
TALK_SMTP_FROM_ADDRESS="The Coral Project" support@coralproject.net
```
or
```plain
TALK_SMTP_FROM_ADDRESS=support@coralproject.net
```
Including the name and email address.
## TALK_SMTP_HOST
@@ -495,8 +505,9 @@ Could be read as:
pre-moderated once in order to post freely again. If they instead get rejected
again, then they must have two of their comments approved in order to get
added back to the queue.
- At the moment of writing, behavior is not attached to the flagging
reliability, but it is recorded.
- At the moment of writing, behavior is not attached to reliable commenters
as well as the flagging reliability and unreliability. Regardless,
all of these scores are recorded for future implementation.
## TALK_DISABLE_IGNORE_FLAGS_AGAINST_STAFF
@@ -589,3 +600,13 @@ can be used to set an authorization header, or change the user agent. (Default
## TALK_SCRAPER_PROXY_URL
Sets a specific HTTP/S proxy to be used by the Asset Scraper using [https-proxy-agent](https://www.npmjs.com/package/https-proxy-agent). (Default `null`)
## TALK_ADDTL_REPLIES_ON_LOAD_MORE
This is a **Build Variable** and must be consumed during build. If using the
[Docker-onbuild](/talk/installation-from-docker/#onbuild)
image you can specify it with `--build-arg TALK_ADDTL_REPLIES_ON_LOAD_MORE=3`.
Specifies the number of replies to load for a comment when clicking "Load More".
It is defaulted quite high to sort of support "loading the rest of the replies".
(Default `999999`)
+5
View File
@@ -81,12 +81,17 @@ Usage: cli-assets [options] [command]
Commands:
list [options] list all the assets in the database
debug <url> prints the scraped metadata from that URL
refresh [age] queues the assets that exceed the age requested
update-url <assetID> <url> update the URL of an asset
merge <srcID> <dstID> merges two assets together by moving comments from src to dst and deleting the src asset
rewrite [options] <search> <replace> rewrites asset url's using the provided regex replacement pattern
```
When using the `refresh` command, the `age` value specifies how far back in time to re-scrape assets; i.e. to re-scrape everything that was scraped in the last week use `1w` or `7d`. Supports ms (milliseconds), s (seconds), m (minutes), h (hours), d (days) and w (weeks). Assets that have not been scraped will also be queued for scraping.
See also, [Asset Scraping](/talk/integrating/asset-scraping/) for more details about asset scraping.
## Setting up the application
You can also run a setup wizard to setup the wizard using `./bin/cli setup`. Below is a list of additional options available for this command:
```
@@ -57,7 +57,7 @@ The timeframe in seconds in which commenters have to edit their comment.
#### Close Comments After
Default time after which all comment streams will close.
Default time after which all comment streams will close. Applies to assets created in Talk after this configuration is saved, and does not update existing assets.
### Moderation Settings
@@ -88,8 +88,9 @@ Comments with suspect words will display until a moderator takes action on them.
#### Permitted Domains
A list of domains where your Talk instance is allowed to be embedded. Typical
use is `localhost`, `staging.yourdomain.com`, `yourdomain.com`, etc.
A list of domains where your Talk instance is allowed to be embedded. List each domain and subdomain in use
separately, for example: `localhost`, `staging.yourdomain.com`, `yourdomain.com`, `www.yourdomain.com`, etc.
#### Embed Script
+6
View File
@@ -47,3 +47,9 @@ Source: [talk-recipes/tree/master/plugins/author-name](https://github.com/coralp
Enables the ability to hover over a commenters name and add plugin
functionality there. The Member Since plugin that is provided in this recipe is
an example of this.
## recipe-custom-auth
Source: [talk-recipes/tree/master/plugins/custom-auth](https://github.com/coralproject/talk-recipes/tree/master/plugins/custom-auth)
Example code for creating, and updating Users in Talk from JWT data provided by your custom SSO authentication service.
@@ -87,6 +87,8 @@ The most important predictors of the success of an online community are:
#### Effectively
* Keep conversations fresh and reduce moderation overhead by configuring Talk to automatically close commenting after a specified time window. Should comments be open for a day, a week, or a month? Set a manageable window and automatically close stories for commenting after that time period.
* If you're using the Toxic Comments plugin, make sure that its threshold is set at the level that catches most comments with fewest false positives (default is 80%). You can see the Likely to be Toxic level of every comment by clicking "More Details" on the comment card in the moderation view.
* Publicly discourage behavior in the comments that doesn't cross the line but suggests that the tone or focus could shift quickly in a direction you don't want. Point to relevant sections of your community guidelines. [Read more about defining and discouraging this kind of behavior here.](https://guides.coralproject.net/manage-a-successful-community/)
+10
View File
@@ -0,0 +1,10 @@
---
title: Embedding Talk in Native Mobile Apps
permalink: /embedding-in-native-mobile-apps/
---
When it comes mobile devices, the Talk client embed is already responsive and mobile friendly. We do not currently have plans to provide mobile SDKs, however, you can do this yourself.
One organization that has taken on the challenge of creating their own iOS native Talk client is [IGN](http://www.ign.com/). They were kind enough to share how they implemented Talk natively on their apps, which can be found [here](http://coralproject.net/wp-content/uploads/2019/01/IGNNativeComments.pdf).
If you implement Talk on your mobile apps and would like to contribute your process for others, you can add those here in our docs via a PR or post an issue on Github and we can help you.
+8 -10
View File
@@ -11,8 +11,6 @@ To log a bug or request a feature, submit a Support ticket ([support@coralprojec
You can also request help on Github by [submitting an issue](https://github.com/coralproject/talk/issues). This also increases your chances of having someone from the community respond to help.
And you can also search our [Coral Community](https://community.coralproject.net) to see if your issue has been solved, or to get tips from the community.
## How can our dev team contribute to Talk?
We are lucky to work with newsroom dev teams and individual contributors who span the world, and come from newsrooms of all sizes. You can read our [Contribution Guide](https://github.com/coralproject/talk/blob/master/CONTRIBUTING.md) to get started, but feel free to reach out to us via Github too.
@@ -35,24 +33,24 @@ Our team is small, so it's difficult for us to provide support packages. However
## Is there a hosted version I can purchase by monthly subscription?
Yes! We are happy to announce that as of July 2018, we provide a SaaS version of Talk, called the Coral Cloud. For a monthly subscription, you get your own hosted Talk instance to embed on your news and blog articles. [Reach out to us](mailto:support@coralproject.net) if you're interested in this option.
Yes! [Visit our hosting page](https://coralproject.net/pricing/) to submit information and receive a quote.
## Where is our data when we use Talk?
If you are hosting Talk on your own:
* Your data is stored in a MongoDB database that you provide
* The Coral Team doesnt have any access to your data
* The Coral team doesnt have any access to your data
If you are using Coral Cloud Hosting for Talk:
If you are using our Hosted SaaS version of Talk:
* Your data is stored in a dedicated MongDB database that is provisioned for your in the Cloud
* Your data is completely isolated from other customers data
* The Coral Team and its third party database hosting providers use strict access controls and auditing to protected your data from unauthorized access by team members
* Your data is stored in a dedicated MongoDB database that is provisioned for you
* Your data is completely isolated from other customers' data
* The Coral Team and its third-party database hosting providers use strict access controls and auditing to protected your data from unauthorized access
## Does Talk have any automated moderation features to protect against spam and trolling?
Talk features a couple of plugins that provide advanced moderation:
As well as basic word/phrase filtering and user reputation scores, Talk offers optional advanced features via third-party services:
* The [Toxic Comments plugin](/talk/plugin/talk-plugin-toxic-comments) integrates with the [Perspective API from Google](https://www.perspectiveapi.com/) to detect the likelihood of toxicity of comments in real-time
* The [Akismet plugin](/talk/plugin/talk-plugin-akismet) detects and blocks spam comments
@@ -66,4 +64,4 @@ Talk features a couple of plugins that provide advanced moderation:
* The Talk software is freely available under the Apache 2.0 open source license
* Associated costs are those for the infrastructure required to run Talk (i.e. cloud hosting fee or bare-metal server costs)
* The Coral Project offers a SaaS version of Talk. Please [get in touch with us](mailto:support@coralproject.net) to discuss pricing for your custom requirements.
* The Coral Project offers a SaaS/hosted version of Talk. Please [get in touch with us](https://coralproject.net/pricing/) to discuss pricing for your requirements.
@@ -38,3 +38,6 @@ If you're using `talk-plugin-auth`:
* See if you can isolate if it's a particular group of users that are experiencing this issue, e.g. mods, admins, subscribers? Confirm they have the appropriate permissions to comment.
* Note if this is a new issue that happened after an upgrade - did you read the [migration docs](/talk/migration/3/) and the [release notes](https://github.com/coralproject/talk/releases)? This might help you resolve the issue.
* If you're still experiencing issues, log a [support ticket](mailto:support@coralproject.net) so we can help diagnose the issue
If a user has been locked out due to too many failed login attempts:
* How long does the user have to wait before they will be allowed to login? 10 mins
+5
View File
@@ -146,3 +146,8 @@
tags:
- default
- sorting
- name: talk-plugin-comment-count
description: This plugin enables adding comment counts to Talks embed or in other locations on your site.
link: https://github.com/coralproject/talk-plugin-comment-count
tags:
- counts
+245 -168
View File
@@ -56,16 +56,32 @@ Thanks to [gql-merge](https://www.npmjs.com/package/gql-merge) the contents of
definitions. `enum`'s will be appended to, types will be appended, and new types
will be added.
This can be included as a plugin via:
```js
const fs = require("fs");
const path = require("path");
module.exports = {
typeDefs: fs.readFileSync(path.join(__dirname, "typeDefs.graphql"), "utf8")
};
```
Assuming the above GraphQL schema is located in the plugin folder at
`typeDefs.graphql`.
### context
```js
{
Slack: (context) => ({
notify: (message) => {
// return a promise after we're done sending notifications.
}
})
}
module.exports = {
context: {
Slack: context => ({
notify: message => {
// return a promise after we're done sending notifications.
},
});
},
};
```
Any property provided here will be added to the context parameter available
@@ -83,41 +99,50 @@ A special context hook, `Sort` will allow plugin authors to provide new
methods to sort data. An example is as follows:
```js
{
Sort: () => ({
Comments: { // <-- (1)
likes: { // <-- (2)
startCursor(ctx, nodes, {cursor}) { // <-- (3)
return cursor != null ? cursor : 0;
},
endCursor(ctx, nodes, {cursor}) { // <-- (4)
return nodes.length ? (cursor != null ? cursor : 0) + nodes.length : null;
},
sort(ctx, query, {cursor, sort}) { // <-- (5)
if (cursor) {
query = query.skip(cursor);
}
module.exports = {
context: {
Sort: () => ({
Comments: {
// <-- (1)
likes: {
// <-- (2)
startCursor(ctx, nodes, { cursor }) {
// <-- (3)
return cursor != null ? cursor : 0;
},
endCursor(ctx, nodes, { cursor }) {
// <-- (4)
return nodes.length
? (cursor != null ? cursor : 0) + nodes.length
: null;
},
sort(ctx, query, { cursor, sort }) {
// <-- (5)
if (cursor) {
query = query.skip(cursor);
}
return query.sort({
'action_counts.like': sort === 'DESC' ? -1 : 1,
created_at: sort === 'DESC' ? -1 : 1,
});
},
},
},
}),
}
return query.sort({
"action_counts.like": sort === "DESC" ? -1 : 1,
created_at: sort === "DESC" ? -1 : 1
});
}
}
}
})
}
};
```
This has a bunch of special features:
1. `Comments` is the name of the type being sorted, this is pluralized and
capitalized.
capitalized.
2. `likes` is the `sortBy` field in lowercase.
3. `startCursor` will retrieve the start cursor based on the current set of
nodes and the current cursor.
nodes and the current cursor.
4. `endCursor` will retrieve the end cursor based on the current set of nodes
and the current cursor.
and the current cursor.
5. `sort` will mutate the `query` to apply the sort operations.
All the `startCursor`, `endCursor`, and `sort` functions must be provided in
@@ -126,11 +151,13 @@ order for the sorting to apply properly.
### loaders
```js
(context) => ({
People: {
load: () => db.people.find({user: context.user})
}
})
module.exports = {
context: context => ({
People: {
load: () => db.people.find({ user: context.user })
}
})
};
```
Loaders should be provided as a function which returns a map which is used in
@@ -139,13 +166,15 @@ the resolvers function. These must return a promise or a value.
### mutators
```js
(context) => ({
People: {
create: (name) => {
return db.people.insert({user: context.user, name});
module.exports = {
context: context => ({
People: {
create: name => {
return db.people.insert({ user: context.user, name });
}
}
}
})
})
};
```
Mutators should be provided as a function which returns a map which is used in
@@ -154,27 +183,41 @@ the resolvers function. These must return a promise or a value.
### resolvers
```js
{
Person: {
name(obj, args, context) {
return obj.name;
module.exports = {
resolvers: {
Person: {
name(obj, args, context) {
return obj.name;
},
colour(obj, args, context) {
// Bill likes the colour red, everyone else likes blue.
return obj.name === "bill" ? "RED" : "BLUE";
}
},
colour(obj, args, context) {
// Bill likes the colour red, everyone else likes blue.
return obj.name === 'bill' ? 'RED' : 'BLUE';
}
},
RootQuery: {
people(obj, args, {loaders: {People}}) {
return People.load();
}
},
RootMutation: {
createPerson(obj, {name}, {mutators: {People}}) {
return People.create(name);
RootQuery: {
people(
obj,
args,
{
loaders: { People }
}
) {
return People.load();
}
},
RootMutation: {
createPerson(
obj,
{ name },
{
mutators: { People }
}
) {
return People.create(name);
}
}
}
}
};
```
Should return a resolver map as described in the
@@ -185,40 +228,44 @@ This will merge with the existing resolvers in core and from previous plugins.
### hooks
```js
{
RootMutation: {
createPerson: {
post: async (obj, args, {plugins: {Slack}}, info, person) {
if (!person) {
module.exports = {
hooks: {
RootMutation: {
createPerson: {
post: async (obj, args, {plugins: {Slack}}, info, person) {
if (!person) {
return person;
}
await Slack.notify(`A new person just was created with name ${person.name}`);
return person;
}
await Slack.notify(`A new person just was created with name ${person.name}`);
return person;
}
}
}
}
};
```
Hooks here are pretty special, for each resolver field, you can specify a
pre/post hook that will execute pre and post field resolution.
If your post function accepts four parameters, then it can modify the field
result. It is *required* that the function resolves a promise (or returns) with
result. It is _required_ that the function resolves a promise (or returns) with
the modified value or simply the original if you didn't modify it.
### setupFunctions
```js
setupFunctions: {
leader: (options, args) => ({
leader: {
filter: (person) => person.place === 1
},
}),
}
module.exports = {
setupFunctions: {
leader: (options, args) => ({
leader: {
filter: person => person.place === 1
}
})
}
};
```
Setup functions allow you to create filters that control which pubsub.publish() events
@@ -229,28 +276,32 @@ For more information, see the [Apollo Docs](https://github.com/apollographql/gra
### tokenUserNotFound
```js
tokenUserNotFound: async ({jwt, token}) => {
let profile = await someExternalService(token);
if (!profile) {
return null;
const Users = require("services/users");
module.exports = {
tokenUserNotFound: async ({ jwt }) => {
const user = await Users.upsertExternalUser(
null,
jwt.sub,
jwt.iss,
jwt.username
);
const email = jwt.email.toLowerCase();
//upsertExternalUser will also create a profile with provider:jwt.iss, id:jwt.sub
//add a "local" profile to persist email on the user
user.profiles.push({
provider: "local",
id: email
});
user.created_at = new Date(jwt.memberSince * 1000);
await user.save();
return user;
}
let user = await UserModel.findOneAndUpdate({
id: profile.id
}, {
id: profile.id,
username: profile.username,
lowercaseUsername: profile.username.toLowerCase(),
roles: [],
profiles: []
}, {
setDefaultsOnInsert: true,
new: true,
upsert: true
});
return user;
}
};
```
The `tokenUserNotFound` hook allows auth integrations to hook into the event
@@ -258,8 +309,15 @@ when a valid token is provided but a user can't be found in the database that
matches the provided id.
The function is async, and should return the user object that was created in the
database, or null if the user wasn't found. The `jwt` parameter of the object
is the unpacked token, while `token` is the original jwt token string.
database. The `jwt` parameter of the object is the unpacked token, which has already been validated.
More details about the `upsertExternalUser` method can be found at:
https://github.com/coralproject/talk/blob/32962aa1e84c09d87141440a1f04cbd1659b3336/services/users.js/#L592
In this example, a unix timestamp was included on the jwt with a date that is being persisted on the user. This is optional, but can be used to handle any extra claims you want to include on the jwt. You can use the metadata object on the user to store custom values.
Having trouble implementing your own `tokenUserNotFound` hook?
Submit a Support ticket ([support@coralproject.net](mailto:support@coralproject.net))
### tags
@@ -268,18 +326,20 @@ or enabled by code). Below is an example pulled from the core off topic plugin
on how to create a hook for the `OFF_TOPIC` name:
```js
[
{
name: 'OFF_TOPIC',
permissions: {
public: true,
self: true,
roles: []
},
models: ['COMMENTS'],
created_at: new Date()
}
]
module.exports = {
tags: [
{
name: "OFF_TOPIC",
permissions: {
public: true,
self: true,
roles: []
},
models: ["COMMENTS"],
created_at: new Date()
}
]
};
```
You can refer to `models/schema/tag.js` for the available schema to match when
@@ -288,11 +348,13 @@ creating models to enable/disable specific features.
### router
```js
(router) => {
router.get('/api/v1/people', (req, res) => {
res.json({people: [{name: 'Bob'}]});
});
}
module.exports = {
router: router => {
router.get("/api/v1/people", (req, res) => {
res.json({ people: [{ name: "Bob" }] });
});
}
};
```
The Router hook allows you to create a function that accepts the base express
@@ -302,56 +364,73 @@ action needed by external applications.
### passport
```js
const FacebookStrategy = require('passport-facebook').Strategy;
const UsersService = require('services/users');
const {ValidateUserLogin, HandleAuthPopupCallback} = require('services/passport');
const FacebookStrategy = require("passport-facebook").Strategy;
const UsersService = require("services/users");
const {
ValidateUserLogin,
HandleAuthPopupCallback
} = require("services/passport");
module.exports = {
passport(passport) {
passport.use(new FacebookStrategy({
clientID: process.env.TALK_FACEBOOK_APP_ID,
clientSecret: process.env.TALK_FACEBOOK_APP_SECRET,
callbackURL: `${process.env.TALK_ROOT_URL}/api/v1/auth/facebook/callback`,
passReqToCallback: true,
profileFields: ['id', 'displayName', 'picture.type(large)']
}, async (req, accessToken, refreshToken, profile, done) => {
passport: passport => {
passport.use(
new FacebookStrategy(
{
clientID: process.env.TALK_FACEBOOK_APP_ID,
clientSecret: process.env.TALK_FACEBOOK_APP_SECRET,
callbackURL: `${
process.env.TALK_ROOT_URL
}/api/v1/auth/facebook/callback`,
passReqToCallback: true,
profileFields: ["id", "displayName", "picture.type(large)"]
},
async (req, accessToken, refreshToken, profile, done) => {
let user;
try {
const { id, provider, displayName } = profile;
user = await UsersService.upsertSocialUser(
req.context,
id,
provider,
displayName
);
} catch (err) {
return done(err);
}
let user;
try {
const { id, provider, displayName } = profile;
user = await UsersService.upsertSocialUser(
req.context,
id,
provider,
displayName
);
} catch (err) {
return done(err);
}
return ValidateUserLogin(profile, user, done);
}));
return ValidateUserLogin(profile, user, done);
}
)
);
},
router(router) {
router: router => {
// Note that we have to import the passport instance here, it is
// instantiated after all the strategies have been mounted.
const {passport} = require('services/passport');
const { passport } = require("services/passport");
/**
* Facebook auth endpoint, this will redirect the user immediately to facebook
* for authorization.
*/
router.get('/facebook', passport.authenticate('facebook', {display: 'popup', authType: 'rerequest', scope: ['public_profile']}));
router.get(
"/facebook",
passport.authenticate("facebook", {
display: "popup",
authType: "rerequest",
scope: ["public_profile"]
})
);
/**
* Facebook callback endpoint, this will send the user a html page designed to
* send back the user credentials upon successful login.
*/
router.get('/facebook/callback', (req, res, next) => {
router.get("/facebook/callback", (req, res, next) => {
// Perform the facebook login flow and pass the data back through the opener.
passport.authenticate('facebook', HandleAuthPopupCallback(req, res, next))(req, res, next);
passport.authenticate(
"facebook",
HandleAuthPopupCallback(req, res, next)
)(req, res, next);
});
}
};
@@ -360,10 +439,10 @@ module.exports = {
### translations
```js
const path = require('path');
const path = require("path");
module.exports = {
translations: path.join(__dirname, 'translations.yml'),
translations: path.join(__dirname, "translations.yml")
};
```
@@ -377,11 +456,11 @@ en:
Which overrides the copy for the `embedlink.copy` template. You can
also provide other languages as well by using the correct language
prefix.
prefix.
When creating a plugin using this `translations` hook to override copy
When creating a plugin using this `translations` hook to override copy
from another plugin, be sure to list it after the plugin it's overriding
in the `plugins.json` file.
in the `plugins.json` file.
### websockets
@@ -392,12 +471,12 @@ module.exports = {
// Do something with the connection params or connection, like
// logging it out, or incrementing a metric.
},
onDisconnect: (connection) => {
onDisconnect: connection => {
// Do something with the connection params or connection, like
// logging it out, or decrementing a metric.
},
},
}
}
}
};
```
This `websockets` hook can be used to attach methods to the
@@ -411,12 +490,13 @@ connections.
module.exports = {
schemaLevelResolveFunction: (root, args, ctx, info) => {
// The GraphQL Operation Name. Example: CoralEmbedStream_Embed
const name = info.operation.name !== null ? info.operation.name.value : null;
const name =
info.operation.name !== null ? info.operation.name.value : null;
// Maybe increment a metric based on the operation name...
// You must _always_ return the root.
return root;
},
}
};
```
@@ -431,9 +511,7 @@ Contents of `plugins.json`:
```json
{
"server": [
"people"
]
"server": ["people"]
}
```
@@ -527,5 +605,4 @@ module.exports = {
}
}
};
```
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+47
View File
@@ -0,0 +1,47 @@
---
title: Accelerated Mobile Page
permalink: /integrating/amp/
---
[AMP](https://amp.dev/) is a light-weight, stripped down HTML page that aims to improve reader experience. _Talk v4.9.0+_ comes with [AMP](https://amp.dev/) support. The current caveat however is that _toast notifications_ are not being rendered when viewing inside AMP.
# How to integrate
Put the following code into your _AMP_ page and replace `$TALK_URL` and `$ASSET_URL` with the
corresponding values. You can also pass `asset_id` instead of `asset_url`.
```html
<amp-iframe
  width=600 height=140
  layout="responsive"
  sandbox="allow-scripts allow-same-origin allow-modals allow-popups allow-forms"
  resizable
  src="https://$TALK_URL/embed/amp#asset_url=$ASSET_URL">
  <div placeholder></div>
  <div overflow tabindex=0 role=button aria-label="Read more">Read more</div>
</amp-iframe>
```
## Single Sign-On
For SSO integration you need to create a page with the following output and replace `$TALK_URL` and `$AUTH_TOKEN` with the appropriate values. Inject your SSO auth scripts to get the `$AUTH_TOKEN` for the current user. Integrating with [amp-access](https://amp.dev/documentation/components/amp-access) is recommended which opens a 1st-party popup to not have browsers block your cookies. This page is then used in `src` of `<amp-iframe>` above. It must be accessed over `https` and live in a different domain than the `amp` page.
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>Coral Talk Amp Embed</title>
</head>
<body>
<div id='coralStreamEmbed'></div>
<script src="https://$TALK_URL/static/embed.js"></script>
<script>
window.TalkEmbed = Coral.Talk.render(document.getElementById('coralStreamEmbed'), {
talk: '$TALK_URL',
auth_token: '$AUTH_TOKEN',
amp: true,
})
</script>
</body>
</html>
```
+9 -2
View File
@@ -9,6 +9,9 @@ in a simple way. We use the following
[meta tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta) on
the target pages that allow us to extract some properties.
Asset scraping is performed by the `scraper` job which is enabled by default when you launch Talk. If your production site is behind a paywall or otherwise prevents scraping, you might need to confiugre a [TALK_SCRAPER_PROXY_URL](/talk/advanced-configuration/#talk-scraper-proxy-url) or custom [TALK_SCRAPER_HEADERS](/talk/advanced-configuration/#talk-scraper-headers).
| Asset Property | Selector |
|--------------------|----------|
| `title` | See [`metascraper-title`](https://github.com/microlinkhq/metascraper/blob/dc664c37ea1b238b1e3e9d5342edfacc9027892c/packages/metascraper-title/index.js) |
@@ -19,7 +22,7 @@ the target pages that allow us to extract some properties.
| `modified_date` | `meta[property="article:modified"]` |
| `section` | `meta[property="article:section"]` |
You can use the `./bin/cli assets debug <url>` to print the scraped metadata
You can use the `./bin/cli assets debug <url>` command to print the scraped metadata
from that URL. For example:
```bash
@@ -41,4 +44,8 @@ from that URL. For example:
├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ section │ │
└──────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
```
```
You can use the `./bin/cli assets refresh [age]` to trigger scraping or rescrape assets where the scraper job was unsuccessful.
+28 -23
View File
@@ -3,38 +3,39 @@ title: Authenticating with Talk
permalink: /integrating/authentication/
---
Out of the box Talk supports account registration with username and password, as well as features like forgot password.
### Authentication Strategies
You can also integrate Talk with any external authentication service that will enable
seamless single sign-on (SSO) for users within your organization. There are a few
methods of doing so:
Talk comes with built in user management features like account registration with username/email and password, as well as features like resetting a forgotten password.
1. Passport Middleware
2. Custom Token Integration
There are four strategies to choose from when it comes to user authentication:
Both methods work, but there are product decisions that will affect the overall
choice.
#### Talk Email Authentication
Best when you want Talk to manage all user registration, creation and authentication. Requires the least amount of setup and configuration. Users register by creating a Username (must be unique across users, no spaces or special chars), Email, and Password and are stored in Talks database. Optionally - you can require an email verification step at time of account creation. *Plugins required: [talk-plugin-local-auth](/talk/plugin/talk-plugin-local-auth), [talk-plugin-auth](/talk/plugin/talk-plugin-auth)*
## Passport Middleware
#### Social Sign-in (FaceBook or Google via Passport Middleware)
You would choose the **Passport Middleware** route when you are OK using an auth
that is triggered from inside Talk that is not connected to an external auth
state (you don't use the auth anywhere else now).
Plugins are available for the following 3rd party authentication providers:
Allows users to use existing social media account to sign in to Talk. Requires you to setup API keys with social sign on provider, and configure your API keys in Talk. Users register and login via a *“Sign in with ….”*, but are not required to set user details such as password or email address. *Plugins required: [talk-plugin-auth](/talk/plugin/talk-plugin-auth), plus at least one of the following:*
* [Facebook](/talk/plugin/talk-plugin-facebook-auth/)
* [Google](/talk/plugin/talk-plugin-google-auth/)
## Custom Token Integration
_FAQ: Can I create a Twitter auth plugin?_
This is currently not possible because Talk uses passport.js which does not support Twitter's oAuth2 requirements.
#### Social Sign-in with Email Association
This strategy is actually a combination of the first two. Talks built in Email Authentication is augmented by also allowing registration with a social account. Users with social accounts are prompted to associate an email address with their social profile to enable notifications. *Plugins required: [talk-plugin-auth](/talk/plugin/talk-plugin-auth), [talk-plugin-local-auth](/talk/plugin/talk-plugin-local-auth), [talk-plugin-facebook-auth](/talk/plugin/talk-plugin-facebook-auth/), and or [talk-plugin-google-auth](/talk/plugin/talk-plugin-google-auth/)*
#### Custom SSO Token Integration
When you want users to authenticate via your existing identity system, and be automatically registered/logged into Talk. Users register, login, and manage their user details on your existing site, your user database maintains the source of truth for all user information. Users are created and updated in Talk via jwt tokens passed from your auth service to Talk. *Required Plugins: requires custom plugin development, as well as disabling talk-plugin-auth, and talk-plugin-local-auth*
## Setting Up Custom SSO Token Integration
You can integrate Talk with any authentication service to enable single sign-on
for users. The steps to do that are:
1. Create a service that generates [JWT tokens](https://jwt.io/introduction/).
2. Push the token into the embed.
3. Implement the [`tokenUserNotFound`](#implement-tokenusernotfound) hook to
process the token.
2. Include the JWT token in your Talk embed script
3. Create a custom plugin to generate and authenticate Talk users from the jwt token
### Create JWT Token
@@ -61,7 +62,10 @@ The generated JWT must contain the following claims:
- [`iss`](https://tools.ietf.org/html/rfc7519#section-4.1.1): the issuer for the token must match the value of `TALK_JWT_ISSUER`
- [`aud`](https://tools.ietf.org/html/rfc7519#section-4.1.3): the audience for the token must match the value of `TALK_JWT_AUDIENCE`
### Push token into embed
### Generate a key to sign the JWT
Optionally you can use https://github.com/coralproject/coralcert to generate a key with which to sign the JWTs and specify the secret as an environment variable.
### Include token in embed
We're assuming that your CMS is capable of authenticating a user account, or
at least having the user's details available to send off to the token creation
@@ -77,15 +81,17 @@ Coral.Talk.render(document.getElementById('coralStreamEmbed'), {
});
```
Which will pass down the token to Talk and will fire the next steps
Which will pass down the token to Talk and will fire the
`tokenUserNotFound` hook to complete the auth flow.
### Implement `tokenUserNotFound`
### Create a Custom Plugin to Generate Talk Users
This is the only piece of code you'll have to write that lives inside Talk.
The role of this code is to live as a plugin and provide Talk with a way of
taking the token that you gave it, and turning into a user.
Your custom plugin will need to include a `tokenUserNotFound` function that will handle creating a user in Talk from the claims provided on the JWT, refer to [`tokenUserNotFound`](/talk/api/server/#tokenusernotfound) for reference.
Using the example application we were working with in the JWT issuing step
above, we'll need to ensure that the configuration is consistent in-between both
Talk and the JWT issuer. Namely, the following environment variables from our
@@ -102,5 +108,4 @@ example issuer and Talk must match:
reference, the basic takeaway is that the secret used to sign the tokens issued
by the issuer must be able to be verified by Talk.
For an example of implementing the plugin, refer to [`tokenUserNotFound`](/talk/api/server/#tokenusernotfound)
reference.
For an example of implementing the plugin, check out our [SSO Custom Auth Recipe](https://github.com/coralproject/talk-recipes/tree/master/plugins/custom-auth)
@@ -3,9 +3,19 @@ title: Tracking Talk Events and Metrics
permalink: /integrating/event-tracking-metrics/
---
Talk supports event emitting via Redux, Apollo and GraphQL. This means that common actions taken within Talk, such as successfully posting a comment, posting a reaction, or changing a setting, are automatically emitted from Talk. To send these events to your analytics tool of choice, however, will require some integration on your part.
Talk supports event emitting. This means that common actions taken within Talk, such as successfully posting a comment, posting a reaction, or changing a setting, are automatically emitted from Talk. To send these events to your analytics tool of choice, youll need to configure your Talk embed to process them.
First, we want to uncomment the tracking code in `article.ejs` (https://github.com/coralproject/talk/blob/93bda87ad061a2dc5eb8dc5b65a579a20efb76f7/views/article.ejs#L34). This will enable events to be sent via the Talk embed that is on your article pages. This will start a stream of events to the browser console, so that you can see which events are available.
The following example demonstrates how the event emitter works on a sample article page generated by Talk. When youre ready to capture and handle events from your actual site, add the events property along with your event handling functions to your Talk embed script.
## Example Using Local Development Instance of Talk
If you have Talk running in a local development environment you can follow these steps to first view all of the events emitted by Talk, and then capture the `PostComment.success` event and send it to a third party analytics provider.
First, with Talk running, ensure that you can access the `/dev/assets` endpoint and create a random article (i.e.: `localhost:3000/dev/assets`).
Then in Talk, uncomment the events code in `/views/dev/article.njk`
(https://github.com/coralproject/talk/blob/master/views/dev/article.njk#L32). This will enable events to be sent via the Talk embed that is on the sample article page. This will start a stream of events to the browser console, so that you can see which events are available.
```
events: function(events) {
@@ -16,7 +26,10 @@ First, we want to uncomment the tracking code in `article.ejs` (https://github.c
},
```
Now, we want to add our code that sends the events to our analytics system. In this case, we're sending the `PostComment.success` event. The particular way you send this will depend on what tool you're using. Refer to your tool's API and docs to determine this.
Save your changes to `article.njk`, restart Talk, and try refreshing your article in a browser with development console open. You should see the console log the list of Talks events.
Next, we want to add our code that sends the events to our analytics system. In this example, we're sending the `PostComment.success` event. The particular way you send this will depend on what tool you're using. Refer to your tool's API and docs to determine this.
```
events: function(events) {
@@ -30,4 +43,24 @@ Now, we want to add our code that sends the events to our analytics system. In t
```
You can continue this process for any specific events you'd like to track. You can also remove the `console.log` to stop events being emitted to the browser and instead only send the events to your analytics tool.
PR for Reference: https://github.com/coralproject/talk/pull/785
## Metrics List
Note: This is not an exhaustive list, but should get you started.
```
mutation.CreateRespectAction.success
mutation.CreateLikeAction.success
mutation.PostComment.success
mutation.PostFlag.success
mutation.EditComment.success
action.CORAL_STREAM_SET_ACTIVE_TAB
action.SHOW_SIGNIN_DIALOG
action.FOCUS_SIGNIN_DIALOG
action.TALK_FRAMEWORK_HANDLE_SUCCESSFUL_LOGIN
action.HIDE_SIGNIN_DIALOG
action.TALK_VIEWING_OPTIONS_OPEN_MENU
action.TALK_VIEWING_OPTIONS_CLOSE_MENU
action.CORAL_STREAM_SET_SORT
action.SET_ACTIVE_REPLY_BOX
```
+67 -21
View File
@@ -3,22 +3,13 @@ title: Notifications
permalink: /integrating/notifications/
---
Talk currently supports 3 types of email notifications.
There are several plugins included with Talk that once enabled will control how and when Talk sends emails to users based on user activity. Only basic user profile notifications are enabled by default.
1. When someone replies to my comment
2. When a staff member replies to my comment
3. When my comment gets featured
Talk support 3 options for notification frequency: immediately, hourly or daily. Commenters can also opt-out of email notifications. Notifications are set to OFF by default.
Commenters cannot enable notifications until they have verified their email.
Note: Notifications are not currently supported for users that sign-up via Facebook or Google auth, or don't have an email attached to their account for any other reason.
_NOTE: Notifications are only supported for users that have an email address in Talk! If you are using authenticate via Facebook, Google, or SSO and you want to persist the users email, you will also need to enable `talk-plugin-local-auth` ([See Authentication](/talk/integrating/authentication/))_
### Configuring SMTP
You must setup SMTP to use notifications. The following ENV variables must be set:
You must setup SMTP to send email notifications. The following ENV variables must be set:
```
TALK_SMTP_FROM_ADDRESS=email@email.com
@@ -28,28 +19,74 @@ TALK_SMTP_HOST=smtp.domain.net
TALK_SMTP_PORT=2525
```
### Enabling Notifications
See our documentation on [setting env variables](/talk/advanced-configuration/#talk-smtp-from-address) for reference.
Enabling the `talk-plugin-notifications` creates a NotificationManager that creates and manages events send from the event emitter that is linked to the Graph API PubSub system.
When running Talk in production we recommend using a 3rd party mail service provider like SendGrid or MailGun.
Adding the `talk-plugin-notifications` plugin will also enable the `notifications` plugin hook. Any plugin that registers before the `talk-plugin-notifications` plugin will get picked up by.
If you are having difficulty with your SMTP settings you can add `DEBUG=talk:jobs:mailer` to your .env to see additional logs from the mailer service.
See https://github.com/coralproject/talk/blob/8b669a31c551a042f0f079d8cfc16825673eb8f0/plugins/talk-plugin-notifications-reply/index.js for an example.
All notifications require SMTP settings to be correctly configured first, then enable the corresponding plugin, and configure any settings in the Talk Admin. If SMTP is not enabled, it will log to the server console that some variables were not provided.
### Notification Categories
### Notification Types & Plugins
Talk currently supports the following Notifications options out of the box:
In addition to the core notifications included with Talk, some plugins add features that are supported by and will add additional types of email notifications. Commenters can opt-out of most email notifications, and comment activity notifications are set to OFF by default. Commenters cannot enable notifications until they have verified their email.
`talk-plugin-notifications-category-reply`
`talk-plugin-notifications-category-staff-reply`
`talk-plugin-notifications-category-featured`
You can see a list of all the plugins related to notifications by visiting:
https://docs.coralproject.net/talk/plugins-directory/?q=notifications
#### Type: User Profile Notifications (Included by Talk core)
* When user registers, sends email confirmation and verification
* When user requests password reset
* When user changes username, sends confirmation
* When a user is banned or suspended
_NOTE: Users can not opt-out of User Profile Notifications_
#### Type: GDPR Notifications (optional)
`talk-plugin-profile-data:`
* When my comment history is ready for download (only one link can be generated every 7 days, and the link is valid for 24 hours)
`talk-plugin-local-auth:`
* When user changes their email address
* When a user adds a new email address
#### Type: Comment Activity Notifications (optional)
Talk support 3 options for notification frequency for this type of notification:
* immediately
* hourly
* daily
`talk-plugin-notifications:`
* Enables notifications configuration (required for all comment activity notifications below)
`talk-plugin-notifications-category-reply:`
* When someone replies to my comment
`talk-plugin-notifications-category-staff-reply:`
* When a staff member replies to my comment
`talk-plugin-notifications-category-featured:`
* When my comment gets featured
### Notification Digests
Notification digests are enabled by enabling the corresponding plugin, otherwise comment activity notifications are sent immediately.
* `talk-plugin-notifications-digest-daily`
* `talk-plugin-notifications-digest-hourly`
Talk supports hourly and daily digests out the box, if you would like to create your own, refer to the below:
https://github.com/coralproject/talk/blob/9cc9969320dca47bb0f8f81e8d944ae4d19e548b/plugins/talk-plugin-notifications/server/connect.js#L69-L102
### Customizing Notifications
Enabling the `talk-plugin-notifications` creates a NotificationManager that creates and manages events send from the event emitter that is linked to the Graph API PubSub system. This allows the instance that received the mutation to also fire off a notification job that can be handled. It also enabels the `notifications` plugin hook. Any plugin that registers after the `talk-plugin-notifications` can export the notifications plugin to reference it.
See https://github.com/coralproject/talk/blob/8b669a31c551a042f0f079d8cfc16825673eb8f0/plugins/talk-plugin-notifications-reply/index.js for an example.
### Connect API
This exposes the `graph/connectors.js` via the `connect` hook.
@@ -67,3 +104,12 @@ See https://github.com/coralproject/talk/blob/90290cfa2de88e62f687e1ed0235ba6dfe
### Email Templates
Email templates are text based and support translations. If you would like to create a new email template, you can register it via the Connect API, see https://github.com/coralproject/talk/blob/8b669a31c551a042f0f079d8cfc16825673eb8f0/plugins/talk-plugin-notifications/server/connect.js#L12-L28###
Any email template registered with the same name as another template will replace the existing template for that type of email. _NOTE: that also means that the template data sent to each email template will __not__ change, so bear that in mind when designing templates that you may not have rich access to data._
An example of this is with the `talk-plugin-notifications-category-featured` plugin:
Notification translation is located: https://github.com/coralproject/talk/blob/dd0601a80132d2849c53ef7eaf12ff382f3920b9/plugins/talk-plugin-notifications-category-featured/translations.yml#L13
Where the template content is provided: https://github.com/coralproject/talk/blob/dd0601a80132d2849c53ef7eaf12ff382f3920b9/plugins/talk-plugin-notifications-category-featured/index.js#L79
@@ -0,0 +1,18 @@
---
title: talk-plugin-notifications-category-moderation-actions
permalink: /plugin/talk-plugin-notifications-category-moderation-actions/
layout: plugin
plugin:
name: talk-plugin-notifications-moderation-actions
default: true
depends:
- name: talk-plugin-notifications
provides:
- Server
- Client
---
When a comment that is initially withheld from publication and is then approved or rejected, the user will receive a notification email.
Configuration:
`TALK_MODERATION_NOTIFICATION_TYPES`. This plugin requires values to be set. Available options: `APPROVED`, `REJECTED` as a single string (comma separated).
+3 -3
View File
@@ -67,9 +67,9 @@ External plugins can be resolved by running:
This achieves two things:
1. It will traverse into local plugin folders and install their dependencies.
_Note that if the plugin is already installed and available in the
__Note that if the plugin is already installed and available in the
node_modules folder, it will not be fetched again unless there is a version
mismatch._ This will result in the project `package.json` and `yarn.lock`
mismatch.__ This will result in the project `package.json` and `yarn.lock`
files to be modified, this is normal as this ensures that repeated deployments
(with the same config) will have the same config, these changes should not be
committed to source control.
@@ -111,7 +111,7 @@ If you deploy using Docker, you can extend from the `*-onbuild` image, an
example `Dockerfile` for your project could be:
```Dockerfile
FROM coralproject/talk:4.5-onbuild
FROM coralproject/talk:4-onbuild
```
Establish a private repository for your instance that includes the following:
+3 -4
View File
@@ -28,9 +28,8 @@
<div class="notice">
<p>Don't see what you're looking for? We're upgrading the docs, check out our <a href="https://github.com/coralproject/talk/tree/ef49d9a3d2acc4d2fc03b00e0c872dfbc57f005a/docs/_docs" target="_blank" class="coral-link-invert">old docs</a>.</p>
<p><a href="https://coralproject.net/" class="coral-link-invert" target="_blank">The Coral Project</a> from Mozilla</p>
<a href="https://www.mozilla.org/" target="_blank" title="Mozilla"><figure class="mozilla" alt="Mozilla">{{ image_tag('images/moz-logo-bw-rgb.svg') }}</figure></a>
<p>Made by <a href="https://coralproject.net/" class="coral-link-invert" target="_blank">The Coral Project</a> by <a href="https://www.voxmedia.com/" class="coral-link-invert" target="_blank" title="Vox Media">Vox Media</a>.</p>
<a href="https://www.voxmedia.com/" target="_blank" title="Vox Media"><figure class="voxmedia" alt="Vox Media">{{ image_tag('images/coralproject.png') }}</figure></a>
</div>
</aside>
<div class="sidebar__backdrop"></div>
<div class="sidebar__backdrop"></div>
+25 -2
View File
@@ -344,9 +344,13 @@ a.brand {
padding: $content_gutter $content_gutter 60px;
}
.mozilla {
width: 50%;
.voxmedia {
// width: 50%;
margin: 0 0 $sidebar_gutter;
> img {
width: 100%;
}
}
.sidebar {
@@ -461,3 +465,22 @@ a.brand {
background: rgb(0, 102, 176);
color: #fff;
}
.callout {
background-color: $coral_button_background;
color: white;
margin: 20px 0;
padding: 20px;
text-align: center;
a {
@extend .coral-link;
color: #FFF;
border-color: #FFF;
&:hover {
color: #FFF;
border-color: darken(#FFF, 5%);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

-22
View File
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 360 102.8" style="enable-background:new 0 0 360 102.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<rect y="-0.2" width="360" height="102.9"/>
<path class="st0" d="M343.8,73.7c-0.7,0.2-1.3,0.3-1.9,0.3c-2.1,0-3.1-0.9-3.1-3.5V51c0-10.3-8.2-15.3-17.9-15.3
c-7.4,0-11.4,0.9-19.3,4.1L300,50.2l10.3,1.1l1.5-5.1c2.1-1.1,4.2-1.3,6.9-1.3c7.3,0,7.4,5.5,7.4,10.1v1.5
c-2.3-0.3-4.9-0.4-7.4-0.4c-10.3,0-21,2.6-21,13.7c0,9.4,7.4,12.9,13.9,12.9c7.3,0,11.9-4.4,14.5-9c0.6,5.5,3.9,9,9.9,9
c2.8,0,5.7-0.8,8.1-2.1L343.8,73.7z M316.2,73.4c-3.9,0-5.3-2.3-5.3-5.2c0-4.9,4-6.2,8.6-6.2c2.1,0,4.4,0.3,6.5,0.6
C325.7,70.1,320.8,73.4,316.2,73.4z M298.9,12.9l-19.5,68.7h-12.7l19.5-68.7H298.9z M272.7,12.9l-19.5,68.7h-12.7L260,12.9H272.7z
M218.7,36.6h13.5v16.2h-13.5V36.6z M218.7,65.5h13.5v16.2h-13.5V65.5z M199,64.9l10.2,1l-2.8,15.8h-39.3l-1.3-6.8l24.8-28.5h-14.1
l-2,7l-9.3-1l1.6-15.8h39.5l1,6.8l-25,28.5h14.6L199,64.9z M134.5,35.7c-16.2,0-24.2,10.9-24.2,24.1c0,14.4,9.6,22.9,23.5,22.9
c14.4,0,24.8-9.1,24.8-23.5C158.6,46.6,150.7,35.7,134.5,35.7z M134.2,72.7c-7,0-10.6-6-10.6-13.8c0-8.5,4.1-13.4,10.7-13.4
c6.1,0,11,4.1,11,13.2C145.3,67.4,140.9,72.7,134.2,72.7z M98.7,71.8h6v9.8H85.9V56.3c0-7.8-2.6-10.8-7.7-10.8
c-6.2,0-8.7,4.4-8.7,10.7v15.7h6v9.8H56.6V56.3c0-7.8-2.6-10.8-7.7-10.8c-6.2,0-8.7,4.4-8.7,10.7v15.7h8.6v9.8H21.4v-9.8h6V46.4h-6
v-9.8h18.9v6.8c2.7-4.8,7.4-7.7,13.7-7.7c6.5,0,12.5,3.1,14.7,9.7c2.5-6,7.6-9.7,14.7-9.7c8.1,0,15.5,4.9,15.5,15.6V71.8z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

+7 -1
View File
@@ -11,7 +11,7 @@ const mergeState = (query, state) => {
}
if (status) {
const { username, banned, suspended } = status;
const { username, banned, suspended, alwaysPremod } = status;
if (typeof username !== 'undefined' && username && username.length > 0) {
query.merge({
@@ -27,6 +27,12 @@ const mergeState = (query, state) => {
});
}
if (typeof alwaysPremod !== 'undefined' && alwaysPremod !== null) {
query.merge({
'status.alwaysPremod.status': alwaysPremod,
});
}
if (typeof suspended !== 'undefined' && suspended !== null) {
if (suspended) {
query.merge({
+14
View File
@@ -10,6 +10,7 @@ const {
SET_USERNAME,
SET_USER_USERNAME_STATUS,
SET_USER_BAN_STATUS,
SET_USER_ALWAYS_PREMOD_STATUS,
SET_USER_SUSPENSION_STATUS,
UPDATE_USER_ROLES,
DELETE_OTHER_USER,
@@ -32,6 +33,13 @@ const setUserBanStatus = async (ctx, id, status = false, message = null) => {
}
};
const setUserAlwaysPremodStatus = async (ctx, id, status = false) => {
const user = await Users.setAlwaysPremodStatus(id, status, ctx.user.id);
if (user.alwaysPremod) {
ctx.pubsub.publish('userAlwaysPremod', user);
}
};
const setUserSuspensionStatus = async (
ctx,
id,
@@ -220,6 +228,7 @@ module.exports = ctx => {
setRole: () => Promise.reject(new ErrNotAuthorized()),
setUserBanStatus: () => Promise.reject(new ErrNotAuthorized()),
setUserSuspensionStatus: () => Promise.reject(new ErrNotAuthorized()),
setUserAlwaysPremodStatus: () => Promise.reject(new ErrNotAuthorized()),
setUserUsernameStatus: () => Promise.reject(new ErrNotAuthorized()),
setUsername: () => Promise.reject(new ErrNotAuthorized()),
stopIgnoringUser: () => Promise.reject(new ErrNotAuthorized()),
@@ -256,6 +265,11 @@ module.exports = ctx => {
setUserBanStatus(ctx, id, status, message);
}
if (ctx.user.can(SET_USER_ALWAYS_PREMOD_STATUS)) {
mutators.User.setUserAlwaysPremodStatus = (id, status) =>
setUserAlwaysPremodStatus(ctx, id, status);
}
if (ctx.user.can(SET_USER_SUSPENSION_STATUS)) {
mutators.User.setUserSuspensionStatus = (id, until, message) =>
setUserSuspensionStatus(ctx, id, until, message);
@@ -0,0 +1,7 @@
const { decorateUserField } = require('./util');
const AlwaysPremodStatusHistory = {};
decorateUserField(AlwaysPremodStatusHistory, 'assigned_by');
module.exports = AlwaysPremodStatusHistory;
+2
View File
@@ -3,6 +3,7 @@ const debug = require('debug')('talk:graph:resolvers');
const Action = require('./action');
const ActionSummary = require('./action_summary');
const AlwaysPremodStatusHistory = require('./always_premod_status_history');
const Asset = require('./asset');
const AssetActionSummary = require('./asset_action_summary');
const BannedStatusHistory = require('./banned_status_history');
@@ -37,6 +38,7 @@ const plugins = require('../../services/plugins');
let resolvers = {
Action,
ActionSummary,
AlwaysPremodStatusHistory,
Asset,
AssetActionSummary,
BannedStatusHistory,
+10
View File
@@ -74,6 +74,16 @@ const RootMutation = {
unbanUser: async (obj, { input: { id } }, { mutators: { User } }) => {
await User.setUserBanStatus(id, false);
},
alwaysPremodUser: async (obj, { input: { id } }, { mutators: { User } }) => {
await User.setUserAlwaysPremodStatus(id, true);
},
removeAlwaysPremodUser: async (
obj,
{ input: { id } },
{ mutators: { User } }
) => {
await User.setUserAlwaysPremodStatus(id, false);
},
ignoreUser: async (_, { id }, { mutators: { User } }) => {
await User.ignoreUser({ id });
},
+3 -3
View File
@@ -64,13 +64,13 @@ const wrapCheck = (
/**
* checkPermissions checks that the current user has all the required
* permissions.
* permissions. It will return true if that's the case.
*
* @param {Object} ctx graph context
* @param {Array<String>} permissions permissions that the user must have
*/
const checkPermissions = (ctx, permissions) =>
!ctx.user || !ctx.user.can(...permissions);
ctx.user && ctx.user.can(...permissions);
/**
* wrapCheckPermissions will wrap a specific field with a permission check.
@@ -89,7 +89,7 @@ const wrapCheckPermissions = (
wrapCheck(
typeResolver,
field,
(obj, args, ctx) => !checkPermissions(ctx, permissions),
(obj, args, ctx) => checkPermissions(ctx, permissions),
skipFieldResolver
);
+48
View File
@@ -142,6 +142,10 @@ input UserStatusInput {
# suspended will restrict the returned users to only those that are, or are not
# suspended. If not provided, no filtering will be performed.
suspended: Boolean
# alwaysPremod will restrict the returned users to only those that are, or are not
# marked as always premoderate. If not provided, no filtering will be performed.
alwaysPremod: Boolean
}
type UsernameStatusHistory {
@@ -166,6 +170,17 @@ type BannedStatus {
history: [BannedStatusHistory!]
}
type AlwaysPremodStatusHistory {
status: Boolean!
assigned_by: User
created_at: Date!
}
type AlwaysPremodStatus {
status: Boolean!
history: [AlwaysPremodStatusHistory!]
}
type SuspensionStatusHistory {
until: Date
assigned_by: User
@@ -184,6 +199,9 @@ type UserStatus {
# banned is the bool that determines if the user is banned or not.
banned: BannedStatus!
# alwaysPremod is the bool that determines if the user comments are always pushed to the premod queue or not
alwaysPremod: AlwaysPremodStatus!
# suspension is the date that the user is suspended until.
suspension: SuspensionStatus!
}
@@ -861,6 +879,9 @@ type Settings {
# customCssUrl is the URL of the custom CSS used to display on the frontend.
customCssUrl: String
# customAdminCssUrl is the URL of the custom CSS used to display on the admin panel.
customAdminCssUrl: String
# closedTimeout is the amount of seconds from the created_at timestamp that a
# given asset will be considered closed.
closedTimeout: Int
@@ -1335,6 +1356,9 @@ input UpdateSettingsInput {
# customCssUrl is the URL of the custom CSS used to display on the frontend.
customCssUrl: String
# customAdminCssUrl is the URL of the custom CSS used to display on the admin panel.
customAdminCssUrl: String
# closedTimeout is the amount of seconds from the created_at timestamp that a
# given asset will be considered closed.
closedTimeout: Int
@@ -1446,6 +1470,22 @@ type UnbanUserResponse implements Response {
errors: [UserError!]
}
input AlwaysPremodUserInput {
id: ID!
}
input RemoveAlwaysPremodUserInput {
id: ID!
}
type AlwaysPremodUserResponse implements Response {
errors: [UserError!]
}
type RemoveAlwaysPremodUserResponse implements Response {
errors: [UserError!]
}
input SuspendUserInput {
id: ID!
message: String!
@@ -1545,6 +1585,14 @@ type RootMutation {
# Mutation is restricted.
unsuspendUser(input: UnsuspendUserInput!): UnsuspendUserResponse
# Sets the always premod status on a given user. Requires the `MODERATOR` role.
# Mutation is restricted.
alwaysPremodUser(input: AlwaysPremodUserInput!): AlwaysPremodUserResponse
# Sets the always premod status on a given user. Requires the `MODERATOR` role.
# Mutation is restricted.
removeAlwaysPremodUser(input: RemoveAlwaysPremodUserInput!): RemoveAlwaysPremodUserResponse
# Sets the ban status on a given user. Requires the `MODERATOR` role.
# Mutation is restricted.
banUser(input: BanUserInput!): BanUsersResponse
+6 -1
View File
@@ -111,7 +111,12 @@ const processJob = transport => async ({ id, data }, done) => {
const { message } = data;
// Get the email address from the job data.
message.to = await getEmailAddress(data);
try {
message.to = await getEmailAddress(data);
} catch (err) {
logger.error({ err }, 'Failed to get user email address to send mail');
return done(err);
}
const log = logger.child({ jobID: id });
log.info('Starting to send mail');
+77 -2
View File
@@ -3,6 +3,13 @@ de:
sort_comments: 'Kommentare sortieren'
view_options: Ansichtsoptionen
already_flagged_username: 'Sie haben diesen Nutzernamen schon markiert.'
alwayspremoddialog:
are_you_sure: 'Sind sie sicher, dass sie immer vormoderieren wollen für {0}?'
always_premod_user: 'Nutzer immer vormoderieren?'
cancel: Abbrechen
note: 'Hinweis: {0}'
note_always_premod_user: 'Kommentare dieses Nutzers werden niemals automatisch freigegeben sondern erscheinen immer in der Liste für Vormoderation.'
yes_always_premod_user: 'Nutzer vormoderieren'
bandialog:
are_you_sure: 'Sind Sie sich sicher, dass Sie {0} sperren möchten?'
ban_user: 'Nutzer sperren?'
@@ -28,6 +35,9 @@ de:
flagged: markiert
undo_reject: 'Rückgängig machen'
view_context: 'Kontext ansehen'
edit_history: 'Verlauf anpassen'
show_edit_history: 'Zeige Verlaufshistorie'
hide_edit_history: 'Verstecke Verlaufshistorie'
comment_box:
cancel: Abbrechen
characters_remaining: 'verbleibende Zeichen'
@@ -48,9 +58,10 @@ de:
comment_post_notif_premod: 'Vielen Dank für Ihren Kommentar. Unsere Moderatoren werden ihn in Kürze bearbeiten.'
comment_singular: Kommentar
common:
copied: 'Kopiert'
notsupported: 'Nicht unterstützt'
contains_link: 'Enthält einen Link'
copy: Kopieren
copied: 'Kopiert'
notsupported: 'Nicht unterstützt'
error: 'Ein Problem ist aufgetreten.'
reaction: 'Reaktion'
reactions: 'Reaktionen'
@@ -62,6 +73,8 @@ de:
active: Aktiv
admin: Administrator
ads_marketing: 'Dies scheint Werbung zu sein'
all: 'Alle'
always_premod: 'Vormoderiert'
are_you_sure: 'Sind Sie sich sicher, dass Sie {0} sperren möchten?'
ban_user: 'Nutzer sperren?'
banned: Gesperrt
@@ -69,6 +82,8 @@ de:
cancel: Abbrechen
commenter: Kommentator
dont_like_username: 'Unsympathischer Nutzername'
filter_users: 'Nutzer filtern'
filter_role: Rolle
flaggedaccounts: 'Gemeldete Nutzernamen'
flags: Markierungen
impersonating: 'Identität unklar'
@@ -85,6 +100,7 @@ de:
spam_ads: Spam/Werbung
staff: Mitarbeiter
status: Status
suspended: 'Vorübergehend gesperrt'
username_and_email: 'Nutzername und E-Mail'
yes_ban_user: 'Ja, Nutzer sperren'
configure:
@@ -111,6 +127,8 @@ de:
copy_and_paste: 'Kopieren Sie diesen Code in Ihr CMS, um die Kommentarfunktion an entsprechender Stelle anzuzeigen.'
custom_css_url: 'Benutzerdefinierte CSS-URL'
custom_css_url_desc: 'URL eines CSS-Stylesheets zum Überschreiben des Standard-Designs'
custom_admin_css_url: 'Benutzerdefinierte CSS URL für Admin Panel'
custom_admin_css_url_desc: 'URL eines CSS-Stylesheets zum Überschreiben des Standart-Designs für das Admin Panel.'
days: Tage
description: 'Ändern Sie die Einstellungen für den Kommentarbereich dieses Artikels.'
disable_commenting_desc: 'Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist.'
@@ -147,6 +165,9 @@ de:
organization_info_copy_2: 'Wir empfehlen, einee generische E-Mail-Adresse (z.B. community@yournewsroom.com) für diesen Zweck einzurichten. Die kann über die Zeit gleich bleiben, und gibt nach außen keine Namen preis, die von Nutzern im Fall von Konflikten für persönliche Angriffe missbraucht werden könnten.'
organization_information: 'Über die Organisation'
organization_name: 'Name der Organisation'
suspect_or_forbidden_words_placeholder: 'Wort oder Phrase'
product_guide_link: 'Produkt Guide'
report_bug_or_feedback: 'Feedback'
require_email_verification: 'E-Mail-Bestätigung erforderlich'
require_email_verification_text: 'Neue Nutzer müssen ihre E-Mail-Adresse bestätigen.'
save: Speichern
@@ -165,6 +186,7 @@ de:
suspect_word_title: 'Liste verdächtiger Wörter'
tech_settings: 'Technische Einstellungen'
title: 'Kommentarbereich konfigurieren'
view_last_version: 'Letzte Version'
weeks: Wochen
wordlist: 'Gesperrte Wörter'
confirm_email:
@@ -222,6 +244,7 @@ de:
copied: 'Kopiert'
error:
ALREADY_EXISTS: 'Ressource existiert bereits'
AUTHENTICATION: 'Bei der Anmeldung ist ein Fehler aufgetreten.'
CANNOT_IGNORE_STAFF: 'Mitarbeiter können nicht ignoriert werden.'
COMMENT_PARENT_NOT_VISIBLE: 'Der Kommentar, auf den Sie antworten möchten, wurde entfernt oder existiert nicht.'
COMMENT_TOO_SHORT: 'Kommentare sollten mehr als ein Zeichen enthalten, bitte überprüfen Sie Ihren Kommentar und probieren Sie es erneut.'
@@ -250,6 +273,7 @@ de:
organization_contact_email: 'E-Mail-Adresse der Organisation ist ungültig.'
organization_name: 'Namen von Organisationen dürfen nur Buchstaben und Zahlen enthalten.'
password: 'Passwort muss mindestens 8 Zeichen enthalten'
PAGE_NOT_AVAILABLE_ROLE: 'Der Zugriff auf diese Seite ist eingeschränkt. Bitte wenden Sie sich an den Administrator.'
PASSWORD_INCORRECT: 'Ihr bestehendes Passwort wurde falsch eingegeben'
PASSWORD_LENGTH: 'Passwort ist zu kurz'
PASSWORD_REQUIRED: 'Passwort ist erforderlich'
@@ -265,6 +289,13 @@ de:
USERNAME_REQUIRED: 'Nutzername muss angegeben werden'
flag_comment: 'Kommentar melden'
flag_reason: 'Grund der Meldung (optional)'
flag_reasons:
username:
impersonating: 'Gibt sich für jemand anderen aus'
nolike: 'Ich mag diesen Nutzernamen nicht'
offensive: 'Dieser Nutzername ist unangemessen'
other: Sonstiges
spam: 'Dies scheint Werbung zu sein'
flag_username: 'Nutzername melden'
flagged_usernames:
notify_approved: '{0} hat Nutzername {1} freigegeben'
@@ -281,6 +312,7 @@ de:
comment_spam: Spam
links: Link
suspect_word: 'Verdächtiges Wort'
trust: Karma
user:
username_impersonating: 'Identität unklar'
username_nolike: Unerwünscht
@@ -300,6 +332,7 @@ de:
comments: Kommentare
configure_stream: Konfigurieren
content_not_available: 'Dieser Inhalt ist nicht verfügbar'
edit: Ändern
edit_name:
button: Senden
error: 'Nutzernamen dürfen nur Buchstaben, Zahlen und _ enthalten'
@@ -343,16 +376,30 @@ de:
title: 'Zugelassene Domains'
like: 'Gefällt mir'
loading_results: 'Lädt Ergebnisse'
login:
email_address: 'E-Mail-Adresse'
forgot_password: 'Passwort vergessen?'
go_back: 'Zurück'
sign_in: 'Anmelden'
sign_in_button: 'Anmelden'
sign_in_message: 'Anmelden um mit der Community zu interagieren.'
password: Passwort
reset_password_send_button: 'Passwort erhalten'
request_passowrd: 'Neues anfordern.'
team_sign_in: 'Team Anmeldung'
marketing: 'Dies scheint Werbung zu sein'
moderate_all_streams: 'Moderate comments on All Stories'
moderate_this_stream: 'Diesen Kommentarbereich moderieren'
modqueue:
account: Konto-Markierungen
actions: Aktionen
all: Alle
all_streams: 'Alle Kommentarbereiche'
always_premod_user_actions: 'Nutzer immer vormoderieren'
approve: Freigeben
approved: Freigegeben
ban_user: Sperren
ban_user_actions: 'Nutzer sperren'
billion: Mrd
close: Schließen
empty_queue: 'Keine weiteren Kommentare zu moderieren! Arbeite nicht zu viel, gönn dir eine Pause!'
@@ -387,6 +434,7 @@ de:
show_shortcuts: 'Tastaturkürzel anzeigen'
singleview: Zen-Modus
sort: Sortieren
suspend: 'Nutzer vorübergehend sperren'
system_withheld: 'System Withheld'
thismenu: 'Dieses Menü öffnen'
thousand: T
@@ -424,6 +472,13 @@ de:
username: Nutzername
write_message: 'Nachricht schreiben'
yes_suspend: 'Ja, vorübergehend sperren'
reject_username_dialog:
cancel: Abbrechen
description: 'Sagen Sie uns warun der Name nicht Ok ist?'
message: 'Grund für die Meldung (optional)'
reason: Begründung
reject_username: 'Nutzernamen ablehnen'
title: 'Nutzernamen ablehnen'
reply: Antworten
report: Melden
report_notif: 'Vielen Dank für Ihre Meldung. Unsere Moderatoren wurden informiert und werden sich in Kürze darum kümmern.'
@@ -452,11 +507,14 @@ de:
closed: Geschlossen
empty_result: 'Ihre Suche war ohne Ergebnisse. Versuchen Sie, Ihre Anfrage weiter zu fassen.'
filter_streams: 'Kommentarbereiche filtern'
most_recent_stories: 'Neueste Artikel'
newest: Neueste
no_results: 'Keine Ergebnisse'
oldest: Älteste
open: Offen
pubdate: Veröffentlichungsdatum
search: Suchen
search_results: Suchergebnisse
sort_by: 'Sortieren nach'
status: Status
stream_status: Status
@@ -484,24 +542,41 @@ de:
username_flags: 'Markierungen für diesen Nutzernamen'
user_detail:
all: Alle
always_premod: 'Nutzer immer vormoderieren'
always_premoded: 'Vormoderiert'
ban: 'Nutzer sperren'
banned: Gesperrt
email: E-Mail
id: ID
karma: Karma
karma_docs_link: 'https://docs.coralproject.net/talk/trust/#user-karma-score'
learn_more: 'Mehr erfahren'
member_since: 'Mitglied seit'
reject_rate: Ablehn-Rate
reject_username: 'Nutzernamen ablehnen'
rejected: Abgelehnte
remove_always_premod: 'Vormoderation entfernen'
remove_ban: 'Sperre aufheben'
remove_suspension: 'Vorübergehende Sperrung aufheben'
suspend: 'Nutzer vorübergehend sperren'
suspended: 'Vorübergehend gesperrt'
total_comments: 'Anzahl Kommentare'
unreliable: Unzuverlässig
user_history: Konto-Verlauf
user_karma_score: 'Nutzer Karma Wert'
username: Username
username_needs_approval: 'Nutzername muss akzetiert werden'
username_rejected: 'Nutzername abgelehnt'
user_history:
action: Aktion
always_premod_removed: 'Vormoderation entfernen'
ban_removed: 'Sperrung aufgehoben'
date: Datum
suspended: 'Vorübergehend gesperrt, {0}'
suspension_removed: 'Vorübergehende Sperrung aufgehoben'
system: System
taken_by: Durch
user_always_premoded: 'Nutzer vormoderiert'
user_banned: 'Nutzer gesperrt'
username_status: 'Nutzername {0}'
user_impersonating: 'Gibt sich für jemand anderen aus'
+21 -2
View File
@@ -3,6 +3,13 @@ en:
sort_comments: 'Sort Comments'
view_options: 'View Options'
already_flagged_username: 'You have already flagged this username.'
alwayspremoddialog:
are_you_sure: 'Are you sure you would like to always premoderate {0}?'
always_premod_user: 'Always premoderate user?'
cancel: Cancel
note: 'Note: {0}'
note_always_premod_user: 'Always premoderating this user will place all of their comments in the Pre-Moderate queue.'
yes_always_premod_user: 'Yes, always premoderate user'
bandialog:
are_you_sure: 'Are you sure you would like to ban {0}?'
ban_user: 'Ban User?'
@@ -28,6 +35,9 @@ en:
flagged: flagged
undo_reject: Undo
view_context: 'View context'
edit_history: 'Edit history'
show_edit_history: 'Show edit history'
hide_edit_history: 'Hide edit history'
comment_box:
cancel: Cancel
characters_remaining: 'characters remaining'
@@ -64,6 +74,7 @@ en:
admin: Administrator
ads_marketing: 'This looks like an ad/marketing'
all: 'All'
always_premod: 'Always premoderated'
are_you_sure: 'Are you sure you would like to ban {0}?'
ban_user: 'Ban User?'
banned: Banned
@@ -116,6 +127,8 @@ en:
copy_and_paste: 'Copy and paste code below into your CMS to embed your comment box in your articles'
custom_css_url: 'Custom CSS URL'
custom_css_url_desc: 'URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.'
custom_admin_css_url: 'Custom Admin Panel CSS URL'
custom_admin_css_url_desc: 'URL of a CSS stylesheet that will override default admin panel styles. Can be internal or external.'
days: Days
description: 'Change the comment settings on this story.'
disable_commenting_desc: 'Write a message that will be displayed while commenting is deactivated.'
@@ -211,7 +224,7 @@ en:
subject: 'Your account has been banned'
confirm:
confirm_email: 'Confirm Email'
has_been_requested: 'A email confirmation has been requested for the following account:'
has_been_requested: 'An email confirmation has been requested for the following account:'
if_you_did_not: 'If you did not request this, you can safely ignore this email.'
subject: 'Email Confirmation'
to_confirm: 'To confirm the account, please visit the following link:'
@@ -251,7 +264,7 @@ en:
EMAIL_REQUIRED: 'An email address is required'
EMAIL_VERIFICATION_TOKEN_INVALID: 'Email verification token is invalid.'
INCORRECT_PASSWORD: 'Incorrect Password'
INVALID_ASSET_URL: 'Assert URL is invalid'
INVALID_ASSET_URL: 'Asset URL is invalid'
LOGIN_MAXIMUM_EXCEEDED: 'You have made too many unsuccessful password attempts. Please wait.'
network_error: 'Failed to connect to server. Check your internet connection and try again.'
NO_SPECIAL_CHARACTERS: 'Usernames can contain letters numbers and _ only'
@@ -382,6 +395,7 @@ en:
actions: Actions
all: all
all_streams: 'All Streams'
always_premod_user_actions: 'Always Premod User'
approve: Approve
approved: Approved
ban_user: Ban
@@ -528,6 +542,8 @@ en:
username_flags: 'flags for this username'
user_detail:
all: All
always_premod: 'Always Premod User'
always_premoded: 'Always premoderated'
ban: 'Ban User'
banned: Banned
email: Email
@@ -539,6 +555,7 @@ en:
reject_rate: 'Reject Rate'
reject_username: 'Reject Username'
rejected: Rejected
remove_always_premod: 'Remove Always Premoderate'
remove_ban: 'Remove Ban'
remove_suspension: 'Remove Suspension'
suspend: 'Suspend User'
@@ -552,12 +569,14 @@ en:
username_rejected: 'Username rejected'
user_history:
action: Action
always_premod_removed: 'Always premoderate removed'
ban_removed: 'Ban removed'
date: Date
suspended: 'Suspended, {0}'
suspension_removed: 'Suspension removed'
system: System
taken_by: 'Taken By'
user_always_premoded: 'User always premoderated'
user_banned: 'User banned'
username_status: 'Username {0}'
user_impersonating: 'This user is impersonating'
+46 -29
View File
@@ -3,31 +3,41 @@ es:
sort_comments: 'Ordenar comentarios'
view_options: 'Ver opciones'
already_flagged_username: 'Usted ya reportó a este usuario.'
bandialog:
are_you_sure: '¿Estás seguro que quieres suspender a {0}?'
ban_user: '¿Quieres suspender al Usuario?'
banned_user: 'Usuario Suspendido'
alwayspremoddialog:
are_you_sure: '¿Estás seguro que quieres pre-moderar a {0}?'
always_premod_user: '¿Pre-moderar al Usuario?'
cancel: Cancelar
email_message_ban: "Estimado/a {0},\n\nUsted o alguien con acceso a su cuenta ha violado los lineamientos de nuestra comunidad. Como consecuencia de esto, su cuenta fue bloqueada. No podrá realizar ni reportar más comentarios. Si usted piensa que esto ha sido un error, por favor contáctese con nosotros."
note: 'Nota: {0}'
note_ban_user: 'Suspender a este usuario no le va a permitir (al usuario) borrar ni editar ni comentar.'
note_reject_comment: 'Suspender a este usuario también va a colocar este comentario en la cola de Rechazados.'
notify_ban_description: 'Esto notificará al usuario por correo electrónico que fueron suspendidos de la comunidad'
notify_ban_headline: 'Notificar al usuario de la suspensión'
note_always_premod_user: 'Pre-moderar a un usuario pondrá todos sus comentarios en la fila de Pre-Moderación.'
yes_always_premod_user: 'Sí, pre-moderar al usuario.'
bandialog:
are_you_sure: '¿Estás seguro que quieres prohibir a {0}?'
ban_user: '¿Quieres prohibir al Usuario?'
banned_user: 'Usuario prohibido'
cancel: Cancelar
email_message_ban: "Estimado/a {0},\n\nUsted o alguien con acceso a su cuenta ha violado los lineamientos de nuestra comunidad. Como consecuencia de esto, su cuenta fue prohibida. No podrá realizar ni reportar más comentarios. Si usted piensa que esto ha sido un error, por favor contáctese con nosotros."
note: 'Nota: {0}'
note_ban_user: 'Prohibir a este usuario no le va a permitir (al usuario) borrar ni editar ni comentar.'
note_reject_comment: 'Prohibir a este usuario también va a colocar este comentario en la cola de Rechazados.'
notify_ban_description: 'Esto notificará al usuario por correo electrónico que fue prohibido de la comunidad'
notify_ban_headline: 'Notificar al usuario de la prohibición'
send: Enviar
write_a_message: 'Escribe un mensaje'
yes_ban_user: 'Si, suspender al usuario'
yes_ban_user: 'Si, prohibir al usuario'
bio_offensive: 'Esta biografia es ofensiva'
cancel: Cancelar
characters_remaining: 'caracteres restantes'
comment:
anon: Anónimo
ban_user: 'Usuario Suspendido'
ban_user: 'Usuario prohibido'
comment: 'Publicar un comentario'
edited: Editado
flagged: Reportado
undo_reject: Deshacer
view_context: 'Ver contexto'
edit_history: 'Historial de ediciones'
show_edit_history: 'Mostrar historial de ediciones'
hide_edit_history: 'Ocultar historial de ediciones'
comment_box:
cancel: Cancelar
characters_remaining: 'caracteres restantes'
@@ -59,23 +69,24 @@ es:
community:
account_creation_date: 'Fecha de creación de la cuenta'
active: Activa
admin: Administrator
admin: Administrador
ads_marketing: 'Esto parece ser un publicidad/acción de comercialización'
all: 'Todos'
always_premod: 'Pre-moderado'
are_you_sure: '¿Estás seguro que quieres suspender a {0}?'
ban_user: '¿Quieres suspender al Usuario?'
banned: Suspendido
banned_user: 'Usuario suspendido'
ban_user: '¿Quieres prohibir al Usuario?'
banned: Prohibido
banned_user: 'Usuario prohibido'
cancel: Cancelar
commenter: Comentarista
dont_like_username: 'No me gusta este nombre de usuario'
filter_users: 'Filtrarr usuarios'
filter_users: 'Filtrar usuarios'
filter_role: Rol
flaggedaccounts: 'Nombres de usuario reportados'
flags: Reportes
impersonating: Impersonando
loading: 'Cargando resultados'
moderator: Moderator
moderator: Moderador
newsroom_role: 'Rol en la redacción'
no_flagged_accounts: 'No hay ningún nombre de usuario reportado en este momento.'
no_results: 'No se encontraron usuarios con ese nombre o correo.'
@@ -89,7 +100,7 @@ es:
status: Estado
suspended: Suspendido
username_and_email: 'Usuario y Correo'
yes_ban_user: 'Sí, suspendan el usuario'
yes_ban_user: 'Sí, prohiban el usuario'
configure:
access_message: 'Usted debe ser un administrador para acceder a esta página. Encuentre a otro administrador y actualice los permisos de su cuenta!'
apply: Aplicar
@@ -200,8 +211,8 @@ es:
seconds_plural: segundos
email:
banned:
body: 'De acuerdo con las guías de comunidad de The Coral Project, su cuenta a sido bloqueada. No podrá hacer comentarios, reportar o entrar en contacto con nuestra comunidad.'
subject: 'Su cuenta ha sido bloqueada'
body: 'De acuerdo con las guías de comunidad de The Coral Project, su cuenta a sido prohibida. No podrá hacer comentarios, reportar o entrar en contacto con nuestra comunidad.'
subject: 'Su cuenta ha sido prohibida'
confirm:
confirm_email: 'Confirmar Correo'
has_been_requested: 'Un correo de confirmación ha sido pedido para la siguiente cuenta:'
@@ -283,7 +294,7 @@ es:
username_spam: 'Contiene spam'
framework:
banned_account_body: 'Esto significa que no puedes gustar, marcar o escribir comentarios.'
banned_account_header: 'Tu cuenta se encuentra suspendida.'
banned_account_header: 'Tu cuenta se encuentra prohibida.'
changed_name:
msg: 'El cambio en su nombre de usuario está siendo revisado por nuestro equipo de moderación.'
comment: comentario
@@ -355,9 +366,10 @@ es:
actions: Acciones
all: todos
all_streams: 'Todos los Hilos'
always_premod_user_actions: 'Siempre Pre-moderar Usuario'
approve: Aprobar
approved: Aprobado
ban_user: Bloquear
ban_user: Prohibir
billion: B
close: Cerrar
empty_queue: '¡No hay más comentarios para moderar! Tiempo para un ☕️'
@@ -486,13 +498,16 @@ es:
username_flags: 'reportes para este nombre de usuario'
user_detail:
all: Todos
ban: 'Bloquear usuario'
banned: Baneado
always_premod: 'Siempre pre-moderar usuario'
always_premoded: 'Siempre pre-moderado'
ban: 'Prohibir usuario'
banned: Prohibido
email: 'Correo electrónico'
member_since: 'Miembro desde'
reject_rate: 'Promedio de rechazo'
rejected: Rechazado
remove_ban: 'Cancelar bloqueo'
remove_always_premod: 'Cancelar siempre pre-moderar'
remove_ban: 'Cancelar prohibición'
remove_suspension: 'Cancelar suspensión'
suspend: 'Suspender usuario'
suspended: Suspendido
@@ -503,13 +518,15 @@ es:
username_rejected: 'Usuario rechazado'
user_history:
action: Acción
ban_removed: 'Bloqueo cancelado'
always_premod_removed: 'Siempre pre-moderar cancelado'
ban_removed: 'Prohibición cancelada'
date: Fecha
suspended: 'Suspendido, {0}'
suspension_removed: 'Suspensión cancelada'
system: Sistema
taken_by: 'Está en uso'
user_banned: 'Usuario bloqueado'
user_always_premoded: 'Usuario siempre pre-moderado'
user_banned: 'Usuario prohibido'
username_status: 'Nombre de usuario {0}'
user_impersonating: 'Este usuario suplanta a alguien'
user_no_comment: 'No has dejado aún ningún comentario. ¡Únete a la conversación!'
@@ -523,6 +540,6 @@ es:
verify_password: 'La contraseña debe tener por lo menos 8 caracteres'
verify_username: 'Los nombres pueden contener letras números y _'
view_conversation: 'Ver Conversación'
your_account_has_been_banned: 'Su cuenta ha sido suspendida.'
your_account_has_been_suspended: 'Su cuenta ha sido temporalmente suspendida.'
your_account_has_been_banned: 'Su cuenta ha sido prohibida.'
your_account_has_been_suspended: 'Su cuenta ha sido suspendida.'
your_username_has_been_rejected: 'Su cuenta ha sido suspendida porque tu nombre de usuario ha sido considerado no apropiado para el espacio. Para recuperar la cuenta, por favor ingresar un nuevo nombre de usuario.'
+469
View File
@@ -0,0 +1,469 @@
he:
your_account_has_been_suspended: החשבון שלך הושעה באופן זמני.
your_account_has_been_banned: החשבון שלך הורחק.
your_username_has_been_rejected: החשבון שלך הושעה מפני ששם המשתמש שלך נחשב לא הולם. כדי לשחזר את החשבון שלך, הזן שם משתמש חדש.
embed_comments_tab: תגובות
bandialog:
are_you_sure: "האם אתה בטוח שאתה רוצה לאסור {0}?"
ban_user: "חסום משתמש?"
banned_user: "משתמש מורשה"
cancel: "בטל"
note: "הערה: {0}"
note_reject_comment: "חסימת משתמש זה תציב גם תגובה זו בתור נדחה."
note_ban_user: "חסימת משתמש זה לא תאפשר לו להגיב על תגובות או לדווח עליהן."
yes_ban_user: "כן. חסום משתמש"
write_a_message: "כתוב הודעה"
send: "שלח"
notify_ban_headline: "הודע למשתמש על האיסור"
notify_ban_description: 'פעולה זו תודיע למשתמש באימייל שהם נאסרו מהקהילה'
email_message_ban: "{0},\n\nמישהו עם גישה לחשבון שלך הפר את הנחיות הקהילה שלנו. כתוצאה מכך, החשבון שלך נאסר. לא תוכל עוד להגיב, לדווח או לדווח על תגובות. אם אתה חושב שהדבר נעשה בטעות, צור קשר עם צוות הקהילה שלנו."
bio_offensive: "ביו זה פוגע"
cancel: "בטל"
confirm_email:
click_to_confirm: 'לחץ למטה כדי לאשר את כתובת האימייל שלך'
confirm: "אשר"
password_reset:
mail_sent: 'אם יש לך חשבון רשום, נשלח קישור לאיפוס סיסמה לאותו דאימייל'
set_new_password: "שנה את סיסמתך"
new_password: "סיסמה חדשה"
new_password_help: "הסיסמה חייבת להיות לפחות 8 תווים"
confirm_new_password: "תאשר סיסמא חדשה"
change_password: "שנה סיסמא"
characters_remaining: "תווים נותרים"
comment:
anon: "אנונימי"
undo_reject: "בטל"
ban_user: "חסום משתמש"
comment: "פרסם תגובה"
edited: ערוך
flagged: "מסומנת"
view_context: "הצג הקשר"
comment_box:
post: "שלח"
cancel: "בטל"
reply: "תשיב"
comment: "פרסם תגובה"
name: "שם"
comment_post_notif: "התגובה שלך פורסמה."
comment_post_notif_premod: "תודה על הפרסום. צוות הפיקוח שלנו יבחן את התגובה שלך בקרוב."
comment_post_banned_word: "התגובה שלך מכילה מילה אחת או יותר שאינן מותרות, לכן היא לא תפורסם. אם אתה סבור שהודעה זו שגויה, צור קשר עם צוות הניהול שלנו."
characters_remaining: "תווים נותרים"
comment_history_blank:
info: 'תולדות של התגובות שלך יופיעו כאן'
title: 'לא כתבת שום תגובה'
comment_offensive: "תגובה זו פוגעת"
comment_singular: תגובה
comment_plural: תגובות
comment_post_banned_word: "התגובה שלך מכילה מילה אחת או יותר שאינן מותרות, לכן היא לא תפורסם. אם אתה סבור שהודעה זו שגויה, צור קשר עם צוות הניהול שלנו."
comment_post_notif: "התגובה שלך כבר פורסמה."
comment_post_notif_premod: "תודה על הפרסום. צוות הפיקוח שלנו יבחן את התגובה שלך בקרוב."
common:
copy: 'עותק'
error: 'אירעה שגיאה.'
reply: 'תשובה'
replies: 'תשובות'
reaction: 'ריאקציה'
reactions: 'ריאקציות'
story: 'כתבה'
flagged_usernames:
notify_approved: '{0} אישר את שם המשתמש {1}'
notify_rejected: '{0} דחה את שם המשתמש {1}'
notify_flagged: '{0} דיווח על שם המשתמש {1}'
notify_changed: 'המשתמש {0} שינה את שם המשתמש שלו ל {1}'
community:
account_creation_date: "תאריך היצירה של החשבון"
active: פעיל
admin: מנהל
ads_marketing: "זה נראה כמו מודעה / שיווק"
are_you_sure: "האם אתה בטוח שברצונך לאסור {0}?"
ban_user: "חסום משתמש?"
banned: אסור
banned_user: "משתמש מורשה"
cancel: בטל
dont_like_username: "לא אוהב את שם המשתמש"
flaggedaccounts: "שמות משתמש שדווחו"
flags: דגלים
impersonating: "התחזות"
loading: "טוען תוצאות"
moderator: מנהל
newsroom_role: "תפקיד בחדר החדשות"
no_flagged_accounts: "תור שמות המשתמש המדווחים ריק כעת."
no_results: "לא נמצאו משתמשים בשם המשתמש או בכתובת האימייל הזו. הם מסתתרים!"
offensive: "פוגע"
other: אחר
people: אנשים
role: "בחר תפקיד ..."
select_status: "בחר סטטוס ..."
spam_ads: "ספאם / מודעות"
staff: "צוות"
status: סטטוס
username_and_email: 'שם משתמש ואימייל'
yes_ban_user: "כן. חסום משתמש"
commenter: "מגיב"
configure:
apply: החל
banned_word_text: "הערות המכילות מילים או ביטויים אלה (לא תלויי רישיות) יוסרו באופן אוטומטי מזרם ההערות. הקלד מילה ולחץ על Enter או על Tab כדי להוסיף. אפשר להדביק רשימה מופרדת בפסיקים."
banned_words_title: "רשימת מילים אסורות"
close: "סגור"
close_after: "סגור הערות לאחר"
close_stream: "סגור את זרם ההערות"
close_stream_configuration: "זרם תגובות זה סגור כעת. על ידי פתיחת תגובה זו זרם תגובות חדשות ניתן להגיש ולהציג"
closed_comments_desc: "כתוב הודעה שתוצג כאשר זרם ההערות שלך ייסגר ולא תקבל עוד הערות."
closed_comments_label: "כתוב הודעה ..."
closed_stream_settings: "הודעת זרם סגור"
comment_count_error: "נא הכנס מספר תקף."
comment_count_header: "הגבל אורך תגובה"
comment_count_text_post: תווים
comment_count_text_pre: "תגובות יוגבלו"
comment_settings: הגדרות
comment_stream: "זרם תגובות"
comment_stream_will_close: "זרם ההערות ייסגר"
community: קהילה
configure: הגדר
copy_and_paste: "העתק והדבק קוד למטה לתוך CMS שלך כדי להטביע את תיבת התגובה לכתבות שלך"
custom_css_url: "כתובת האתר של ה- CSS המותאם אישית שלך"
custom_css_url_desc: "כתובת אתר של גיליון סגנונות CSS שתבטל את ברירת המחדל של סגנונות 'הזרמת זרם'. יכול להיות פנימי או חיצוני."
days: ימים
description: "כמנהל, תוכל להתאים אישית את ההגדרות עבור זרם ההערות עבור הסיפור הזה:"
domain_list_text: "הזן את הדומיינים שברצונך להרשות עבור Talk. כלומר, סביבות האחסון הזמני וההפקה המקומית שלך (לדוגמה localhost: 3000, staging.domain.com, domain.com)."
domain_list_title: "דומיינים מותרים"
edit_comment_timeframe_heading: "עריכת מסגרת זמן של תגובה"
edit_comment_timeframe_text_pre: "למשתמשים יהיו"
edit_comment_timeframe_text_post: "שניות כדי לערוך את התגובות שלהם."
embed_comment_stream: "הטמע את הזרם"
enable_premod_links_text: "על המתווכים לאשר כל תגובה המכילה קישור לפני פרסומה."
enable_pre_moderation: "אפשר התנהלות מראש"
enable_pre_moderation_text: "על המנחים לאשר כל הערה לפני פרסומה."
enable_premod_links: "תגובות המכילות קישורים צריך להיות מנוהל מראש"
enable_premod: "אפשר התנהלות מראש"
enable_premod_description: "על המנחים לאשר כל הערה לפני פרסומה."
enable_premod_links_description: "על המתווכים לאשר כל תגובה המכילה קישור לפני פרסומה."
enable_questionbox: "שאל את הקוראים שאלה"
enable_questionbox_description: "שאלה זו תופיע בחלק העליון של זרם תגובות זה. לשאול את הקוראים על בעיה מסוימת במאמר או להציג שאלות דיון וכו '"
hours: שעות
include_comment_stream: "כלול תיאור בזרם תגובות עבור הקוראים"
include_comment_stream_desc: "כתוב הודעה שתופיע בחלק העליון של זרם התגובה שלך. הוסף נושא להנחיות הקהילה וכו '."
include_text: "כלול את הטקסט שלך כאן."
include_question_here: "כתוב את השאלה שלך כאן:"
moderate: מתון
moderation_settings: "הגדרות פיקוח"
open: "פתח"
open_stream: "פתח את הזרם"
open_stream_configuration: "זרם תגובות זה פתוח כעת. על ידי סגירת זרם תגובות זה לא ניתן להגיש תגובות חדשות וכל התגובות הקודמות עדיין יוצגו."
organization_contact_email: "אימייל של הארגון"
require_email_verification: 'דרוש אימות אימייל'
require_email_verification_text: 'משתמשים חדשים חייבים לאמת את האימייל שלהם לפני שתגיב'
save_changes: "שמור שינויים"
shortcuts: קיצורי דרך
sign_out: "התנתק"
stories: כתבות
stream_settings: "הגדרות זרם"
suspect_word_title: "רשימת מילים חשוד"
suspect_word_text: "תגובות שמכילות מילים או ביטויים אלה (לא תלויי רישיות) יודגשו בזרם התגובות. הקלד מילה ולחץ על Enter או על Tab כדי להוסיף. אפשר להדביק רשימה מופרדת בפסיקים."
tech_settings: "הגדרות טכנולוגיה"
title: "הגדר זרם תגובות"
weeks: שבועות
wordlist: "מילים אסורות"
continue: "המשך"
createdisplay:
check_the_form: "טופס לא חוקי. בדוק את השדות"
continue: "המשך עם אותו שם משתמש ב- Facebook"
error_create: "שגיאה בעת שינוי שם המשתמש"
fake_comment_body: "זוהי תגובה לדוגמה. הקוראים יכולים לשתף את מחשבותיהם ואת דעותיהם עם צוות החדשות בקטע התגובות."
fake_comment_date: "לפני 1 דקה"
if_you_dont_change_your_name: "אם לא תשנה את שם המשתמש שלך בשלב זה שם התצוגה שלך ב- Facebook יופיע לצד כל ההערות שלך."
required_field: "שדה נדרש"
save: שמור
special_characters: "שמות משתמש יכולים להכיל מספרי אותיות ו- _ בלבד"
username: שם משתמש
write_your_username: "ערוך את שם המשתמש שלך"
your_username: "שם המשתמש שלך מופיע בכל תגובה שתפרסם."
done: בוצע
edit_comment:
body_input_label: "ערוך תגובה זו"
save_button: "שמור שינויים"
edit_window_expired: "לא ניתן עוד לערוך את ההערה הזו. פרק הזמן לביצוע זה פג. למה לא לכתוב עוד אחד?"
edit_window_expired_close: "סגור"
edit_window_timer_prefix: "פרק זמן זה לעריכה: "
second: "שנייה"
seconds_plural: "שניות"
minute: "דקה"
minutes_plural: "דקות"
email:
suspended:
subject: "חשבונך הושעה"
banned:
subject: "החשבון שלך הורחק"
body: "בהתאם להנחיות הקהילה של פרויקט אלמוגים, החשבון שלך נאסר. כעת אתה מורשה יותר להגיב, לדגל או ליצור מעורבות עם הקהילה שלנו."
confirm:
has_been_requested: 'התבקש אישור באימייל עבור החשבון הבא:'
to_confirm: "כדי לאשר את החשבון, בקר בקישור הבא:"
confirm_email: "אשר אימייל"
if_you_did_not: 'אם לא ביקשת זאת, תוכל להתעלם בבטחה מאימייל זה.'
subject: "אישור דואר אלקטרוני"
password_reset:
we_received_a_request: "קיבלנו בקשה לאפס את הסיסמה שלך. אם לא ביקשת שינוי זה, תוכל להתעלם מהודעת אימייל זו."
if_you_did: "אם עשית,"
please_click: "לחץ כאן כדי לאפס את הסיסמה"
embedlink:
copy: "העתק ללוח"
error:
COMMENT_PARENT_NOT_VISIBLE: "התגובה שאתה משיב לה הוסרה או אינה קיימת."
EMAIL_VERIFICATION_TOKEN_INVALID: "אסימון האימייל אינו חוקי."
PASSWORD_RESET_TOKEN_INVALID: "הקישור לאיפוס הסיסמה אינו חוקי."
COMMENT_TOO_SHORT: "התגובות צריכות להיות יותר מתו אחד, אנא שנה את תגובתך ונסה שוב."
NOT_AUTHORIZED: "אינך מורשה לבצע פעולה זו."
NO_SPECIAL_CHARACTERS: "שמות משתמש יכולים להכיל מספרי אותיות ו- _ בלבד"
PASSWORD_LENGTH: "הסיסמה קצרה מדי"
PROFANITY_ERROR: "שמות משתמש לא יכולים להכיל גסות. פנה למנהל המערכת אם אתה סבור שמדובר בטעות."
RATE_LIMIT_EXCEEDED: "חרגת מגבלת התעריף"
USERNAME_IN_USE: "שם משתמש כבר בשימוש"
USERNAME_REQUIRED: "חייב להזין שם משתמש"
EMAIL_NOT_VERIFIED: "כתובת האימייל לא אומתה"
EDIT_WINDOW_ENDED: "לא ניתן עוד לערוך את התגובה הזו. פרק הזמן לביצוע זה פג."
EDIT_USERNAME_NOT_AUTHORIZED: "אין לך הרשאה לעדכן את שם המשתמש שלך."
SAME_USERNAME_PROVIDED: "עליך לשלוח שם משתמש אחר."
EMAIL_IN_USE: 'כתובת האימייל כבר בשימוש'
EMAIL_REQUIRED: 'נדרשת כתובת אימייל'
LOGIN_MAXIMUM_EXCEEDED: "עשית יותר מדי ניסיונות סיסמה לא מוצלחים. המתן בבקשה."
PASSWORD_REQUIRED: "יש להזין סיסמה"
COMMENTING_CLOSED: "התגובה כבר סגורה"
NOT_FOUND: "זרם התגובה כבר סגור"
ALREADY_EXISTS: "המשאב כבר קיים"
INVALID_ASSET_URL: "כתובת האתר של הנכס אינה חוקית"
CANNOT_IGNORE_STAFF: "לא ניתן להתעלם מחברי צוות."
email: "אימייל לא חוקי"
confirm_password: "סיסמאות אינן תואמות. אנא בדוק שוב"
network_error: "נכשל נסיון להתחבר לשרת. בדוק את חיבור האינטרנט שלך ונסה שוב."
email_not_verified: "כתובת האימייל {0} לא אומתה."
email_password: "שילוב דואר אלקטרוני ו / או סיסמה שגוי."
organization_name: "שם הארגון חייב להכיל רק אותיות או מספרים."
password: "הסיסמה צריכה להיות לפחות 8 תווים"
username: "שמות משתמש יכולים להכיל מספרי אותיות ו- _ בלבד"
unexpected: "אירעה שגיאה לא צפויה. מצטער!"
required_field: "שדה חובה"
temporarily_suspended: "החשבון שלך מושעה כעת. הוא יופעל מחדש {0}. אנא צור איתנו קשר אם יש לך שאלות."
flag_comment: "דווח על תגובה"
flag_reason: "סיבה לדיווח (אופציונלי)"
flag_username: "דווח על שם משתמש"
framework:
banned_account_header: "החשבון שלך מוחרם כעת."
banned_account_body: "פירוש הדבר שאינך אוהב, לדווח או לכתוב תגובות."
comment: תגובה
comment_is_ignored: "תגובה זו מוסתרת מפני שהתעלמת ממשתמש זה."
comment_is_rejected: "דחית את התגובה הזו."
comment_is_hidden: "תגובה זו אינה זמינה."
comments: תגובות
configure_stream: "הגדר"
content_not_available: "תוכן זה אינו זמין"
edit_name:
button: שלח
error: "שמות משתמש יכולים להכיל מספרי אותיות ו- _ בלבד"
label: "שם משתמש חדש"
msg: "החשבון שלך מושעה כרגע מפני ששם המשתמש שלך נחשב לא הולם. כדי לשחזר את החשבון שלך, הזן שם משתמש חדש. אנא צור איתנו קשר אם יש לך שאלות."
changed_name:
msg: "שינוי שם המשתמש שלך נמצא בבדיקה על ידי צוות הניהול שלנו."
my_comments: "התגובות שלי"
my_profile: "הפרופיל שלי"
new_count: "הצג {0} עוד {1}"
profile: פרופיל
show_all_comments: "הצג את כל התגובות"
success_bio_update: "הביוגרפיה שלך עודכנה"
success_name_update: "שם המשתמש שלך עודכן"
success_update_settings: "השינויים שביצעת הוחלו על זרם התגובה בכתבה זה"
show_all_replies: הצג את כל התשובות
show_more_replies: הצג תשובות נוספות
view_more_comments: "הצג תגובות נוספות"
view_reply: "הצג תשובה"
from_settings_page: "בדף הפרופיל תוכל לראות את היסטוריית התגובות שלך."
like: לייק
loading_results: "טוען תוצאות"
marketing: "זה נראה כמו מודעה / שיווק"
moderate_this_stream: "נהל את הזרם הזה"
flags:
reasons:
user:
username_offensive: "פוגע"
username_nolike: "לא אוהב"
username_impersonating: "התחזות"
username_spam: "ספאם"
username_other: "אחר"
comment:
comment_offensive: "פוגע"
comment_spam: "ספאם"
comment_noagree: "לא מסכים"
comment_other: "אחר"
suspect_word: "מילה חשודה"
banned_word: "מילה אסורה"
body_count: "גוף התגובה עולה על אורך מרבי"
trust: "אמון"
links: "קישור"
modqueue:
account: "דגלים של החשבון"
actions: פעולות
all: הכל
all_streams: "כל הזרמים"
notify_edited: '{0} ערך תגובה "{1}"'
notify_accepted: '{0} קיבל תגובה "{1}"'
notify_rejected: '{0} דחה תגובה "{1}"'
notify_flagged: '{0} דגל תגובה "{1}"'
notify_reset: '{0} אפס את סטטוס התגובה "{1}"'
approve: "אישרו"
approved: "אושר"
ban_user: "חסום"
billion: ב
close: סגור
empty_queue: "אין תגובות נוספות כדי להתמתן! כולכם תקועים. לכי וליהנות קצת ☕️"
flagged: מסומנת
reported: דיווח
less_detail: "פחות פרטים"
likes: לייקס
million: מ
mod_faster: "מתון מהר יותר עם קיצורי מקשים"
moderate: "מתון ←"
more_detail: "פרטים נוספים"
new: חדש
newest_first: "הכי חדש קודם"
navigation: ניווט
next_comment: "עבור לתגובה הבאה"
toggle_search: "פתח חיפוש"
next_queue: "הפעל תורים"
oldest_first: "הכי עתיק קודם"
premod: מתינות מראש
prev_comment: "עבור לתגובה הקודמת"
reject: "דחה"
rejected: "נדחה"
reply: "תשיב"
select_stream: "בחר זרם"
shift_key: "⇧"
shortcuts: "קיצורי דרך"
sort: "מיין"
show_shortcuts: "הצג קיצורי דרך"
singleview: "מצב זן"
thismenu: "פתח את התפריט"
jump_to_queue: "קפיצה לתור ספציפי"
thousand: k
try_these: "נסה את אלה"
view_more_shortcuts: "הצג קיצורי דרך נוספים"
my_comment_history: "ההיסטוריה של התגובות שלי"
name: שם
no_agree_comment: "אני לא מסכים עם תגובה זו"
no_like_bio: "אני לא אוהב את הביוגרפיה הזאת"
no_like_username: "אני לא אוהב את שם המשתמש הזה"
already_flagged_username: "כבר סימנת שם משתמש זה."
other: אחר
permalink: שתף
personal_info: "תגובה זו מגלה מידע המאפשר זיהוי אישי"
post: שלח
profile: פרופיל
profile_settings: "הגדרות פרופיל"
reply: תשיב
report: דווח
report_notif: "תודה שדיווחת על תגובה זו. צוות ההתייחסות שלנו קיבל הודעה על כך ויבדוק אותו בקרוב."
report_notif_remove: "הדוח שלך הוסר."
reported: דווח
settings:
from_settings_page: "בדף הפרופיל תוכל לראות את היסטוריית התגובות שלך."
my_comment_history: "ההיסטוריה של התגובות שלי"
profile: פרופיל
profile_settings: "הגדרות פרופיל"
sign_in: "היכנס"
to_access: "כדי לגשת לפרופיל"
user_no_comment: "מעולם לא השארת תגובה. הצטרף לשיחה!"
stream:
all_comments: "כל התגובות"
temporarily_suspended: "בהתאם להנחיות הקהילה {0}, חשבונך הושעה באופן זמני. חזור לשיחה {1}."
comment_not_found: "תגובה זו הוסרה או אינה קיימת."
no_comments: "עדיין אין תגובות. האם אתה רוצה לכתוב אחד?"
no_comments_and_closed: "לא היו תגובות על כתבה זה."
step_1_header: "דווח על בעיה"
step_2_header: "עזור לנו להבין"
step_3_header: "תודה על הקלט שלך"
streams:
all: הכל
article: כתבה
closed: סגור
empty_result: "אין נכסים שמתאימים לחיפוש זה. אולי לנסות להרחיב את החיפוש שלך?"
filter_streams: "סינון זרמים"
newest: החדש ביותר
oldest: הוותיק ביותר
open: פתח
pubdate: "תאריך פרסום"
search: לחפש
sort_by: "מיין לפי"
status: "מצב זרם"
stream_status: "מצב זרם"
suspenduser:
title_suspend: "להשעות משתמש"
description_suspend: "אתה משעה את {0}. תגובה זו תעבור לתור נדחה, ו- {0} לא יהיה יכול ללייק, לדווח, להשיב או לפרסם עד להשלמת זמן ההשעיה."
select_duration: "בחר משך השעיה"
one_hour: "1 שעה"
hours: "{0} שעות"
days: "{0} ימים"
cancel: "בטל"
suspend_user: "להשעות משתמש"
email_message_suspend: "{0}, \n\n בהתאם להנחיות הקהילה {1}, חשבונך הושעה באופן זמני. במהלך ההשעיה, לא תוכל להגיב, לדגל או לשתף פעולה עם מפרסמים אחרים. חזור לשיחה {2}."
title_notify: "הודע למשתמש על השעיה זמנית"
notify_suspend_until: "המשתמש {0} הושעה באופן זמני. ההשעיה הזו תסתיים באופן אוטומטי {1}."
description_notify: "השעיית משתמש זה תשבית זמנית את החשבון שלו."
write_message: "לכתוב הודעה"
send: שלח
reject_username:
username: שם משתמש
no_cancel: "אין ביטול"
description_reject: "האם אתה רוצה לאסור את המשתמש הזה באופן זמני בגלל {0} שלו? פעולה זו תשעה את המשתמש הזה באופן זמני עד שיכתבו מחדש את {0}."
title_notify: "הודע למשתמש על השעיה זמנית"
description_notify: "השעיית משתמש זה תשבית זמנית את החשבון שלו."
title_reject: "שמנו לב שדחית שם משתמש"
suspend_user: "להשעות משתמש"
yes_suspend: "כן, להשעות"
email_message_reject: 'לאחרונה חבר בקהילה שלנו סימן את שם המשתמש שלך לבדיקה. בגלל התוכן של שם המשתמש שלך, שם המשתמש שלך נדחה. פירוש הדבר שאינך יכול עוד להגיב או לסמן תוכן עד שתשנה את שם המשתמש שלך. אנא שלח לנו אימייל אם יש לך שאלות או חששות.'
write_message: "לכתוב הודעה"
send: שלח
thank_you: "אנו מעריכים את בטיחותך ומשובך. מנחה יסקור את הדוח שלך."
user:
bio_flags: "דגלים עבור ביוגרפיה זו"
user_bio: "ביוגרפיה של המשתמש"
username_flags: "דגלים עבור שם משתמש זה"
user_detail:
remove_suspension: "הסר השעיה"
suspend: "להשעות משתמש"
remove_ban: "הסרת חסימה"
ban: "לחסום משתמש"
member_since: "חבר מאז"
email: 'אימייל'
total_comments: "סך הכל תגובות"
reject_rate: "שיעור דחייה"
reports: "דיווחים"
all: "כל"
rejected: "נדחה"
account_history: "היסטוריית החשבון"
user_impersonating: "משתמש זה מתחזה"
user_no_comment: "מעולם לא השארת תגובה. הצטרף לשיחה!"
username_offensive: "שם משתמש זה פוגע"
view_conversation: "הצג שיחה"
install:
initial:
description: "בואו נגדיר את קהילת Talk שלך בכמה שלבים קצרים בלבד."
submit: "תחל"
add_organization:
description: 'ספר לנו את שם הארגון שלך. פעולה זו תופיע באימייל בעת הזמנת חברי צוות חדשים.'
label: "שם ארגון"
save: "שמור"
create:
email: 'כתובת אימייל'
username: "שם משתמש"
password: "סיסמה"
confirm_password: "אשר סיסמה"
save: "שמור"
permitted_domains:
title: "דומיינים מותרים"
description: "הזן את הדומיינים שברצונך להרשות עבור Talk. כלומר, סביבות האחסון הזמני וההפקה המקומית שלך (לדוגמה localhost: 3000, staging.domain.com, domain.com)."
submit: "סיים את ההתקנה"
final:
description: "תודה שהתקנת את Talk! שלחנו הודעת אימייל לאימות כתובת האימייל שלך. בזמן שתסיים להגדיר את החשבון, תוכל להתחיל לעסוק עם הקוראים שלך כעת."
launch: "הפעל את Talk"
close: "סגור את המתקין"
admin_sidebar:
view_options: "הצג אפשרויות"
sort_comments: "מיין תגובות"
+374 -353
View File
@@ -1,556 +1,577 @@
nl_NL:
admin_sidebar:
sort_comments: 'Sorteer reacties'
view_options: 'Bekijk opties'
already_flagged_username: 'Je hebt deze gebruikersnaam al gemeld.'
sort_comments: "Sorteer reacties"
view_options: "Bekijk opties"
already_flagged_username: "Je hebt deze gebruikersnaam al gemeld."
bandialog:
are_you_sure: 'Weet je zeker dat je {0} wil verbannen?'
ban_user: 'Gebruiker verbannen?'
banned_user: 'Verbannen gebruiker'
are_you_sure: "Weet je zeker dat je {0} wil verbannen?"
ban_user: "Gebruiker verbannen?"
banned_user: "Verbannen gebruiker"
cancel: Annuleren
email_message_ban: "Beste {0},\n\nIemand met toegang tot je account heeft onze community richtlijnen overtreden. Om die reden is je account verbannen. Je kunt niet langer reageren, of reacties goedkeuren of rapporteren. Als je denkt dat dit berust op een vergissing, neem dan contact op met ons community team."
note: 'Opmerking: {0}'
note_ban_user: 'Door deze gebruiker te verbannen kan deze geen reactie meer wijzigen of verwijderen.'
note_reject_comment: 'Door deze gebruiker te verbannen verplaats je diens reactie ook naar de lijst met afgewezen reacties.'
notify_ban_description: 'Dit stelt de gebruiker via email op de hoogte verbannen te zijn van de community'
notify_ban_headline: 'Stel gebruiker op de hoogte van verbanning'
note: "Opmerking: {0}"
note_ban_user: "Door deze gebruiker te verbannen kan deze geen reactie meer wijzigen of verwijderen."
note_reject_comment: "Door deze gebruiker te verbannen verplaats je diens reactie ook naar de lijst met afgewezen reacties."
notify_ban_description: "Dit stelt de gebruiker via e-mail op de hoogte verbannen te zijn van de community"
notify_ban_headline: "Stel gebruiker op de hoogte van verbanning"
send: Versturen
write_a_message: 'Schrijf een bericht'
yes_ban_user: 'Ja, verban gebruiker'
bio_offensive: 'Deze biografie is aanstootgevend.'
write_a_message: "Schrijf een bericht"
yes_ban_user: "Ja, verban gebruiker"
bio_offensive: "Deze biografie is aanstootgevend."
cancel: Annuleren
characters_remaining: 'tekens resterend'
characters_remaining: "tekens resterend"
comment:
anon: Anoniem
ban_user: 'Verban gebruiker'
comment: 'Plaats een reactie'
ban_user: "Verban gebruiker"
comment: "Plaats een reactie"
edited: Gewijzigd
flagged: Gemarkeerd
undo_reject: 'Ongedaan maken'
view_context: 'Bekijk context'
undo_reject: "Ongedaan maken"
view_context: "Bekijk context"
comment_box:
cancel: Annuleren
characters_remaining: 'tekens resterend'
comment: 'Plaats een reactie'
comment_post_banned_word: 'Je reactie bevat een of meerdere termen die wij niet toestaan. Neem contact op wanneer je het er niet mee eens bent.'
comment_post_notif: 'Je reactie is geplaatst'
comment_post_notif_premod: 'Dank voor je reactie! Deze wordt zo snel mogelijk gemodereerd.'
characters_remaining: "tekens resterend"
comment: "Plaats een reactie"
comment_post_banned_word: "Je reactie bevat een of meerdere termen die wij niet toestaan. Neem contact op wanneer je het er niet mee eens bent."
comment_post_notif: "Je reactie is geplaatst"
comment_post_notif_premod: "Dank voor je reactie! Deze wordt zo snel mogelijk gemodereerd."
name: Naam
post: Plaats
reply: Beantwoord
comment_history_blank:
info: 'Reacties die je hebt geplaatst zullen hier verschijnen'
title: 'Je hebt nog geen reacties geplaatst'
comment_offensive: 'Deze reactie is aanstootgevend'
info: "Reacties die je hebt geplaatst zullen hier verschijnen"
title: "Je hebt nog geen reacties geplaatst"
comment_offensive: "Deze reactie is aanstootgevend"
comment_plural: Reacties
comment_post_banned_word: 'Je reactie bevat een of meerdere termen die wij niet toestaan. Neem contact op wanneer je het er niet mee eens bent.'
comment_post_notif: 'Je reactie is geplaatst.'
comment_post_notif_premod: 'Dank voor je reactie! Deze wordt zo snel mogelijk gemodereerd.'
comment_post_banned_word: "Je reactie bevat een of meerdere termen die wij niet toestaan. Neem contact op wanneer je het er niet mee eens bent."
comment_post_notif: "Je reactie is geplaatst."
comment_post_notif_premod: "Dank voor je reactie! Deze wordt zo snel mogelijk gemodereerd."
comment_singular: Reactie
common:
contains_link: 'Bevat link'
contains_link: "Bevat link"
copy: Kopieer
copied: Gekopieerd
notsupported: 'Niet ondersteund'
error: 'Er is een fout opgetreden.'
notsupported: "Niet ondersteund"
error: "Er is een fout opgetreden."
reaction: reactie
reactions: reacties
replies: antwoorden
reply: antwoord
replies: antwoorden
story: Verhaal
community:
account_creation_date: 'Aanmaakdatum account'
account_creation_date: "Aanmaakdatum account"
active: Actief
admin: Administrator
ads_marketing: 'Dit lijkt op een advertentie/marketing'
are_you_sure: 'Weet je zeker dat je {0} wil verbannen?'
ban_user: 'Verban gebruiker?'
ads_marketing: "Dit lijkt op een advertentie/marketing"
all: "Alle"
are_you_sure: "Weet je zeker dat je {0} wil verbannen?"
ban_user: "Verban gebruiker?"
banned: Verbannen
banned_user: 'Verbannen gebruiker'
banned_user: "Verbannen gebruiker"
cancel: Annuleren
commenter: Reageerder
dont_like_username: 'Keur gebruikersnaam af'
flaggedaccounts: 'Gerapporteerde gebruikersnamen'
dont_like_username: "Keur gebruikersnaam af"
filter_users: "Filter gebruikers"
filter_role: Rol
flaggedaccounts: "Gerapporteerde gebruikersnamen"
flags: Rapporteringen
impersonating: Imitatie
loading: 'Resultaten worden geladen'
loading: "Resultaten worden geladen"
moderator: Moderator
newsroom_role: 'Newsroom rol'
no_flagged_accounts: 'De lijst met gerapporteerde gebruikers is momenteel leeg.'
no_results: 'Geen accounts gevonden met deze gebruikersnaam of e-mailadres.'
newsroom_role: "Newsroom rol"
no_flagged_accounts: "De lijst met gerapporteerde gebruikers is momenteel leeg."
no_results: "Geen accounts gevonden met deze gebruikersnaam of e-mailadres."
offensive: Aanstootgevend
other: Anders
people: Gebruikers
role: 'Selecteer rol...'
select_status: 'Selecteer status...'
role: "Selecteer rol..."
select_status: "Selecteer status..."
spam_ads: Spam/Ads
staff: Staff
status: Status
suspended: Geschorst
username_and_email: 'Gebruikersnaam en e-mailadres'
yes_ban_user: 'Ja, verban gebruiker'
username_and_email: "Gebruikersnaam en e-mailadres"
yes_ban_user: "Ja, verban gebruiker"
configure:
access_message: 'Je moet een admin zijn om toegang te krijgen tot de configuratie instellingen. Vraag de dichtsbijzijnde Admin om toegang!'
access_message: "Je moet een admin zijn om toegang te krijgen tot de configuratie instellingen. Vraag de dichtsbijzijnde Admin om toegang!"
apply: Toepassen
banned_word_text: 'Reacties die deze woorden of zinnen bevatten (niet hoofdlettergevoelig) worden automatisch uit de conversatie verwijderd. Voer een woord in, en druk op enter of Tab om toe te passen. Je kunt ook een kommagescheiden lijst plakken.'
banned_words_title: 'Lijst met verbannen woorden'
banned_word_text: "Reacties die deze woorden of zinnen bevatten (niet hoofdlettergevoelig) worden automatisch uit de conversatie verwijderd. Voer een woord in, en druk op enter of Tab om toe te passen. Je kunt ook een kommagescheiden lijst plakken."
banned_words_title: "Lijst met verbannen woorden"
close: Sluiten
close_after: 'Reacties afsluiten na'
close_stream: 'Sluit conversatie'
close_stream_configuration: 'Deze conversatie is momenteel afgesloten. Door deze te heropenen kunnen nieuwe reacties worden toegevoegd en weergegeven.'
closed_comments_desc: 'Schrijf een bericht om weer te geven wanneer de conversatie is afgesloten.'
closed_comments_label: 'Schrijf een bericht...'
closed_stream_settings: 'Afgesloten conversatie bericht'
comment_count_error: 'Voer een geldig getal in.'
comment_count_header: 'Reactielengte beperken'
close_after: "Reacties afsluiten na"
close_stream: "Sluit conversatie"
close_stream_configuration: "Deze conversatie is momenteel afgesloten. Door deze te heropenen kunnen nieuwe reacties worden toegevoegd en weergegeven."
closed_comments_desc: "Schrijf een bericht om weer te geven wanneer de conversatie is afgesloten."
closed_comments_label: "Schrijf een bericht..."
closed_stream_settings: "Afgesloten conversatie bericht"
comment_count_error: "Voer een geldig getal in."
comment_count_header: "Reactielengte beperken"
comment_count_text_post: tekens
comment_count_text_pre: 'Reacties worden ingekort op'
comment_count_text_pre: "Reacties worden ingekort op"
comment_settings: Instellingen
comment_stream: Conversatie
comment_stream_will_close: 'Deze conversatie zal worden afgesloten.'
comment_stream_will_close: "Deze conversatie zal worden afgesloten."
community: Community
configure: Instellen
copy_and_paste: 'Kopieer en plak onderstaande code om je reactie-box in je artikel op te nemen.'
custom_css_url: 'Eigen CSS URL'
custom_css_url_desc: 'URL van CSS stylesheet die de standaard Embed Conversatie stylesheet overschrijft. Kan intern of extern zijn.'
copy_and_paste: "Kopieer en plak onderstaande code om je reactie-box in je artikel op te nemen."
custom_css_url: "Eigen CSS URL"
custom_css_url_desc: "URL van CSS stylesheet die de standaard Embed Conversatie stylesheet overschrijft. Kan intern of extern zijn."
days: Dagen
description: 'Als admin kun je de instellingen aanpassen voor de conversatie bij dit verhaal:'
disable_commenting_desc: 'Schrijf een bericht dat wordt weergeven wanneer reageren is afgesloten.'
disable_commenting_title: 'Reacties afsluiten voor de gehele site'
domain_list_text: 'Voer de domeinen in die je wil toestaan voor Talk, bijvoorbeeld je staging en productie-omgevingen (bijv. localhost:3000 staging.domeinnaam.com domeinnaam.com).'
domain_list_title: 'Toegestane domeinnamen'
edit_comment_timeframe_heading: 'Wijzig reactie tijdsduur'
edit_comment_timeframe_text_post: 'secondes om hun reactie te wijzigen.'
edit_comment_timeframe_text_pre: 'Gebruikers hebben'
embed_comment_stream: 'Embed conversatie'
enable_pre_moderation: 'Pre-moderatie inschakelen'
enable_pre_moderation_text: 'Moderators moeten elke reactie goedkeuren voordat deze is gepubliceerd.'
enable_premod: 'Pre-moderatie inschakelen'
enable_premod_description: 'Moderators moeten elke reactie goedkeuren voordat deze is gepubliceerd.'
enable_premod_links: 'Pre-Modereer reacties met een link'
enable_premod_links_description: 'Moderators moeten elke reactie met een link goedkeuren voordat deze is gepubliceerd.'
enable_premod_links_text: 'Moderators moeten elke reactie met een link goedkeuren voordat deze is gepubliceerd.'
enable_questionbox: 'Stel een vraag aan de lezers'
enable_questionbox_description: 'Deze vraag zal bovenaan de conversatie verschijnen. Vraag lezers naar een probleem in het artikel, poneer discussie vragen, enzovoort.'
description: "Als admin kun je de instellingen aanpassen voor de conversatie bij dit verhaal:"
disable_commenting_desc: "Schrijf een bericht dat wordt weergeven wanneer reageren is afgesloten."
disable_commenting_title: "Reacties afsluiten voor de gehele site"
domain_list_text: "Voer de domeinen in die je wil toestaan voor Talk, bijvoorbeeld je staging en productie-omgevingen (bijv. localhost:3000 staging.domeinnaam.com domeinnaam.com)."
domain_list_title: "Toegestane domeinnamen"
edit_comment_timeframe_heading: "Wijzig reactie tijdsduur"
edit_comment_timeframe_text_post: "secondes om hun reactie te wijzigen."
edit_comment_timeframe_text_pre: "Gebruikers hebben"
edit_info: "Wijzig info"
embed_comment_stream: "Embed conversatie"
enable_pre_moderation: "Pre-moderatie inschakelen"
enable_pre_moderation_text: "Moderators moeten elke reactie goedkeuren voordat deze is gepubliceerd."
enable_premod: "Pre-moderatie inschakelen"
enable_premod_description: "Moderators moeten elke reactie goedkeuren voordat deze is gepubliceerd."
enable_premod_links: "Pre-Modereer reacties met een link"
enable_premod_links_description: "Moderators moeten elke reactie met een link goedkeuren voordat deze is gepubliceerd."
enable_premod_links_text: "Moderators moeten elke reactie met een link goedkeuren voordat deze is gepubliceerd."
enable_questionbox: "Stel een vraag aan de lezers"
enable_questionbox_description: "Deze vraag zal bovenaan de conversatie verschijnen. Vraag lezers naar een probleem in het artikel, poneer discussie vragen, enzovoort."
hours: Uren
code_of_conduct_summary: 'Neem conversatie beschrijving op voor lezers.'
code_of_conduct_summary_desc: 'Schrijf een bericht voor boven je conversatie. Poneer een stelling, wijs op de community richtlijnen, etc.'
include_question_here: 'Schrijf je vraag hier:'
include_text: 'Schrijf hier je tekst.'
code_of_conduct_summary: "Neem conversatie beschrijving op voor lezers."
code_of_conduct_summary_desc: "Schrijf een bericht voor boven je conversatie. Poneer een stelling, wijs op de community richtlijnen, etc."
include_an_icon: 'Include an Icon'
include_question_here: "Schrijf je vraag hier:"
include_text: "Schrijf hier je tekst."
moderate: Modereer
moderation_settings: 'Moderatie instellingen'
moderation_settings: "Moderatie instellingen"
open: Open
open_stream: 'Open Stream'
open_stream_configuration: 'Deze converstatie is momenteel open. Door deze te sluiten kunnen geen nieuwe reacties meer worden geplaatst, maar de oude zullen nog steeds worden weergegeven.'
organization_contact_email: 'Organisatie Contact E-mailadres'
organization_info_copy: 'We gebruiken deze informatie in e-mail notificaties die door Talk worden verstuurd. Dit verbind de berichten met je organisatie en biedt gebruikers een manier om contact op te nemen mochten ze een probleem met hun account ondervinden.'
organization_info_copy_2: 'We raden aan om een algemeen e-mail account (bijvoorbeeld community@yournewsroom.com) te gebruiken voor dit doeleinde. Dit betekent dat dit adres onveranderd kan blijven en deze geen naam blootstelt die gebruikers kunnen gebruiken mocht hun account geblokkeerd worden.'
organization_information: 'Organisatie Informatie'
organization_name: 'Organisatie Naam'
suspect_or_forbidden_words_placeholder: 'Woord of uitdrukking'
product_guide_link: 'Product Handleiding'
report_bug_or_feedback: 'Rapporteer een bug of geef feedback'
require_email_verification: 'Maak e-mail verificatie vereist'
require_email_verification_text: 'Nieuwe gebruikers moeten hun e-mailadres verifiëren voordat ze door kunnen gaan.'
save_changes: 'Wijzigingen opslaan'
open_stream: "Open Stream"
open_stream_configuration: "Deze converstatie is momenteel open. Door deze te sluiten kunnen geen nieuwe reacties meer worden geplaatst, maar de oude zullen nog steeds worden weergegeven."
organization_contact_email: "Organisatie Contact E-mailadres"
organization_info_copy: "We gebruiken deze informatie in e-mail notificaties die door Talk worden verstuurd. Dit verbind de berichten met je organisatie en biedt gebruikers een manier om contact op te nemen mochten ze een probleem met hun account ondervinden."
organization_info_copy_2: "We raden aan om een algemeen e-mail account (bijvoorbeeld community@yournewsroom.com) te gebruiken voor dit doeleinde. Dit betekent dat dit adres onveranderd kan blijven en deze geen naam blootstelt die gebruikers kunnen gebruiken mocht hun account geblokkeerd worden."
organization_information: "Organisatie Informatie"
organization_name: "Organisatie Naam"
suspect_or_forbidden_words_placeholder: "Woord of uitdrukking"
product_guide_link: "Product Handleiding"
report_bug_or_feedback: "Rapporteer een bug of geef feedback"
require_email_verification: "Maak e-mail verificatie vereist"
require_email_verification_text: "Nieuwe gebruikers moeten hun e-mailadres verifiëren voordat ze door kunnen gaan."
save: "Opslaan"
save_changes: "Wijzigingen opslaan"
save_changes_dialog:
cancel: Annuleren
copy: 'Je hebt een of meerdere wijzigingen gedaan zonder op te slaan. Wil je je wijzigingen opslaan of ongedaan maken?'
discard: 'Ongedaan maken'
save_settings: 'Instellingen Opslaan'
unsaved_changes: 'Niet-opgeslagen wijzigingen'
copy: "Je hebt een of meerdere wijzigingen gedaan zonder op te slaan. Wil je je wijzigingen opslaan of ongedaan maken?"
discard: "Ongedaan maken"
save_settings: "Instellingen Opslaan"
unsaved_changes: "Niet-opgeslagen wijzigingen"
shortcuts: Sneltoetsen
sign_out: Uitloggen
stories: Conversaties
stream_settings: 'Conversatie instellingen'
suspect_word_text: 'Reacties die deze woorden of zinsdelen bevatten (niet hoofdlettergevoelig) zullen worden gemarkeerd in de conversatie. Type een woord en druk op enter of tab om toe te voegen. Je kunt optioneel een komma-gescheiden lijst plakken.'
suspect_word_title: 'Lijst met verdachte woorden'
tech_settings: 'Technische instellingen'
title: 'Conversatie configureren'
stream_settings: "Conversatie instellingen"
suspect_word_text: "Reacties die deze woorden of zinsdelen bevatten (niet hoofdlettergevoelig) zullen worden gemarkeerd in de conversatie. Type een woord en druk op enter of tab om toe te voegen. Je kunt optioneel een komma-gescheiden lijst plakken."
suspect_word_title: "Lijst met verdachte woorden"
tech_settings: "Technische instellingen"
title: "Conversatie configureren"
view_last_version: "Bekijk meest recente versie"
weeks: Weken
wordlist: 'Zwarte woordenlijst'
wordlist: "Zwarte woordenlijst"
confirm_email:
click_to_confirm: 'Klik hieronder om je e-mailadres te bevestigen.'
click_to_confirm: "Klik hieronder om je e-mailadres te bevestigen."
confirm: Bevestig
email_confirmation: "E-mailadres bevestiging"
continue: Doorgaan
createdisplay:
check_the_form: 'Ongeldig formulier. Kijk de invoer na.'
continue: 'Doorgaan met dezelfde Facebook gebruikersnaam'
error_create: 'Fout bij het wijzigen van de gebruikersnaam'
fake_comment_body: 'Dit is een voorbeeld reactie. Lezers kunnen hun gedachten en meningen delen met de Newsrooms in de reactie-sectie.'
fake_comment_date: '1 minuut geleden'
if_you_dont_change_your_name: 'Wanneer je gebruikersnaam niet verandert, zal je Facebook gebruikersnaam verschijnen bij al je reacties.'
required_field: 'Verplicht veld'
check_the_form: "Ongeldig formulier. Kijk de invoer na."
continue: "Doorgaan met dezelfde Facebook gebruikersnaam"
error_create: "Fout bij het wijzigen van de gebruikersnaam"
fake_comment_body: "Dit is een voorbeeld reactie. Lezers kunnen hun gedachten en meningen delen met de Newsrooms in de reactie-sectie."
fake_comment_date: "1 minuut geleden"
if_you_dont_change_your_name: "Wanneer je gebruikersnaam niet verandert, zal je Facebook gebruikersnaam verschijnen bij al je reacties."
required_field: "Verplicht veld"
save: Opslaan
special_characters: 'Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten.'
special_characters: "Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten."
username: Gebruikersnaam
write_your_username: 'Wijzig je gebruikersnaam'
your_username: 'Je gebruikersnaam verschijnt bij elke reactie die je plaatst.'
write_your_username: "Wijzig je gebruikersnaam"
your_username: "Je gebruikersnaam verschijnt bij elke reactie die je plaatst."
done: Klaar
edit_comment:
body_input_label: 'Wijzig deze reactie'
edit_window_expired: 'Je kunt deze reactie niet meer wijzigen. De tijdsduur hiervoor is verstreken.'
body_input_label: "Wijzig deze reactie"
edit_window_expired: "Je kunt deze reactie niet meer wijzigen. De tijdsduur hiervoor is verstreken."
edit_window_expired_close: Sluiten
edit_window_timer_prefix: 'Wijzig venster: '
edit_window_timer_prefix: "Wijzig venster: "
minute: minuut
minutes_plural: minuten
save_button: 'Wijzigingen opslaan'
save_button: "Wijzigingen opslaan"
second: seconde
seconds_plural: secondes
email:
banned:
body: 'In lijn met The Coral Project''s community richtlijnen is je account verbannen. Je kunt niet langer reageren, rapporteren of interacteren met onze community.'
subject: 'Je account is verbannen.'
body: "In lijn met The Coral Project's community richtlijnen is je account verbannen. Je kunt niet langer reageren, rapporteren of interacteren met onze community."
subject: "Je account is verbannen."
confirm:
confirm_email: 'Bevestig e-mail'
has_been_requested: 'Een e-mail bevestiging is aangevraagd voor het volgend account:'
if_you_did_not: 'Wanneer jij dit niet hebt aangevraagd, kun je deze e-mail negeren.'
subject: 'Email bevestiging'
to_confirm: 'Ga naar de volgende link om het account te bevestigen:'
confirm_email: "Bevestig e-mail"
has_been_requested: "Een e-mail bevestiging is aangevraagd voor het volgend account:"
if_you_did_not: "Wanneer jij dit niet hebt aangevraagd, kun je deze e-mail negeren."
subject: "Email bevestiging"
to_confirm: "Ga naar de volgende link om het account te bevestigen:"
password_change:
body: 'Het wachtwoord voor je account is gewijzigd.\n\nAls je deze wijziging niet hebt aangevraagd, neem dan contact met ons op: {0}'
subject: '{0} wachtwoord wijziging'
subject: "{0} wachtwoord wijziging"
password_reset:
if_you_did: 'Wanneer je dit zelf was,'
please_click: 'klik dan hier om je wachtwoord te veranderen'
we_received_a_request: 'We hebben een verzoek gekregen om je wachtwoord opnieuw in te stellen. Wanneer je dit niet zelf was, kun je deze mail negeren.'
if_you_did: "Wanneer je dit zelf was,"
please_click: "klik dan hier om je wachtwoord te veranderen"
subject: 'Wachtwoord veranderen'
we_received_a_request: "We hebben een verzoek gekregen om je wachtwoord opnieuw in te stellen. Wanneer je dit niet zelf was, kun je deze mail negeren."
suspended:
subject: 'Je account is tijdelijk geschorst.'
subject: "Je account is tijdelijk geschorst."
embed_comments_tab: Reacties
embedlink:
copy: 'Kopieer naar klembord'
copy: "Kopieer naar klembord"
copied: Gekopieerd
error:
ALREADY_EXISTS: 'Bron bestaat al'
AUTHENTICATION: 'Er is een fout opgetreden tijdens het aanmelden van je account'
CANNOT_IGNORE_STAFF: 'Kan geen Staff-leden negeren.'
COMMENT_PARENT_NOT_VISIBLE: 'De reactie waarop je probeert te reageren bestaat niet of is inmiddels verwijderd.'
COMMENT_TOO_SHORT: 'Reacties moeten meer dan één teken hebben. Herzie je reactie en probeer opnieuw.'
COMMENT_TOO_LONG: 'Tekst is te lang'
COMMENTING_CLOSED: 'Reageren is al afgesloten.'
COMMENTING_DISABLED: 'Reageren is momenteel uigeschakeld op deze site'
confirm_password: 'Wachtwoorden komen niet overeen. Controleer opnieuw.'
DELETION_NOT_SCHEDULED: 'Verwijdering was niet ingepland'
EDIT_USERNAME_NOT_AUTHORIZED: 'Je bent niet gemachtigd om je gebruikersnaam te wijzigen.'
EDIT_WINDOW_ENDED: 'Dit commentaar kan niet langer worden gewijzigd. Het tijdsbestek is verstreken.'
email: 'Geen geldig e-mailadres'
EMAIL_ALREADY_VERIFIED: 'E-mailadres is reeds geverifiëerd'
EMAIL_IN_USE: 'E-mailadres al in gebruik'
email_not_verified: 'E-mailadres {0} is niet geverifiëerd'
EMAIL_NOT_VERIFIED: 'E-mailadres is niet geverifiëerd'
email_password: 'E-mail en/of wachtwoord combinatie onjuist'
EMAIL_REQUIRED: 'Een e-mailadres is vereist'
EMAIL_VERIFICATION_TOKEN_INVALID: 'Ongeldig e-mail verificatie token'
INCORRECT_PASSWORD: 'Ongeldig wachtwoord'
INVALID_ASSET_URL: 'Ongeldige URL'
LOGIN_MAXIMUM_EXCEEDED: 'Je hebt te veel mislukte inlogpogingen gedaan. Even geduld aub.'
network_error: 'Kon geen verbinding maken met server. Controleer je internetverbinding en probeer het opnieuw.'
NO_SPECIAL_CHARACTERS: 'Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten.'
NOT_AUTHORIZED: 'Je bent niet geauthoriseerd om dit te doen.'
NOT_FOUND: 'Bron niet gevonden'
organization_contact_email: 'Organisatie e-mailadres is niet geldig.'
organization_name: 'Organisatienaam kan alleen cijfers en letters bevatten.'
password: 'Wachtwoord moet minimaal 8 karakters lang zijn'
PAGE_NOT_AVAILABLE_ROLE: 'Deze pagina is enkel voor toegankelijk voor teamleden. Neem contact op met een admin als je toegang tot dit team wilt.'
PASSWORD_INCORRECT: 'Je huidige wachtwoord is incorrect ingevuld'
PASSWORD_LENGTH: 'Wachtwoord is te kort'
PASSWORD_REQUIRED: 'Je moet een wachtwoord invoeren.'
PASSWORD_RESET_TOKEN_INVALID: 'Je wachtwoord-herstel token is ongeldig.'
PROFANITY_ERROR: 'Gebruikersnamen mogen niet aanstootgevend zijn. Neem contact op met de administrator wanneer je denkt dat dit niet klopt.'
RATE_LIMIT_EXCEEDED: 'Gebruikslimiet overschreden'
required_field: 'Dit veld is verplicht'
SAME_USERNAME_PROVIDED: 'Je moet een andere gebruikersnaam invoeren.'
temporarily_suspended: 'Je account is momenteel geschorst. Deze zal worden gereactiveerd {0}. Neem s.v.p. contact met ons op voor vragen.'
unexpected: 'Onverwachte fout opgetreden. Sorry!'
username: 'Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten.'
USERNAME_IN_USE: 'Gebruikersnaam al in gebruik'
USERNAME_REQUIRED: 'Gebruikersnaam is vereist'
flag_comment: 'Rapporteer reactie'
flag_reason: 'Reden voor rapporteren (optioneel)'
ALREADY_EXISTS: "Bron bestaat al"
AUTHENTICATION: "Er is een fout opgetreden tijdens het aanmelden van je account"
CANNOT_IGNORE_STAFF: "Kan geen Staff-leden negeren."
COMMENT_PARENT_NOT_VISIBLE: "De reactie waarop je probeert te reageren bestaat niet of is inmiddels verwijderd."
COMMENT_TOO_SHORT: "Reacties moeten meer dan één teken hebben. Herzie je reactie en probeer opnieuw."
COMMENT_TOO_LONG: "Tekst is te lang"
COMMENTING_CLOSED: "Reageren is al afgesloten."
COMMENTING_DISABLED: "Reageren is momenteel uigeschakeld op deze site"
confirm_password: "Wachtwoorden komen niet overeen. Controleer opnieuw."
DELETION_NOT_SCHEDULED: "Verwijdering was niet ingepland"
EDIT_USERNAME_NOT_AUTHORIZED: "Je bent niet gemachtigd om je gebruikersnaam te wijzigen."
EDIT_WINDOW_ENDED: "Dit commentaar kan niet langer worden gewijzigd. Het tijdsbestek is verstreken."
email: "Geen geldig e-mailadres"
EMAIL_ALREADY_VERIFIED: "E-mailadres is reeds geverifiëerd"
EMAIL_IN_USE: "E-mailadres al in gebruik"
email_not_verified: "E-mailadres {0} is niet geverifiëerd"
EMAIL_NOT_VERIFIED: "E-mailadres is niet geverifiëerd"
email_password: "E-mail en/of wachtwoord combinatie onjuist"
EMAIL_REQUIRED: "Een e-mailadres is vereist"
EMAIL_VERIFICATION_TOKEN_INVALID: "Ongeldig e-mail verificatie token"
INCORRECT_PASSWORD: "Ongeldig wachtwoord"
INVALID_ASSET_URL: "Ongeldige URL"
LOGIN_MAXIMUM_EXCEEDED: "Je hebt te veel mislukte inlogpogingen gedaan. Even geduld aub."
network_error: "Kon geen verbinding maken met server. Controleer je internetverbinding en probeer het opnieuw."
NO_SPECIAL_CHARACTERS: "Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten."
NOT_AUTHORIZED: "Je bent niet geauthoriseerd om dit te doen."
NOT_FOUND: "Bron niet gevonden"
organization_contact_email: "Organisatie e-mailadres is niet geldig."
organization_name: "Organisatienaam kan alleen cijfers en letters bevatten."
password: "Wachtwoord moet minimaal 8 karakters lang zijn"
PAGE_NOT_AVAILABLE_ROLE: "Deze pagina is enkel voor toegankelijk voor teamleden. Neem contact op met een admin als je toegang tot dit team wilt."
PASSWORD_INCORRECT: "Je huidige wachtwoord is incorrect ingevuld"
PASSWORD_LENGTH: "Wachtwoord is te kort"
PASSWORD_REQUIRED: "Je moet een wachtwoord invoeren."
PASSWORD_RESET_TOKEN_INVALID: "Je wachtwoord-herstel token is ongeldig."
PROFANITY_ERROR: "Gebruikersnamen mogen niet aanstootgevend zijn. Neem contact op met de administrator wanneer je denkt dat dit niet klopt."
RATE_LIMIT_EXCEEDED: "Gebruikslimiet overschreden"
required_field: "Dit veld is verplicht"
SAME_USERNAME_PROVIDED: "Je moet een andere gebruikersnaam invoeren."
temporarily_suspended: "Je account is momenteel geschorst. Deze zal worden gereactiveerd {0}. Neem s.v.p. contact met ons op voor vragen."
unexpected: "Onverwachte fout opgetreden. Sorry!"
username: "Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten."
USERNAME_IN_USE: "Gebruikersnaam al in gebruik"
USERNAME_REQUIRED: "Gebruikersnaam is vereist"
flag_comment: "Rapporteer reactie"
flag_reason: "Reden voor rapporteren (optioneel)"
flag_reasons:
username:
impersonating: 'Deze gebruiker doet zich voor als iemand anders'
nolike: 'Ik vind deze gebruikersnaam niet leuk'
offensive: 'Deze gebruikersnaam is aanstootgevend'
impersonating: "Deze gebruiker doet zich voor als iemand anders"
nolike: "Ik vind deze gebruikersnaam niet leuk"
offensive: "Deze gebruikersnaam is aanstootgevend"
other: Andere
spam: 'Dit lijkt op een advertentie/marketing'
flag_username: 'Rapporteer gebruikersnaam'
spam: "Dit lijkt op een advertentie/marketing"
flag_username: "Rapporteer gebruikersnaam"
flagged_usernames:
notify_approved: '{0} heeft gebruikersnaam {1} goedgekeurd'
notify_changed: 'gebruiker {0} heeft zijn/haar gebruikersnaam veranderd naar {1}'
notify_flagged: '{0} heeft gebruikersnaam {1} gerapporteerd'
notify_rejected: '{0} heeft gebruikersnaam {1} afgekeurd'
notify_approved: "{0} heeft gebruikersnaam {1} goedgekeurd"
notify_changed: "gebruiker {0} heeft zijn/haar gebruikersnaam veranderd naar {1}"
notify_flagged: "{0} heeft gebruikersnaam {1} gerapporteerd"
notify_rejected: "{0} heeft gebruikersnaam {1} afgekeurd"
flags:
reasons:
comment:
banned_word: 'Geblokeerd woord'
comment_noagree: 'Niet eens'
banned_word: "Geblokeerd woord"
comment_noagree: "Niet eens"
comment_offensive: Aanstootgevend
comment_other: Anders
comment_spam: Spam
links: Link
suspect_word: 'Verdacht woord'
suspect_word: "Verdacht woord"
trust: Karma
user:
username_impersonating: Impersonatie
username_nolike: 'Niet leuk'
username_nolike: "Niet leuk"
username_offensive: Aanstootgevend
username_other: Anders
username_spam: Spam
framework:
banned_account_body: 'Dit betekent dat je niet kunt reageren, liken of rapporteren.'
banned_account_header: 'Je account is momenteel verbannen.'
banned_account_body: "Dit betekent dat je niet kunt reageren, liken of rapporteren."
banned_account_header: "Je account is momenteel verbannen."
changed_name:
msg: 'De verandering van je gebruikersnaam wordt door ons moderatieteam gecontroleerd.'
msg: "De verandering van je gebruikersnaam wordt door ons moderatieteam gecontroleerd."
comment: reactie
comment_is_deleted: 'De reageerder heeft zijn account verwijderd.'
comment_is_hidden: 'Deze reactie is niet beschikbaar.'
comment_is_ignored: 'Deze reactie is verborgen omdat je de gebruiker negeert.'
comment_is_rejected: 'Je hebt deze reactie afgewezen.'
comment_is_deleted: "De reageerder heeft zijn account verwijderd."
comment_is_hidden: "Deze reactie is niet beschikbaar."
comment_is_ignored: "Deze reactie is verborgen omdat je de gebruiker negeert."
comment_is_rejected: "Je hebt deze reactie afgewezen."
comments: reacties
configure_stream: Configureren
content_not_available: 'Deze inhoud is niet beschikbaar'
content_not_available: "Deze inhoud is niet beschikbaar"
edit: Wijzig
edit_name:
button: Versturen
error: 'Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten.'
label: 'Nieuwe gebruikersnaam'
msg: 'Je account is momenteel geschorst omdat je gebruikersnaam ongepast is bevonden. Om je account te herstellen, moet je je gebruikersnaam herstellen. Neem contact met ons op wanneer je vragen hebt.'
my_comments: 'Mijn reacties'
my_profile: 'Mijn profiel'
new_count: 'Bekijk {0} meer {1}'
error: "Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten."
label: "Nieuwe gebruikersnaam"
msg: "Je account is momenteel geschorst omdat je gebruikersnaam ongepast is bevonden. Om je account te herstellen, moet je je gebruikersnaam herstellen. Neem contact met ons op wanneer je vragen hebt."
my_comments: "Mijn reacties"
my_profile: "Mijn profiel"
new_count: "Bekijk {0} meer {1}"
profile: Profiel
show_all_comments: 'Toon alle reacties'
show_all_replies: 'Toon alle reacties'
show_more_replies: 'Toon meer reacties'
success_bio_update: 'Je biografie is bijgewerkt.'
success_name_update: 'Je gebruikersnaam is bijgewerkt.'
success_update_settings: 'De conversatie is aangepast.'
view_more_comments: 'Bekijk meer reacties'
view_reply: 'Bekijk reactie'
from_settings_page: 'Vanuit de profielpagina kun je je reactiegeschiedenis bekijken.'
show_all_comments: "Toon alle reacties"
show_all_replies: "Toon alle reacties"
show_more_replies: "Toon meer reacties"
success_bio_update: "Je biografie is bijgewerkt."
success_name_update: "Je gebruikersnaam is bijgewerkt."
success_update_settings: "De conversatie is aangepast."
view_more_comments: "Bekijk meer reacties"
view_reply: "Bekijk reactie"
from_settings_page: "Vanuit de profielpagina kun je je reactiegeschiedenis bekijken."
install:
add_organization:
description: 'Vertel ons de naam van je organisatie. Deze zal te zien zijn in e-mails wanneer je nieuwe teamleden uitnodigt.'
description: "Vertel ons de naam van je organisatie. Deze zal te zien zijn in e-mails wanneer je nieuwe teamleden uitnodigt."
label: Organisatienaam
save: Opslaan
create:
confirm_password: 'Bevestig wachtwoord'
confirm_password: "Bevestig wachtwoord"
email: E-mailadres
organization_contact_email: "Organisatie Contact E-mailadres"
password: Wachtwoord
save: Opslaan
username: Gebruikersnaam
final:
close: 'Installatie afsluiten'
description: 'Dank voor het installeren van Talk! We hebben een bericht gestuurd om je e-mailadres te valideren. Terwijl je je account verder opzet, kun je alvast de interactie aangaan met je gebruikers.'
launch: 'Start Talk'
close: "Installatie afsluiten"
description: "Dank voor het installeren van Talk! We hebben een bericht gestuurd om je e-mailadres te valideren. Terwijl je je account verder opzet, kun je alvast de interactie aangaan met je gebruikers."
launch: "Start Talk"
initial:
description: 'Laten we je Talk-community opzetten met een paar simpele stappen.'
description: "Laten we je Talk-community opzetten met een paar simpele stappen."
submit: Begin
permitted_domains:
description: 'Voer de domeinen in die je wil toestaan voor Talk, bijvoorbeeld je staging en productie-omgevingen (bijv. localhost:3000 staging.domeinnaam.com domeinnaam.com)'
submit: 'Installatie afronden'
title: 'Toegestane domeinnamen'
description: "Voer de domeinen in die je wil toestaan voor Talk, bijvoorbeeld je staging en productie-omgevingen (bijv. localhost:3000 staging.domeinnaam.com domeinnaam.com)"
submit: "Installatie afronden"
title: "Toegestane domeinnamen"
like: Like
loading_results: 'Resultaten worden geladen'
loading_results: "Resultaten worden geladen"
login:
email_address: E-mailadres
forgot_password: 'Wachtwoord vergeten?'
go_back: 'Ga terug'
forgot_password: "Wachtwoord vergeten?"
go_back: "Ga terug"
sign_in: Inloggen
sign_in_button: Inloggen
sign_in_message: 'Log in om te communiceren met je community'
sign_in_message: "Log in om te communiceren met je community"
password: Wachtwoord
reset_password_send_button: 'Wachtwoord ophalen'
request_passowrd: 'Vraag een nieuwe aan.'
team_sign_in: 'Team login'
marketing: 'Dit lijkt op een advertentie/marketing'
moderate_this_stream: 'Modereer deze conversatie'
reset_password_send_button: "Wachtwoord ophalen"
request_passowrd: "Vraag een nieuwe aan."
team_sign_in: "Team login"
marketing: "Dit lijkt op een advertentie/marketing"
moderate_all_streams: "Modereer reacties op alle artikelen"
moderate_this_stream: "Modereer deze conversatie"
modqueue:
account: 'account meldingen'
account: "account meldingen"
actions: Acties
all: Alle
all_streams: 'Alle conversaties'
all_streams: "Alle conversaties"
approve: Goedkeuren
approved: Goedgekeurd
ban_user: Verban
ban_user_actions: "Verban gebruiker"
billion: G
close: Sluiten
empty_queue: 'Geen reacties meer te beoordelen!'
empty_queue: "Geen reacties meer te beoordelen!"
flagged: gemeld
jump_to_queue: 'Spring naar specifieke wachtrij'
less_detail: 'Minder detail'
jump_to_queue: "Spring naar specifieke wachtrij"
less_detail: "Minder detail"
likes: likes
million: M
mod_faster: 'Beoordeel sneller met sneltoetsen'
moderate: 'Beoordeel →'
more_detail: 'Meer detail'
mod_faster: "Beoordeel sneller met sneltoetsen"
moderate: "Beoordeel →"
more_detail: "Meer detail"
navigation: Navigatie
new: Nieuw
newest_first: 'Nieuwste eerst'
next_comment: 'Ga naar de volgende reactie'
next_queue: 'Verander wachtrij'
newest_first: "Nieuwste eerst"
next_comment: "Ga naar de volgende reactie"
next_queue: "Verander wachtrij"
notify_accepted: '{0} accepteerde reactie "{1}"'
notify_edited: '{0} wijzigde reactie "{1}"'
notify_flagged: '{0} heeft reactie "{1}" gerapporteerd'
notify_rejected: '{0} heeft reactie "{1}" afgewezen'
notify_reset: '{0} heeft de status van reactie "{1}" hersteld'
oldest_first: 'Oudste eerst'
oldest_first: "Oudste eerst"
premod: Pre-moderatie
prev_comment: 'Ga naar de vorige reactie'
reject: 'Wijs af'
prev_comment: "Ga naar de vorige reactie"
reject: "Wijs af"
rejected: Afgewezen
reply: Beantwoord
reported: gerapporteerd
select_stream: 'Selecteer conversatie'
select_stream: "Selecteer conversatie"
shift_key:
shortcuts: Sneltoetsen
show_shortcuts: 'Toon sneltoetsen'
show_shortcuts: "Toon sneltoetsen"
singleview: Zen-modus
sort: Sorteer
suspend: 'Schors gebruiker'
system_withheld: 'Achtergehouden door systeem'
thismenu: 'Open dit menu'
suspend: "Schors gebruiker"
system_withheld: "Achtergehouden door systeem"
thismenu: "Open dit menu"
thousand: k
toggle_search: 'Open zoekvenster'
try_these: 'Probeer deze'
view_more_shortcuts: 'Bekijk meer sneltoetsen'
my_comment_history: 'Mijn reactie geschiedenis'
toggle_search: "Open zoekvenster"
try_these: "Probeer deze"
view_more_shortcuts: "Bekijk meer sneltoetsen"
my_comment_history: "Mijn reactie geschiedenis"
name: Naam
no_agree_comment: 'Ik ben het niet eens met deze reactie'
no_like_bio: 'Ik vind deze biografie niet leuk'
no_like_username: 'Ik vind deze gebruikersnaam niet leuk'
no_agree_comment: "Ik ben het niet eens met deze reactie"
no_like_bio: "Ik vind deze biografie niet leuk"
no_like_username: "Ik vind deze gebruikersnaam niet leuk"
other: Ander
password_reset:
change_password: 'Verander wachtwoord'
change_password_help: 'Voer een nieuw wachtwoord in om mee in te loggen. Gebruik een veilig wachtwoord!'
confirm_new_password: 'Bevestig nieuw wachtwoord'
new_password: 'Nieuw wachtwoord'
new_password_help: 'Wachtwoord moet minimaal 8 karakters lang zijn.'
set_new_password: 'Verander je wachtwoord'
change_password: "Verander wachtwoord"
change_password_help: "Voer een nieuw wachtwoord in om mee in te loggen. Gebruik een veilig wachtwoord!"
confirm_new_password: "Bevestig nieuw wachtwoord"
mail_sent: "Wanneer je een account geregistreerd hebt, is er een wachtwoord-herstel link gestuurd naar dat e-mailadres"
new_password: "Nieuw wachtwoord"
new_password_help: "Wachtwoord moet minimaal 8 karakters lang zijn."
set_new_password: "Verander je wachtwoord"
permalink: Deel
personal_info: 'Deze reactie onthult persoonlijk identificeerbare gegevens.'
personal_info: "Deze reactie onthult persoonlijk identificeerbare gegevens."
post: Plaats
profile: Profiel
profile_settings: Instellingen
reject_username:
description_notify: 'Door de schorsing zal deze tijdelijk diens account niet kunnen gebruiken.'
description_reject: 'Wil je deze gebruiker tijdelijk schorsen om diens {0}? Dan wordt de gebruiker geschorst totdat deze diens {0} heeft herschreven.'
email_message_reject: 'Iemand anders uit de community heeft je gebruikersnaam gemeld ter controle. Vanwege de inhoud van je gebruikersnaam is je account geschorst. Dit betekent dat je niet langer kunt reageen, liken of inhoud melden totdat je je gebruikersnaam hebt veranderd. Stuur ons een e-mail wanneer je vragen of zorgen hebt.'
no_cancel: 'Geen annuleringsmogelijkheid'
description_notify: "Door de schorsing zal deze tijdelijk diens account niet kunnen gebruiken."
description_reject: "Wil je deze gebruiker tijdelijk schorsen om diens {0}? Dan wordt de gebruiker geschorst totdat deze diens {0} heeft herschreven."
email_message_reject: "Iemand anders uit de community heeft je gebruikersnaam gemeld ter controle. Vanwege de inhoud van je gebruikersnaam is je account geschorst. Dit betekent dat je niet langer kunt reageen, liken of inhoud melden totdat je je gebruikersnaam hebt veranderd. Stuur ons een e-mail wanneer je vragen of zorgen hebt."
no_cancel: "Geen annuleringsmogelijkheid"
send: Verstuur
suspend_user: 'Schors gebruiker'
title_notify: 'Breng de gebruiker op de hoogte van de schorsing.'
title_reject: 'We zagen dat je een gebruikersnaam hebt afgewezen'
suspend_user: "Schors gebruiker"
title_notify: "Breng de gebruiker op de hoogte van de schorsing."
title_reject: "We zagen dat je een gebruikersnaam hebt afgewezen"
username: gebruikersnaam
write_message: 'Schrijf een bericht'
yes_suspend: 'Ja, schors'
write_message: "Schrijf een bericht"
yes_suspend: "Ja, schors"
reject_username_dialog:
cancel: Annuleren
description: 'Help ons dit te begrijpen'
message: 'Reden voor rapporteren (Optioneel)'
description: "Help ons dit te begrijpen"
message: "Reden voor rapporteren (Optioneel)"
reason: Reden
reject_username: 'Gebruikersnaam afwijzen'
title: 'Gebruikersnaam afwijzen'
reject_username: "Gebruikersnaam afwijzen"
title: "Gebruikersnaam afwijzen"
reply: Beantwoord
report: Rapporteer
report_notif: 'Dank voor het rapporteren van deze reactie. Deze wordt zo snel mogelijk gemodereerd.'
report_notif_remove: 'Je melding is verwijderd.'
report_notif: "Dank voor het rapporteren van deze reactie. Deze wordt zo snel mogelijk gemodereerd."
report_notif_remove: "Je melding is verwijderd."
reported: Gerapporteerd
settings:
from_settings_page: 'Op je profielpagina kun je je reactie-geschiedenis zien.'
my_comment_history: 'Mijn reactie geschiedenis'
from_settings_page: "Op je profielpagina kun je je reactie-geschiedenis zien."
my_comment_history: "Mijn reactie geschiedenis"
profile: Profiel
profile_settings: 'Profiel instellingen'
profile_settings: "Profiel instellingen"
sign_in: Inloggen
to_access: 'om profiel te benaderen'
user_no_comment: 'Je hebt nog niet eerder gereageerd.'
step_1_header: 'Rapporteer een issue'
step_2_header: 'Help ons begrijpen'
step_3_header: 'Dankjewel voor je input'
to_access: "om profiel te benaderen"
user_no_comment: "Je hebt nog niet eerder gereageerd."
step_1_header: "Rapporteer een issue"
step_2_header: "Help ons begrijpen"
step_3_header: "Dankjewel voor je input"
stream:
all_comments: 'Alle reacties'
comment_not_found: 'Deze opmerking is verwijderd of bestaat niet.'
no_comments: 'Er zijn nog geen reacties. Schrijf er zelf eentje!'
no_comments_and_closed: 'Er waren geen reacties op dit artikel.'
temporarily_suspended: 'In overeenstemming met de community richtlijnen van {0} is je account tijdelijk geschorst. Keer terug naar de conversaties {1}.'
all_comments: "Alle reacties"
comment_not_found: "Deze opmerking is verwijderd of bestaat niet."
no_comments: "Er zijn nog geen reacties. Schrijf er zelf eentje!"
no_comments_and_closed: "Er waren geen reacties op dit artikel."
temporarily_suspended: "In overeenstemming met de community richtlijnen van {0} is je account tijdelijk geschorst. Keer terug naar de conversaties {1}."
streams:
all: Alle
article: Artikel
closed: Gesloten
empty_result: 'Niets gevonden bij deze zoekopdracht. Misschien moet je je zoekopdracht proberen te verbreden?'
filter_streams: 'Filter conversaties'
empty_result: "Niets gevonden bij deze zoekopdracht. Misschien moet je je zoekopdracht proberen te verbreden?"
filter_streams: "Filter conversaties"
most_recent_stories: "Meest recente artikelen"
newest: Nieuwste
no_results: "Geen resultaten"
oldest: Oudste
open: Open
pubdate: 'Publicatie datum'
pubdate: "Publicatie datum"
search: Zoeken
sort_by: 'Sorteer op'
status: 'Conversatie status'
stream_status: 'Conversatie status'
search_results: "Zoekresultaten"
sort_by: "Sorteer op"
status: "Conversatie status"
stream_status: "Conversatie status"
suspenduser:
cancel: Annuleren
days: '{0} dagen'
description_notify: 'Wanneer je de gebruiker schorst zal zijn/haar account tijdelijk worden uitgeschakeld.'
description_suspend: 'Je schorst {0}. Deze reactie wordt afgewezen, en {0} zal niet meer kunnen liken, rapporteren of reageren totdat de schorsingsduur verstreken is.'
day: "{0} days"
days: "{0} dagen"
description_notify: "Wanneer je de gebruiker schorst zal zijn/haar account tijdelijk worden uitgeschakeld."
description_suspend: "Je schorst {0}. Deze reactie wordt afgewezen, en {0} zal niet meer kunnen liken, rapporteren of reageren totdat de schorsingsduur verstreken is."
email_message_suspend: "Beste {0},\n\nIn overeenstemming met de community richtlijnen van {1} is je account tijdelijk geschorst. Tijdens deze schorsing kun je niet reageren, liken of interacteren met je collega-reageerders. Hervat het gesprek {2}."
hours: '{0} uur'
notify_suspend_until: 'Gebruiker {0} is tijdelijk geschorst. Deze schorsing houdt automatisch op {1}.'
one_hour: '1 uur'
select_duration: 'Selecteer schorsingsduur'
hour: "{0} hours"
hours: "{0} uur"
notify_suspend_until: "Gebruiker {0} is tijdelijk geschorst. Deze schorsing houdt automatisch op {1}."
one_hour: "1 uur"
select_duration: "Selecteer schorsingsduur"
send: Verstuur
suspend_user: 'Schors gebruiker'
title_notify: 'Breng de gebruiker op de hoogte van de schorsing.'
title_suspend: 'Schors gebruiker'
write_message: 'Schrijf een bericht'
thank_you: 'We waarderen je feedback. Een moderator zal je rapport bekijken.'
suspend_user: "Schors gebruiker"
title_notify: "Breng de gebruiker op de hoogte van de schorsing."
title_suspend: "Schors gebruiker"
write_message: "Schrijf een bericht"
thank_you: "We waarderen je feedback. Een moderator zal je rapport bekijken."
user:
bio_flags: 'Meldingen voor deze biografie'
user_bio: 'Gebruikers biografie'
username_flags: 'Meldingen voor deze gebruikersnaam'
bio_flags: "Meldingen voor deze biografie"
user_bio: "Gebruikers biografie"
username_flags: "Meldingen voor deze gebruikersnaam"
user_detail:
all: Alle
ban: 'Gebruiker verbannen'
ban: "Gebruiker verbannen"
banned: "Verbannen"
email: E-mailadres
id: ID
karma: Karma
karma_docs_link: 'https://docs.coralproject.net/talk/trust/#user-karma-score'
learn_more: 'Meer informatie'
member_since: 'Lid sinds'
reject_rate: 'Beoordeling verwijderen'
reject_username: 'Gebruikersnaam afwijzen'
karma_docs_link: "https://docs.coralproject.net/talk/trust/#user-karma-score"
learn_more: "Meer informatie"
member_since: "Lid sinds"
reject_rate: "Beoordeling verwijderen"
reject_username: "Gebruikersnaam afwijzen"
rejected: Afgewezen
remove_ban: 'Verbanning verwijderen'
remove_suspension: 'Schorsing opheffen'
suspend: 'Gebruiker schorsen'
remove_ban: "Verbanning verwijderen"
remove_suspension: "Schorsing opheffen"
suspend: "Gebruiker schorsen"
suspended: Geschorst
total_comments: 'Totaal aantal reacties'
total_comments: "Totaal aantal reacties"
unreliable: Onbetrouwbaar
user_history: Accountgeschiedenis
user_karma_score: 'Gebruiker Karma Score'
user_karma_score: "Gebruiker Karma Score"
username: Gebruikersnaam
username_needs_approval: 'Gebruikersnaam heeft goedkeuring nodig'
username_rejected: 'Gebruikersnaam afgewezen'
username_needs_approval: "Gebruikersnaam heeft goedkeuring nodig"
username_rejected: "Gebruikersnaam afgewezen"
user_history:
action: Actie
ban_removed: 'Schorsing opgeheven'
ban_removed: "Schorsing opgeheven"
date: Datum
suspended: 'Geschorst, {0}'
suspension_removed: 'Schorsing opgeheven'
suspended: "Geschorst, {0}"
suspension_removed: "Schorsing opgeheven"
system: Systeem
taken_by: 'Genomen door'
user_banned: 'Gebruiker geschorst'
username_status: 'Gebruikersnaam {0}'
user_impersonating: 'Deze gebruiker doet zich voor als iemand anders'
user_no_comment: 'Je hebt nog niet eerder gereageerd. Laat je mening horen!'
username_offensive: 'Dit is een aanstootgevende gebruikersnaam.'
taken_by: "Genomen door"
user_banned: "Gebruiker geschorst"
username_status: "Gebruikersnaam {0}"
user_impersonating: "Deze gebruiker doet zich voor als iemand anders"
user_no_comment: "Je hebt nog niet eerder gereageerd. Laat je mening horen!"
username_offensive: "Dit is een aanstootgevende gebruikersnaam."
validators:
confirm_email: 'E-mailadressen komen niet overeen. Controleer opnieuw.'
confirm_email: "E-mailadressen komen niet overeen. Controleer opnieuw."
confirm_password: Wachtwoorden komen niet overeen. Controleer opnieuw.
required: 'Dit veld is verplicht'
verify_email: 'Geen geldig e-mailadres'
verify_organization_name: 'Organisatienaam kan alleen cijfers en letters bevatten.'
verify_password: 'Wachtwoord moet minimaal 8 karakters lang zijn'
verify_username: 'Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten.'
view_conversation: 'Bekijk conversatie'
your_account_has_been_banned: 'Je account is verbannen.'
your_account_has_been_suspended: 'Je account is tijdelijk geschorst.'
your_username_has_been_rejected: 'Je account is geschorst omdat we je gebruikersnaam ongepast vinden. Verander je gebruikersnaam om hem weer te activeren.'
required: "Dit veld is verplicht"
verify_email: "Geen geldig e-mailadres"
verify_organization_name: "Organisatienaam kan alleen cijfers en letters bevatten."
verify_password: "Wachtwoord moet minimaal 8 karakters lang zijn"
verify_username: "Gebruikersnamen kunnen alleen cijfers, letters en _ bevatten."
view_conversation: "Bekijk conversatie"
your_account_has_been_banned: "Je account is verbannen."
your_account_has_been_suspended: "Je account is tijdelijk geschorst."
your_username_has_been_rejected: "Je account is geschorst omdat we je gebruikersnaam ongepast vinden. Verander je gebruikersnaam om hem weer te activeren."
+576
View File
@@ -0,0 +1,576 @@
sr:
admin_sidebar:
sort_comments: 'Sortiranje komentara'
view_options: 'Opcije pregleda'
already_flagged_username: 'Već ste obilježili ovog korisnika'
bandialog:
are_you_sure: 'Jeste li sigurni da želite da banujete {0}?'
ban_user: 'Banuj korisnika'
banned_user: 'Banovan korisnik'
cancel: 'Otkaži'
email_message_ban: 'Poštovani {0},\n\nneko sa pristupom vašem nalogu je prekršio pravila komentarisanja. Zbog toga smo bili primorani da banujemo vaš nalog i više nećete moći da komentarišete, reagujete i prijavljujete komentare. Ukoliko smatrate da je došlo do greške, molim vas da kontaktirate naš tim'
note: 'Napomena: {0}'
note_ban_user: 'Banovanje ovog korisnika će onemogućiti komentarisanje, prijavljivanje i reagovanje na komentare.'
note_reject_comment: 'Banovanje ovog korisnika će staviti ovaj komentar na listu odbijeno'
notify_ban_description: 'Ovo će obavijestit korisnika putem e-maila da je njegov/njen nalog banovan'
notify_ban_headline: 'Obavijesti korisnika o banovanju'
send: 'Pošalji'
write_a_message: 'Napiši poruku'
yes_ban_user: 'Banuj koriniska'
bio_offensive: 'Ova biografija je neprimjerenog sadržaja.'
cancel: 'Otkaži'
characters_remaining: 'Preostali znakovi'
comment:
anon: 'Anoniman'
ban_user: 'Banuj korisnika'
comment: 'Postavi komentar'
edited: 'Izmijenjeno'
flagged: 'Obilježeno'
undo_reject: 'Prethodni korak'
view_context: 'Vidi kontekst'
comment_box:
cancel: 'Otkaži'
characters_remaining: 'Preostali znakovi'
comment: 'Postavi komentar'
comment_post_banned_word: 'Vaš komentar sadrži jednu ili više riječi koje nisu dozvoljene i neće biti objavljen. Ukoliko smatrate nije tako, molim vas kontaktirajte naš tim moderatora.'
comment_post_notif: 'Vaš komentar je postavljen'
comment_post_notif_premod: 'Hvala na objavi. Naš tim moderatora će ubrzo pregledati vaš komentar'
name: 'Ime'
post: 'Objava'
reply: 'Odgovori'
comment_history_blank:
info: 'Istorija vaših komentara će se prikazati ovdje'
title: 'Niste postavili nijedan komentar'
comment_offensive: 'Neprimjereno'
comment_plural: 'Komentari'
comment_post_banned_word: 'Vaš komentar sadrži jednu ili više riječi koje nisu dozvoljene i neće biti objavljen. Ukoliko smatrate nije tako, molim vas kontaktirajte naš tim moderatora.'
comment_post_notif: 'Vaš komentar je postavljen'
comment_post_notif_premod: 'Hvala na objavi. Naš tim moderatora će ubrzo pregledati vaš komentar'
comment_singular: 'Komentar'
common:
contains_link: 'Sadrži link'
copy: 'Kopiraj na tablu'
copied: 'Kopirano'
notsupported: 'Nije podržano'
error: 'Došlo je do greške'
reaction: 'Reakcija'
reactions: 'Reakcije'
reply: 'Odgovori'
replies: 'Odgovori'
story: 'Priča'
community:
account_creation_date: 'Datum kreiranja naloga'
active: 'Aktivan'
admin: 'Administrator'
ads_marketing: 'Ovo izgleda kao reklama'
all: 'Sve'
are_you_sure: 'Jeste li sigurni da želite da banujete {0}?'
ban_user: 'Banuj korisnika'
banned: 'Banovan'
banned_user: 'Banovan korisnik'
cancel: 'Otkaži'
commenter: 'Komentator'
dont_like_username: 'Ne sviđa mi se korisničko ime'
filter_users: 'Segmentiraj korisnike'
filter_role: 'Uloga'
flaggedaccounts: 'Prijavljena korisnička imena'
flags: 'Prijave'
impersonating: 'Korisnik se lažno predstavlja'
loading: 'Učitavanje rezultata'
moderator: 'Moderator'
newsroom_role: 'Uloga u redakciji'
no_flagged_accounts: 'Nema prijavljenih korisničkih naloga'
no_results: 'Nema rezultata'
offensive: 'Korisničko ime je neprimjereno'
other: 'Drugo'
people: 'Ljudi'
role: 'Izaberi ulogu'
select_status: 'Izaberi status'
spam_ads: 'Reklame'
staff: 'Član redakcije'
status: 'Status rasprave'
suspended: 'Suspendovan'
username_and_email: 'Korisničko ime i e-mail'
yes_ban_user: 'Banuj koriniska'
configure:
access_message: 'Morate biti administrator kako biste pristupili podešavanjima. Zamolite administratora da vam da tu ulogu'
apply: 'Primijeni'
banned_word_text: 'Komentari koji sadrže ove riječi ili fraze (a nijesu osjetljivi na veličinu slova) automatski će biti uklonjeni iz komentara. Unesite riječ i pritisnite Enter ili Tab da dodate. Opciono stavite listu sa odvojenu zarezima'
banned_words_title: 'Lista zabranjenih riječi'
close: 'Zatvori instalaciju'
close_after: 'Zatvori komentare poslije'
close_stream: 'Zatvori raspravu'
close_stream_configuration: 'Ova rasprava je trenutno zatvorena. Otvaranjem ove rasprave novi komentari mogu biti postavljani i prikazivani'
closed_comments_desc: 'Napišite poruku koja će se prikazati kada zatvorite vašu raspravu i kada ne prihvatate dalje komentare.'
closed_comments_label: 'Napiši poruku'
closed_stream_settings: 'Poruka za zatvaranje rasprave'
comment_count_error: 'Unesite validan broj'
comment_count_header: 'Ograniči dužinu komentara'
comment_count_text_post: 'Karakteri'
comment_count_text_pre: 'Komentari će biti ograničeni na'
comment_settings: 'Podešavanja'
comment_stream: 'Rasprava'
comment_stream_will_close: 'Rasprava će se zatvoriti'
community: 'Zajednica'
configure: 'Podesite'
copy_and_paste: 'Kopirajte i zalijepite ispod u CMS'
custom_css_url: 'Prilagođen CSS URL'
custom_css_url_desc: 'URL od CSS-a koji će da prepravi standardni stil ugrađivanja. Može biti interni ili eksterni?'
days: 'Dani'
description: 'Hvala što ste instalirali Talk! Poslali smo vam e-mail kako biste povrdili vašu e-mail adresu. Dok završavate podešavanje naloga, možete početi da komunicirate sa čitaocima.'
disable_commenting_desc: 'Napišite poruku koja će se prikazivati kada su komentari deaktivirani.'
disable_commenting_title: 'Deaktiviraj komentare na čitavom sajtu'
domain_list_text: 'Unesite domene koje biste želeli da dozvolite za Talk npr. vaše lokalno okruženje za postavljanje i proizvodnju (npr. localhost 3000 staging.domain.com domain.com)?'
domain_list_title: 'Dozvoljeni domeni'
edit_comment_timeframe_heading: 'Uredi vremenski okvir komentara'
edit_comment_timeframe_text_post: 'Sekunde za uređenje njihovih komentara'
edit_comment_timeframe_text_pre: 'Komentatori će imati'
edit_info: 'Uredi informacije'
embed_comment_stream: 'Ugradi raspravu'
enable_pre_moderation: 'Omogući moderiranje prije objave'
enable_pre_moderation_text: 'Moderatori moraju odobriti svaki komentar prije nego je objavljen'
enable_premod: 'Omogući moderiranje prije objave'
enable_premod_description: 'Moderatori moraju odobriti svaki komentar prije nego je objavljen'
enable_premod_links: 'Moderiraj komentare sa linkovima prije objave'
enable_premod_links_description: 'Moderatori moraju odobriti svaki komentar sa linkom prije nego je objavljen'
enable_premod_links_text: 'Moderatori moraju odobriti svaki komentar sa linkom prije nego je objavljen'
enable_questionbox: 'Pitaj čitaoce'
enable_questionbox_description: 'Ovo pitanje će se pojaviti na vrhu rasprave. Pitajte čitaoce o određenoj temi u članku ili postavite pitanja za diskusiju itd'
hours: 'Sati'
code_of_conduct_summary: 'Rezime Kodeksa Ponašanja'
code_of_conduct_summary_desc: 'Ova poruka će se pojaviti iznad svake rasprave na vašem sajtu. Kliknite ovdje da saznate više o pisanju dobrog koda.'
include_question_here: 'Napišite pitanje ovdje'
include_text: 'Ubacite tekst ovdje'
moderate: 'Moderiraj'
moderation_settings: 'Podešavanja moderacije'
open: 'Otvori'
open_stream: 'Otvori raspravu'
open_stream_configuration: 'Ovaj stream komentara trenutačno je otvoren. Zatvaranjem ovog komentarskog streama ne mogu se poslati novi komentari, a svi prethodni komentari i dalje će biti prikazani.'
organization_contact_email: 'Email organizacije nije validan'
organization_info_copy: 'Ove informacije se koriste u e-mailovima koje generiše Talk. Ovo povezuje poruke sa vašom organizacijom i pruža mogućnost korisnicima da vas kontaktiraju ako imaju problem sa svojim nalogom.'
organization_info_copy_2: 'Preporučujemo kreiranje generičkog email naloga (organizacija@organizacija.me) za ovu svrhu. Ovo znači da nalog može da traje a da ne izlaže konkretna imena ljudi koja bi bila podložna targetiranju korisnika ukoliko je njihov nalog blokian'
organization_information: 'Informacije o organizaciji'
organization_name: 'Ime organizacije može sadržati brojeve ili slova'
suspect_or_forbidden_words_placeholder: 'Riječ ili fraza'
product_guide_link: 'Priručnik'
report_bug_or_feedback: 'Prijavi grešku ili pošalji povratnu informaciju'
require_email_verification: 'Zahtijeva e-mail verifikaciju'
require_email_verification_text: 'Novi korisnici moraju verifikovati svoj e-mail prije mogućnosti postavljanja komentara'
save: 'Sačuvaj'
save_changes: 'Sačuvaj izmjene'
save_changes_dialog:
cancel: 'Otkaži'
copy: 'Kopiraj na tablu'
discard: 'Izbriši/Odbaci'
save_settings: 'Sačuvaj podešavanja'
unsaved_changes: 'Nesačuvane promjene'
shortcuts: 'Prečice'
sign_out: 'Odjavi se'
stories: 'Priče'
stream_settings: 'Podešavanje rasprave'
suspect_word_text: 'Komentari koji sadrže ove riječi ili fraze (a nijesu osjetljivi na veličinu slova) automatski će biti uklonjeni iz komentara. Unesite riječ i pritisnite Enter ili Tab da dodate. Opciono stavite listu sa odvojenu zarezima'
suspect_word_title: 'Lista sumnjivih riječi'
tech_settings: 'Tehnička podešavanja'
title: 'Niste postavili nijedan komentar'
view_last_version: 'Vidi poslednju verziju'
weeks: 'Nedelje'
wordlist: 'Banovane riječi'
confirm_email:
click_to_confirm: 'Kliknite ispod da potvrdite Vašu e-mail adresu'
confirm: 'Potvrdi'
email_confirmation: 'E-mail potvrda'
continue: 'Nastavi'
createdisplay:
check_the_form: 'Nevažeća forma. Molim vas provjerite polja'
continue: 'Nastavi'
error_create: 'Greška u promjeni korisničkog imena'
fake_comment_body: 'Ovo je primjer komentara. Čitaoci mogu da podijele stavove i komuniciraju sa redakcijom u sekciji komentara'
fake_comment_date: 'Prije minut'
if_you_dont_change_your_name: 'Ako ne promijenite svoje korisničko ime na ovom koraku, vaše ime na Facebook-u će se pojaviti zajedno sa svim Vašim komentarima'
required_field: 'Obavezno polje'
save: 'Sačuvaj'
special_characters: 'Korisničko ime može da sadrži slova, brojeve i'
username: 'Korisničko ime mora sadržati slova, brojeve I _ samo'
write_your_username: 'Izmijeni svoje korisničko ime'
your_username: 'Vaše korisničko ime se pojavljuje u svakom komentaru koji napišete'
done: 'Završeno'
edit_comment:
body_input_label: 'Izmijeni komentar'
edit_window_expired: 'Vrijeme je isteklo i ovaj komentar se više ne može izmijeniti. Zašto ne postavite novi komentar?'
edit_window_expired_close: 'Zatvori'
edit_window_timer_prefix: 'Uredi prozor'
minute: 'Minut'
minutes_plural: 'Minuti'
save_button: 'Sačuvaj izmjene'
second: 'Sekund'
seconds_plural: 'Sekunde'
email:
banned:
body: 'Svaš nalog je banovan. Više vam nije dozvoljeno da komentarišete, prijavljujete i budete dio zajednice'
subject: 'Potvrda e-maila'
confirm:
confirm_email: 'Email adrese se ne podudaraju, probajte ponovo'
has_been_requested: 'Potvrda e-mail adrese je neophodna za ovaj nalog'
if_you_did_not: 'Ukoliko niste ovo zahtijevali, ignorišite ovaj e mail.'
subject: 'Potvrda e-maila'
to_confirm: 'Da aktivirate nalog, posjetite sljedeći link:'
password_change:
body: 'Lozinka za vaš nalog je promjenjena.\n\nUkoliko niste vi zatražili ovu promjenu, molimo kontaktirajte nas {0}.'
subject: '{0} promena lozinke'
password_reset:
if_you_did: 'Ako jeste'
please_click: 'Kliknite ovdje da obnovite šifru'
subject: 'Potvrda e-maila'
we_received_a_request: 'Primili smo vaš zahtjev za obnovu šifre. Ukoliko niste tražili ovu promjenu, ignorišite ovaj mail.'
suspended:
subject: 'Potvrda e-maila'
embed_comments_tab: 'Komentari'
embedlink:
copy: 'Kopiraj na tablu'
copied: 'Kopirano'
error:
ALREADY_EXISTS: 'Resurs već postoji'
AUTHENTICATION: 'Došlo je do greške prilikom potvrde vašeg naloga.'
CANNOT_IGNORE_STAFF: 'Ne možete ignorisati članove redakcije.'
COMMENT_PARENT_NOT_VISIBLE: 'Komentar na koji odgovarate je uklonjen ili ne postoji'
COMMENT_TOO_SHORT: 'Komentar mora sadržati više od jednog znaka. Molimo vas izmijenite vaš komentar i pokušajte ponovo'
COMMENT_TOO_LONG: 'Komentar je predugačak'
COMMENTING_CLOSED: 'Komentarisanje je zatvoreno'
COMMENTING_DISABLED: 'Komentarisanje trenutno nije moguće na sajtu.'
confirm_password: 'Potvrdi šifru'
DELETION_NOT_SCHEDULED: 'Brisanje nije zakazano.'
EDIT_USERNAME_NOT_AUTHORIZED: 'Nemate dozvolu da izmijenite vaše korisiničko ime.'
EDIT_WINDOW_ENDED: 'Ne možete izmijeniti komentar, vrijeme je isteklo'
email: 'Molimo Vas unesite validan e-mail'
EMAIL_ALREADY_VERIFIED: 'E-mail adresa je već potvrđena.'
EMAIL_IN_USE: 'E-mail adresa je već u upotrebi'
email_not_verified: 'E-mail adresa nije potvrđena.'
EMAIL_NOT_VERIFIED: 'E-mail adresa nije potvrđena.'
email_password: 'E-mail i/ili šifra se ne podudaraju'
EMAIL_REQUIRED: 'Obavezna e-mail adresa'
EMAIL_VERIFICATION_TOKEN_INVALID: 'Šifra potvrde maila nije validna'
INCORRECT_PASSWORD: 'Pogrešna šifra'
INVALID_ASSET_URL: 'Istaknuti URL nije validan'
LOGIN_MAXIMUM_EXCEEDED: 'Ukucali ste pogrešnu šifru previše puta. Molimo sačekajte.'
network_error: 'Nemoguće povezivanje sa serverom. Provjerite konekciju i pokušajte ponovo'
NO_SPECIAL_CHARACTERS: 'Korisničko ime može samo sadržati slova, brojeve i _'
NOT_AUTHORIZED: 'Nemate dozvolu da sprovedete akciju'
NOT_FOUND: 'Podatak nije pronađen'
organization_contact_email: 'Email organizacije nije validan'
organization_name: 'Ime organizacije može sadržati brojeve ili slova'
password: 'Šifra mora sadržati minimum 8 karaktera'
PAGE_NOT_AVAILABLE_ROLE: 'Ovu stranicu mogu koristiti samo članovi redakcije. Molimo kontaktirajte administratora ukoliko želite da se priključite timu'
PASSWORD_INCORRECT: 'Pogrešno ste unijeli šifru'
PASSWORD_LENGTH: 'Šifra je prekratka'
PASSWORD_REQUIRED: 'Obavezno unijeti šifru'
PASSWORD_RESET_TOKEN_INVALID: 'Link za resetovanje šifre je nevažeći'
PROFANITY_ERROR: 'Korisničko ime ne može sadržati psovke. Kontaktirajte administratora ukoliko smatrate da je u pitanju greška'
RATE_LIMIT_EXCEEDED: 'Premašeno je ograničenje'
required_field: 'Obavezno polje'
SAME_USERNAME_PROVIDED: 'Morate izabrati drugo korisničko ime'
temporarily_suspended: 'U skladu sa pravilima naše zajednice, vaš nalog je privremeno suspendovan. Molimo vas da se ponovo uključite u razgovor.'
unexpected: 'Došlo je do greške. Izvinite.'
username: 'Korisničko ime mora sadržati isključivo slova, brojeve i _'
USERNAME_IN_USE: 'Korisničko ime je već u upotrebi'
USERNAME_REQUIRED: 'Morate unijeti korisničko ime'
flag_comment: 'Prijavi komentar'
flag_reason: 'Razlog prijave (opciono)'
flag_reasons:
username:
impersonating: 'Korisnik se lažno predstavlja'
nolike: 'Ne dopada mi se korisničko ime'
offensive: 'Korisničko ime je neprimjereno'
other: 'Drugo'
spam: 'Ovo izgleda kao reklama/marketing'
flag_username: 'Prijavi korisničko ime'
flagged_usernames:
notify_approved: '{0} je odobrio korisničko ime {1}'
notify_changed: 'Korisnik {0} je promijenio korisničko ime u {1}'
notify_flagged: '{0} je prijavio korisničko ime {1}'
notify_rejected: '{0} je odbio korisničko ime {1}'
flags:
reasons:
comment:
banned_word: 'Banovana riječ'
comment_noagree: 'Nisam saglasan'
comment_offensive: 'Neprimjereno'
comment_other: 'drugo'
comment_spam: 'spam'
links: 'link'
suspect_word: 'Neprimjerena riječ'
trust: 'karma'
user:
username_impersonating: 'Lažno predstavljanje'
username_nolike: 'ne dopada mi se'
username_offensive: 'Korisničko ime je neprimjereno.'
username_other: 'drugo'
username_spam: 'spam'
framework:
banned_account_body: 'To znači da ne možete reagovati, prijavljivati ili pisati komentare'
banned_account_header: 'Vaš nalog je trenutno banovan'
changed_name:
msg: 'Izmjena vašeg korisničkog imena prolazi provjeru našeg tima moderatora'
comment: 'Postavi komentar'
comment_is_deleted: 'Korisnik je izbrisao nalog'
comment_is_hidden: 'Komentar nije dostupan'
comment_is_ignored: 'Komentar je skriven, jer ste ignorisali korisnika'
comment_is_rejected: 'Odbili ste komentar'
comments: 'Komentari'
configure_stream: 'Podesi'
content_not_available: 'Sadržaj nije dostupan'
edit: 'Izmijeni'
edit_name:
button: 'Podnesi'
error: 'Došlo je do greške'
label: 'Novo korisničko ime'
msg: 'Izmjena vašeg korisničkog imena prolazi provjeru našeg tima moderatora'
my_comments: 'Moji komentari'
my_profile: 'Moj profil'
new_count: 'Vidi još {0} / {1}'
profile: 'Nalog'
show_all_comments: 'Prikaži sve komentare'
show_all_replies: 'Prikaži sve odgovore'
show_more_replies: 'Prikaži još odgovora'
success_bio_update: 'Vaša biografija je izmijenjena'
success_name_update: 'Vaše korisničko ime je izmijenjeno'
success_update_settings: 'Promjene koje ste unijeli su primijenjene na raspravu na ovom članku.'
view_more_comments: 'Vidi još komentara'
view_reply: 'vidi odgovor'
from_settings_page: 'Na profilu možete vidjeti istoriju komentara'
install:
add_organization:
description: 'Hvala što ste instalirali Talk! Poslali smo vam e-mail kako biste povrdili vašu e-mail adresu. Dok završavate podešavanje naloga, možete početi da komunicirate sa čitaocima.'
label: 'Novo korisničko ime'
save: 'Sačuvaj'
create:
confirm_password: 'Potvrdi šifru'
email: 'Molimo Vas unesite validan e-mail'
organization_contact_email: 'Email organizacije nije validan'
password: 'Šifra mora sadržati minimum 8 karaktera'
save: 'Sačuvaj'
username: 'Korisničko ime mora sadržati isključivo slova, brojeve i _'
final:
close: 'Zatvori instalaciju'
description: 'Hvala što ste instalirali Talk! Poslali smo vam e-mail kako biste povrdili vašu e-mail adresu. Dok završavate podešavanje naloga, možete početi da komunicirate sa čitaocima.'
launch: 'Pokreni Talk'
initial:
description: 'Hvala što ste instalirali Talk! Poslali smo vam e-mail kako biste povrdili vašu e-mail adresu. Dok završavate podešavanje naloga, možete početi da komunicirate sa čitaocima.'
submit: 'Počni'
permitted_domains:
description: 'Hvala što ste instalirali Talk! Poslali smo vam e-mail kako biste povrdili vašu e-mail adresu. Dok završavate podešavanje naloga, možete početi da komunicirate sa čitaocima.'
submit: 'Počni'
title: 'Niste postavili nijedan komentar'
like: 'Dopada mi se'
loading_results: 'rezultati se učitavaju'
login:
email_address: 'e-mail adresa'
forgot_password: 'Zaboravili ste šifru?'
go_back: 'Vrati se'
sign_in: 'Prijavi se'
sign_in_button: 'Dugme za prijavu'
sign_in_message: 'Prijavi se kako bi komunikacirao sa zajednicom'
password: 'Šifra mora sadržati minimum 8 karaktera'
reset_password_send_button: 'povrati šifru'
request_passowrd: 'Zahtijevaj novu šifru'
team_sign_in: 'Prijava tima'
marketing: 'Ovo izgleda kao reklama/marketing'
moderate_all_streams: 'Moderiraj komentare na svim pričama'
moderate_this_stream: 'Moderiraju ovu raspravu'
modqueue:
account: 'Prijave naloga'
actions: 'akcije'
all: 'Sve'
all_streams: 'Sve rasprave'
approve: 'Odobri'
approved: 'Odobreno'
ban_user: 'Banuj korisnika'
ban_user_actions: 'Banuj korisničke akcije'
billion: 'Milijardi'
close: 'Zatvori instalaciju'
empty_queue: 'Nema više komentara za moderiranje.'
flagged: 'Obilježeno'
jump_to_queue: 'Preskoči na red'
less_detail: 'Manje detalja'
likes: 'Sviđanja'
million: 'milion'
mod_faster: 'Moderiraj brže uz prečice na tastaturi'
moderate: 'Moderiraj'
more_detail: 'Više detalja'
navigation: 'navigacija'
new: 'novo'
newest_first: 'Prvo najnoviji'
next_comment: 'Idi na sljedeći komentar'
next_queue: 'Preskoči red'
notify_accepted: '{0} je prihvatio komentar "{1}"'
notify_edited: '{0} je izmjenio komentar "{1}"'
notify_flagged: '{0} je označio komentar "{1}"'
notify_rejected: '{0} je odbio komentar "{1}"'
notify_reset: '{0} je resetovao status komentara "{1}"'
oldest_first: 'Prvo najstariji'
premod: 'mod pre-moderacija'
prev_comment: 'idi na prethodni komentar'
reject: 'Odbij'
rejected: 'Odbijen'
reply: 'Odgovori'
reported: 'Prijavljen'
select_stream: 'Odaberi raspravu'
shift_key: '⇧'
shortcuts: 'Prečice'
show_shortcuts: 'Prikaži prečice'
singleview: 'Zen stanje'
sort: 'Sortiraj'
suspend: 'Suspenduj korisnika'
system_withheld: 'Zadržan u sistemu'
thismenu: 'Otvori meni'
thousand: 'hiljada'
toggle_search: 'Otvori pretragu'
try_these: 'Pokušaj ovo'
view_more_shortcuts: 'Vidi dodatne prečice'
my_comment_history: 'Istorija komentara'
name: 'Ime'
no_agree_comment: 'Nisam saglasan sa ovim komentarom'
no_like_bio: 'Ne dopada mi se ova biografija'
no_like_username: 'Ne dopada mi se ovo korisničko ime'
other: 'Drugo'
password_reset:
change_password: 'Promijeni šifru'
change_password_help: 'Unesite novu šifru za prijavu. Vodite računa da je šifra bezbjedna'
confirm_new_password: 'Potvrdite novu šifru'
mail_sent: 'Ukoliko imate registrovan nalog, link za resetovanje šifre je poslat na email'
new_password: 'Nova šifra'
new_password_help: 'Šifra mora sadržati minimum 8 znakova'
set_new_password: 'Promijeni šifru'
permalink: 'Podijeli'
personal_info: 'Ovaj komentar sadrži lične informacije'
post: 'Objava'
profile: 'Nalog'
profile_settings: 'Podešavanja naloga'
reject_username:
description_notify: 'Suspendovanje korisnika će im privremeno onemogućiti nalog'
description_reject: 'Da li želite da privremeno banujete ovog korisnika? Ukoliko to učinite, korisnik će biti suspendovan dok ne izmijeni'
email_message_reject: 'Član zajednice je zatražio provjeru vašeg korisničkog imena. Zbog tog sadržaja je vaše korisničko ime odbijeno. To znači da ne možete komentarisati, označavati i reagovati na komentare dok ne promijenite korisničko ime. Molimo da pošaljete e-mail ako imate komentare ili primjedbe.'
no_cancel: 'Ne poništavaj'
send: 'Pošalji'
suspend_user: 'Suspenduj korisnika'
title_notify: 'Obavijesti korisnika o privremenoj suspenziji'
title_reject: 'Primijetili smo da ste odbili korisničko ime'
username: 'Korisničko ime mora sadržati slova, brojeve I _ samo'
write_message: 'Napiši poruku'
yes_suspend: 'Potvrdi suspenziju'
reject_username_dialog:
cancel: 'Otkaži'
description: 'Hvala što ste instalirali Talk! Poslali smo vam e-mail kako biste povrdili vašu e-mail adresu. Dok završavate podešavanje naloga, možete početi da komunicirate sa čitaocima.'
message: 'Razlog prijave (opciono)'
reason: 'Razlog'
reject_username: 'Odbij korisničko ime'
title: 'Niste postavili nijedan komentar'
reply: 'Odgovori'
report: 'Prijavi'
report_notif: 'Hvala što ste prijavili komentar. Naš tim je obaviješten i provjera će biti izvršena brzo.'
report_notif_remove: 'Vaša prijava je uklonjena'
reported: 'Prijavljen'
settings:
from_settings_page: 'Na profilu možete vidjeti istoriju komentara'
my_comment_history: 'Istorija komentara'
profile: 'Nalog'
profile_settings: 'Podešavanja naloga'
sign_in: 'Prijavi se'
to_access: 'Pristupi nalogu'
user_no_comment: 'Nikada niste napisali komentar. Priključite se raspravi.'
step_1_header: 'Prijavi problem'
step_2_header: 'Pomozite nam da razumijemo'
step_3_header: 'Hvala na informaciji'
stream:
all_comments: 'Svi komentari'
comment_not_found: 'Komentar je uklonjen ili ne postoji'
no_comments: 'Još uvijek nema komentara. Zašto ne napišete nešto?'
no_comments_and_closed: 'Nema komenatara za ovaj članak'
temporarily_suspended: 'U skladu sa pravilima naše zajednice, vaš nalog je privremeno suspendovan. Molimo vas da se ponovo uključite u razgovor.'
streams:
all: 'Sve'
article: 'Priča'
closed: 'Zatvoreno'
empty_result: 'Nema rezultata pretrage. Pokušajte da proširite pretragu.'
filter_streams: 'Filteruj rasprave'
most_recent_stories: 'Najnovije priče'
newest: 'Najnovije'
no_results: 'Nema rezultata'
oldest: 'Najstarije'
open: 'Otvori'
pubdate: 'Datum objave'
search: 'Pretraga'
search_results: 'Rezultati pretrage'
sort_by: 'Sortiraj po'
status: 'Status rasprave'
stream_status: 'Status rasprave'
suspenduser:
cancel: 'Otkaži'
day: '{0} dana'
days: '{0} dana'
description_notify: 'Suspendovanje korisnika će im privremeno onemogućiti nalog'
description_suspend: 'Suspendujete {0}. Ovaj komentar će ići na spisak odbijenih komentare i neće moći da postavlja, odgovara i prijavljuje komentare dok ne istekne suspenzija.'
email_message_suspend: 'Poštovani {0},\n\nu skladu sa {1} pravilima komentarisanja, vaš nalog je trenutno suspendovan. Tokom suspenzije ne možete da komentarišete i imate interakciju sa ostalim komentatorima. Molimo da se vratite raspravi {2}.'
hour: '{0} sat'
hours: '{0} sati'
notify_suspend_until: 'Korisnik {0} je privremeno suspendovan. Suspenzija će se automatski okončati'
one_hour: 'Sat vremena'
select_duration: 'odaberi trajanje suspenzije'
send: 'Pošalji'
suspend_user: 'Suspenduj korisnika'
title_notify: 'Obavijesti korisnika o privremenoj suspenziji'
title_suspend: 'Suspenduj korisnika'
write_message: 'Napiši poruku'
thank_you: 'Cijenimo vašu povratnu reakciju i vašu bezbjedost. Moderator će ukoro pogledati vašu prijavu'
user:
bio_flags: 'Prijave za ovu biografiju.'
user_bio: 'Korisnička biografija'
username_flags: 'Prijave za ovo korisničko ime'
user_detail:
all: 'Sve'
ban: 'Banuj korisnika'
banned: 'Banovan'
email: 'Molimo Vas unesite validan e mail'
id: 'ID'
karma: 'karma'
karma_docs_link: 'https://docs.coralproject.net/talk/trust/#user-karma-score'
learn_more: 'Saznaj više'
member_since: 'Član od'
reject_rate: 'Odbijanja'
reject_username: 'Odbij korisničko ime'
rejected: 'Odbijen'
remove_ban: 'Ukloni ban'
remove_suspension: 'Ukloni suspenziju'
suspend: 'Suspenduj korisnika'
suspended: 'Suspendovan'
total_comments: 'Svi komentari'
unreliable: 'Nepouzdano'
user_history: 'Istorija korisnika'
user_karma_score: 'Karma poeni'
username: 'Korisničko ime mora sadržati isključivo slova, brojeve i _ '
username_needs_approval: 'Potrebno odobrenje korisničkog imena'
username_rejected: 'Korisničko ime odbijeno'
user_history:
action: 'Akcija'
ban_removed: 'Zabrana uklonjena'
date: 'Datum'
suspended: 'Suspendovan, {0}'
suspension_removed: 'Suspenzija uklonjena'
system: 'Sistem'
taken_by: 'Preduzeo'
user_banned: 'Korisnik banovan'
username_status: 'Korisnik {0}'
user_impersonating: 'Korisnik se lažno predstavlja'
user_no_comment: 'Nikada niste napisali komentar. Priključite se raspravi.'
username_offensive: 'Korisničko ime je neprimjereno.'
validators:
confirm_email: 'Email adrese se ne podudaraju, probajte ponovo'
confirm_password: 'Potvrdi šifru'
required: 'polje je obavezno'
verify_email: 'Unesite validan e mail'
verify_organization_name: 'Ime organizacije mora sadržati samo slova ili brojeve'
verify_password: 'Šifra mora imati makar 8 znakova'
verify_username: 'Korisničko ime može sadržati isključivo slova, brojeve i _'
view_conversation: 'Vidi razgovor'
your_account_has_been_banned: 'Vaš nalog je banovan'
your_account_has_been_suspended: 'Vaš nalog je privremeno suspendovan'
your_username_has_been_rejected: 'Vaš nalog je suspendovan jer je korisničko ime označeno kao neprikladno. Da povratite nalog, unesite novo korisničko ime'
+11 -2
View File
@@ -12,6 +12,8 @@ const {
STATIC_ORIGIN,
} = require('../url');
const { PORT } = require('../config');
const { RECAPTCHA_PUBLIC, WEBSOCKET_LIVE_URI } = require('../config');
// Grab TALK_CLIENT_* environment variables.
@@ -42,6 +44,7 @@ const TEMPLATE_LOCALS = {
MOUNT_PATH,
STATIC_URL,
TALK_CLIENT_ENV,
PORT,
data: TALK_CLIENT_ENV,
};
@@ -96,12 +99,18 @@ const createResolveFactory = (() => {
module.exports = async (req, res, next) => {
try {
// Attach the custom css url and organization name.
const { customCssUrl, organizationName } = await SettingsService.select(
// Attach the custom css urls and organization name.
const {
customCssUrl,
customAdminCssUrl,
organizationName,
} = await SettingsService.select(
'customCssUrl',
'customAdminCssUrl',
'organizationName'
);
res.locals.customCssUrl = customCssUrl;
res.locals.customAdminCssUrl = customAdminCssUrl;
res.locals.organizationName = organizationName;
} catch (err) {
console.warn(err);
+4
View File
@@ -81,6 +81,10 @@ Asset.index(
}
);
// Indexes for listing the assets on the admin page.
Asset.index({ created_at: -1, publication_date: -1 }, { background: true });
Asset.index({ created_at: 1, publication_date: 1 }, { background: true });
/**
* Returns true if the asset is closed, false else.
*/
+4
View File
@@ -28,6 +28,10 @@ const Setting = new Schema(
type: String,
default: '',
},
customAdminCssUrl: {
type: String,
default: '',
},
infoBoxContent: {
type: String,
default: '',
+45
View File
@@ -180,6 +180,30 @@ const User = new Schema(
},
],
},
// alwaysPremod stores the current user premod status as well as the history of
// changes.
alwaysPremod: {
// Status stores the current user premod status.
status: {
type: Boolean,
required: true,
default: false,
index: true,
},
history: [
{
// Status stores the historical premod status.
status: Boolean,
// assigned_by stores the user id of the user who assigned this status.
assigned_by: { type: String, default: null },
// created_at stores the date when this status was assigned.
created_at: { type: Date, default: Date.now },
},
],
},
},
// IgnoresUsers is an array of user id's that the current user is ignoring.
@@ -359,6 +383,27 @@ User.virtual('banned')
});
});
/**
* alwaysPremod returns true when the user is currently in always premod, and sets the alwaysPremod
* status locally.
*/
User.virtual('alwaysPremod')
.get(function() {
return this.status.alwaysPremod.status;
})
.set(function(status) {
this.status.alwaysPremod.status = status;
if (!this.status.alwaysPremod.history) {
this.status.alwaysPremod.history = [];
}
this.status.alwaysPremod.history.push({
status,
created_at: new Date(),
});
});
/**
* suspended returns true when the user is currently suspended, and sets the
* suspension status locally.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "talk",
"version": "4.7.0",
"version": "4.9.1",
"description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net",
"main": "app.js",
"private": true,
+1
View File
@@ -7,6 +7,7 @@ module.exports = {
EDIT_COMMENT: 'EDIT_COMMENT',
SET_USER_USERNAME_STATUS: 'SET_USER_USERNAME_STATUS',
SET_USER_BAN_STATUS: 'SET_USER_BAN_STATUS',
SET_USER_ALWAYS_PREMOD_STATUS: 'SET_USER_ALWAYS_PREMOD_STATUS',
SET_USER_SUSPENSION_STATUS: 'SET_USER_SUSPENSION_STATUS',
SET_COMMENT_STATUS: 'SET_COMMENT_STATUS',
ADD_COMMENT_TAG: 'ADD_COMMENT_TAG',
+1
View File
@@ -47,6 +47,7 @@ module.exports = (user, perm) => {
case types.SET_USER_USERNAME_STATUS:
case types.SET_USER_BAN_STATUS:
case types.SET_USER_SUSPENSION_STATUS:
case types.SET_USER_ALWAYS_PREMOD_STATUS:
case types.UPDATE_ASSET_SETTINGS:
case types.UPDATE_ASSET_STATUS:
return check(user, ['ADMIN', 'MODERATOR']);
+22 -6
View File
@@ -1,26 +1,42 @@
{
"server": [
"talk-plugin-featured-comments",
"talk-plugin-local-auth",
"talk-plugin-featured-comments",
"talk-plugin-respect",
"talk-plugin-rich-text",
"talk-plugin-profile-data",
"talk-plugin-respect"
"talk-plugin-notifications",
"talk-plugin-notifications-category-featured",
"talk-plugin-notifications-category-moderation-actions",
"talk-plugin-notifications-category-reply",
"talk-plugin-notifications-category-staff",
"talk-plugin-notifications-digest-hourly",
"talk-plugin-notifications-digest-daily"
],
"client": [
"talk-plugin-auth",
"talk-plugin-local-auth",
"talk-plugin-author-menu",
"talk-plugin-featured-comments",
"talk-plugin-flag-details",
"talk-plugin-ignore-user",
"talk-plugin-local-auth",
"talk-plugin-member-since",
"talk-plugin-moderation-actions",
"talk-plugin-permalink",
"talk-plugin-profile-data",
"talk-plugin-respect",
"talk-plugin-rich-text",
"talk-plugin-viewing-options",
"talk-plugin-sort-most-replied",
"talk-plugin-sort-most-respected",
"talk-plugin-sort-newest",
"talk-plugin-sort-oldest",
"talk-plugin-viewing-options"
"talk-plugin-profile-data",
"talk-plugin-notifications",
"talk-plugin-notifications-category-featured",
"talk-plugin-notifications-category-moderation-actions",
"talk-plugin-notifications-category-reply",
"talk-plugin-notifications-category-staff",
"talk-plugin-notifications-digest-hourly",
"talk-plugin-notifications-digest-daily",
"talk-plugin-ignore-user"
]
}
@@ -42,6 +42,21 @@ en:
reasons:
comment:
spam_comment: "Detected Spam"
sr:
error:
COMMENT_IS_SPAM: |
Sadržaj ovog komentara liči na spam. Možete
urediti komentar, ili ga svejedno poslati moderatoru na odobrenje.
talk-plugin-akismet:
spam: "Spam"
spam_comment: "Spam"
detected: "Detected by Akismet"
still_spam: |
Hvala Vam. Naš tim moderatora će uskoro prgeldati vš komentar.
flags:
reasons:
comment:
spam_comment: "Detected Spam"
es:
error:
COMMENT_IS_SPAM: |
@@ -72,6 +87,36 @@ fr:
reasons:
comment:
spam_comment: "Detected Spam"
he:
error:
COMMENT_IS_SPAM: |
תגובה זו נראית כמו ספאם.
תוכל לערוך את התגובה או לשלוח אותה בכל מקרה לביקורת של מפקח.
talk-plugin-akismet:
spam: "ספאם"
spam_comment: "ספאם"
detected: "זוהה על ידי אקיזמט"
still_spam: |
תודה. צוות הפיקוח שלנו יבחן את התגובה שלך בקרוב.
flags:
reasons:
comment:
spam_comment: "זוהה ספאם"
it:
error:
COMMENT_IS_SPAM: |
Il linguaggio in questo commento sembra spam. Puoi
modificare il commento o sottometterlo alla revisione dei moderatori.
talk-plugin-akismet:
spam: "Spam"
spam_comment: "Spam"
detected: "Rilevato da Akismet"
still_spam: |
Grazie. Il nostro team di moderatori revisionerà il tuo commento a breve.
flags:
reasons:
comment:
spam_comment: "Rilevata spam"
nl_NL:
error:
COMMENT_IS_SPAM: |

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