├── .discourse-compatibility
├── .github
└── workflows
│ └── discourse-plugin.yml
├── .gitignore
├── .npmrc
├── .prettierrc.cjs
├── .rubocop.yml
├── .streerc
├── .template-lintrc.cjs
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── app
├── helpers
│ └── yearly_review_helper.rb
├── jobs
│ └── yearly_review.rb
└── views
│ └── yearly-review
│ ├── _yearly_review.html.erb
│ └── _yearly_review_category.html.erb
├── assets
├── javascripts
│ └── discourse
│ │ ├── components
│ │ └── yearly-review-admin-notice.gjs
│ │ └── initializers
│ │ └── yearly-review-admin-notice.js
└── stylesheets
│ └── yearly_review.scss
├── config
├── locales
│ ├── client.en.yml
│ ├── server.ar.yml
│ ├── server.be.yml
│ ├── server.bg.yml
│ ├── server.bs_BA.yml
│ ├── server.ca.yml
│ ├── server.cs.yml
│ ├── server.da.yml
│ ├── server.de.yml
│ ├── server.el.yml
│ ├── server.en.yml
│ ├── server.en_GB.yml
│ ├── server.es.yml
│ ├── server.et.yml
│ ├── server.fa_IR.yml
│ ├── server.fi.yml
│ ├── server.fr.yml
│ ├── server.gl.yml
│ ├── server.he.yml
│ ├── server.hr.yml
│ ├── server.hu.yml
│ ├── server.hy.yml
│ ├── server.id.yml
│ ├── server.it.yml
│ ├── server.ja.yml
│ ├── server.ko.yml
│ ├── server.lt.yml
│ ├── server.lv.yml
│ ├── server.nb_NO.yml
│ ├── server.nl.yml
│ ├── server.pl_PL.yml
│ ├── server.pt.yml
│ ├── server.pt_BR.yml
│ ├── server.ro.yml
│ ├── server.ru.yml
│ ├── server.sk.yml
│ ├── server.sl.yml
│ ├── server.sq.yml
│ ├── server.sr.yml
│ ├── server.sv.yml
│ ├── server.sw.yml
│ ├── server.te.yml
│ ├── server.th.yml
│ ├── server.tr_TR.yml
│ ├── server.ug.yml
│ ├── server.uk.yml
│ ├── server.ur.yml
│ ├── server.vi.yml
│ ├── server.zh_CN.yml
│ └── server.zh_TW.yml
└── settings.yml
├── db
└── migrate
│ └── 20230208123631_backfill_yearly_review_custom_fields.rb
├── eslint.config.mjs
├── package.json
├── plugin.rb
├── pnpm-lock.yaml
├── spec
├── jobs
│ └── yearly_review_spec.rb
└── system
│ └── core_features_spec.rb
├── stylelint.config.mjs
└── translator.yml
/.discourse-compatibility:
--------------------------------------------------------------------------------
1 | < 3.5.0.beta1-dev: 439e0d78f1d8a0f387c0ec26f233a090ce82ef72
2 | < 3.4.0.beta1-dev: bb124c211c37873c1d54e96e7063f1868c65d0ad
3 | < 3.3.0.beta1-dev: 59b98bab5ee370da4774f60ea7b5122dddcbd83a
4 | 3.1.999: 3246c6b378f9e69e664c575efc63c2ad83bcac2f
5 | 2.9.0.beta3: 3377b0d9f168eef839cb5fd0f4dcabcb3e313b4b
6 |
--------------------------------------------------------------------------------
/.github/workflows/discourse-plugin.yml:
--------------------------------------------------------------------------------
1 | name: Discourse Plugin
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 |
9 | jobs:
10 | ci:
11 | uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict = true
2 | auto-install-peers = false
3 |
--------------------------------------------------------------------------------
/.prettierrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = require("@discourse/lint-configs/prettier");
2 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | inherit_gem:
2 | rubocop-discourse: stree-compat.yml
3 |
--------------------------------------------------------------------------------
/.streerc:
--------------------------------------------------------------------------------
1 | --print-width=100
2 | --plugins=plugin/trailing_comma
3 |
--------------------------------------------------------------------------------
/.template-lintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = require("@discourse/lint-configs/template-lint");
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | group :development do
6 | gem "rubocop-discourse"
7 | gem "syntax_tree"
8 | end
9 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | activesupport (8.0.2)
5 | base64
6 | benchmark (>= 0.3)
7 | bigdecimal
8 | concurrent-ruby (~> 1.0, >= 1.3.1)
9 | connection_pool (>= 2.2.5)
10 | drb
11 | i18n (>= 1.6, < 2)
12 | logger (>= 1.4.2)
13 | minitest (>= 5.1)
14 | securerandom (>= 0.3)
15 | tzinfo (~> 2.0, >= 2.0.5)
16 | uri (>= 0.13.1)
17 | ast (2.4.3)
18 | base64 (0.2.0)
19 | benchmark (0.4.0)
20 | bigdecimal (3.1.9)
21 | concurrent-ruby (1.3.5)
22 | connection_pool (2.5.3)
23 | drb (2.2.3)
24 | i18n (1.14.7)
25 | concurrent-ruby (~> 1.0)
26 | json (2.12.2)
27 | language_server-protocol (3.17.0.5)
28 | lint_roller (1.1.0)
29 | logger (1.7.0)
30 | minitest (5.25.5)
31 | parallel (1.27.0)
32 | parser (3.3.8.0)
33 | ast (~> 2.4.1)
34 | racc
35 | prettier_print (1.2.1)
36 | prism (1.4.0)
37 | racc (1.8.1)
38 | rack (3.1.15)
39 | rainbow (3.1.1)
40 | regexp_parser (2.10.0)
41 | rubocop (1.75.7)
42 | json (~> 2.3)
43 | language_server-protocol (~> 3.17.0.2)
44 | lint_roller (~> 1.1.0)
45 | parallel (~> 1.10)
46 | parser (>= 3.3.0.2)
47 | rainbow (>= 2.2.2, < 4.0)
48 | regexp_parser (>= 2.9.3, < 3.0)
49 | rubocop-ast (>= 1.44.0, < 2.0)
50 | ruby-progressbar (~> 1.7)
51 | unicode-display_width (>= 2.4.0, < 4.0)
52 | rubocop-ast (1.44.1)
53 | parser (>= 3.3.7.2)
54 | prism (~> 1.4)
55 | rubocop-capybara (2.22.1)
56 | lint_roller (~> 1.1)
57 | rubocop (~> 1.72, >= 1.72.1)
58 | rubocop-discourse (3.12.1)
59 | activesupport (>= 6.1)
60 | lint_roller (>= 1.1.0)
61 | rubocop (>= 1.73.2)
62 | rubocop-capybara (>= 2.22.0)
63 | rubocop-factory_bot (>= 2.27.0)
64 | rubocop-rails (>= 2.30.3)
65 | rubocop-rspec (>= 3.0.1)
66 | rubocop-rspec_rails (>= 2.31.0)
67 | rubocop-factory_bot (2.27.1)
68 | lint_roller (~> 1.1)
69 | rubocop (~> 1.72, >= 1.72.1)
70 | rubocop-rails (2.32.0)
71 | activesupport (>= 4.2.0)
72 | lint_roller (~> 1.1)
73 | rack (>= 1.1)
74 | rubocop (>= 1.75.0, < 2.0)
75 | rubocop-ast (>= 1.44.0, < 2.0)
76 | rubocop-rspec (3.6.0)
77 | lint_roller (~> 1.1)
78 | rubocop (~> 1.72, >= 1.72.1)
79 | rubocop-rspec_rails (2.31.0)
80 | lint_roller (~> 1.1)
81 | rubocop (~> 1.72, >= 1.72.1)
82 | rubocop-rspec (~> 3.5)
83 | ruby-progressbar (1.13.0)
84 | securerandom (0.4.1)
85 | syntax_tree (6.2.0)
86 | prettier_print (>= 1.2.0)
87 | tzinfo (2.0.6)
88 | concurrent-ruby (~> 1.0)
89 | unicode-display_width (3.1.4)
90 | unicode-emoji (~> 4.0, >= 4.0.4)
91 | unicode-emoji (4.0.4)
92 | uri (1.0.3)
93 |
94 | PLATFORMS
95 | ruby
96 |
97 | DEPENDENCIES
98 | rubocop-discourse
99 | syntax_tree
100 |
101 | BUNDLED WITH
102 | 2.6.9
103 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Civilized Discourse Construction Kit, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Discourse Yearly Review
2 |
3 | https://meta.discourse.org/t/discourse-yearly-review-plugin/105713/
4 |
5 | Creates a Yearly Review topic that summarizes user and topic stats for the previous year.
6 | Stats are only selected from a site's public categories.
7 |
8 | The review categories can be configured with the `yearly_review_categories` Site Setting. The review is published to the category set in
9 | the `yearly_review_publish_category` Site Setting. If the `yearly_review_featured_badge` setting is configured, users who
10 | have been granted that badge will be displayed.
11 |
12 | User stats:
13 |
14 | - most topics
15 | - most replies
16 | - most likes given
17 | - most likes received
18 | - most visits
19 | - most replied to
20 | - users who have been granted the featured badge
21 |
22 | Topic stats:
23 |
24 | - most popular topics
25 | - most liked topics (OP like count)
26 | - most replied to topics
27 | - most bookmarked topics
28 |
--------------------------------------------------------------------------------
/app/helpers/yearly_review_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module YearlyReviewHelper
4 | include ActionView::Helpers::NumberHelper
5 |
6 | AVATAR_SIZE = "50"
7 |
8 | def avatar_image(username, uploaded_avatar_id)
9 | template = User.avatar_template(username, uploaded_avatar_id).gsub(/{size}/, AVATAR_SIZE)
10 | ""
11 | end
12 |
13 | def user_link(username)
14 | "@#{username}"
15 | end
16 |
17 | def topic_link(title, slug, topic_id)
18 | link = "#{Discourse.base_url}/t/#{slug}/#{topic_id}"
19 | "[#{title}](#{link})"
20 | end
21 |
22 | def class_from_key(key)
23 | key.gsub("_", "-")
24 | end
25 |
26 | def slug_from_name(name)
27 | name.downcase.gsub(" ", "-")
28 | end
29 |
30 | def badge_link(name, id, more)
31 | url = "#{Discourse.base_url}/badges/#{id}/#{slug_from_name(name)}"
32 | "[#{t("yearly_review.more_badge_users", more: more)}](#{url})"
33 | end
34 |
35 | def category_link(name)
36 | category = Category.find_by(name: name)
37 | if category.parent_category_id
38 | parent_category = Category.find(category.parent_category_id)
39 | url = "#{Discourse.base_url}/c/#{parent_category.slug}/#{category.slug}/l/top"
40 | else
41 | url = "#{Discourse.base_url}/c/#{category.slug}/l/top"
42 | end
43 | link_text = t("yearly_review.category_topics_title", category: name)
44 | "[#{link_text}](#{url})"
45 | end
46 |
47 | def user_visits_link
48 | if SiteSetting.enable_user_directory && !SiteSetting.hide_user_profiles_from_public
49 | url = "#{Discourse.base_url}/u?order=days_visited&period=yearly"
50 | "[#{t("yearly_review.all_yearly_visits")}](#{url})"
51 | end
52 | end
53 |
54 | def format_number(number)
55 | number_to_human(number, units: { thousand: "k" }, format: "%n%u")
56 | end
57 |
58 | def table_row(*values)
59 | "|#{values.join("|")}|"
60 | end
61 |
62 | def table_header(*labels)
63 | headings = labels.map { |label| I18n.t("yearly_review.#{label}") }
64 | "|#{headings.join("|")}|"
65 | end
66 |
67 | def compiled_method_container
68 | self.class
69 | end
70 | end
71 |
--------------------------------------------------------------------------------
/app/jobs/yearly_review.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "../../app/helpers/yearly_review_helper"
4 |
5 | module ::Jobs
6 | class YearlyReview < ::Jobs::Scheduled
7 | MAX_USERS = 10
8 | MAX_BADGE_USERS = 15
9 |
10 | every 1.day
11 |
12 | def execute(args)
13 | now = Time.now
14 | review_year = args[:review_year] ? args[:review_year] : ::YearlyReview.last_year
15 | review_start = Time.new(review_year, 1, 1)
16 | review_end = review_start.end_of_year
17 | title = I18n.t("yearly_review.topic_title", year: review_year)
18 |
19 | if !args[:force]
20 | return if !SiteSetting.yearly_review_enabled
21 | return unless now.month == 1 && now.day <= 31
22 | return if review_topic_exists?(review_year)
23 | end
24 |
25 | view = ActionView::Base.with_view_paths(ActionController::Base.view_paths)
26 | view.singleton_class.include(YearlyReviewHelper)
27 |
28 | raw_topic_html = render_raw_topic_view(view, review_year, review_start, review_end)
29 | if raw_topic_html.present?
30 | topic_opts = {
31 | title: title,
32 | raw: raw_topic_html,
33 | category: SiteSetting.yearly_review_publish_category,
34 | skip_validations: true,
35 | custom_fields: {
36 | ::YearlyReview::POST_CUSTOM_FIELD => review_year,
37 | },
38 | }
39 |
40 | post = PostCreator.create!(Discourse.system_user, topic_opts)
41 |
42 | if post.respond_to? :topic_id
43 | create_category_posts view, review_start, review_end, post.topic_id
44 | end
45 | end
46 | end
47 |
48 | def render_raw_topic_view(view, review_year, review_start, review_end)
49 | review_featured_badge = SiteSetting.yearly_review_featured_badge
50 | include_user_stats = SiteSetting.yearly_review_include_user_stats
51 |
52 | user_stats = include_user_stats ? user_stats(review_start, review_end) : []
53 | featured_badge_users =
54 | (
55 | if review_featured_badge.blank?
56 | []
57 | else
58 | featured_badge_users(review_featured_badge, review_start, review_end)
59 | end
60 | )
61 | daily_visits = daily_visits review_start, review_end
62 | view.assign(
63 | review_year: review_year,
64 | user_stats: user_stats,
65 | daily_visits: daily_visits,
66 | featured_badge_users: featured_badge_users,
67 | )
68 |
69 | view.render partial: "yearly_review", layout: false
70 | end
71 |
72 | def create_category_posts(view, review_start, review_end, topic_id)
73 | review_categories = review_categories_from_settings
74 |
75 | review_categories.each do |category_id|
76 | category_post_topics = category_post_topics category_id, review_start, review_end
77 | if category_post_topics[:topics]
78 | view.assign(category_topics: category_post_topics)
79 | raw_html = view.render partial: "yearly_review_category", layout: false
80 | if raw_html.present?
81 | post_opts = {
82 | topic_id: topic_id,
83 | raw: raw_html,
84 | skip_validations: true,
85 | custom_fields: {
86 | ::YearlyReview::POST_CUSTOM_FIELD => review_start.year,
87 | },
88 | }
89 |
90 | PostCreator.create!(Discourse.system_user, post_opts)
91 | end
92 | end
93 | end
94 | end
95 |
96 | def category_post_topics(cat_id, start_date, end_date)
97 | data = {}
98 |
99 | most_read = ranked_topics(cat_id, start_date, end_date, most_read_topic_sql)
100 | most_liked = ranked_topics(cat_id, start_date, end_date, most_liked_topic_sql)
101 | most_replied_to = ranked_topics(cat_id, start_date, end_date, most_replied_to_topic_sql)
102 | most_popular = ranked_topics(cat_id, start_date, end_date, most_popular_topic_sql)
103 | most_bookmarked = ranked_topics(cat_id, start_date, end_date, most_bookmarked_topic_sql)
104 |
105 | category_topics = {}
106 | category_topics[:most_read] = most_read if most_read.any?
107 | category_topics[:most_liked] = most_liked if most_liked.any?
108 | category_topics[:most_replied_to] = most_replied_to if most_replied_to.any?
109 | category_topics[:most_popular] = most_popular if most_popular.any?
110 | category_topics[:most_bookmarked] = most_bookmarked if most_bookmarked.any?
111 |
112 | if category_topics.any?
113 | category_name = Category.find(cat_id).name
114 | data[:category_name] = category_name
115 | data[:topics] = category_topics
116 | end
117 |
118 | data
119 | end
120 |
121 | def review_categories_from_settings
122 | read_restricted = SiteSetting.yearly_review_include_private_categories
123 |
124 | if SiteSetting.yearly_review_categories.blank?
125 | Category.where(read_restricted: false).order("topics_year DESC")[0, 5].pluck(:id)
126 | else
127 | opts = {}
128 | opts[:read_restricted] = false if read_restricted == false
129 | opts[:id] = SiteSetting.yearly_review_categories.split("|")
130 | Category.where(opts).order("topics_year DESC").pluck(:id)
131 | end
132 | end
133 |
134 | def user_stats(review_start, review_end)
135 | exclude_staff = SiteSetting.yearly_review_exclude_staff
136 | read_restricted = SiteSetting.yearly_review_include_private_categories
137 | user_stats = []
138 | most_time_read = most_time_read review_start, review_end, exclude_staff, read_restricted
139 | most_topics = most_topics review_start, review_end, exclude_staff, read_restricted
140 | most_replies = most_replies review_start, review_end, exclude_staff, read_restricted
141 | most_likes = most_likes_given review_start, review_end, exclude_staff, read_restricted
142 | most_likes_received =
143 | most_likes_received review_start, review_end, exclude_staff, read_restricted
144 | most_visits = most_visits review_start, review_end, exclude_staff
145 | most_replied_to = most_replied_to review_start, review_end, exclude_staff, read_restricted
146 | user_stats << { key: "time_read", users: most_time_read } if most_time_read.any?
147 | user_stats << { key: "topics_created", users: most_topics } if most_topics.any?
148 | user_stats << { key: "replies_created", users: most_replies } if most_replies.any?
149 | user_stats << { key: "most_replied_to", users: most_replied_to } if most_replied_to.any?
150 | user_stats << { key: "likes_given", users: most_likes } if most_likes.any?
151 | if most_likes_received.any?
152 | user_stats << { key: "likes_received", users: most_likes_received }
153 | end
154 | user_stats << { key: "visits", users: most_visits } if most_visits.any?
155 | user_stats
156 | end
157 |
158 | def ranked_topics(cat_id, start_date, end_date, sql)
159 | data = []
160 | exclude_staff = SiteSetting.yearly_review_exclude_staff
161 | DB
162 | .query(
163 | sql,
164 | start_date: start_date,
165 | end_date: end_date,
166 | cat_id: cat_id,
167 | exclude_staff: exclude_staff,
168 | limit: 5,
169 | )
170 | .each do |row|
171 | if row
172 | action = row.action
173 | case action
174 | when "likes"
175 | next if row.action_count < 10
176 | when "replies"
177 | next if row.action_count < 10
178 | when "bookmarks"
179 | next if row.action_count < 5
180 | when "score"
181 | next if row.action_count < 10
182 | when "read_time"
183 | next if row.action_count < 5
184 | end
185 | data << row
186 | end
187 | end
188 | data
189 | end
190 |
191 | def most_topics(start_date, end_date, exclude_staff, read_restricted)
192 | sql = <<~SQL
193 | SELECT
194 | t.user_id,
195 | COUNT(t.user_id) AS action_count,
196 | u.username,
197 | u.uploaded_avatar_id
198 | FROM topics t
199 | JOIN users u
200 | ON u.id = t.user_id
201 | JOIN categories c
202 | ON c.id = t.category_id
203 | WHERE t.archetype = 'regular'
204 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
205 | #{"AND c.read_restricted = false" unless read_restricted}
206 | AND t.user_id > 0
207 | AND t.created_at >= :start_date
208 | AND t.created_at <= :end_date
209 | AND t.deleted_at IS NULL
210 | GROUP BY t.user_id, u.username, u.uploaded_avatar_id
211 | ORDER BY action_count DESC
212 | LIMIT #{MAX_USERS}
213 | SQL
214 |
215 | DB.query(sql, exclude_staff:, start_date:, end_date:)
216 | end
217 |
218 | def most_replies(start_date, end_date, exclude_staff, read_restricted)
219 | sql = <<~SQL
220 | SELECT
221 | p.user_id,
222 | u.username,
223 | u.uploaded_avatar_id,
224 | COUNT(p.user_id) AS action_count
225 | FROM posts p
226 | JOIN users u
227 | ON u.id = p.user_id
228 | JOIN topics t
229 | ON t.id = p.topic_id
230 | JOIN categories c
231 | ON c.id = t.category_id
232 | WHERE t.archetype = 'regular'
233 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
234 | #{"AND c.read_restricted = false" unless read_restricted}
235 | AND p.user_id > 0
236 | AND p.post_number > 1
237 | AND p.post_type = 1
238 | AND p.created_at >= :start_date
239 | AND p.created_at <= :end_date
240 | AND t.deleted_at IS NULL
241 | AND p.deleted_at IS NULL
242 | GROUP BY p.user_id, u.username, u.uploaded_avatar_id
243 | ORDER BY action_count DESC
244 | LIMIT #{MAX_USERS}
245 | SQL
246 |
247 | DB.query(sql, exclude_staff:, start_date:, end_date:)
248 | end
249 |
250 | def daily_visits(start_date, end_date)
251 | sql = <<~SQL
252 | WITH visits AS (
253 | SELECT
254 | user_id,
255 | COUNT(user_id) AS days_visited_count
256 | FROM user_visits uv
257 | WHERE uv.visited_at >= :start_date
258 | AND uv.visited_at <= :end_date
259 | GROUP BY user_id
260 | )
261 | SELECT
262 | COUNT(user_id) AS users,
263 | days_visited_count AS days
264 | FROM visits
265 | GROUP BY days_visited_count
266 | ORDER BY days_visited_count DESC
267 | LIMIT 10
268 | SQL
269 |
270 | DB.query(sql, start_date:, end_date:)
271 | end
272 |
273 | def most_visits(start_date, end_date, exclude_staff)
274 | sql = <<~SQL
275 | SELECT
276 | uv.user_id,
277 | u.username,
278 | u.uploaded_avatar_id,
279 | COUNT(uv.user_id) AS action_count
280 | FROM user_visits uv
281 | JOIN users u
282 | ON u.id = uv.user_id
283 | WHERE u.id > 0
284 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
285 | AND uv.visited_at >= :start_date
286 | AND uv.visited_at <= :end_date
287 | GROUP BY uv.user_id, u.username, u.uploaded_avatar_id
288 | ORDER BY action_count DESC
289 | LIMIT #{MAX_USERS}
290 | SQL
291 |
292 | DB.query(sql, exclude_staff:, start_date:, end_date:)
293 | end
294 |
295 | def most_time_read(start_date, end_date, exclude_staff, read_restricted)
296 | sql = <<~SQL
297 | SELECT
298 | u.id,
299 | u.username,
300 | u.uploaded_avatar_id,
301 | ROUND(SUM(tu.total_msecs_viewed::numeric) / (1000 * 60 * 60)::numeric, 2) AS action_count
302 | FROM users u
303 | JOIN topic_users tu
304 | ON tu.user_id = u.id
305 | JOIN topics t
306 | ON t.id = tu.topic_id
307 | JOIN categories c
308 | ON c.id = t.category_id
309 | WHERE t.archetype = 'regular'
310 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
311 | #{"AND c.read_restricted = false" unless read_restricted}
312 | AND u.id > 0
313 | AND t.created_at >= :start_date
314 | AND t.created_at <= :end_date
315 | AND t.deleted_at IS NULL
316 | AND tu.total_msecs_viewed > (1000 * 60)
317 | GROUP BY u.id, username, uploaded_avatar_id
318 | ORDER BY action_count DESC
319 | LIMIT #{MAX_USERS}
320 | SQL
321 |
322 | DB.query(sql, exclude_staff:, start_date:, end_date:)
323 | end
324 |
325 | def most_likes_given(start_date, end_date, exclude_staff, read_restricted)
326 | sql = <<~SQL
327 | SELECT
328 | ua.acting_user_id,
329 | u.username,
330 | u.uploaded_avatar_id,
331 | COUNT(ua.user_id) AS action_count
332 | FROM user_actions ua
333 | JOIN topics t
334 | ON t.id = ua.target_topic_id
335 | JOIN users u
336 | ON u.id = ua.acting_user_id
337 | JOIN categories c
338 | ON c.id = t.category_id
339 | WHERE t.archetype = 'regular'
340 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
341 | #{"AND c.read_restricted = false" unless read_restricted}
342 | AND u.id > 0
343 | AND ua.created_at >= :start_date
344 | AND ua.created_at <= :end_date
345 | AND ua.action_type = 2
346 | AND t.deleted_at IS NULL
347 | GROUP BY ua.acting_user_id, u.username, u.uploaded_avatar_id
348 | ORDER BY action_count DESC
349 | LIMIT #{MAX_USERS}
350 | SQL
351 |
352 | DB.query(sql, exclude_staff:, start_date:, end_date:)
353 | end
354 |
355 | def most_likes_received(start_date, end_date, exclude_staff, read_restricted)
356 | sql = <<~SQL
357 | SELECT
358 | u.username,
359 | u.uploaded_avatar_id,
360 | COUNT(ua.user_id) AS action_count
361 | FROM user_actions ua
362 | JOIN topics t
363 | ON t.id = ua.target_topic_id
364 | JOIN users u
365 | ON u.id = ua.user_id
366 | JOIN categories c
367 | ON c.id = t.category_id
368 | WHERE t.archetype = 'regular'
369 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
370 | #{"AND c.read_restricted = false" unless read_restricted}
371 | AND u.id > 0
372 | AND ua.created_at >= :start_date
373 | AND ua.created_at <= :end_date
374 | AND ua.action_type = 2
375 | AND t.deleted_at IS NULL
376 | GROUP BY u.username, u.uploaded_avatar_id
377 | ORDER BY action_count DESC
378 | LIMIT #{MAX_USERS}
379 | SQL
380 |
381 | DB.query(sql, exclude_staff:, start_date:, end_date:)
382 | end
383 |
384 | def most_replied_to(start_date, end_date, exclude_staff, read_restricted)
385 | sql = <<~SQL
386 | SELECT
387 | u.username,
388 | u.uploaded_avatar_id,
389 | SUM(p.reply_count) AS action_count
390 | FROM posts p
391 | JOIN topics t
392 | ON t.id = p.topic_id
393 | JOIN users u
394 | ON u.id = p.user_id
395 | JOIN categories c
396 | ON c.id = t.category_id
397 | WHERE t.archetype = 'regular'
398 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
399 | #{"AND c.read_restricted = false" unless read_restricted}
400 | AND p.created_at >= :start_date
401 | AND p.created_at <= :end_date
402 | AND p.reply_count > 0
403 | AND t.deleted_at IS NULL
404 | AND p.deleted_at IS NULL
405 | AND p.post_type = 1
406 | AND p.user_id > 0
407 | GROUP BY u.username, u.uploaded_avatar_id
408 | ORDER BY action_count DESC
409 | LIMIT #{MAX_USERS}
410 | SQL
411 |
412 | DB.query(sql, exclude_staff:, start_date:, end_date:)
413 | end
414 |
415 | def featured_badge_users(badge_name, start_date, end_date)
416 | sql = <<~SQL
417 | SELECT DISTINCT ON(u.id)
418 | u.id AS user_id,
419 | username,
420 | uploaded_avatar_id,
421 | b.name,
422 | b.id,
423 | ((COUNT(*) OVER()) - #{MAX_BADGE_USERS}) AS more_users
424 | FROM badges b
425 | JOIN user_badges ub
426 | ON ub.badge_id = b.id
427 | JOIN users u
428 | ON u.id = ub.user_id
429 | WHERE b.name = :badge_name
430 | AND ((NOT :exclude_staff) OR (u.admin = false AND u.moderator = false))
431 | AND ub.granted_at BETWEEN :start_date AND :end_date
432 | AND u.id > 0
433 | ORDER BY u.id
434 | LIMIT #{MAX_BADGE_USERS}
435 | SQL
436 |
437 | DB.query(
438 | sql,
439 | exclude_staff: SiteSetting.yearly_review_exclude_staff,
440 | badge_name:,
441 | start_date:,
442 | end_date:,
443 | )
444 | end
445 |
446 | def most_read_topic_sql
447 | <<~SQL
448 | SELECT
449 | username,
450 | uploaded_avatar_id,
451 | t.id,
452 | t.slug AS topic_slug,
453 | t.title,
454 | t.created_at,
455 | c.slug AS category_slug,
456 | c.name AS category_name,
457 | c.id AS category_id,
458 | ROUND(SUM(tu.total_msecs_viewed::numeric) / (1000 * 60 * 60)::numeric, 2) AS action_count,
459 | 'read_time' AS action
460 | FROM users u
461 | JOIN topics t
462 | ON t.user_id = u.id
463 | JOIN topic_users tu
464 | ON tu.topic_id = t.id
465 | JOIN categories c
466 | ON c.id = t.category_id
467 | WHERE t.deleted_at IS NULL
468 | AND ((:exclude_staff = false) OR (u.admin = false AND u.moderator = false))
469 | AND t.created_at BETWEEN :start_date AND :end_date
470 | AND t.visible = true
471 | AND c.id = :cat_id
472 | AND u.id > 0
473 | GROUP BY t.id, username, uploaded_avatar_id, c.id
474 | ORDER BY action_count DESC
475 | LIMIT :limit
476 | SQL
477 | end
478 |
479 | def most_popular_topic_sql
480 | <<~SQL
481 | SELECT
482 | username,
483 | uploaded_avatar_id,
484 | t.id,
485 | t.slug AS topic_slug,
486 | t.title,
487 | t.created_at,
488 | c.slug AS category_slug,
489 | c.name AS category_name,
490 | c.id AS category_id,
491 | ROUND(tt.yearly_score::numeric, 2) AS action_count,
492 | 'score' AS action
493 | FROM top_topics tt
494 | JOIN topics t
495 | ON t.id = tt.topic_id
496 | JOIN categories c
497 | ON c.id = t.category_id
498 | JOIN users u
499 | ON u.id = t.user_id
500 | WHERE t.deleted_at IS NULL
501 | AND ((:exclude_staff = false) OR (u.admin = false AND u.moderator = false))
502 | AND t.created_at BETWEEN :start_date AND :end_date
503 | AND t.visible = true
504 | AND c.id = :cat_id
505 | AND u.id > 0
506 | ORDER BY tt.yearly_score DESC
507 | LIMIT :limit
508 | SQL
509 | end
510 |
511 | def most_liked_topic_sql
512 | <<~SQL
513 | SELECT
514 | username,
515 | uploaded_avatar_id,
516 | t.id,
517 | t.slug AS topic_slug,
518 | t.title,
519 | t.created_at,
520 | c.slug AS category_slug,
521 | c.name AS category_name,
522 | c.id AS category_id,
523 | COUNT(*) AS action_count,
524 | 'likes' AS action
525 | FROM post_actions pa
526 | JOIN posts p
527 | ON p.id = pa.post_id
528 | JOIN topics t
529 | ON t.id = p.topic_id
530 | JOIN categories c
531 | ON c.id = t.category_id
532 | JOIN users u
533 | ON u.id = t.user_id
534 | WHERE pa.created_at BETWEEN :start_date AND :end_date
535 | AND ((:exclude_staff = false) OR (u.admin = false AND u.moderator = false))
536 | AND pa.post_action_type_id = 2
537 | AND c.id = :cat_id
538 | AND p.post_number = 1
539 | AND p.deleted_at IS NULL
540 | AND t.deleted_at IS NULL
541 | AND t.visible = true
542 | AND u.id > 0
543 | GROUP BY p.id, t.id, topic_slug, category_slug, category_name, c.id, username, uploaded_avatar_id
544 | ORDER BY action_count DESC
545 | LIMIT :limit
546 | SQL
547 | end
548 |
549 | def most_replied_to_topic_sql
550 | <<~SQL
551 | SELECT
552 | username,
553 | uploaded_avatar_id,
554 | t.id,
555 | t.slug AS topic_slug,
556 | t.title,
557 | t.created_at,
558 | c.slug AS category_slug,
559 | c.name AS category_name,
560 | c.id AS category_id,
561 | COUNT(*) AS action_count,
562 | 'replies' AS action
563 | FROM posts p
564 | JOIN topics t
565 | ON t.id = p.topic_id
566 | JOIN categories c
567 | ON c.id = t.category_id
568 | JOIN users u
569 | ON u.id = t.user_id
570 | WHERE p.created_at BETWEEN :start_date AND :end_date
571 | AND ((:exclude_staff = false) OR (u.admin = false AND u.moderator = false))
572 | AND c.id = :cat_id
573 | AND t.deleted_at IS NULL
574 | AND t.visible = true
575 | AND p.deleted_at IS NULL
576 | AND p.post_type = 1
577 | AND p.post_number > 1
578 | AND t.posts_count > 1
579 | AND u.id > 0
580 | GROUP BY t.id, topic_slug, category_slug, category_name, c.id, username, uploaded_avatar_id
581 | ORDER BY action_count DESC
582 | LIMIT :limit
583 | SQL
584 | end
585 |
586 | def most_bookmarked_topic_sql
587 | post_bookmark_join_sql =
588 | if SiteSetting.use_polymorphic_bookmarks
589 | "ON p.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Post'"
590 | else
591 | "ON p.id = bookmarks.post_id"
592 | end
593 | <<~SQL
594 | SELECT
595 | username,
596 | uploaded_avatar_id,
597 | t.id,
598 | t.slug AS topic_slug,
599 | t.title,
600 | t.created_at,
601 | c.slug AS category_slug,
602 | c.name AS category_name,
603 | c.id AS category_id,
604 | COUNT(*) AS action_count,
605 | 'bookmarks' AS action
606 | FROM bookmarks
607 | JOIN posts p
608 | #{post_bookmark_join_sql}
609 | JOIN topics t
610 | ON t.id = p.topic_id
611 | JOIN categories c
612 | ON c.id = t.category_id
613 | JOIN users u
614 | ON u.id = t.user_id
615 | WHERE bookmarks.created_at BETWEEN :start_date AND :end_date
616 | AND ((:exclude_staff = false) OR (u.admin = false AND u.moderator = false))
617 | AND c.id = :cat_id
618 | AND t.deleted_at IS NULL
619 | AND t.visible = true
620 | AND p.deleted_at IS NULL
621 | GROUP BY t.id, category_slug, category_name, c.id, username, uploaded_avatar_id
622 | ORDER BY action_count DESC
623 | LIMIT :limit
624 | SQL
625 | end
626 |
627 | def review_topic_exists?(review_year)
628 | TopicCustomField.joins(:topic).exists?(
629 | name: ::YearlyReview::POST_CUSTOM_FIELD,
630 | value: review_year.to_s,
631 | topic: {
632 | deleted_at: nil,
633 | },
634 | )
635 | end
636 | end
637 | end
638 |
--------------------------------------------------------------------------------
/app/views/yearly-review/_yearly_review.html.erb:
--------------------------------------------------------------------------------
1 | <% if @user_stats.any? %>
2 |
3 |
4 | ## <%= t('yearly_review.title.users_section', year: @review_year) %>
5 | <% @user_stats.each do |obj| %>
6 | <% if obj[:users] %>
7 | ## <%= t("yearly_review.title.#{obj[:key]}") %>
8 |
9 |
10 |
11 | <%= table_header('user', "action.#{obj[:key]}") %>
12 | |---|---|
13 | <% obj[:users].each_with_index do |user, i| %>
14 | <%= table_row("#{avatar_image(user.username, user.uploaded_avatar_id)} @#{user.username}", format_number(user.action_count < 1 ? 1 : user.action_count.round)) %>
15 | <% end %>
16 |
17 |
18 |
19 | <% if obj[:key] == 'visits' %>
20 | <%= raw(user_visits_link) %>
21 | <% end %>
22 | <% end %>
23 | <% end %>
24 |
25 | <% end %>
26 |
27 | <% if @daily_visits.any? %>
28 |
29 |
30 | ## <%= t("yearly_review.title.daily_visits") %>
31 |
32 | <%= table_header("days_visited", "users") %>
33 | |---|---|
34 | <% @daily_visits.each do |visit| %>
35 | <%= table_row(format_number(visit.days), format_number(visit.users)) %>
36 | <% end %>
37 |
38 |
39 | <% end %>
40 |
41 | <% if @featured_badge_users.any? %>
42 |
43 |
44 | ## <%= t("yearly_review.title.featured_badge", badge_name: SiteSetting.yearly_review_featured_badge) %>
45 |
46 | <% @featured_badge_users.each do |user| %>
47 | @<%= user.username %>
48 | <% end %>
49 | <% if @featured_badge_users[0].more_users > 0 %>
50 | <% @badge = @featured_badge_users[0] %>
51 | <%= raw(badge_link(@badge.name, @badge.id, format_number(@badge.more_users))) %>
52 | <% end %>
53 |
54 |
55 | <% end %>
56 |
--------------------------------------------------------------------------------
/app/views/yearly-review/_yearly_review_category.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## <%= raw(category_link(@category_topics[:category_name])) %>
4 | <% @category_topics[:topics].each do |key, val| %>
5 | ### <%= t("yearly_review.rank_type.title.#{key}") %>
6 |
7 | <%= table_header('user', 'topic', "rank_type.action_types.#{key}") %>
8 | |---|---|---|
9 | <% val.each do |topic| %>
10 | <%= table_row(avatar_image(topic.username, topic.uploaded_avatar_id), topic_link(topic.title, topic.topic_slug, topic.id), format_number(topic.action_count.round)) %>
11 | <% end %>
12 |
13 | <% end %>
14 |
15 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/yearly-review-admin-notice.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@glimmer/component";
2 | import { htmlSafe } from "@ember/template";
3 | import replaceEmoji from "discourse/helpers/replace-emoji";
4 | import getURL from "discourse/lib/get-url";
5 | import { i18n } from "discourse-i18n";
6 |
7 | export function janNextYear() {
8 | return new Date(new Date().getFullYear() + 1, 0, 1);
9 | }
10 |
11 | export default class YearlyReviewAdminNotice extends Component {
12 | get toBeCreatedDate() {
13 | return moment(janNextYear()).format(i18n("dates.full_with_year_no_time"));
14 | }
15 |
16 | get settingsUrl() {
17 | return getURL(
18 | "/admin/site_settings/category/plugins?filter=plugin%3Adiscourse-yearly-review"
19 | );
20 | }
21 |
22 |
23 |
24 | {{replaceEmoji
25 | (htmlSafe
26 | (i18n
27 | "yearly_review.admin_notice"
28 | to_be_created_date=this.toBeCreatedDate
29 | settings_url=this.settingsUrl
30 | )
31 | )
32 | }}
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/initializers/yearly-review-admin-notice.js:
--------------------------------------------------------------------------------
1 | import { withPluginApi } from "discourse/lib/plugin-api";
2 | import YearlyReviewAdminNotice from "discourse/plugins/discourse-yearly-review/discourse/components/yearly-review-admin-notice";
3 |
4 | export default {
5 | name: "yearly-review-admin-notice",
6 | initialize(container) {
7 | withPluginApi("1.18.0", (api) => {
8 | const siteSettings = container.lookup("service:site-settings");
9 |
10 | if (!siteSettings.yearly_review_enabled) {
11 | return;
12 | }
13 |
14 | // Only show this in December of the current year (getMonth is 0-based).
15 | const now = new Date();
16 | if (now.getMonth() === 11) {
17 | api.renderInOutlet("admin-dashboard-top", YearlyReviewAdminNotice);
18 | }
19 | });
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/assets/stylesheets/yearly_review.scss:
--------------------------------------------------------------------------------
1 | [data-review-topic-users="true"] table,
2 | [data-review-featured-topics="true"] table {
3 | width: 100%;
4 | }
5 |
6 | [data-review-topic-users="true"] table th,
7 | [data-review-featured-topics="true"] table th {
8 | text-align: left;
9 | }
10 |
11 | [data-review-topic-users="true"] table {
12 | th {
13 | width: 50%;
14 | }
15 |
16 | td:first-child img {
17 | border-radius: 50%;
18 | }
19 | }
20 |
21 | [data-review-topic-users="true"] table table tr {
22 | border-top: none;
23 | border-bottom: none;
24 | }
25 |
26 | [data-review-topic-users="true"] table table tbody {
27 | border-top: none;
28 | }
29 |
30 | [data-review-topic-users="true"] table table td {
31 | text-align: left;
32 | padding-left: 0;
33 | }
34 |
35 | [data-review-topic-users="true"] table table td:first-child {
36 | width: 25px;
37 | }
38 |
39 | [data-review-users="true"] span {
40 | white-space: pre;
41 | display: inline-block;
42 | margin-bottom: 4px;
43 | }
44 |
45 | [data-review-featured-topics="true"] table th:first-child {
46 | width: 10%;
47 | }
48 |
49 | [data-review-featured-topics="true"] table th:nth-child(2) {
50 | width: 60%;
51 | }
52 |
53 | [data-review-featured-topics="true"] table th:last-child {
54 | width: 30%;
55 | }
56 |
57 | [data-review-featured-topics="true"] table td:first-child img {
58 | border-radius: 50%;
59 | }
60 |
--------------------------------------------------------------------------------
/config/locales/client.en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | js:
3 | yearly_review:
4 | admin_notice: "The Yearly Review topic will be created soon on %{to_be_created_date}. Please review the settings now and be sure to set the yearly review publish category to the staff or other private category so you can view it before making it public, and maybe add a celebratory note! :partying_face: More details…"
5 |
6 |
--------------------------------------------------------------------------------
/config/locales/server.ar.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ar:
8 | site_settings:
9 | yearly_review_enabled: "تفعيل المراجعة السنوية. سيتم إنشاء موضوع تلقائيًا في الأول من يناير لتلخيص نشاط المنتدى في العام السابق."
10 | yearly_review_categories: "الفئات العامة التي سيتم تلخيصها. سيتم إنشاء منشور واحد يتضمن الإحصاءات لكل فئة ضمن أبرز 5 فئات في هذه القائمة. اتركها فارغة لاستخدام أبرز 5 فئات عامة."
11 | yearly_review_exclude_staff: "استثناء فريق العمل من إحصاءات الأعضاء."
12 | yearly_review_include_user_stats: "إضافة إحصاءات تحدد هوية الأعضاء."
13 | yearly_review_include_private_categories: "تضمين نشاط الأعضاء من الفئات الخاصة أو المقيَّدة قراءتها في المراجعة."
14 | yearly_review_publish_category: "الفئة التي سيتم نشر المراجعة فيها. يوصى بشدة بتحديد فئة فريق العمل أو الفئة الخاصة الأخرى؛ حتى تتمكن من عرض الموضوع قبل نشره للعامة."
15 | yearly_review_featured_badge: "أدخل اسم الشارة بالكامل. يمكن تركه فارغًا."
16 | yearly_review:
17 | topic_title: "%{year}: العام قيد المراجعة"
18 | category_topics_title: "أبرز #%{category} من الموضوعات"
19 | title:
20 | users_section: "أبرز المستخدمين في %{year}"
21 | topics_created: "الأكثر في عدد الموضوعات"
22 | replies_created: "الأكثر في عدد الردود"
23 | likes_given: "الأكثر في عدد الإعجابات الممنوحة"
24 | likes_received: "الأكثر في عدد الإعجابات المتلقاة"
25 | visits: "الأكثر في عدد الزيارات"
26 | daily_visits: "الزيارات اليومية"
27 | time_read: "الأكثر في وقت القراءة"
28 | most_replied_to: "الأكثر ردًا عليه"
29 | featured_badge: "المستخدمون الذين تم منحهم شارة %{badge_name}"
30 | action:
31 | topics_created: "الموضوعات"
32 | most_replied_to: "الردود"
33 | replies_created: "الردود"
34 | likes_given: "الإعجابات"
35 | likes_received: "الإعجابات"
36 | visits: "أيام الزيارة"
37 | time_read: "ساعات القراءة"
38 | rank_type:
39 | title:
40 | most_liked: "الأكثر تلقيًا للإعجاب"
41 | most_replied_to: "الأكثر في عدد الردود"
42 | most_popular: "الأكثر شعبية"
43 | most_bookmarked: "الأكثر تسجيلًا للإشارات المرجعية"
44 | most_read: "الأكثر قراءة"
45 | action_types:
46 | most_popular: "النقاط"
47 | most_replied_to: "الردود"
48 | most_liked: "الإعجابات"
49 | most_bookmarked: "الإشارات المرجعية"
50 | most_read: "ساعات القراءة"
51 | user: "المستخدم"
52 | users: "المستخدمون"
53 | days_visited: "أيام الزيارة"
54 | all_yearly_visits: "جميع الزيارات السنوية"
55 | topics: "الموضوعات"
56 | topic: "الموضوع"
57 | likes: "الإعجابات"
58 | bookmarks: "الإشارات المرجعية"
59 | score: "النقاط"
60 | replies: "الردود"
61 | visits: "الزيارات"
62 | more_badge_users: "و%{more} أخرى..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.be.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | be:
8 | yearly_review:
9 | action:
10 | topics_created: "тэмы"
11 | most_replied_to: "Адказы"
12 | replies_created: "Адказы"
13 | likes_given: "сімпатыі"
14 | likes_received: "сімпатыі"
15 | visits: "дзён наведанае"
16 | rank_type:
17 | action_types:
18 | most_popular: "кошт"
19 | most_replied_to: "Адказы"
20 | most_liked: "сімпатыі"
21 | most_bookmarked: "закладкі"
22 | user: "карыстальнік"
23 | users: "карыстальнікаў"
24 | days_visited: "дзён наведанае"
25 | topics: "тэмы"
26 | topic: "тэма"
27 | likes: "сімпатыі"
28 | bookmarks: "закладкі"
29 | score: "кошт"
30 | replies: "Адказы"
31 | visits: "наведванне"
32 |
--------------------------------------------------------------------------------
/config/locales/server.bg.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | bg:
8 | yearly_review:
9 | action:
10 | topics_created: "Теми"
11 | most_replied_to: "Отговори"
12 | replies_created: "Отговори"
13 | likes_given: "Дадени харесвания"
14 | likes_received: "Дадени харесвания"
15 | visits: "Дни Посетена"
16 | rank_type:
17 | title:
18 | most_liked: "Най-харесвани"
19 | action_types:
20 | most_popular: "Точки"
21 | most_replied_to: "Отговори"
22 | most_liked: "Дадени харесвания"
23 | most_bookmarked: "Отметки"
24 | user: "Потребител "
25 | users: "Потребители"
26 | days_visited: "Дни Посетена"
27 | topics: "Теми"
28 | topic: "Тема"
29 | likes: "Дадени харесвания"
30 | bookmarks: "Отметки"
31 | score: "Точки"
32 | replies: "Отговори"
33 | visits: "Посещения "
34 |
--------------------------------------------------------------------------------
/config/locales/server.bs_BA.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | bs_BA:
8 | yearly_review:
9 | action:
10 | topics_created: "Topics"
11 | most_replied_to: "Odgovori"
12 | replies_created: "Odgovori"
13 | likes_given: "Lajkovi"
14 | likes_received: "Lajkovi"
15 | visits: "Dani posjete"
16 | rank_type:
17 | title:
18 | most_liked: "Najviše sviđanja"
19 | action_types:
20 | most_popular: "bodovi"
21 | most_replied_to: "Odgovori"
22 | most_liked: "Lajkovi"
23 | most_bookmarked: "Zabilješke"
24 | user: "Korisnik"
25 | users: "Users"
26 | days_visited: "Dani posjete"
27 | topics: "Topics"
28 | topic: "Topic"
29 | likes: "Lajkovi"
30 | bookmarks: "Zabilješke"
31 | score: "bodovi"
32 | replies: "Odgovori"
33 | visits: "Visits"
34 | more_badge_users: "I %{more} vIše..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.ca.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ca:
8 | yearly_review:
9 | action:
10 | topics_created: "Temes"
11 | most_replied_to: "Respostes"
12 | replies_created: "Respostes"
13 | likes_given: "'M'agrada'"
14 | likes_received: "'M'agrada'"
15 | visits: "Dies visitats"
16 | rank_type:
17 | title:
18 | most_liked: "Ha tingut més 'm'agrada'"
19 | action_types:
20 | most_popular: "Puntuació"
21 | most_replied_to: "Respostes"
22 | most_liked: "'M'agrada'"
23 | most_bookmarked: "Preferits"
24 | user: "Usuari"
25 | users: "Usuaris"
26 | days_visited: "Dies visitats"
27 | topics: "Temes"
28 | topic: "Tema"
29 | likes: "'M'agrada'"
30 | bookmarks: "Preferits"
31 | score: "Puntuació"
32 | replies: "Respostes"
33 | visits: "Visites"
34 | more_badge_users: "I %{more} més..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.cs.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | cs:
8 | yearly_review:
9 | action:
10 | topics_created: "Témata"
11 | most_replied_to: "Odpovědi"
12 | replies_created: "Odpovědi"
13 | likes_given: "Nová 'líbí se'"
14 | likes_received: "Nová 'líbí se'"
15 | visits: "Přítomen dnů"
16 | rank_type:
17 | title:
18 | most_liked: "Nejoblíbenější"
19 | action_types:
20 | most_popular: "Skóre"
21 | most_replied_to: "Odpovědi"
22 | most_liked: "Nová 'líbí se'"
23 | most_bookmarked: "Záložky"
24 | user: "Uživatel"
25 | users: "Účastníci"
26 | days_visited: "Přítomen dnů"
27 | topics: "Témata"
28 | topic: "Témata"
29 | likes: "Nová 'líbí se'"
30 | bookmarks: "Záložky"
31 | score: "Skóre"
32 | replies: "Odpovědi"
33 | visits: "Návštěv"
34 |
--------------------------------------------------------------------------------
/config/locales/server.da.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | da:
8 | yearly_review:
9 | action:
10 | topics_created: "Emner"
11 | most_replied_to: "Svar"
12 | replies_created: "Svar"
13 | likes_given: "Syntes godt om"
14 | likes_received: "Syntes godt om"
15 | visits: "Besøgsdage"
16 | rank_type:
17 | title:
18 | most_liked: "Flest 'Synes godt om' andre"
19 | action_types:
20 | most_popular: "Score"
21 | most_replied_to: "Svar"
22 | most_liked: "Syntes godt om"
23 | most_bookmarked: "Bogmærker"
24 | user: "bruger"
25 | users: "Deltagere"
26 | days_visited: "Besøgsdage"
27 | topics: "Emner"
28 | topic: "Emne"
29 | likes: "Syntes godt om"
30 | bookmarks: "Bogmærker"
31 | score: "Score"
32 | replies: "Svar"
33 | visits: "Besøg"
34 | more_badge_users: "Og %{more} mere..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.de.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | de:
8 | site_settings:
9 | yearly_review_enabled: "Aktiviere den Jahresrückblick. Am 1. Januar wird automatisch ein Thema erstellt, in dem die Forumsaktivitäten des vergangenen Jahres zusammengefasst werden."
10 | yearly_review_categories: "Öffentliche Kategorien zum Zusammenfassen. Für jede der Top-5-Kategorien in dieser Liste wird ein Beitrag mit Statistiken erstellt. Lass das Feld leer, um die Top 5 der öffentlichen Kategorien zu verwenden."
11 | yearly_review_exclude_staff: "Schließe das Team aus der Mitgliederstatistik aus."
12 | yearly_review_include_user_stats: "Füge Statistiken zur Identifizierung der Mitglieder hinzu."
13 | yearly_review_include_private_categories: "Beziehe Mitgliederaktivitäten aus privaten oder lesebeschränkten Kategorien in den Rückblick ein."
14 | yearly_review_publish_category: "Kategorie, in welcher der Rückblick veröffentlicht werden soll. Es wird dringend empfohlen, die Kategorie Team oder eine andere private Kategorie anzugeben, damit du das Thema vor der Veröffentlichung sehen kannst."
15 | yearly_review_featured_badge: "Gib den vollständigen Namen des Abzeichens ein. Kann leer gelassen werden."
16 | yearly_review:
17 | topic_title: "%{year}: das Jahr im Rückblick"
18 | category_topics_title: "Top #%{category} Themen"
19 | title:
20 | users_section: "Top-Benutzer %{year}"
21 | topics_created: "Meiste Themen"
22 | replies_created: "Meiste Antworten"
23 | likes_given: "Meiste vergebene „Gefällt mir“"
24 | likes_received: "Meiste erhaltene „Gefällt mir“"
25 | visits: "Meiste Besuche"
26 | daily_visits: "Tägliche Besuche"
27 | time_read: "Meiste Lesezeit"
28 | most_replied_to: "Häufigste Antworten an"
29 | featured_badge: "Benutzer, denen das Abzeichen „%{badge_name}“ verliehen wurde"
30 | action:
31 | topics_created: "Themen"
32 | most_replied_to: "Antworten"
33 | replies_created: "Antworten"
34 | likes_given: "„Gefällt mir“"
35 | likes_received: "„Gefällt mir“"
36 | visits: "Besuchstage"
37 | time_read: "Stunden gelesen"
38 | rank_type:
39 | title:
40 | most_liked: "Am meisten „Gefällt mir“"
41 | most_replied_to: "Meiste Antworten"
42 | most_popular: "Am beliebtesten"
43 | most_bookmarked: "Am häufigsten mit Lesezeichen versehen"
44 | most_read: "Meist gelesen"
45 | action_types:
46 | most_popular: "Score"
47 | most_replied_to: "Antworten"
48 | most_liked: "„Gefällt mir“"
49 | most_bookmarked: "Lesezeichen"
50 | most_read: "Stunden gelesen"
51 | user: "Benutzer"
52 | users: "Benutzer"
53 | days_visited: "Besuchstage"
54 | all_yearly_visits: "Alle jährlichen Besuche"
55 | topics: "Themen"
56 | topic: "Thema"
57 | likes: "„Gefällt mir“"
58 | bookmarks: "Lesezeichen"
59 | score: "Score"
60 | replies: "Antworten"
61 | visits: "Besuche"
62 | more_badge_users: "Und %{more} mehr …"
63 |
--------------------------------------------------------------------------------
/config/locales/server.el.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | el:
8 | yearly_review:
9 | action:
10 | topics_created: "Θέματα"
11 | most_replied_to: "Απαντήσεις"
12 | replies_created: "Απαντήσεις"
13 | likes_given: "Μου αρέσει"
14 | likes_received: "Μου αρέσει"
15 | visits: "Μέρες Επίσκεψης"
16 | rank_type:
17 | title:
18 | most_liked: "Περισσότερα \"Μου Αρέσει\""
19 | action_types:
20 | most_popular: "Βαθμολογία"
21 | most_replied_to: "Απαντήσεις"
22 | most_liked: "Μου αρέσει"
23 | most_bookmarked: "Σελιδοδείκτες"
24 | user: "Όνομα Χρήστη"
25 | users: "Χρήστες"
26 | days_visited: "Μέρες Επίσκεψης"
27 | topics: "Θέματα"
28 | topic: "Νήμα"
29 | likes: "Μου αρέσει"
30 | bookmarks: "Σελιδοδείκτες"
31 | score: "Βαθμολογία"
32 | replies: "Απαντήσεις"
33 | visits: "Επισκέψεις"
34 | more_badge_users: "Και %{more} ακόμη..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | site_settings:
3 | yearly_review_enabled: "Enable the yearly review. On January 1st, a topic will be automatically created summarizing the previous year's forum activity."
4 | yearly_review_categories: "Public categories to summarize. One post with stats will be created for each of the top 5 categories in this list. Leave blank to use the top 5 public categories."
5 | yearly_review_exclude_staff: "Exclude Staff from member stats."
6 | yearly_review_include_user_stats: "Add member-identifying stats."
7 | yearly_review_include_private_categories: "Include member activity from private or read-restricted categories in the review."
8 | yearly_review_publish_category: "Category the review will be published in. It is highly recommended to specify the staff or other private category so you can view the topic before making it public."
9 | yearly_review_featured_badge: "Enter the full badge name. Can be left blank."
10 | yearly_review:
11 | topic_title: "%{year}: The Year in Review"
12 | category_topics_title: "Top #%{category} Topics"
13 | title:
14 | users_section: "%{year}'s Top Users"
15 | topics_created: "Most Topics"
16 | replies_created: "Most Replies"
17 | likes_given: "Most Likes Given"
18 | likes_received: "Most Likes Received"
19 | visits: "Most Visits"
20 | daily_visits: "Daily Visits"
21 | time_read: "Most Time Reading"
22 | most_replied_to: "Most Replied to"
23 | featured_badge: "Users Granted the %{badge_name} Badge"
24 | action:
25 | topics_created: "Topics"
26 | most_replied_to: "Replies"
27 | replies_created: "Replies"
28 | likes_given: "Likes"
29 | likes_received: "Likes"
30 | visits: "Days Visited"
31 | time_read: "Hours Read"
32 | rank_type:
33 | title:
34 | most_liked: "Most Liked"
35 | most_replied_to: "Most Replies"
36 | most_popular: "Most Popular"
37 | most_bookmarked: "Most Bookmarked"
38 | most_read: "Most Read"
39 | action_types:
40 | most_popular: "Score"
41 | most_replied_to: "Replies"
42 | most_liked: "Likes"
43 | most_bookmarked: "Bookmarks"
44 | most_read: "Hours Read"
45 | user: "User"
46 | users: "Users"
47 | days_visited: "Days Visited"
48 | all_yearly_visits: "All Yearly Visits"
49 | topics: "Topics"
50 | topic: "Topic"
51 | likes: "Likes"
52 | bookmarks: "Bookmarks"
53 | score: "Score"
54 | replies: "Replies"
55 | visits: "Visits"
56 | more_badge_users: "And %{more} more..."
57 |
--------------------------------------------------------------------------------
/config/locales/server.en_GB.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | en_GB:
8 |
--------------------------------------------------------------------------------
/config/locales/server.es.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | es:
8 | site_settings:
9 | yearly_review_enabled: "Activa la revisión anual. El 1 de enero se creará automáticamente un tema que resumirá la actividad del foro del año anterior."
10 | yearly_review_categories: "Categorías públicas para resumir. Se creará una entrada con estadísticas para cada una de las 5 categorías principales de esta lista. Déjalo en blanco para utilizar las 5 categorías públicas principales."
11 | yearly_review_exclude_staff: "Excluir al personal de las estadísticas de los miembros."
12 | yearly_review_include_user_stats: "Añadir estadísticas identificativas de los miembros."
13 | yearly_review_include_private_categories: "Incluir en la revisión la actividad de los miembros de las categorías privadas o de lectura restringida."
14 | yearly_review_publish_category: "Categoría en la que se publicará la revisión. Es muy recomendable especificar la categoría personal u otra categoría privada para que puedas ver el tema antes de hacerlo público."
15 | yearly_review_featured_badge: "Introduce el nombre completo de la insignia. Se puede dejar en blanco."
16 | yearly_review:
17 | topic_title: "%{year}: Resumen del año"
18 | category_topics_title: "Principales #%{category} temas"
19 | title:
20 | users_section: "Usuarios principales de %{year}"
21 | topics_created: "Más temas"
22 | replies_created: "Más respuestas"
23 | likes_given: "Mayor número de «Me gusta» dados"
24 | likes_received: "Mayor número de «Me gusta» recibidos"
25 | visits: "Más visitas"
26 | daily_visits: "Visitas diarias"
27 | time_read: "Más tiempo de lectura"
28 | most_replied_to: "Más respondido a"
29 | featured_badge: "Usuarios con la insignia %{badge_name}"
30 | action:
31 | topics_created: "Temas"
32 | most_replied_to: "Respuestas"
33 | replies_created: "Respuestas"
34 | likes_given: "Me gusta dados"
35 | likes_received: "Me gusta recibidos"
36 | visits: "Días visitados"
37 | time_read: "Horas de lectura"
38 | rank_type:
39 | title:
40 | most_liked: "Más me gusta recibidos"
41 | most_replied_to: "Más respuestas"
42 | most_popular: "Más popular"
43 | most_bookmarked: "Más marcados"
44 | most_read: "Más leídos"
45 | action_types:
46 | most_popular: "Puntuación"
47 | most_replied_to: "Respuestas"
48 | most_liked: "Me gusta"
49 | most_bookmarked: "Marcadores"
50 | most_read: "Horas de lectura"
51 | user: "Usuario"
52 | users: "Usuarios"
53 | days_visited: "Días visitados"
54 | all_yearly_visits: "Todas las visitas anuales"
55 | topics: "Temas"
56 | topic: "Tema"
57 | likes: "Me gusta"
58 | bookmarks: "Marcadores"
59 | score: "Puntuación"
60 | replies: "Respuestas"
61 | visits: "Visitas"
62 | more_badge_users: "Y %{more} más..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.et.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | et:
8 | yearly_review:
9 | action:
10 | topics_created: "Teemasid"
11 | most_replied_to: "Vastused"
12 | replies_created: "Vastused"
13 | likes_given: "Meeldimisi antud"
14 | likes_received: "Meeldimisi antud"
15 | visits: "Päevi külastatud"
16 | rank_type:
17 | title:
18 | most_liked: "Enim meeldinud"
19 | action_types:
20 | most_popular: "Skoor"
21 | most_replied_to: "Vastused"
22 | most_liked: "Meeldimisi antud"
23 | most_bookmarked: "Järjehoidjat"
24 | user: "Kasutaja"
25 | users: "Kasutajad"
26 | days_visited: "Päevi külastatud"
27 | topics: "Teemasid"
28 | topic: "Teema"
29 | likes: "Meeldimisi antud"
30 | bookmarks: "Järjehoidjat"
31 | score: "Skoor"
32 | replies: "Vastused"
33 | visits: "Külastusi"
34 |
--------------------------------------------------------------------------------
/config/locales/server.fa_IR.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | fa_IR:
8 | yearly_review:
9 | action:
10 | topics_created: "موضوعات"
11 | most_replied_to: "پاسخها"
12 | replies_created: "پاسخها"
13 | likes_given: "پسندیدهها"
14 | likes_received: "پسندیدهها"
15 | visits: "روز های بازدید شده"
16 | rank_type:
17 | title:
18 | most_liked: "بیشترین پسندیده شده"
19 | action_types:
20 | most_popular: "امتیاز"
21 | most_replied_to: "پاسخها"
22 | most_liked: "پسندیدهها"
23 | most_bookmarked: "نشانکها"
24 | user: "کاربر"
25 | users: "کاربران"
26 | days_visited: "روز های بازدید شده"
27 | topics: "موضوعات"
28 | topic: "موضوعات"
29 | likes: "پسندیدهها"
30 | bookmarks: "نشانکها"
31 | score: "امتیاز"
32 | replies: "پاسخها"
33 | visits: "بازدیدها"
34 |
--------------------------------------------------------------------------------
/config/locales/server.fi.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | fi:
8 | site_settings:
9 | yearly_review_enabled: "Ota vuosikatsaus käyttöön. Tammikuun 1. päivänä luodaan automaattisesti ketju, joka sisältää yhteenvedon edellisen vuoden foorumitoiminnasta."
10 | yearly_review_categories: "Yleiset alueet, joista yhteenveto tehdään. Yksi tilastot sisältävä viesti luodaan jokaiselle tämän luettelon viidelle suosituimmalle alueelle. Jätä tyhjäksi käyttääksesi viittä suosituinta julkista aluetta."
11 | yearly_review_exclude_staff: "Jätä henkilökunta pois jäsentilastoista."
12 | yearly_review_include_user_stats: "Lisää tilastoja, joista jäsenet ovat tunnistettavissa."
13 | yearly_review_include_private_categories: "Sisällytä katsaukseen jäsenten toiminta yksityisillä tai lukurajoitetuilla alueilla."
14 | yearly_review_publish_category: "Alue, jolla katsausjulkaistaan. On erittäin suositeltavaa määrittää henkilökunnan alue tai muu yksityinen alue, jotta voit tarkastella aihetta ennen sen julkistamista."
15 | yearly_review_featured_badge: "Anna kunniamerkin koko nimi. Voidaan jättää tyhjäksi."
16 | yearly_review:
17 | topic_title: "%{year}: vuosikatsaus"
18 | category_topics_title: "Alueen %{category} suosituimmat ketjut"
19 | title:
20 | users_section: "Vuoden %{year} huippukäyttäjät"
21 | topics_created: "Eniten ketjuja"
22 | replies_created: "Eniten vastauksia"
23 | likes_given: "Eniten annettuja tykkäyksiä"
24 | likes_received: "Eniten saatuja tykkäyksiä"
25 | visits: "Eniten vierailuja"
26 | daily_visits: "Päivittäisiä vierailuja"
27 | time_read: "Eniten lukuaikaa"
28 | most_replied_to: "Useimmin vastatut"
29 | featured_badge: "Käyttäjät, joille on annettu kunniamerkki %{badge_name}"
30 | action:
31 | topics_created: "Ketjuja"
32 | most_replied_to: "Vastauksia"
33 | replies_created: "Vastauksia"
34 | likes_given: "Tykkäyksiä"
35 | likes_received: "Tykkäyksiä"
36 | visits: "Vierailupäiviä"
37 | time_read: "Lukutunteja"
38 | rank_type:
39 | title:
40 | most_liked: "Tykätyimmät"
41 | most_replied_to: "Eniten vastauksia"
42 | most_popular: "Suosituimmat"
43 | most_bookmarked: "Kirjanmerkityimmät"
44 | most_read: "Luetuimmat"
45 | action_types:
46 | most_popular: "Pistemäärä"
47 | most_replied_to: "Vastauksia"
48 | most_liked: "Tykkäyksiä"
49 | most_bookmarked: "Kirjanmerkkejä"
50 | most_read: "Lukutunteja"
51 | user: "Käyttäjä"
52 | users: "Käyttäjiä"
53 | days_visited: "Vierailupäiviä"
54 | all_yearly_visits: "Kaikki vuosittaiset vierailut"
55 | topics: "Ketjuja"
56 | topic: "Ketju"
57 | likes: "Tykkäyksiä"
58 | bookmarks: "Kirjanmerkkejä"
59 | score: "Pistemäärä"
60 | replies: "Vastauksia"
61 | visits: "Vierailuja"
62 | more_badge_users: "Ja %{more} muuta..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.fr.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | fr:
8 | site_settings:
9 | yearly_review_enabled: "Activez la révision annuelle. Le 1er janvier, un sujet sera automatiquement créé pour résumer l'activité du forum de l'année précédente."
10 | yearly_review_categories: "Catégories publiques à résumer. Une publication avec des statistiques sera créée pour chacune des 5 premières catégories de cette liste. Laissez-les vide pour utiliser les 5 principales catégories publiques."
11 | yearly_review_exclude_staff: "Exclure le personnel des statistiques des membres."
12 | yearly_review_include_user_stats: "Ajouter les statistiques d'identification des membres."
13 | yearly_review_include_private_categories: "Inclure l'activité du membre à partir de catégories privées ou en lecture restreintes dans la révision."
14 | yearly_review_publish_category: "Catégorie dans laquelle l'avis sera publié. Il est fortement recommandé de spécifier la catégorie du personnel ou une autre catégorie privée afin de pouvoir consulter le sujet avant de le rendre public."
15 | yearly_review_featured_badge: "Saisissez le nom complet du badge. Cet espace peut être laissé vide."
16 | yearly_review:
17 | topic_title: "%{year} : bilan de l'année"
18 | category_topics_title: "%{category} principaux sujets"
19 | title:
20 | users_section: "Meilleurs utilisateurs de %{year}"
21 | topics_created: "Le plus de sujets"
22 | replies_created: "Le plus de réponses"
23 | likes_given: "Le plus de « J'aime » donnés"
24 | likes_received: "Le plus de « J'aime » reçus"
25 | visits: "Le plus de visites"
26 | daily_visits: "Visites quotidiennes"
27 | time_read: "Le plus de temps de lecture"
28 | most_replied_to: "Le plus de réponses reçues"
29 | featured_badge: "Utilisateurs ayant obtenu le badge %{badge_name}"
30 | action:
31 | topics_created: "Sujets"
32 | most_replied_to: "Réponses"
33 | replies_created: "Réponses"
34 | likes_given: "« J'aime » attribués"
35 | likes_received: "« J'aime » attribués"
36 | visits: "Jours de visite"
37 | time_read: "Heures de lecture"
38 | rank_type:
39 | title:
40 | most_liked: "Le plus aimé"
41 | most_replied_to: "Le plus de réponses"
42 | most_popular: "Le plus populaire"
43 | most_bookmarked: "Le plus marqué"
44 | most_read: "Le plus lu"
45 | action_types:
46 | most_popular: "Score"
47 | most_replied_to: "Réponses"
48 | most_liked: "« J'aime » attribués"
49 | most_bookmarked: "Signets"
50 | most_read: "Heures de lecture"
51 | user: "Utilisateur"
52 | users: "Utilisateurs"
53 | days_visited: "Jours de visite"
54 | all_yearly_visits: "Toutes les visites de l'année"
55 | topics: "Sujets"
56 | topic: "Sujet"
57 | likes: "« J'aime » attribués"
58 | bookmarks: "Signets"
59 | score: "Score"
60 | replies: "Réponses"
61 | visits: "Visites"
62 | more_badge_users: "Et %{more} de plus…"
63 |
--------------------------------------------------------------------------------
/config/locales/server.gl.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | gl:
8 | yearly_review:
9 | action:
10 | topics_created: "Temas"
11 | most_replied_to: "Réplicas"
12 | replies_created: "Réplicas"
13 | likes_given: "Gústame"
14 | likes_received: "Gústame"
15 | visits: "Días desde visita"
16 | rank_type:
17 | title:
18 | most_liked: "Con máis gústames"
19 | action_types:
20 | most_popular: "Puntuación"
21 | most_replied_to: "Réplicas"
22 | most_liked: "Gústame"
23 | most_bookmarked: "Marcadores"
24 | user: "Usuario"
25 | users: "Usuarios"
26 | days_visited: "Días desde visita"
27 | topics: "Temas"
28 | topic: "Tema"
29 | likes: "Gústame"
30 | bookmarks: "Marcadores"
31 | score: "Puntuación"
32 | replies: "Réplicas"
33 | visits: "Visitas"
34 |
--------------------------------------------------------------------------------
/config/locales/server.he.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | he:
8 | site_settings:
9 | yearly_review_enabled: "הפעלת הסקירה השנתית. ב־1 בינואר, ייווצר נושא אוטומטית שמסכם את פעילות הפורום בשנה החולפת."
10 | yearly_review_categories: "קטגוריות ציבוריות לסקירה. ייווצר פוסט אחד עם סטטיסטיקה לכל אחת מחמש הקטגוריות המובילות ברשימה הזאת. יש להשאיר ריק כדי להשתמש בחמש הקטגוריות הציבוריות המובילות."
11 | yearly_review_exclude_staff: "להחריג את הסגל מסטטיסטיקת החברים."
12 | yearly_review_include_user_stats: "הוספת נתונים גלויים על משתמשים."
13 | yearly_review_include_private_categories: "לכלול פעילות חברים מקטגוריות פרטיות או מוגבלות לקריאה בסקירה."
14 | yearly_review_publish_category: "הקטגוריה בה תתפרסם הסקירה. מומלץ מאוד לציין את הסגל או קטגוריה פרטית אחרת כדי לאפשר לך לצפות בנושא לפני הצגתו לציבור."
15 | yearly_review_featured_badge: "נא למלא את שם העיטור המלא. יכול להישאר ריק."
16 | yearly_review:
17 | topic_title: "%{year}: סקירת השנה"
18 | category_topics_title: "%{category} הנושאים המובילים"
19 | title:
20 | users_section: "המשתמשים המובילים לשנת %{year}"
21 | topics_created: "הכי הרבה נושאים"
22 | replies_created: "הכי הרבה תגובות"
23 | likes_given: "הכי הרבה לייקים ניתנו"
24 | likes_received: "הכי הרבה לייקים התקבלו"
25 | visits: "הכי הרבה ביקורים"
26 | daily_visits: "ביקורים יומיים"
27 | time_read: "זמן הקריאה המרבי"
28 | most_replied_to: "התקבלו הכי הרבה תגובות"
29 | featured_badge: "משתמשים שהוענק להם העיטור %{badge_name}"
30 | action:
31 | topics_created: "נושאים"
32 | most_replied_to: "תגובות"
33 | replies_created: "תגובות"
34 | likes_given: "לייקים"
35 | likes_received: "לייקים"
36 | visits: "ביקורים יומיים"
37 | time_read: "שעות קריאה"
38 | rank_type:
39 | title:
40 | most_liked: "הכי הרבה לייקים"
41 | most_replied_to: "הכי הרבה תגובות"
42 | most_popular: "הכי נפוץ"
43 | most_bookmarked: "הכי נוסף לסימניות"
44 | most_read: "הכי נקרא"
45 | action_types:
46 | most_popular: "ניקוד"
47 | most_replied_to: "תגובות"
48 | most_liked: "לייקים"
49 | most_bookmarked: "סימניות"
50 | most_read: "שעות קריאה"
51 | user: "משתמש"
52 | users: "משתמשים"
53 | days_visited: "ביקורים יומיים"
54 | all_yearly_visits: "כל הביקורים השנתיים"
55 | topics: "נושאים"
56 | topic: "נושא"
57 | likes: "לייקים"
58 | bookmarks: "סימניות"
59 | score: "ניקוד"
60 | replies: "תגובות"
61 | visits: "ביקורים"
62 | more_badge_users: "ועוד %{more}…"
63 |
--------------------------------------------------------------------------------
/config/locales/server.hr.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | hr:
8 | yearly_review:
9 | action:
10 | topics_created: "Tema"
11 | most_replied_to: "Odgovori"
12 | replies_created: "Odgovori"
13 | likes_given: "Like-ova"
14 | likes_received: "Like-ova"
15 | visits: "Dana posjećeno"
16 | rank_type:
17 | title:
18 | most_liked: "Najviše se sviđa"
19 | action_types:
20 | most_popular: "Ocjena"
21 | most_replied_to: "Odgovori"
22 | most_liked: "Like-ova"
23 | most_bookmarked: "Zabilješke"
24 | user: "¸Korisnik"
25 | users: "Korisnika"
26 | days_visited: "Dana posjećeno"
27 | topics: "Tema"
28 | topic: "Teme"
29 | likes: "Like-ova"
30 | bookmarks: "Zabilješke"
31 | score: "Ocjena"
32 | replies: "Odgovori"
33 | visits: "Posjeta"
34 | more_badge_users: "I %{more} vIše..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.hu.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | hu:
8 | yearly_review:
9 | action:
10 | topics_created: "Témák"
11 | most_replied_to: "Válaszok"
12 | replies_created: "Válaszok"
13 | likes_given: "Kapott kedvelések"
14 | likes_received: "Kapott kedvelések"
15 | visits: "Látogatott nap"
16 | rank_type:
17 | title:
18 | most_liked: "Legtöbbet kedvelt"
19 | action_types:
20 | most_popular: "Pontszám"
21 | most_replied_to: "Válaszok"
22 | most_liked: "Kapott kedvelések"
23 | most_bookmarked: "Könyvjelzők"
24 | user: "Felhasználó"
25 | users: "Felhasználók"
26 | days_visited: "Látogatott nap"
27 | topics: "Témák"
28 | topic: "Témák"
29 | likes: "Kapott kedvelések"
30 | bookmarks: "Könyvjelzők"
31 | score: "Pontszám"
32 | replies: "Válaszok"
33 | visits: "Látogatás"
34 | more_badge_users: "És még további %{more}..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.hy.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | hy:
8 | yearly_review:
9 | action:
10 | topics_created: "Թեմա"
11 | most_replied_to: "Պատասխաններ"
12 | replies_created: "Պատասխաններ"
13 | likes_given: "Հավանում"
14 | likes_received: "Հավանում"
15 | visits: "Այցելության Օր"
16 | rank_type:
17 | title:
18 | most_liked: "Ամենաշատ Հավանած"
19 | action_types:
20 | most_popular: "Քանակ"
21 | most_replied_to: "Պատասխաններ"
22 | most_liked: "Հավանում"
23 | most_bookmarked: "Էջանշաններ"
24 | user: "Օգտատեր"
25 | users: "Օգտատեր"
26 | days_visited: "Այցելության Օր"
27 | topics: "Թեմա"
28 | topic: "Թեմա"
29 | likes: "Հավանում"
30 | bookmarks: "Էջանշաններ"
31 | score: "Քանակ"
32 | replies: "Պատասխաններ"
33 | visits: "Այցելություններ"
34 |
--------------------------------------------------------------------------------
/config/locales/server.id.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | id:
8 | yearly_review:
9 | action:
10 | topics_created: "Topik-topik"
11 | most_replied_to: "balasan"
12 | replies_created: "balasan"
13 | likes_given: "Likes Diberikan"
14 | likes_received: "Likes Diberikan"
15 | visits: "Hari Berkunjung"
16 | rank_type:
17 | title:
18 | most_liked: "Paling Disukai"
19 | action_types:
20 | most_popular: "Skor"
21 | most_replied_to: "balasan"
22 | most_liked: "Likes Diberikan"
23 | most_bookmarked: "Markah"
24 | user: "Pengguna"
25 | users: "Pengguna"
26 | days_visited: "Hari Berkunjung"
27 | topics: "Topik-topik"
28 | topic: "Topik"
29 | likes: "Likes Diberikan"
30 | bookmarks: "Markah"
31 | score: "Skor"
32 | replies: "balasan"
33 | visits: "mengunjungi"
34 |
--------------------------------------------------------------------------------
/config/locales/server.it.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | it:
8 | site_settings:
9 | yearly_review_enabled: "Abilita la revisione annuale. Il 1° gennaio verrà creato automaticamente un argomento che riassume l'attività del forum dell'anno precedente."
10 | yearly_review_categories: "Categorie pubbliche da riassumere. Verrà creato un post con statistiche per ciascuna delle prime 5 categorie in questo elenco. Lascia vuoto per utilizzare le prime 5 categorie pubbliche."
11 | yearly_review_exclude_staff: "Escludi lo staff dalle statistiche dei membri."
12 | yearly_review_include_user_stats: "Aggiungi statistiche identificative dei membri."
13 | yearly_review_include_private_categories: "Includi nella revisione l'attività dei membri di categorie private o con limitazioni di lettura."
14 | yearly_review_publish_category: "Categoria in cui verrà pubblicata la revisione. Si consiglia vivamente di specificare la categoria personale o altra categoria privata in modo da poter visualizzare l'argomento prima di renderlo pubblico."
15 | yearly_review_featured_badge: "Inserisci il nome completo del distintivo. Può essere lasciato vuoto."
16 | yearly_review:
17 | topic_title: "%{year}: L'anno della revisione"
18 | category_topics_title: "I primi %{category} argomenti"
19 | title:
20 | users_section: "I principali utenti dell'anno %{year}"
21 | topics_created: "Con più argomenti"
22 | replies_created: "Con più risposte"
23 | likes_given: "Più \"Mi piace\" dati"
24 | likes_received: "Più \"Mi piace\" ricevuti"
25 | visits: "Con più visite"
26 | daily_visits: "Visite giornaliere"
27 | time_read: "Maggiori tempi di lettura"
28 | most_replied_to: "Più risposte ricevute"
29 | featured_badge: "Utenti che hanno ottenuto il distintivo %{badge_name}"
30 | action:
31 | topics_created: "Argomenti"
32 | most_replied_to: "Risposte"
33 | replies_created: "Risposte"
34 | likes_given: "Mi piace"
35 | likes_received: "Mi piace"
36 | visits: "Giorni di frequenza"
37 | time_read: "Ore di lettura"
38 | rank_type:
39 | title:
40 | most_liked: "Con più \"Mi Piace\""
41 | most_replied_to: "Più risposte"
42 | most_popular: "Più popolari"
43 | most_bookmarked: "Più aggiunti ai segnalibri"
44 | most_read: "Più letti"
45 | action_types:
46 | most_popular: "Punteggio"
47 | most_replied_to: "Risposte"
48 | most_liked: "Mi piace"
49 | most_bookmarked: "Segnalibri"
50 | most_read: "Ore di lettura"
51 | user: "Utente"
52 | users: "Utenti"
53 | days_visited: "Giorni di frequenza"
54 | all_yearly_visits: "Tutte le visite annuali"
55 | topics: "Argomenti"
56 | topic: "Argomento"
57 | likes: "Mi piace"
58 | bookmarks: "Segnalibri"
59 | score: "Punteggio"
60 | replies: "Risposte"
61 | visits: "Visite"
62 | more_badge_users: "E altri %{more}..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.ja.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ja:
8 | site_settings:
9 | yearly_review_enabled: "年次レビューを有効化します。1 月 1 日に、前年のフォーラムのアクティビティを要約したトピックが自動的に作成されます。"
10 | yearly_review_categories: "要約する公開カテゴリです。このリストの上位 5 つのカテゴリごとに、統計付きの投稿が 1 件作成されます。上位 5 件の公開カテゴリを使用する場合は、空白のままにします。"
11 | yearly_review_exclude_staff: "メンバー統計からスタッフを除外します。"
12 | yearly_review_include_user_stats: "メンバーを特定する統計を追加します。"
13 | yearly_review_include_private_categories: "レビューに非公開のカテゴリまたは読み取り制限のあるカテゴリのメンバーアクティビティを含めます。"
14 | yearly_review_publish_category: "レビューが公開されるカテゴリです。公開前にトピックを確認できるように、スタッフまたはその他の非公開カテゴリを指定することを強くお勧めします。"
15 | yearly_review_featured_badge: "バッジのフルネームを入力します。空白にすることができます。"
16 | yearly_review:
17 | topic_title: "%{year} 年を振り返る"
18 | category_topics_title: "上位 %{category} 件のトピック"
19 | title:
20 | users_section: "%{year} 年の上位ユーザー"
21 | topics_created: "最も多かったトピック"
22 | replies_created: "最も多かった返信"
23 | likes_given: "最も多く与えた「いいね!」"
24 | likes_received: "最も多く受けた「いいね!」"
25 | visits: "最も多かったアクセス"
26 | daily_visits: "1 日当たりのアクセス"
27 | time_read: "最も長く閲覧された項目"
28 | most_replied_to: "最も返信の多かった項目"
29 | featured_badge: "%{badge_name} バッジを付与されたユーザー"
30 | action:
31 | topics_created: "トピック"
32 | most_replied_to: "返信先"
33 | replies_created: "返信"
34 | likes_given: "「いいね!」"
35 | likes_received: "「いいね!」"
36 | visits: "アクセス日数"
37 | time_read: "閲覧時間"
38 | rank_type:
39 | title:
40 | most_liked: "最も「いいね!」の多い項目"
41 | most_replied_to: "最も返信の多い項目"
42 | most_popular: "最も人気の高い項目"
43 | most_bookmarked: "最もブックマークされた項目"
44 | most_read: "最も閲覧された項目"
45 | action_types:
46 | most_popular: "スコア"
47 | most_replied_to: "返信"
48 | most_liked: "「いいね!」"
49 | most_bookmarked: "ブックマーク"
50 | most_read: "閲覧時間"
51 | user: "ユーザー"
52 | users: "ユーザー"
53 | days_visited: "アクセス日数"
54 | all_yearly_visits: "年間アクセス数"
55 | topics: "トピック"
56 | topic: "トピック"
57 | likes: "「いいね!」"
58 | bookmarks: "ブックマーク"
59 | score: "スコア"
60 | replies: "返信"
61 | visits: "アクセス"
62 | more_badge_users: "および他 %{more} 人..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.ko.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ko:
8 | yearly_review:
9 | action:
10 | topics_created: "글"
11 | most_replied_to: "댓글"
12 | replies_created: "댓글"
13 | likes_given: "좋아요 수"
14 | likes_received: "좋아요 수"
15 | visits: "방문 일수"
16 | rank_type:
17 | title:
18 | most_liked: "가장 좋아함"
19 | action_types:
20 | most_popular: "점수"
21 | most_replied_to: "댓글"
22 | most_liked: "좋아요 수"
23 | most_bookmarked: "북마크"
24 | user: "사용자"
25 | users: "사용자들"
26 | days_visited: "방문 일수"
27 | topics: "글"
28 | topic: "토픽"
29 | likes: "좋아요 수"
30 | bookmarks: "북마크"
31 | score: "점수"
32 | replies: "댓글"
33 | visits: "방문"
34 | more_badge_users: "그리고 %{more} 더..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.lt.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | lt:
8 | yearly_review:
9 | action:
10 | topics_created: "Temos"
11 | most_replied_to: "Atsakymai"
12 | replies_created: "Atsakymai"
13 | likes_given: "Patikimai"
14 | likes_received: "Patikimai"
15 | visits: "Apsilankymo dienos"
16 | rank_type:
17 | title:
18 | most_liked: "Labiausiai Mėgstamos"
19 | action_types:
20 | most_popular: "Rezultatas"
21 | most_replied_to: "Atsakymai"
22 | most_liked: "Patikimai"
23 | most_bookmarked: "Žymės"
24 | user: "Vartotojas"
25 | users: "Vartotojai"
26 | days_visited: "Apsilankymo dienos"
27 | topics: "Temos"
28 | topic: "Tema"
29 | likes: "Patikimai"
30 | bookmarks: "Žymės"
31 | score: "Rezultatas"
32 | replies: "Atsakymai"
33 | visits: "Apsilankymai"
34 | more_badge_users: "Ir %{more} daugiau..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.lv.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | lv:
8 | yearly_review:
9 | action:
10 | topics_created: "Tēmas"
11 | most_replied_to: "Atbildes"
12 | replies_created: "Atbildes"
13 | likes_given: "Patīk"
14 | likes_received: "Patīk"
15 | visits: "Dienas, kurās apmeklēja"
16 | rank_type:
17 | title:
18 | most_liked: "Visvairāk atzinību"
19 | action_types:
20 | most_popular: "Rezultāts"
21 | most_replied_to: "Atbildes"
22 | most_liked: "Patīk"
23 | most_bookmarked: "Grāmatzīmes"
24 | user: "Lietotājs"
25 | users: "Lietotāji"
26 | days_visited: "Dienas, kurās apmeklēja"
27 | topics: "Tēmas"
28 | topic: "Tēmas"
29 | likes: "Patīk"
30 | bookmarks: "Grāmatzīmes"
31 | score: "Rezultāts"
32 | replies: "Atbildes"
33 | visits: "Apmeklējumi"
34 |
--------------------------------------------------------------------------------
/config/locales/server.nb_NO.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | nb_NO:
8 | yearly_review:
9 | action:
10 | topics_created: "Emner"
11 | most_replied_to: "Svar"
12 | replies_created: "Svar"
13 | likes_given: "Likes tildelt"
14 | likes_received: "Likes tildelt"
15 | visits: "Dager besøkt"
16 | rank_type:
17 | title:
18 | most_liked: "Mest Likt"
19 | action_types:
20 | most_popular: "Poeng"
21 | most_replied_to: "Svar"
22 | most_liked: "Likes tildelt"
23 | most_bookmarked: "Bokmerker"
24 | user: "Bruker"
25 | users: "Deltakere"
26 | days_visited: "Dager besøkt"
27 | topics: "Emner"
28 | topic: "Emne"
29 | likes: "Likes tildelt"
30 | bookmarks: "Bokmerker"
31 | score: "Poeng"
32 | replies: "Svar"
33 | visits: "Besøk"
34 |
--------------------------------------------------------------------------------
/config/locales/server.nl.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | nl:
8 | site_settings:
9 | yearly_review_enabled: "Schakel de jaarlijkse beoordeling in. Op 1 januari wordt automatisch een topic gemaakt met een samenvatting van de forumactiviteit van het afgelopen jaar."
10 | yearly_review_categories: "Openbare categorieën om samen te vatten. Er wordt één bericht met statistieken gemaakt voor elk van de top 5 categorieën in deze lijst. Laat dit veld leeg om de top 5 openbare categorieën te gebruiken."
11 | yearly_review_exclude_staff: "Sluit medewerkers uit van ledenstatistieken."
12 | yearly_review_include_user_stats: "Voeg ledenidentificerende statistieken toe."
13 | yearly_review_include_private_categories: "Neem ledenactiviteit van privécategorieën of categorieën met leesbeperkingen op in de beoordeling."
14 | yearly_review_publish_category: "Categorie waarin de beoordeling wordt gepubliceerd. Het wordt sterk aanbevolen om de medewerkerscategorie of een andere privécategorie op te geven, zodat je het topic kunt bekijken voordat je het openbaar maakt."
15 | yearly_review_featured_badge: "Voer de volledige badgenaam in. Mag leeg worden gelaten."
16 | yearly_review:
17 | topic_title: "%{year}: het jaaroverzicht"
18 | category_topics_title: "Top %{category} topics"
19 | title:
20 | users_section: "Topgebruikers van %{year}"
21 | topics_created: "Meeste topics"
22 | replies_created: "Meeste antwoorden"
23 | likes_given: "Meeste likes gegeven"
24 | likes_received: "Meeste likes ontvangen"
25 | visits: "Meeste bezoeken"
26 | daily_visits: "Dagelijkse bezoeken"
27 | time_read: "Meeste leestijd"
28 | most_replied_to: "Meest op geantwoord"
29 | featured_badge: "Gebruikers met de badge %{badge_name}"
30 | action:
31 | topics_created: "Topics"
32 | most_replied_to: "Antwoorden"
33 | replies_created: "Antwoorden"
34 | likes_given: "Likes"
35 | likes_received: "Likes"
36 | visits: "Dagen bezocht"
37 | time_read: "Uren gelezen"
38 | rank_type:
39 | title:
40 | most_liked: "Meest geliket"
41 | most_replied_to: "Meeste antwoorden"
42 | most_popular: "Populairst"
43 | most_bookmarked: "Meest gebladwijzerd"
44 | most_read: "Meest gelezen"
45 | action_types:
46 | most_popular: "Score"
47 | most_replied_to: "Antwoorden"
48 | most_liked: "Likes"
49 | most_bookmarked: "Bladwijzers"
50 | most_read: "Uren gelezen"
51 | user: "Gebruiker"
52 | users: "Gebruikers"
53 | days_visited: "Dagen bezocht"
54 | all_yearly_visits: "Alle jaarlijkse bezoeken"
55 | topics: "Topics"
56 | topic: "Topic"
57 | likes: "Likes"
58 | bookmarks: "Bladwijzers"
59 | score: "Score"
60 | replies: "Antwoorden"
61 | visits: "Bezoeken"
62 | more_badge_users: "En nog %{more}..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.pl_PL.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | pl_PL:
8 | site_settings:
9 | yearly_review_enabled: "Włącz przegląd roczny. 1 stycznia zostanie automatycznie utworzony temat podsumowujący aktywność na forum w poprzednim roku."
10 | yearly_review_categories: "Publiczne kategorie do podsumowania. Jeden post ze statystykami zostanie utworzony dla każdej z 5 najlepszych kategorii z tej listy. Pozostaw puste, aby użyć 5 najlepszych kategorii publicznych."
11 | yearly_review_exclude_staff: "Wyklucz personel ze statystyk członków."
12 | yearly_review_include_user_stats: "Dodaj statystyki identyfikujące członków."
13 | yearly_review_include_private_categories: "Uwzględnij w przeglądzie aktywność użytkowników z kategorii prywatnych lub z ograniczonym dostępem."
14 | yearly_review_publish_category: "Kategoria, w której recenzja zostanie opublikowana. Zaleca się określenie kategorii personelu lub innej kategorii prywatnej, abyś mógł wyświetlić temat przed jego upublicznieniem."
15 | yearly_review_featured_badge: "Wprowadź pełną nazwę odznaki. Można pozostawić puste."
16 | yearly_review:
17 | topic_title: "%{year}: Podsumowanie roku"
18 | category_topics_title: "Top #%{category} tematów"
19 | title:
20 | users_section: "Najlepsi użytkownicy %{year}"
21 | topics_created: "Najwięcej utworzonych tematów"
22 | replies_created: "Najwięcej odpowiedzi"
23 | likes_given: "Najwięcej danych polubień"
24 | likes_received: "Najwięcej danych polubień"
25 | visits: "Najwięcej odwiedzin"
26 | daily_visits: "Dzienne odwiedziny"
27 | time_read: "Najwięcej czasu czytania"
28 | most_replied_to: "Najwięcej odpowiedzi do"
29 | featured_badge: "Użytkownicy, którym przyznano odznakę %{badge_name}"
30 | action:
31 | topics_created: "Tematy"
32 | most_replied_to: "Odpowiedzi"
33 | replies_created: "Odpowiedzi"
34 | likes_given: "Polubienia"
35 | likes_received: "Polubienia"
36 | visits: "Dni odwiedzin"
37 | time_read: "Godzin czytania"
38 | rank_type:
39 | title:
40 | most_liked: "Najbardziej lubiane"
41 | most_replied_to: "Najwięcej odpowiedzi"
42 | most_popular: "Najbardziej popularne"
43 | most_bookmarked: "Najczęściej dodawane do zakładek"
44 | most_read: "Najczęściej czytane"
45 | action_types:
46 | most_popular: "Wynik"
47 | most_replied_to: "Odpowiedzi"
48 | most_liked: "Polubień"
49 | most_bookmarked: "Zakładek"
50 | most_read: "Godzin czytania"
51 | user: "Użytkownik"
52 | users: "Użytkownicy"
53 | days_visited: "Dni odwiedzin"
54 | all_yearly_visits: "Wszystkie roczne wizyty"
55 | topics: "Tematy"
56 | topic: "Temat"
57 | likes: "Polubienia"
58 | bookmarks: "Zakładek"
59 | score: "Wynik"
60 | replies: "Odpowiedzi"
61 | visits: "Odwiedzin"
62 | more_badge_users: "I %{more} wIęcej..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.pt.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | pt:
8 | site_settings:
9 | yearly_review_featured_badge: "Introduza o nome completo do badge. Pode ficar em branco."
10 | yearly_review:
11 | topic_title: "%{year}: O Ano em Revista"
12 | category_topics_title: "Melhores tópicos da categoria #%{category}"
13 | title:
14 | users_section: "Principais utilizadores do ano %{year}"
15 | topics_created: "Com Mais Tópicos"
16 | replies_created: "Com Mais Respostas"
17 | likes_given: "Com Mais Gostos Dados"
18 | likes_received: "Com Mais Gostos Recebidos"
19 | visits: "Com Mais Visitas"
20 | daily_visits: "Com Mais Dias Visitados"
21 | time_read: "Com Mais Tempo de Leitura"
22 | most_replied_to: "Com Mais Respostas Recebidas"
23 | featured_badge: "Utilizadores aos quais foi atribuido a etiqueta %{badge_name}"
24 | action:
25 | topics_created: "Tópicos"
26 | most_replied_to: "Respostas"
27 | replies_created: "Respostas"
28 | likes_given: "Gostos"
29 | likes_received: "Gostos"
30 | visits: "Dias Visitados"
31 | time_read: "Horas Leitura"
32 | rank_type:
33 | title:
34 | most_liked: "Os Mais Gostados"
35 | most_replied_to: "Os Mais Respondidos"
36 | most_popular: "Os Mais Populares"
37 | most_bookmarked: "Os Mais Marcados"
38 | most_read: "Os Mais Lidos"
39 | action_types:
40 | most_popular: "Total"
41 | most_replied_to: "Respostas"
42 | most_liked: "Gostos"
43 | most_bookmarked: "Marcadores"
44 | most_read: "Horas Leitura"
45 | user: "Utilizador"
46 | users: "Utilizadores"
47 | days_visited: "Dias Visitados"
48 | all_yearly_visits: "Todas as Visitas Anuais"
49 | topics: "Tópicos"
50 | topic: "Tópico"
51 | likes: "Gostos"
52 | bookmarks: "Marcadores"
53 | score: "Total"
54 | replies: "Respostas"
55 | visits: "Visitas"
56 | more_badge_users: "E mais %{more} utilizadores..."
57 |
--------------------------------------------------------------------------------
/config/locales/server.pt_BR.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | pt_BR:
8 | site_settings:
9 | yearly_review_enabled: "Ative a revisão anual. No dia 1º de janeiro, será criado automaticamente um tópico para resumir a atividade do fórum no ano anterior."
10 | yearly_review_categories: "Categorias públicas para resumir. Será criada uma postagem com estatísticas para cada uma das cinco melhores categorias desta lista. Deixe vazio para usar as cinco melhores categorias públicas."
11 | yearly_review_exclude_staff: "Excluir Equipe das estatísticas dos membros."
12 | yearly_review_include_user_stats: "Adicionar estatísticas para identificar os membros."
13 | yearly_review_include_private_categories: "Inclua atividade de membro da categoria privada ou restrita à leitura na revisão."
14 | yearly_review_publish_category: "A categoria na qual a revisão será publicada. É altamente recomendável especificar a equipe ou outra categoria privada para poder revisar o tópico antes de torná-lo público."
15 | yearly_review_featured_badge: "Insira o nome completo do emblema. Não pode ser deixado em branco."
16 | yearly_review:
17 | topic_title: "%{year}: ano da revisão"
18 | category_topics_title: "Melhores #%{category} tópicos"
19 | title:
20 | users_section: "Melhores usuários(as) do ano %{year}"
21 | topics_created: "Mais tópicos"
22 | replies_created: "Mais respostas"
23 | likes_given: "Mais curtidas dadas"
24 | likes_received: "Mais curtidas recebidas"
25 | visits: "Mais visitas"
26 | daily_visits: "Visitas diárias"
27 | time_read: "Mais tempo de leitura"
28 | most_replied_to: "Mais respondidos(as)"
29 | featured_badge: "Os(as) usuários(as) concederam o emblema %{badge_name}"
30 | action:
31 | topics_created: "Tópicos"
32 | most_replied_to: "Respostas"
33 | replies_created: "Respostas"
34 | likes_given: "Curtidas"
35 | likes_received: "Curtidas"
36 | visits: "Dias visitados"
37 | time_read: "Horas lidas"
38 | rank_type:
39 | title:
40 | most_liked: "Mais curtido(a)"
41 | most_replied_to: "Mais respostas"
42 | most_popular: "Mais popular"
43 | most_bookmarked: "Mais favoritado"
44 | most_read: "Mais lidos"
45 | action_types:
46 | most_popular: "Pontuação"
47 | most_replied_to: "Respostas"
48 | most_liked: "Curtidas"
49 | most_bookmarked: "Favoritos"
50 | most_read: "Horas lidas"
51 | user: "Usuário(a)"
52 | users: "Usuários(as)"
53 | days_visited: "Dias visitados"
54 | all_yearly_visits: "Todas as visitas anuais"
55 | topics: "Tópicos"
56 | topic: "Tópico"
57 | likes: "Curtidas"
58 | bookmarks: "Favoritos"
59 | score: "Pontuação"
60 | replies: "Respostas"
61 | visits: "Acessos"
62 | more_badge_users: "E mais %{more}..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.ro.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ro:
8 | yearly_review:
9 | action:
10 | topics_created: "Discuții"
11 | most_replied_to: "Răspunsuri"
12 | replies_created: "Răspunsuri"
13 | likes_given: "Aprecieri date"
14 | likes_received: "Aprecieri date"
15 | visits: "Zile de vizită"
16 | rank_type:
17 | title:
18 | most_liked: "Cele mai apreciate"
19 | action_types:
20 | most_popular: "Scor"
21 | most_replied_to: "Răspunsuri"
22 | most_liked: "Aprecieri date"
23 | most_bookmarked: "Semne de carte"
24 | user: "Utilizator"
25 | users: "Utilizatori"
26 | days_visited: "Zile de vizită"
27 | topics: "Discuții"
28 | topic: "Discuție"
29 | likes: "Aprecieri date"
30 | bookmarks: "Semne de carte"
31 | score: "Scor"
32 | replies: "Răspunsuri"
33 | visits: "Vizite"
34 |
--------------------------------------------------------------------------------
/config/locales/server.ru.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ru:
8 | site_settings:
9 | yearly_review_enabled: "Включить ежегодный обзор. Тогда 1 января будет автоматически создана тема с подведением итогов работы форума за предыдущий год."
10 | yearly_review_categories: "Публичные категории для подведения итогов. Для каждой из 5 лучших категорий в этом списке будет создана публикация со статистикой. Оставьте поле пустым, чтобы использовать 5 самых популярных публичных категорий."
11 | yearly_review_exclude_staff: "Исключить персонал из статистики участников."
12 | yearly_review_include_user_stats: "Добавить статистику, идентифицирующую участников."
13 | yearly_review_include_private_categories: "Включить в обзор действия участников из закрытых или ограниченных для чтения категорий."
14 | yearly_review_publish_category: "Категория, в которой будет опубликован обзор. Настоятельно рекомендуем указать категорию персонала или другую закрытую категорию, чтобы вы могли ознакомиться с темой до публикации в общем доступе."
15 | yearly_review_featured_badge: "Введите полное имя награды. Можно оставить пустым."
16 | yearly_review:
17 | topic_title: "%{year}: годовой обзор"
18 | category_topics_title: "Лучшие темы #%{category}"
19 | title:
20 | users_section: "Лучшие пользователи %{year}"
21 | topics_created: "По количеству тем"
22 | replies_created: "По количеству ответов"
23 | likes_given: "По количеству поставленных лайков"
24 | likes_received: "По количеству полученных лайков"
25 | visits: "По количеству посещений"
26 | daily_visits: "По количеству ежедневных посещений"
27 | time_read: "По времени чтения"
28 | most_replied_to: "По количеству ответов на тему"
29 | featured_badge: "Пользователи получили награду: %{badge_name}"
30 | action:
31 | topics_created: "Тем"
32 | most_replied_to: "Ответов"
33 | replies_created: "Ответов"
34 | likes_given: "Лайков"
35 | likes_received: "Лайков"
36 | visits: "Дней посещения"
37 | time_read: "Часов чтения"
38 | rank_type:
39 | title:
40 | most_liked: "Фаворит"
41 | most_replied_to: "Большинство ответов"
42 | most_popular: "Самые популярные темы"
43 | most_bookmarked: "Больше всего закладок"
44 | most_read: "Тексточитатель"
45 | action_types:
46 | most_popular: "Оценка"
47 | most_replied_to: "Ответов"
48 | most_liked: "Лайков"
49 | most_bookmarked: "Закладок"
50 | most_read: "Часов чтения"
51 | user: "Пользователь"
52 | users: "Пользователей"
53 | days_visited: "Дней посещения"
54 | all_yearly_visits: "Все посещения за год"
55 | topics: "Темы"
56 | topic: "Тема"
57 | likes: "Лайки"
58 | bookmarks: "Закладки"
59 | score: "Оценка"
60 | replies: "Ответов"
61 | visits: "Посещений"
62 | more_badge_users: "И ещё %{more}..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.sk.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sk:
8 | yearly_review:
9 | action:
10 | topics_created: "Témy"
11 | most_replied_to: "Odpovede"
12 | replies_created: "Odpovede"
13 | likes_given: "Rozdaných 'páči sa mi'"
14 | likes_received: "Rozdaných 'páči sa mi'"
15 | visits: "Dní na stránke"
16 | rank_type:
17 | title:
18 | most_liked: "Najviac sa páčia"
19 | action_types:
20 | most_popular: "Skóre"
21 | most_replied_to: "Odpovede"
22 | most_liked: "Rozdaných 'páči sa mi'"
23 | most_bookmarked: "Záložky"
24 | user: "Používateľ"
25 | users: "Používatelia"
26 | days_visited: "Dní na stránke"
27 | topics: "Témy"
28 | topic: "Témy"
29 | likes: "Rozdaných 'páči sa mi'"
30 | bookmarks: "Záložky"
31 | score: "Skóre"
32 | replies: "Odpovede"
33 | visits: "Návštev"
34 | more_badge_users: "A %{more} ďAlšie..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.sl.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sl:
8 | site_settings:
9 | yearly_review_featured_badge: "Vnesite polno ime značke. Lahko ostane prazno."
10 | yearly_review:
11 | topic_title: "%{year}: Letni pregled"
12 | category_topics_title: "Najboljše teme v #%{category}"
13 | title:
14 | users_section: "Najboljši uporabniki leta %{year}"
15 | topics_created: "Največ ustvarjenih tem"
16 | replies_created: "Največ odgovorov"
17 | likes_given: "Največ danih všečkov"
18 | likes_received: "Največ prejetih všečkov"
19 | visits: "Največ obiskov"
20 | daily_visits: "Dnevnih obiskov"
21 | time_read: "Najzvestejši bralci"
22 | most_replied_to: "Prejemniki največ odgovorov"
23 | featured_badge: "Uporabniki, ki so prejeli značko %{badge_name}"
24 | action:
25 | topics_created: "Teme"
26 | most_replied_to: "Odgovori"
27 | replies_created: "Odgovori"
28 | likes_given: "Všečki"
29 | likes_received: "Všečki"
30 | visits: "Dni prisotnosti"
31 | time_read: "Ur branja"
32 | rank_type:
33 | title:
34 | most_liked: "Najbolj všečkani"
35 | most_replied_to: "Največ odgovorov"
36 | most_popular: "Najbolj priljubljeni"
37 | most_bookmarked: "Največkrat zaznamovano"
38 | most_read: "Najbolj brano"
39 | action_types:
40 | most_popular: "Ocena"
41 | most_replied_to: "Odgovori"
42 | most_liked: "Všečki"
43 | most_bookmarked: "Zaznamki"
44 | most_read: "Ur branja"
45 | user: "Uporabnik"
46 | users: "Uporabniki"
47 | days_visited: "Dni prisotnosti"
48 | all_yearly_visits: "Vsi letni obiski"
49 | topics: "Teme"
50 | topic: "Tema"
51 | likes: "Všečki"
52 | bookmarks: "Zaznamki"
53 | score: "Ocena"
54 | replies: "Odgovori"
55 | visits: "Obiski"
56 | more_badge_users: "In še %{more}..."
57 |
--------------------------------------------------------------------------------
/config/locales/server.sq.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sq:
8 | yearly_review:
9 | action:
10 | topics_created: "Topics"
11 | most_replied_to: "Përgjigjet"
12 | replies_created: "Përgjigjet"
13 | likes_given: "Pëlqimet"
14 | likes_received: "Pëlqimet"
15 | visits: "Ditë vizituar"
16 | rank_type:
17 | title:
18 | most_liked: "Më të pëlqyer"
19 | action_types:
20 | most_replied_to: "Përgjigjet"
21 | most_liked: "Pëlqimet"
22 | most_bookmarked: "Të preferuarat"
23 | user: "Përdorues"
24 | users: "Përdoruesit"
25 | days_visited: "Ditë vizituar"
26 | topics: "Topics"
27 | topic: "Temë"
28 | likes: "Pëlqimet"
29 | bookmarks: "Të preferuarat"
30 | replies: "Përgjigjet"
31 | visits: "Vizita"
32 |
--------------------------------------------------------------------------------
/config/locales/server.sr.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sr:
8 | yearly_review:
9 | action:
10 | topics_created: "Teme"
11 | most_replied_to: "Odgovori"
12 | replies_created: "Odgovori"
13 | likes_given: "Lajkova"
14 | likes_received: "Lajkova"
15 | visits: "Dana posećeno"
16 | rank_type:
17 | title:
18 | most_liked: "Najviše sviđanja"
19 | action_types:
20 | most_replied_to: "Odgovori"
21 | most_liked: "Lajkova"
22 | most_bookmarked: "Markiraj"
23 | user: "Korisnik"
24 | users: "Korisnici"
25 | days_visited: "Dana posećeno"
26 | topics: "Teme"
27 | topic: "Tema"
28 | likes: "Lajkova"
29 | bookmarks: "Markiraj"
30 | replies: "Odgovori"
31 | visits: "Poseta"
32 |
--------------------------------------------------------------------------------
/config/locales/server.sv.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sv:
8 | site_settings:
9 | yearly_review_featured_badge: "Ange utmärkelsens hela namn. Kan lämnas tomt."
10 | yearly_review:
11 | topic_title: "%{year}: En granskning av året"
12 | category_topics_title: "Toppämnen i #%{category}"
13 | title:
14 | users_section: "Toppanvändarna %{year}"
15 | topics_created: "Flest ämnen"
16 | replies_created: "Flest svar"
17 | likes_given: "Flest givna gillningar"
18 | likes_received: "Flest mottagna gillningar"
19 | visits: "Flest besök"
20 | daily_visits: "Dagliga besök"
21 | time_read: "Mest tid läst"
22 | most_replied_to: "Mest besvarade"
23 | featured_badge: "Användare beviljade utmärkelsen %{badge_name}"
24 | action:
25 | topics_created: "Ämnen"
26 | most_replied_to: "Svar"
27 | replies_created: "Svar"
28 | likes_given: "Gillningar"
29 | likes_received: "Gillningar"
30 | visits: "Besökta dagar"
31 | time_read: "Lästa timmar"
32 | rank_type:
33 | title:
34 | most_liked: "Mest gillade"
35 | most_replied_to: "Flest svar"
36 | most_popular: "Mest populära"
37 | most_bookmarked: "Mest bokmärkta"
38 | most_read: "Mest lästa"
39 | action_types:
40 | most_popular: "Poäng"
41 | most_replied_to: "Svar"
42 | most_liked: "Gillningar"
43 | most_bookmarked: "Bokmärken"
44 | most_read: "Lästa timmar"
45 | user: "Användare"
46 | users: "Användare"
47 | days_visited: "Besökta dagar"
48 | all_yearly_visits: "Årets alla besök"
49 | topics: "Ämnen"
50 | topic: "Ämne"
51 | likes: "Gillningar"
52 | bookmarks: "Bokmärken"
53 | score: "Poäng"
54 | replies: "Svar"
55 | visits: "Besök"
56 | more_badge_users: "Och ytterligare %{more}..."
57 |
--------------------------------------------------------------------------------
/config/locales/server.sw.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sw:
8 | yearly_review:
9 | action:
10 | topics_created: "Mada"
11 | most_replied_to: "Majibu"
12 | replies_created: "Majibu"
13 | likes_given: "Upendo Uliotolewa"
14 | likes_received: "Upendo Uliotolewa"
15 | visits: "Siku Iliyotembelewa"
16 | rank_type:
17 | title:
18 | most_liked: "Iliyopendwa Zaidi"
19 | action_types:
20 | most_replied_to: "Majibu"
21 | most_liked: "Upendo Uliotolewa"
22 | most_bookmarked: "Mialamisho"
23 | user: "Mtumiaji"
24 | users: "Watumiaji"
25 | days_visited: "Siku Iliyotembelewa"
26 | topics: "Mada"
27 | topic: "Mada"
28 | likes: "Upendo Uliotolewa"
29 | bookmarks: "Mialamisho"
30 | replies: "Majibu"
31 | visits: "Waliotembelea"
32 |
--------------------------------------------------------------------------------
/config/locales/server.te.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | te:
8 | yearly_review:
9 | action:
10 | topics_created: "విషయాలు"
11 | most_replied_to: "జవాబులు"
12 | replies_created: "జవాబులు"
13 | likes_given: "ఇచ్చిన ఇష్టాలు "
14 | likes_received: "ఇచ్చిన ఇష్టాలు "
15 | visits: "దర్శించిన రోజులు"
16 | rank_type:
17 | title:
18 | most_liked: "ఎక్కువగా ఇష్టపడింది"
19 | action_types:
20 | most_popular: "స్కోర్"
21 | most_replied_to: "జవాబులు"
22 | most_liked: "ఇచ్చిన ఇష్టాలు "
23 | most_bookmarked: "పేజీకలు"
24 | user: "వాడుకరి"
25 | users: "సభ్యులు"
26 | days_visited: "దర్శించిన రోజులు"
27 | topics: "విషయాలు"
28 | topic: "విషయం"
29 | likes: "ఇచ్చిన ఇష్టాలు "
30 | bookmarks: "పేజీకలు"
31 | score: "స్కోర్"
32 | replies: "జవాబులు"
33 | visits: "సందర్శనాలు"
34 |
--------------------------------------------------------------------------------
/config/locales/server.th.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | th:
8 | yearly_review:
9 | action:
10 | topics_created: "หัวข้อ"
11 | most_replied_to: "ตอบ"
12 | replies_created: "ตอบ"
13 | likes_given: "ถูกใจ"
14 | likes_received: "ถูกใจ"
15 | visits: "วันที่เข้าชม"
16 | rank_type:
17 | title:
18 | most_liked: "ถูกใจมากที่สุด"
19 | action_types:
20 | most_popular: "คะแนน"
21 | most_replied_to: "ตอบ"
22 | most_liked: "ถูกใจ"
23 | most_bookmarked: "บุ๊คมาร์ค"
24 | user: "ชื่อผู้ใช้"
25 | users: "ผู้ใช้"
26 | days_visited: "วันที่เข้าชม"
27 | topics: "หัวข้อ"
28 | topic: "กระทู้"
29 | likes: "ถูกใจ"
30 | bookmarks: "บุ๊คมาร์ค"
31 | score: "คะแนน"
32 | replies: "ตอบ"
33 | visits: "เยี่ยมชม"
34 |
--------------------------------------------------------------------------------
/config/locales/server.tr_TR.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | tr_TR:
8 | site_settings:
9 | yearly_review_enabled: "Yıllık incelemeyi etkinleştirin. 1 Ocak'ta, bir önceki yılın forum aktivitesini özetleyen bir konu otomatik olarak oluşturulacaktır."
10 | yearly_review_categories: "Özetlenecek herkese açık kategoriler. Bu listedeki ilk 5 kategorinin her biri için istatistikleri içeren bir gönderi oluşturulacaktır. En iyi 5 herkese açık kategoriyi kullanmak için boş bırakın."
11 | yearly_review_exclude_staff: "Personeli üye istatistiklerinden hariç tutun."
12 | yearly_review_include_user_stats: "Üye tanımlayıcı istatistikler ekleyin."
13 | yearly_review_include_private_categories: "Özel veya okuma kısıtlamalı kategorilerdeki üye aktivitesini incelemeye dahil edin."
14 | yearly_review_publish_category: "İncelemenin yayınlanacağı kategori. Herkese açık hâle getirmeden önce konuyu görüntüleyebilmeniz için personel veya diğer özel kategoriyi belirtmeniz şiddetle tavsiye edilir."
15 | yearly_review_featured_badge: "Tam rozet adını girin. Boş bırakılabilir."
16 | yearly_review:
17 | topic_title: "%{year}: Yılın Değerlendirmesi"
18 | category_topics_title: "En İyi #%{category} Konuları"
19 | title:
20 | users_section: "%{year} Yılının En İyi Kullanıcıları"
21 | topics_created: "En Çok Konu"
22 | replies_created: "En Çok Yanıt"
23 | likes_given: "En Çok Beğeni Veren"
24 | likes_received: "En Çok Beğeni Alan"
25 | visits: "En Çok Ziyaret"
26 | daily_visits: "Günlük Ziyaretler"
27 | time_read: "En Çok Okuma Süresi"
28 | most_replied_to: "En Çok Yanıtlanan"
29 | featured_badge: "%{badge_name} Rozeti Verilen Kullanıcılar"
30 | action:
31 | topics_created: "Konular"
32 | most_replied_to: "Yanıtlar"
33 | replies_created: "Yanıtlar"
34 | likes_given: "Beğeniler"
35 | likes_received: "Beğeniler"
36 | visits: "Ziyaret Edilen Gün"
37 | time_read: "Okumakla Geçen Saat"
38 | rank_type:
39 | title:
40 | most_liked: "En Çok Beğenilen"
41 | most_replied_to: "En Çok Yanıt"
42 | most_popular: "En Popüler"
43 | most_bookmarked: "En Çok Yer İmi Eklenen"
44 | most_read: "En Çok Okunan"
45 | action_types:
46 | most_popular: "Puan"
47 | most_replied_to: "Yanıtlar"
48 | most_liked: "Beğeniler"
49 | most_bookmarked: "Yer imleri"
50 | most_read: "Okumakla Geçen Saat"
51 | user: "Kullanıcı"
52 | users: "Kullanıcı"
53 | days_visited: "Ziyaret Edilen Gün"
54 | all_yearly_visits: "Tüm Yıllık Ziyaretler"
55 | topics: "Konular"
56 | topic: "Konu"
57 | likes: "Beğeniler"
58 | bookmarks: "Yer imleri"
59 | score: "Puan"
60 | replies: "Yanıtlar"
61 | visits: "Ziyaretler"
62 | more_badge_users: "Ve %{more} tane daha..."
63 |
--------------------------------------------------------------------------------
/config/locales/server.ug.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ug:
8 | yearly_review:
9 | action:
10 | topics_created: "تېما"
11 | most_replied_to: "جاۋاب"
12 | replies_created: "جاۋاب"
13 | likes_given: "ياقتۇرۇش"
14 | likes_received: "ياقتۇرۇش"
15 | visits: "زىيارەت كۈن سانى"
16 | rank_type:
17 | title:
18 | most_liked: "كۆپ ياقتۇرغان"
19 | action_types:
20 | most_popular: "نومۇر"
21 | most_replied_to: "جاۋاب"
22 | most_liked: "ياقتۇرۇش"
23 | most_bookmarked: "خەتكۈچ"
24 | user: "ئىشلەتكۈچى"
25 | users: "ئىشلەتكۈچى"
26 | days_visited: "زىيارەت كۈن سانى"
27 | topics: "تېما"
28 | topic: "تېما"
29 | likes: "ياقتۇرۇش"
30 | bookmarks: "خەتكۈچ"
31 | score: "نومۇر"
32 | replies: "جاۋاب"
33 | visits: "زىيارەت"
34 | more_badge_users: "ۋە باشقا %{more}..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.uk.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | uk:
8 | yearly_review:
9 | action:
10 | topics_created: "Теми"
11 | most_replied_to: "Відповіді"
12 | replies_created: "Відповіді"
13 | likes_given: "Вподобані"
14 | likes_received: "Вподобані"
15 | visits: "Днів відвідувань"
16 | rank_type:
17 | title:
18 | most_liked: "Найбільше подобається"
19 | action_types:
20 | most_popular: "Бал"
21 | most_replied_to: "Відповіді"
22 | most_liked: "Вподобані"
23 | most_bookmarked: "Закладки"
24 | user: "Користувач"
25 | users: "Користувачі"
26 | days_visited: "Днів відвідувань"
27 | topics: "Теми"
28 | topic: "Тема"
29 | likes: "Вподобані"
30 | bookmarks: "Закладки"
31 | score: "Бал"
32 | replies: "Відповіді"
33 | visits: "Відвідини"
34 | more_badge_users: "І бІльше %{more}..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.ur.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ur:
8 | yearly_review:
9 | action:
10 | topics_created: "ٹاپکس"
11 | most_replied_to: "جوابات"
12 | replies_created: "جوابات"
13 | likes_given: "لائیکس دیے گئے"
14 | likes_received: "لائیکس دیے گئے"
15 | visits: "دورہ کیے گئے دن"
16 | rank_type:
17 | title:
18 | most_liked: "سب سے زیادہ لائک کیا گیا"
19 | action_types:
20 | most_popular: "اسکور"
21 | most_replied_to: "جوابات"
22 | most_liked: "لائیکس دیے گئے"
23 | most_bookmarked: "بُک مارکس"
24 | user: "صارف"
25 | users: "صارفین"
26 | days_visited: "دورہ کیے گئے دن"
27 | topics: "ٹاپکس"
28 | topic: "ٹاپک"
29 | likes: "لائیکس دیے گئے"
30 | bookmarks: "بُک مارکس"
31 | score: "اسکور"
32 | replies: "جوابات"
33 | visits: "زائرین کی تعداد"
34 |
--------------------------------------------------------------------------------
/config/locales/server.vi.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | vi:
8 | yearly_review:
9 | action:
10 | topics_created: "Chủ đề"
11 | most_replied_to: "Trả lời"
12 | replies_created: "Trả lời"
13 | likes_given: "Lượt Thích"
14 | likes_received: "Lượt Thích"
15 | visits: "Số ngày đã thăm"
16 | rank_type:
17 | title:
18 | most_liked: "Thích nhiều nhất"
19 | action_types:
20 | most_popular: "Điểm số"
21 | most_replied_to: "Trả lời"
22 | most_liked: "Lượt Thích"
23 | most_bookmarked: "Các đánh dấu"
24 | user: "Thành viên"
25 | users: "Tài khoản"
26 | days_visited: "Số ngày đã thăm"
27 | topics: "Chủ đề"
28 | topic: "Chủ đề"
29 | likes: "Lượt Thích"
30 | bookmarks: "Các đánh dấu"
31 | score: "Điểm số"
32 | replies: "Trả lời"
33 | visits: "Lượt xem"
34 | more_badge_users: "Và %{more} nữa..."
35 |
--------------------------------------------------------------------------------
/config/locales/server.zh_CN.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | zh_CN:
8 | site_settings:
9 | yearly_review_enabled: "启用年度回顾。1 月 1 日,将自动创建一个话题,总结去年的论坛活动。"
10 | yearly_review_categories: "要总结的公开类别。将为此列表中前 5 个类别中的每个类别创建一篇包含统计信息的帖子。留空则会使用前 5 个公开类别。"
11 | yearly_review_exclude_staff: "从成员统计中排除管理人员。"
12 | yearly_review_include_user_stats: "添加成员识别统计信息。"
13 | yearly_review_include_private_categories: "在回顾中包括不公开或阅读限制类别的成员活动。"
14 | yearly_review_publish_category: "回顾将被发布到的类别。强烈建议指定管理人员或其他不公开类别,以便您可以在公开之前查看话题。"
15 | yearly_review_featured_badge: "输入完整的徽章名称。可以留空。"
16 | yearly_review:
17 | topic_title: "%{year} 年度回顾"
18 | category_topics_title: "#%{category} 的最佳话题"
19 | title:
20 | users_section: "%{year} 的热门用户"
21 | topics_created: "最多话题"
22 | replies_created: "回复最多"
23 | likes_given: "给出最多赞"
24 | likes_received: "收到最多赞"
25 | visits: "最常访问"
26 | daily_visits: "每日访问"
27 | time_read: "最长阅读时间"
28 | most_replied_to: "收到回复最多"
29 | featured_badge: "被授予%{badge_name}徽章的用户"
30 | action:
31 | topics_created: "话题"
32 | most_replied_to: "回复"
33 | replies_created: "回复"
34 | likes_given: "赞"
35 | likes_received: "赞"
36 | visits: "访问天数"
37 | time_read: "阅读小时数"
38 | rank_type:
39 | title:
40 | most_liked: "最多赞"
41 | most_replied_to: "最多回复"
42 | most_popular: "最受欢迎"
43 | most_bookmarked: "添加为书签最多"
44 | most_read: "最多阅读"
45 | action_types:
46 | most_popular: "分数"
47 | most_replied_to: "回复"
48 | most_liked: "赞"
49 | most_bookmarked: "书签"
50 | most_read: "阅读小时数"
51 | user: "用户"
52 | users: "用户"
53 | days_visited: "访问天数"
54 | all_yearly_visits: "所有年度访问"
55 | topics: "话题"
56 | topic: "话题"
57 | likes: "赞"
58 | bookmarks: "书签"
59 | score: "分数"
60 | replies: "回复"
61 | visits: "访问次数"
62 | more_badge_users: "和其他 %{more} 个…"
63 |
--------------------------------------------------------------------------------
/config/locales/server.zh_TW.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | zh_TW:
8 | yearly_review:
9 | action:
10 | topics_created: "討論話題"
11 | most_replied_to: "回覆"
12 | replies_created: "回覆"
13 | likes_given: "新的讚"
14 | likes_received: "新的讚"
15 | visits: "到訪天數"
16 | rank_type:
17 | title:
18 | most_liked: "最多讚"
19 | action_types:
20 | most_popular: "分數"
21 | most_replied_to: "回覆"
22 | most_liked: "新的讚"
23 | most_bookmarked: "書籤"
24 | user: "使用者"
25 | users: "使用者數量"
26 | days_visited: "到訪天數"
27 | topics: "討論話題"
28 | topic: "話題"
29 | likes: "新的讚"
30 | bookmarks: "書籤"
31 | score: "分數"
32 | replies: "回覆"
33 | visits: "造訪"
34 |
--------------------------------------------------------------------------------
/config/settings.yml:
--------------------------------------------------------------------------------
1 | plugins:
2 | yearly_review_enabled:
3 | default: false
4 | client: true
5 | yearly_review_categories:
6 | type: category_list
7 | default: ""
8 | yearly_review_exclude_staff:
9 | default: true
10 | yearly_review_include_user_stats:
11 | default: true
12 | yearly_review_include_private_categories:
13 | default: false
14 | yearly_review_publish_category:
15 | type: category
16 | default: ""
17 | yearly_review_featured_badge:
18 | default: ""
19 |
--------------------------------------------------------------------------------
/db/migrate/20230208123631_backfill_yearly_review_custom_fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class BackfillYearlyReviewCustomFields < ActiveRecord::Migration[6.1]
4 | def change
5 | 2017.upto(2022) do |year|
6 | topic_title = I18n.t("yearly_review.topic_title", year: year)
7 | DB.exec(
8 | <<~SQL,
9 | INSERT INTO post_custom_fields (post_id, name, value, created_at, updated_at)
10 | SELECT posts.id, :name, :value, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
11 | FROM posts
12 | INNER JOIN topics ON topics.id = posts.topic_id
13 | WHERE posts.user_id = :user_id AND topics.title = :title
14 | ON CONFLICT DO NOTHING
15 | SQL
16 | title: topic_title,
17 | user_id: Discourse::SYSTEM_USER_ID,
18 | name: YearlyReview::POST_CUSTOM_FIELD,
19 | value: year.to_s,
20 | )
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import DiscourseRecommended from "@discourse/lint-configs/eslint";
2 |
3 | export default [...DiscourseRecommended];
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "devDependencies": {
4 | "@discourse/lint-configs": "2.20.0",
5 | "ember-template-lint": "7.7.0",
6 | "eslint": "9.27.0",
7 | "prettier": "3.5.3",
8 | "stylelint": "16.19.1"
9 | },
10 | "engines": {
11 | "node": ">= 22",
12 | "npm": "please-use-pnpm",
13 | "yarn": "please-use-pnpm",
14 | "pnpm": "9.x"
15 | },
16 | "packageManager": "pnpm@9.15.5"
17 | }
18 |
--------------------------------------------------------------------------------
/plugin.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # name: discourse-yearly-review
4 | # about: Creates a topic that summarizes the previous year’s forum activity.
5 | # meta_topic_id: 105713
6 | # version: 0.2
7 | # author: Simon Cossar
8 | # url: https://github.com/discourse/discourse-yearly-review
9 |
10 | enabled_site_setting :yearly_review_enabled
11 | register_asset "stylesheets/yearly_review.scss"
12 |
13 | after_initialize do
14 | module ::YearlyReview
15 | PLUGIN_NAME = "yearly-review"
16 | POST_CUSTOM_FIELD = "yearly_review"
17 |
18 | def self.current_year
19 | Time.now.year
20 | end
21 |
22 | def self.last_year
23 | current_year - 1
24 | end
25 | end
26 |
27 | ::ActionController::Base.prepend_view_path File.expand_path(
28 | "../app/views/yearly-review",
29 | __FILE__,
30 | )
31 |
32 | require_relative "app/jobs/yearly_review"
33 |
34 | require_dependency "email/styles"
35 | Email::Styles.register_plugin_style do |doc|
36 | doc.css("[data-review-topic-users] table").each { |element| element["width"] = "100%" }
37 | doc.css("[data-review-featured-topics] table").each { |element| element["width"] = "100%" }
38 |
39 | doc
40 | .css("[data-review-topic-users] th")
41 | .each do |element|
42 | element["style"] = "text-align: left;padding-bottom: 12px;"
43 | element["width"] = "50%"
44 | end
45 | doc
46 | .css("[data-review-featured-topics] th")
47 | .each { |element| element["style"] = "text-align: left;padding-bottom: 12px;" }
48 | doc
49 | .css("[data-review-featured-topics] th:first-child")
50 | .each { |element| element["width"] = "15%" }
51 | doc
52 | .css("[data-review-featured-topics] th:nth-child(2)")
53 | .each { |element| element["width"] = "60%" }
54 | doc
55 | .css("[data-review-featured-topics] th:last-child")
56 | .each { |element| element["width"] = "25%" }
57 |
58 | doc
59 | .css("[data-review-topic-users] td")
60 | .each do |element|
61 | element["style"] = "padding-bottom: 6px;"
62 | element["valign"] = "top"
63 | end
64 | doc
65 | .css("[data-review-featured-topics] td")
66 | .each do |element|
67 | element["style"] = "padding-bottom: 6px;"
68 | element["valign"] = "top"
69 | end
70 |
71 | doc
72 | .css("[data-review-topic-users] td table td:first-child")
73 | .each do |element|
74 | element["style"] = "padding-bottom: 6px;"
75 | element["width"] = "25"
76 | end
77 | doc
78 | .css("[data-review-topic-users] td table td:nth-child(2)")
79 | .each { |element| element["style"] = "padding-left: 4px;padding-bottom: 6px;" }
80 | end
81 |
82 | on(:username_changed) do |old_username, new_username|
83 | Post
84 | .joins(:_custom_fields)
85 | .where(
86 | "post_custom_fields.name = ? AND posts.raw LIKE ?",
87 | YearlyReview::POST_CUSTOM_FIELD,
88 | "%/#{old_username}/%",
89 | )
90 | .update_all(
91 | "raw = REPLACE(raw, '/#{old_username}/', '/#{new_username}/'), baked_version = NULL",
92 | )
93 | end
94 | end
95 |
--------------------------------------------------------------------------------
/spec/jobs/yearly_review_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe Jobs::YearlyReview do
6 | class Helper
7 | extend YearlyReviewHelper
8 | end
9 |
10 | before { SiteSetting.yearly_review_enabled = true }
11 |
12 | let(:category) { Fabricate(:category) }
13 | let(:top_review_user) { Fabricate(:user, username: "top_review_user") }
14 | let(:reviewed_user) { Fabricate(:user, username: "reviewed_user") }
15 |
16 | describe "publishing the topic" do
17 | describe "on January 1st" do
18 | before do
19 | SiteSetting.yearly_review_publish_category = category.id
20 | freeze_time DateTime.parse("#{::YearlyReview.current_year}-01-01")
21 | Fabricate(:topic, created_at: 1.month.ago)
22 | end
23 |
24 | it "publishes a review topic" do
25 | Jobs::YearlyReview.new.execute({})
26 | topic = Topic.last
27 | expect(topic.title).to eq(
28 | I18n.t("yearly_review.topic_title", year: ::YearlyReview.last_year),
29 | )
30 | expect(topic.first_post.custom_fields).to eq(
31 | YearlyReview::POST_CUSTOM_FIELD => ::YearlyReview.last_year.to_s,
32 | )
33 | expect(topic.custom_fields).to eq(
34 | YearlyReview::POST_CUSTOM_FIELD => ::YearlyReview.last_year.to_s,
35 | )
36 | end
37 | end
38 |
39 | describe "on February 1st" do
40 | before do
41 | freeze_time DateTime.parse("#{::YearlyReview.current_year}-02-01")
42 | Fabricate(
43 | :topic,
44 | created_at: 2.months.ago,
45 | title: "A topic from #{::YearlyReview.last_year}",
46 | )
47 | end
48 |
49 | it "doesn't publish a review topic" do
50 | expect { Jobs::YearlyReview.new.execute({}) }.not_to change { Topic.count }
51 | end
52 | end
53 |
54 | describe "after the review has been published" do
55 | before do
56 | SiteSetting.yearly_review_publish_category = category.id
57 | freeze_time DateTime.parse("#{::YearlyReview.current_year}-01-01")
58 | Fabricate(:topic, created_at: 1.month.ago)
59 | Jobs::YearlyReview.new.execute({})
60 | @yearly_review_topic = Topic.last
61 | end
62 |
63 | it "doesn't publish the review topic again if it already exists with the custom field and a different title" do
64 | @yearly_review_topic.update!(title: "This is a test for yearly review")
65 | expect { Jobs::YearlyReview.new.execute({}) }.not_to change { Topic.count }
66 | end
67 |
68 | it "doesn't publish the review topic again if it already exists and a previous version was deleted" do
69 | @yearly_review_topic.trash!
70 | expect { Jobs::YearlyReview.new.execute({}) }.to change { Topic.count }
71 | expect { Jobs::YearlyReview.new.execute({}) }.not_to change { Topic.count }
72 | end
73 |
74 | it "doesn't publish the review topic again if it already exists and has been moved to another category" do
75 | @yearly_review_topic.update!(category: Fabricate(:category))
76 | expect { Jobs::YearlyReview.new.execute({}) }.not_to change { Topic.count }
77 | end
78 | end
79 | end
80 |
81 | describe "user stats" do
82 | before do
83 | freeze_time DateTime.parse("#{::YearlyReview.current_year}-01-01")
84 | SiteSetting.yearly_review_publish_category = category.id
85 | end
86 |
87 | describe "most topics" do
88 | before do
89 | 5.times { Fabricate(:topic, user: top_review_user, created_at: 1.month.ago) }
90 | Fabricate(:topic, user: reviewed_user, created_at: 1.month.ago)
91 | end
92 |
93 | it "ranks topics created by users correctly" do
94 | Jobs::YearlyReview.new.execute({})
95 | raw = Topic.last.first_post.raw
96 | expect(raw).to have_tag("div.topics-created") { with_text(/\@top_review_user\|5/) }
97 | expect(raw).to have_tag("div.topics-created") { with_text(/\@reviewed_user\|1/) }
98 | end
99 |
100 | it "updates username correctly after anonymizing the user" do
101 | Jobs.run_immediately!
102 | UserActionManager.enable
103 | stub_image_size
104 |
105 | upload = Fabricate(:upload, user: top_review_user)
106 | top_review_user.user_avatar =
107 | UserAvatar.new(user_id: top_review_user.id, custom_upload_id: upload.id)
108 | top_review_user.uploaded_avatar_id = upload.id
109 | top_review_user.save!
110 |
111 | Jobs::YearlyReview.new.execute({})
112 | post = Topic.last.first_post
113 | raw = post.raw
114 | expect(raw).to have_tag("div.topics-created") { with_text(/\@top_review_user\|5/) }
115 | expect(raw).to have_tag("div.topics-created") { with_text(%r{/top_review_user/50/}) }
116 |
117 | user = UserAnonymizer.new(top_review_user, Discourse.system_user, {}).make_anonymous
118 | raw = post.reload.raw
119 | expect(raw).to have_tag("div.topics-created") { with_text(/\@#{user.username}\|5/) }
120 | expect(raw).to have_tag("div.topics-created") { with_text(%r{/#{user.username}/50/}) }
121 | expect(post.baked_version).to be_nil
122 | end
123 | end
124 |
125 | describe "most replies" do
126 | before do
127 | SiteSetting.max_consecutive_replies = 5
128 | SiteSetting.yearly_review_publish_category = category.id
129 | topic_user = Fabricate(:user)
130 | reviewed_topic = Fabricate(:topic, user: topic_user, created_at: 1.year.ago)
131 | Fabricate(:post, topic: reviewed_topic, user: topic_user)
132 | 5.times do
133 | Fabricate(:post, topic: reviewed_topic, user: top_review_user, created_at: 1.month.ago)
134 | end
135 | Fabricate(:post, topic: reviewed_topic, user: reviewed_user, created_at: 1.month.ago)
136 | end
137 |
138 | it "ranks replies created by users correctly" do
139 | Jobs::YearlyReview.new.execute({})
140 | raw = Topic.last.first_post.raw
141 | expect(raw).to have_tag("div.replies-created") { with_text(/\@top_review_user\|5/) }
142 | expect(raw).to have_tag("div.replies-created") { with_text(/\@reviewed_user\|1/) }
143 | end
144 | end
145 |
146 | describe "most bookmarks" do
147 | let(:topic_user) { Fabricate(:user) }
148 | let(:reviewed_topic) { Fabricate(:topic, user: topic_user, created_at: 1.year.ago) }
149 |
150 | before do
151 | SiteSetting.yearly_review_publish_category = category.id
152 | 10.times do
153 | Fabricate(:post, topic: reviewed_topic, created_at: 1.month.ago, user: top_review_user)
154 | end
155 | reviewed_topic.reload
156 | Fabricate(
157 | :bookmark,
158 | bookmarkable: reviewed_topic.posts[1],
159 | user: topic_user,
160 | created_at: 1.month.ago,
161 | )
162 | Fabricate(
163 | :bookmark,
164 | bookmarkable: reviewed_topic.posts[2],
165 | user: topic_user,
166 | created_at: 1.month.ago,
167 | )
168 | Fabricate(
169 | :bookmark,
170 | bookmarkable: reviewed_topic.posts[3],
171 | user: topic_user,
172 | created_at: 1.month.ago,
173 | )
174 | Fabricate(
175 | :bookmark,
176 | bookmarkable: reviewed_topic.posts[4],
177 | user: topic_user,
178 | created_at: 1.month.ago,
179 | )
180 | Fabricate(
181 | :bookmark,
182 | bookmarkable: reviewed_topic.posts[5],
183 | user: topic_user,
184 | created_at: 1.month.ago,
185 | )
186 | end
187 |
188 | it "ranks bookmarks created by users correctly" do
189 | Jobs::YearlyReview.new.execute({})
190 | topic = Topic.last
191 | raw = Post.where(topic_id: topic.id).second.raw
192 | expect(raw).to include(
193 | Helper.table_header("user", "topic", "rank_type.action_types.most_bookmarked"),
194 | )
195 | expect(raw).to include(
196 | Helper.table_row(
197 | Helper.avatar_image(
198 | reviewed_topic.user.username,
199 | reviewed_topic.user.uploaded_avatar_id,
200 | ),
201 | Helper.topic_link(reviewed_topic.title, reviewed_topic.slug, reviewed_topic.id),
202 | 5,
203 | ),
204 | )
205 | end
206 | end
207 |
208 | describe "likes given and received" do
209 | SiteSetting.max_consecutive_replies = 20
210 | let(:reviewed_topic) { Fabricate(:topic, created_at: 1.year.ago) }
211 | before do
212 | 11.times do
213 | post =
214 | Fabricate(:post, topic: reviewed_topic, user: reviewed_user, created_at: 1.month.ago)
215 | UserAction.create!(
216 | action_type: PostActionType.types[:like],
217 | user_id: reviewed_user.id,
218 | acting_user_id: top_review_user.id,
219 | target_post_id: post.id,
220 | target_topic_id: reviewed_topic.id,
221 | created_at: 1.month.ago,
222 | )
223 | end
224 | 10.times do
225 | post =
226 | Fabricate(:post, topic: reviewed_topic, user: top_review_user, created_at: 1.month.ago)
227 | UserAction.create!(
228 | action_type: PostActionType.types[:like],
229 | user_id: top_review_user.id,
230 | acting_user_id: reviewed_user.id,
231 | target_post_id: post.id,
232 | target_topic_id: reviewed_topic.id,
233 | created_at: 1.month.ago,
234 | )
235 | end
236 | end
237 |
238 | it "should rank likes given and received correctly" do
239 | Jobs::YearlyReview.new.execute({})
240 | raw = Topic.last.first_post.raw
241 | expect(raw).to have_tag("div.likes-given") { with_text(/\@top_review_user\|11/) }
242 | expect(raw).to have_tag("div.likes-given") { with_text(/\@reviewed_user\|10/) }
243 |
244 | expect(raw).to have_tag("div.likes-received") { with_text(/\@reviewed_user\|11/) }
245 | expect(raw).to have_tag("div.likes-received") { with_text(/\@top_review_user\|10/) }
246 | end
247 | end
248 | end
249 |
250 | describe "featured badge" do
251 | let(:admin) { Fabricate(:user, admin: true) }
252 | let(:badge) { Fabricate(:badge) }
253 |
254 | before do
255 | SiteSetting.yearly_review_featured_badge = badge.name
256 | SiteSetting.yearly_review_publish_category = category.id
257 | freeze_time DateTime.parse("#{::YearlyReview.current_year}-01-01")
258 | 16.times do
259 | user = Fabricate(:user)
260 | UserBadge.create!(
261 | badge_id: badge.id,
262 | user_id: user.id,
263 | granted_at: 1.month.ago,
264 | granted_by_id: admin.id,
265 | )
266 | end
267 | end
268 |
269 | it "it should only display the first 100 users" do
270 | Jobs::YearlyReview.new.execute({})
271 | raw = Topic.last.first_post.raw
272 | expect(raw).to include("[And 1 more...](")
273 | end
274 | end
275 | end
276 |
--------------------------------------------------------------------------------
/spec/system/core_features_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe "Core features", type: :system do
4 | before { enable_current_plugin }
5 |
6 | it_behaves_like "having working core features"
7 | end
8 |
--------------------------------------------------------------------------------
/stylelint.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | extends: ["@discourse/lint-configs/stylelint"],
3 | };
4 |
--------------------------------------------------------------------------------
/translator.yml:
--------------------------------------------------------------------------------
1 | # Configuration file for discourse-translator-bot
2 |
3 | files:
4 | - source_path: config/locales/server.en.yml
5 | destination_path: server.yml
6 |
--------------------------------------------------------------------------------