decidim-comments 0.22.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/decidim/comments/bundle.js +53 -53
  3. data/app/assets/javascripts/decidim/comments/bundle.js.map +1 -1
  4. data/app/cells/decidim/comments/comment_activity_cell.rb +2 -22
  5. data/app/cells/decidim/comments/comment_cell.rb +22 -0
  6. data/app/cells/decidim/comments/comment_m/footer.erb +5 -0
  7. data/app/cells/decidim/comments/comment_m/top.erb +7 -0
  8. data/app/cells/decidim/comments/comment_m_cell.rb +29 -0
  9. data/app/commands/decidim/comments/create_comment.rb +1 -1
  10. data/app/forms/decidim/comments/comment_form.rb +8 -1
  11. data/app/frontend/comments/add_comment_form.component.test.tsx +30 -28
  12. data/app/frontend/comments/add_comment_form.component.tsx +32 -16
  13. data/app/frontend/comments/comment.component.test.tsx +35 -4
  14. data/app/frontend/comments/comment.component.tsx +24 -15
  15. data/app/frontend/comments/comment_thread.component.test.tsx +9 -8
  16. data/app/frontend/comments/comment_thread.component.tsx +3 -1
  17. data/app/frontend/comments/comments.component.test.tsx +17 -14
  18. data/app/frontend/comments/comments.component.tsx +28 -4
  19. data/app/frontend/comments/down_vote_button.component.tsx +24 -9
  20. data/app/frontend/comments/up_vote_button.component.tsx +24 -9
  21. data/app/frontend/mutations/add_comment.mutation.graphql +2 -2
  22. data/app/frontend/mutations/down_vote.mutation.graphql +2 -2
  23. data/app/frontend/mutations/up_vote.mutation.graphql +2 -2
  24. data/app/frontend/queries/comments.query.graphql +2 -2
  25. data/app/frontend/support/schema.ts +1060 -735
  26. data/app/helpers/decidim/comments/comment_cells_helper.rb +33 -0
  27. data/app/models/decidim/comments/comment.rb +73 -20
  28. data/app/models/decidim/comments/seed.rb +1 -1
  29. data/app/types/decidim/comments/commentable_interface.rb +1 -1
  30. data/app/types/decidim/comments/commentable_mutation_type.rb +4 -1
  31. data/config/locales/am-ET.yml +1 -0
  32. data/config/locales/bg.yml +6 -0
  33. data/config/locales/ca.yml +1 -0
  34. data/config/locales/cs.yml +1 -0
  35. data/config/locales/da.yml +1 -0
  36. data/config/locales/en.yml +1 -0
  37. data/config/locales/eo.yml +1 -0
  38. data/config/locales/es-MX.yml +1 -0
  39. data/config/locales/es-PY.yml +1 -0
  40. data/config/locales/es.yml +3 -2
  41. data/config/locales/et.yml +1 -0
  42. data/config/locales/fi-plain.yml +1 -0
  43. data/config/locales/fi.yml +2 -1
  44. data/config/locales/fr-CA.yml +2 -1
  45. data/config/locales/fr.yml +2 -1
  46. data/config/locales/hr.yml +1 -0
  47. data/config/locales/hu.yml +1 -1
  48. data/config/locales/is-IS.yml +0 -2
  49. data/config/locales/is.yml +76 -0
  50. data/config/locales/ja-JP.yml +2 -2
  51. data/config/locales/ja.yml +121 -0
  52. data/config/locales/ko-KR.yml +1 -0
  53. data/config/locales/ko.yml +1 -0
  54. data/config/locales/lt.yml +1 -0
  55. data/config/locales/{lv-LV.yml → lv.yml} +0 -0
  56. data/config/locales/mt.yml +1 -0
  57. data/config/locales/nl.yml +3 -2
  58. data/config/locales/om-ET.yml +1 -0
  59. data/config/locales/pl.yml +5 -5
  60. data/config/locales/so-SO.yml +1 -0
  61. data/config/locales/sv.yml +1 -0
  62. data/config/locales/ti-ER.yml +1 -0
  63. data/config/locales/uk.yml +0 -1
  64. data/config/locales/vi-VN.yml +1 -0
  65. data/config/locales/vi.yml +1 -0
  66. data/config/locales/zh-CN.yml +121 -0
  67. data/config/locales/zh-TW.yml +1 -0
  68. data/db/migrate/20200706123136_make_comments_handle_i18n.rb +41 -0
  69. data/db/migrate/20200828101910_add_commentable_counter_cache_to_comments.rb +9 -0
  70. data/lib/decidim/comments/api/comment_type.rb +5 -1
  71. data/lib/decidim/comments/comment_serializer.rb +7 -2
  72. data/lib/decidim/comments/comment_vote_serializer.rb +5 -1
  73. data/lib/decidim/comments/commentable.rb +11 -0
  74. data/lib/decidim/comments/comments_helper.rb +28 -4
  75. data/lib/decidim/comments/engine.rb +13 -0
  76. data/lib/decidim/comments/mutation_extensions.rb +8 -0
  77. data/lib/decidim/comments/query_extensions.rb +4 -0
  78. data/lib/decidim/comments/test/factories.rb +10 -1
  79. data/lib/decidim/comments/test/shared_examples/comment_event.rb +1 -1
  80. data/lib/decidim/comments/version.rb +1 -1
  81. metadata +37 -11
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Comments
5
+ # Custom helpers for comments cells.
6
+ #
7
+ module CommentCellsHelper
8
+ def renderable?
9
+ comment.present? && root_commentable.present?
10
+ end
11
+
12
+ def resource_link_text
13
+ comment.formatted_body
14
+ end
15
+
16
+ def resource_link_path
17
+ return root_commentable.polymorphic_resource_path(url_params) if root_commentable&.respond_to?(:polymorphic_resource_path)
18
+
19
+ resource_locator(root_commentable).path(url_params)
20
+ end
21
+
22
+ delegate :root_commentable, to: :comment
23
+
24
+ def root_commentable_title
25
+ decidim_html_escape(translated_attribute(root_commentable.title))
26
+ end
27
+
28
+ def url_params
29
+ { commentId: comment.id }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -13,6 +13,9 @@ module Decidim
13
13
  include Decidim::DataPortability
14
14
  include Decidim::Traceable
15
15
  include Decidim::Loggable
16
+ include Decidim::Searchable
17
+ include Decidim::TranslatableResource
18
+ include Decidim::TranslatableAttributes
16
19
 
17
20
  # Limit the max depth of a comment tree. If C is a comment and R is a reply:
18
21
  # C (depth 0)
@@ -22,23 +25,42 @@ module Decidim
22
25
  # |--R (depth 3)
23
26
  MAX_DEPTH = 3
24
27
 
28
+ translatable_fields :body
29
+
25
30
  belongs_to :commentable, foreign_key: "decidim_commentable_id", foreign_type: "decidim_commentable_type", polymorphic: true
26
- belongs_to :root_commentable, foreign_key: "decidim_root_commentable_id", foreign_type: "decidim_root_commentable_type", polymorphic: true
31
+ belongs_to :root_commentable, foreign_key: "decidim_root_commentable_id", foreign_type: "decidim_root_commentable_type", polymorphic: true, touch: true
27
32
  has_many :up_votes, -> { where(weight: 1) }, foreign_key: "decidim_comment_id", class_name: "CommentVote", dependent: :destroy
28
33
  has_many :down_votes, -> { where(weight: -1) }, foreign_key: "decidim_comment_id", class_name: "CommentVote", dependent: :destroy
29
34
 
30
- validates :body, presence: true
31
- validates :depth, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: MAX_DEPTH }
32
- validates :alignment, inclusion: { in: [0, 1, -1] }
35
+ # Updates the counter caches for the root_commentable when a comment is
36
+ # created or updated.
37
+ after_save :update_counter
33
38
 
34
- validates :body, length: { maximum: 1000 }
39
+ # Updates the counter caches for the root_commentable when a comment is
40
+ # deleted.
41
+ after_destroy :update_counter
35
42
 
36
- validate :commentable_can_have_comments
43
+ # Updates the counter caches for the root_commentable when a comment is
44
+ # touched, which happens when a comment was reported and its moderation
45
+ # is accepted and sets the comment as hidden.
46
+ after_touch :update_counter
37
47
 
38
48
  before_validation :compute_depth
49
+ validates :body, presence: true
50
+ validates :depth, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: MAX_DEPTH }
51
+ validates :alignment, inclusion: { in: [0, 1, -1] }
52
+ validate :body_length
53
+ validate :commentable_can_have_comments
39
54
 
40
55
  delegate :organization, to: :commentable
41
56
 
57
+ translatable_fields :body
58
+ searchable_fields(
59
+ participatory_space: :itself,
60
+ A: :body,
61
+ datetime: :created_at
62
+ )
63
+
42
64
  def self.positive
43
65
  where(alignment: 1)
44
66
  end
@@ -99,12 +121,13 @@ module Decidim
99
121
 
100
122
  # Public: Overrides the `reported_content_url` Reportable concern method.
101
123
  def reported_content_url
102
- ResourceLocatorPresenter.new(root_commentable).url(anchor: "comment_#{id}")
103
- end
124
+ url_params = { anchor: "comment_#{id}" }
104
125
 
105
- # Public: Returns the comment message ready to display (it is expected to include HTML)
106
- def formatted_body
107
- @formatted_body ||= Decidim::ContentProcessor.render(sanitized_body, "div")
126
+ if root_commentable&.respond_to?(:polymorphic_resource_url)
127
+ root_commentable.polymorphic_resource_url(url_params)
128
+ else
129
+ ResourceLocatorPresenter.new(root_commentable).url(url_params)
130
+ end
108
131
  end
109
132
 
110
133
  def self.export_serializer
@@ -112,10 +135,10 @@ module Decidim
112
135
  end
113
136
 
114
137
  def self.newsletter_participant_ids(space)
115
- Decidim::Comments::Comment.includes(:root_commentable).not_hidden
116
- .where("decidim_comments_comments.decidim_author_id IN (?)", Decidim::User.where(organization: space.organization).pluck(:id))
117
- .where("decidim_comments_comments.decidim_author_type IN (?)", "Decidim::UserBaseEntity")
118
- .map(&:author).pluck(:id).flatten.compact.uniq
138
+ authors_sql = Decidim::Comments::Comment.select("DISTINCT decidim_comments_comments.decidim_author_id").not_hidden
139
+ .where("decidim_comments_comments.decidim_author_type" => "Decidim::UserBaseEntity").to_sql
140
+
141
+ Decidim::User.where(organization: space.organization).where("id IN (#{authors_sql})").pluck(:id)
119
142
  end
120
143
 
121
144
  def can_participate?(user)
@@ -124,8 +147,35 @@ module Decidim
124
147
  root_commentable.can_participate?(user)
125
148
  end
126
149
 
150
+ def formatted_body
151
+ Decidim::ContentProcessor.render(sanitize_content(render_markdown(translated_body)), "div")
152
+ end
153
+
154
+ def translated_body
155
+ @translated_body ||= translated_attribute(body, organization)
156
+ end
157
+
127
158
  private
128
159
 
160
+ def body_length
161
+ language = (body.keys - ["machine_translations"]).first
162
+ errors.add(:body, :too_long, count: comment_maximum_length) unless body[language].length <= comment_maximum_length
163
+ end
164
+
165
+ def comment_maximum_length
166
+ return unless commentable.commentable?
167
+ return component.settings.comments_max_length if component_settings_comments_max_length?
168
+ return organization.comments_max_length if organization.comments_max_length.positive?
169
+
170
+ 1000
171
+ end
172
+
173
+ def component_settings_comments_max_length?
174
+ return unless component&.settings.respond_to?(:comments_max_length)
175
+
176
+ component.settings.comments_max_length.positive?
177
+ end
178
+
129
179
  # Private: Check if commentable can have comments and if not adds
130
180
  # a validation error to the model
131
181
  def commentable_can_have_comments
@@ -138,11 +188,8 @@ module Decidim
138
188
  end
139
189
 
140
190
  # Private: Returns the comment body sanitized, sanitizing HTML tags
141
- def sanitized_body
142
- Rails::Html::WhiteListSanitizer.new.sanitize(
143
- render_markdown(body),
144
- scrubber: Decidim::Comments::UserInputScrubber.new
145
- ).try(:html_safe)
191
+ def sanitize_content(content)
192
+ Decidim::ContentProcessor.sanitize(content)
146
193
  end
147
194
 
148
195
  # Private: Initializes the Markdown parser
@@ -154,6 +201,12 @@ module Decidim
154
201
  def render_markdown(string)
155
202
  markdown.render(string)
156
203
  end
204
+
205
+ def update_counter
206
+ return unless root_commentable
207
+
208
+ root_commentable.update_comments_count
209
+ end
157
210
  end
158
211
  end
159
212
  end
@@ -25,7 +25,7 @@ module Decidim
25
25
  params = {
26
26
  commentable: resource,
27
27
  root_commentable: resource,
28
- body: ::Faker::Lorem.sentence(50),
28
+ body: { en: ::Faker::Lorem.sentence(50) },
29
29
  author: author,
30
30
  user_group: user_group
31
31
  }
@@ -41,7 +41,7 @@ module Decidim
41
41
  description "The number of comments in all levels this resource holds"
42
42
 
43
43
  resolve lambda { |obj, _args, _ctx|
44
- obj.comments.count
44
+ obj.comments_count
45
45
  }
46
46
  end
47
47
 
@@ -17,7 +17,10 @@ module Decidim
17
17
 
18
18
  resolve lambda { |obj, args, ctx|
19
19
  params = { "comment" => { "body" => args[:body], "alignment" => args[:alignment], "user_group_id" => args[:userGroupId], "commentable" => obj } }
20
- form = Decidim::Comments::CommentForm.from_params(params).with_context(current_organization: ctx[:current_organization])
20
+ form = Decidim::Comments::CommentForm.from_params(params).with_context(
21
+ current_organization: ctx[:current_organization],
22
+ current_component: obj.component
23
+ )
21
24
  Decidim::Comments::CreateComment.call(form, ctx[:current_user]) do
22
25
  on(:ok) do |comment|
23
26
  return comment
@@ -0,0 +1 @@
1
+ am:
@@ -0,0 +1,6 @@
1
+ bg:
2
+ activemodel:
3
+ models:
4
+ decidim/comments/comment_by_followed_user_event: Коментар
5
+ decidim/comments/comment_created_event: Коментар
6
+ decidim/comments/reply_created_event: Отговор на коментар
@@ -20,6 +20,7 @@ ca:
20
20
  comments_count: Número de comentaris
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Nou comentari a %{link}</span>"
23
+ view: Mostrar
23
24
  votes:
24
25
  create:
25
26
  error: S'ha produït un error en votar el comentari.
@@ -24,6 +24,7 @@ cs:
24
24
  comments_count: Počet komentářů
25
25
  last_activity:
26
26
  new_comment_at_html: "<span>Nový komentář v %{link}</span>"
27
+ view: Zobrazit
27
28
  votes:
28
29
  create:
29
30
  error: Při hlasování o komentáři došlo k chybě.
@@ -0,0 +1 @@
1
+ da:
@@ -21,6 +21,7 @@ en:
21
21
  comments_count: Comments count
22
22
  last_activity:
23
23
  new_comment_at_html: "<span>New comment at %{link}</span>"
24
+ view: View
24
25
  votes:
25
26
  create:
26
27
  error: There was a problem voting the comment.
@@ -0,0 +1 @@
1
+ eo:
@@ -20,6 +20,7 @@ es-MX:
20
20
  comments_count: Número de comentarios
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Nuevo comentario en %{link}</span>"
23
+ view: Ver
23
24
  votes:
24
25
  create:
25
26
  error: Ha habido errores al votar el comentario.
@@ -20,6 +20,7 @@ es-PY:
20
20
  comments_count: Número de comentarios
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Nuevo comentario en %{link}</span>"
23
+ view: Ver
23
24
  votes:
24
25
  create:
25
26
  error: Ha habido errores al votar el comentario.
@@ -20,6 +20,7 @@ es:
20
20
  comments_count: Número de comentarios
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Nuevo comentario en %{link}</span>"
23
+ view: Ver
23
24
  votes:
24
25
  create:
25
26
  error: Se ha producido un error al votar el comentario.
@@ -88,8 +89,8 @@ es:
88
89
  email_subject: Hay un nuevo comentario de %{author_name} en %{resource_title}
89
90
  notification_title: Hay un nuevo comentario de <a href="%{author_path}">%{author_name} %{author_nickname}</a> en <a href="%{resource_path}">%{resource_title}</a>.
90
91
  comment_by_followed_user_group:
91
- email_intro: '%{author_name} ha dejado un comentario en %{resource_title}. Puede leerlo en esta página:'
92
- email_outro: Recibes esta notificación porque sigues a %{author_name}. Puedes dejar de seguir a este grupo des de su página de perfil.
92
+ email_intro: '%{author_name} ha dejado un comentario en %{resource_title}. Puedes leerlo en esta página:'
93
+ email_outro: Recibes esta notificación porque sigues a %{author_name}. Puedes dejar de seguir a este grupo desde su página de perfil.
93
94
  email_subject: Hay un nuevo comentario de %{author_name} en %{resource_title}
94
95
  notification_title: Hay un nuevo comentario de <a href="%{author_path}">%{author_name} %{author_nickname}</a> en <a href="%{resource_path}">%{resource_title}</a>.
95
96
  comment_created:
@@ -0,0 +1 @@
1
+ et:
@@ -20,6 +20,7 @@ fi-pl:
20
20
  comments_count: Kommenttien määrä
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Uusi kommentti osoitteessa %{link}</span>"
23
+ view: Näytä
23
24
  votes:
24
25
  create:
25
26
  error: Äänestettäessä kommenttia tapahtui virhe.
@@ -20,6 +20,7 @@ fi:
20
20
  comments_count: Kommenttien määrä
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Uusi kommentti osoitteessa %{link}</span>"
23
+ view: Näytä
23
24
  votes:
24
25
  create:
25
26
  error: Kommentin äänestys epäonnistui.
@@ -109,7 +110,7 @@ fi:
109
110
  notification_title: Käyttäjä <a href="%{author_path}">%{author_name}%{author_nickname}</a> on maininnut sinut kohteessa <a href="%{resource_path}">%{resource_title}</a> ryhmän <a href="%{group_path}">%{group_name} %{group_nickname}</a> jäsenenä
110
111
  user_mentioned:
111
112
  email_intro: Sinut on mainittu
112
- email_outro: Tämä ilmoitus on lähetetty sinulle, koska sinut on mainittu kohdssa %{resource_title}.
113
+ email_outro: Tämä ilmoitus on lähetetty sinulle, koska sinut on mainittu kohteessa %{resource_title}.
113
114
  email_subject: Sinut on mainittu kohdassa %{resource_title}
114
115
  notification_title: <a href="%{author_path}">%{author_name} %{author_nickname}</a> on maininnut sinut kohdassa <a href="%{resource_path}">%{resource_title}</a>
115
116
  metrics:
@@ -16,10 +16,11 @@ fr-CA:
16
16
  other: Votes
17
17
  decidim:
18
18
  comments:
19
- comments: Commentaires
19
+ comments: commentaires
20
20
  comments_count: Nombre de commentaires
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Nouveau commentaire à %{link}</span>"
23
+ view: Voir
23
24
  votes:
24
25
  create:
25
26
  error: Une erreur s'est produite lors du vote sur le commentaire.
@@ -16,10 +16,11 @@ fr:
16
16
  other: Votes
17
17
  decidim:
18
18
  comments:
19
- comments: Commentaires
19
+ comments: commentaires
20
20
  comments_count: Nombre de commentaires
21
21
  last_activity:
22
22
  new_comment_at_html: "<span>Nouveau commentaire à %{link}</span>"
23
+ view: Voir
23
24
  votes:
24
25
  create:
25
26
  error: Une erreur s'est produite lors du vote sur le commentaire.
@@ -0,0 +1 @@
1
+ hr:
@@ -16,7 +16,7 @@ hu:
16
16
  other: Szavazatok
17
17
  decidim:
18
18
  comments:
19
- comments: Megjegyzések
19
+ comments: Hozzászólások
20
20
  last_activity:
21
21
  new_comment_at_html: "<span>Új megjegyzés: %{link}</span>"
22
22
  votes:
@@ -1,7 +1,5 @@
1
1
  is-IS:
2
2
  decidim:
3
- comments:
4
- comments: Athugasemdir
5
3
  components:
6
4
  add_comment_form:
7
5
  account_message: <a href="%{sign_in_url}">Skráðu þig inn með reikningnum þínum</a> eða <a href="%{sign_up_url}">skráðu þig</a> til að bæta við ummælum þínum.
@@ -0,0 +1,76 @@
1
+ is:
2
+ decidim:
3
+ comments:
4
+ comments: Athugasemdir
5
+ components:
6
+ add_comment_form:
7
+ account_message: <a href="%{sign_in_url}">Skráðu þig inn með reikningnum þínum</a> eða <a href="%{sign_up_url}">skráðu þig</a> til að bæta við ummælum þínum.
8
+ form:
9
+ body:
10
+ label: Athugasemd
11
+ placeholder: Hvað finnst þér um þetta?
12
+ form_error: Textinn er krafist og það má ekki vera lengri en %{length} stafir.
13
+ submit: Senda
14
+ user_group_id:
15
+ label: Athugasemd sem
16
+ opinion:
17
+ neutral: Hlutlaus
18
+ remaining_characters: "%{count} stafir eftir"
19
+ remaining_characters_1: "%{count} stafur eftir"
20
+ title: Bæta við athugasemd þinni
21
+ comment:
22
+ alignment:
23
+ against: Gegn
24
+ in_favor: Í hag
25
+ reply: Svara
26
+ report:
27
+ action: Skýrsla
28
+ already_reported: Þetta efni er þegar tilkynnt og það verður endurskoðað af stjórnanda.
29
+ close: Loka
30
+ description: Er þetta efni óviðeigandi?
31
+ details: Önnur athugasemdir
32
+ reasons:
33
+ does_not_belong: Inniheldur ólöglega starfsemi, sjálfsvígshugmyndir, persónulegar upplýsingar eða eitthvað sem þér finnst ekki tilheyra %{organization_name}.
34
+ offensive: Inniheldur kynþáttafordóma, kynhneigð, slurðir, persónulegar árásir, dauðarefsárásir, sjálfsvígstilraunir eða hvers konar hatursmál.
35
+ spam: Inniheldur clickbait, auglýsingar, óþekktarangi eða handritabots.
36
+ comment_order_selector:
37
+ order:
38
+ best_rated: Bestu einkunnir
39
+ most_discussed: Mest rætt
40
+ older: Eldri
41
+ recent: Nýleg
42
+ title: 'Raða eftir:'
43
+ comment_thread:
44
+ title: Samtal við %{authorName}
45
+ comments:
46
+ blocked_comments_warning: Athugasemdir eru gerðar óvirkar á þessum tíma, en þú getur lesið þau fyrri.
47
+ loading: Hleð inn athugasemdir ...
48
+ title: "%{count} athugasemdir"
49
+ events:
50
+ comments:
51
+ comment_by_followed_user:
52
+ email_intro: "%{author_name} hefur skilið eftir athugasemd í %{resource_title}. Þú getur lesið það á þessari síðu:"
53
+ email_outro: Þú hefur fengið þessa tilkynningu vegna þess að þú fylgist með %{author_name}. Þú getur sleppt þessari notanda frá prófílssíðunni sinni.
54
+ email_subject: Það er nýtt ummæli um %{author_name} í %{resource_title}
55
+ notification_title: Það er nýtt ummæli við <a href="%{author_path}">%{author_name} %{author_nickname}</a> í <a href="%{resource_path}">%{resource_title}</a>.
56
+ comment_by_followed_user_group:
57
+ email_subject: Það er nýtt ummæli um %{author_name} í %{resource_title}
58
+ notification_title: Það er nýtt ummæli við <a href="%{author_path}">%{author_name} %{author_nickname}</a> í <a href="%{resource_path}">%{resource_title}</a>.
59
+ comment_created:
60
+ email_intro: "%{resource_title} hefur verið skrifað ummæli. Þú getur lesið athugasemdina á þessari síðu:"
61
+ email_outro: Þú hefur fengið þessa tilkynningu vegna þess að þú fylgist með "%{resource_title}" eða höfundinum. Þú getur sleppt því frá fyrri tengilinn.
62
+ email_subject: Það er nýtt ummæli frá %{author_name} í %{resource_title}
63
+ notification_title: Það er nýtt ummæli frá <a href="%{author_path}">%{author_name} %{author_nickname}</a> í <a href="%{resource_path}">%{resource_title}</a>
64
+ reply_created:
65
+ email_intro: "%{author_name} hefur svarað ummæli þín í %{resource_title}. Þú getur lesið það á þessari síðu:"
66
+ email_outro: Þú hefur fengið þessa tilkynningu vegna þess að ummæli þín voru svarað.
67
+ email_subject: "%{author_name} hefur svarað ummæli þín í %{resource_title}"
68
+ notification_title: <a href="%{author_path}">%{author_name} %{author_nickname}</a> hefur svarað athugasemd þinni í <a href="%{resource_path}">%{resource_title}</a>
69
+ user_mentioned:
70
+ email_intro: Þú hefur verið nefndur
71
+ email_outro: Þú hefur fengið þessa tilkynningu vegna þess að þú hefur verið nefndur í %{resource_title}.
72
+ email_subject: Þú hefur verið nefndur í %{resource_title}
73
+ notification_title: Þú hefur verið nefndur í <a href="%{resource_path}">%{resource_title}</a> af <a href="%{author_path}">%{author_name} %{author_nickname}</a>
74
+ errors:
75
+ messages:
76
+ cannot_have_comments: getur ekki haft athugasemdir