├── .npmrc ├── .rubocop.yml ├── .discourse-compatibility ├── .prettierrc.cjs ├── coverage └── .last_run.json ├── spec ├── plugin_helper.rb ├── system │ └── core_features_spec.rb ├── requests │ ├── admin │ │ └── rating_type_spec.rb │ └── posts_controller_spec.rb ├── lib │ └── ratings │ │ ├── cache_spec.rb │ │ ├── rating_type_spec.rb │ │ └── object_spec.rb ├── extensions │ └── post_revisor_spec.rb ├── jobs │ └── destroy_rating_type_spec.rb └── serializers │ └── post_serializer_spec.rb ├── .template-lintrc.cjs ├── .streerc ├── .gitignore ├── eslint.config.mjs ├── Gemfile ├── assets ├── javascripts │ └── discourse │ │ ├── ratings-route-map.js │ │ ├── components │ │ ├── star-rating.hbs │ │ ├── rating-actions.js │ │ ├── topic-rating-tip.hbs │ │ ├── star-rating.js │ │ ├── select-rating.hbs │ │ ├── rating-actions.hbs │ │ ├── select-rating.js │ │ ├── rating-type-chooser.js │ │ ├── rating-destroy.hbs │ │ ├── rating-star.js │ │ ├── rating-migrate.hbs │ │ ├── topic-rating-tip.js │ │ ├── rating-object-list.hbs │ │ ├── rating-type.js │ │ ├── rating-destroy.js │ │ ├── rating-type.hbs │ │ ├── rating-migrate.js │ │ ├── rating-object.hbs │ │ ├── rating-object-list.js │ │ └── rating-object.js │ │ ├── connectors │ │ ├── topic-title │ │ │ ├── topic-rating-container.hbs │ │ │ └── topic-rating-container.js │ │ ├── topic-category │ │ │ ├── topic-tip-container.hbs │ │ │ └── topic-tip-container.js │ │ ├── composer-fields │ │ │ ├── composer-controls-rating.hbs │ │ │ └── composer-controls-rating.js │ │ └── topic-list-after-title │ │ │ └── topic-list-rating.gjs │ │ ├── helpers │ │ └── rating-list.js │ │ ├── models │ │ ├── rating.js │ │ ├── rating-type.js │ │ └── rating-object.js │ │ ├── widgets │ │ ├── rating-star.js │ │ └── star-rating.js │ │ ├── templates │ │ └── admin │ │ │ └── plugins-ratings.hbs │ │ ├── routes │ │ └── admin-plugins-ratings.js │ │ ├── controllers │ │ └── admin-plugins-ratings.js │ │ └── lib │ │ └── rating-utilities.js └── stylesheets │ ├── desktop │ └── ratings.scss │ ├── mobile │ └── ratings.scss │ └── common │ └── admin.scss ├── app ├── serializers │ └── ratings │ │ ├── object.rb │ │ ├── rating_type.rb │ │ └── rating.rb ├── views │ └── connectors │ │ └── topic_header │ │ └── aggregate_rating.html.erb └── controllers │ └── ratings │ ├── rating.rb │ ├── object.rb │ └── rating_type.rb ├── .travis.yml ├── .simplecov ├── .github └── workflows │ └── discourse-plugin.yml ├── .tx └── config ├── lib └── ratings │ ├── engine.rb │ ├── cache.rb │ ├── rating_type.rb │ └── object.rb ├── jobs └── regular │ ├── destroy_ratings.rb │ ├── migrate_ratings.rb │ └── destroy_rating_type.rb ├── crowdin.yml ├── package.json ├── config ├── settings.yml ├── routes.rb └── locales │ ├── client.zh_CN.yml │ ├── client.bo.yml │ ├── client.id.yml │ ├── client.ja.yml │ ├── client.km.yml │ ├── client.ko.yml │ ├── client.lo.yml │ ├── client.ms.yml │ ├── client.th.yml │ ├── client.tt.yml │ ├── client.vi.yml │ ├── client.zh.yml │ ├── client.af.yml │ ├── client.az.yml │ ├── client.bg.yml │ ├── client.bn.yml │ ├── client.ca.yml │ ├── client.da.yml │ ├── client.de.yml │ ├── client.el.yml │ ├── client.eo.yml │ ├── client.et.yml │ ├── client.eu.yml │ ├── client.fa.yml │ ├── client.fi.yml │ ├── client.gl.yml │ ├── client.hi.yml │ ├── client.hu.yml │ ├── client.hy.yml │ ├── client.is.yml │ ├── client.ka.yml │ ├── client.kk.yml │ ├── client.kn.yml │ ├── client.ku.yml │ ├── client.mk.yml │ ├── client.ml.yml │ ├── client.mn.yml │ ├── client.ne.yml │ ├── client.nl.yml │ ├── client.om.yml │ └── client.pa.yml ├── extensions ├── topic.rb ├── posts_controller.rb └── post_revisor.rb ├── COPYRIGHT.txt ├── Gemfile.lock ├── db └── migrate │ └── 20200520084648_add_rating_types.rb └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict = true 2 | auto-install-peers = false 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_gem: 2 | rubocop-discourse: stree-compat.yml 3 | -------------------------------------------------------------------------------- /.discourse-compatibility: -------------------------------------------------------------------------------- 1 | < 3.3.0.beta1-dev: b2c73f8909dec23c5a0bf18ccd380e298e6aa775 -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = require("@discourse/lint-configs/prettier"); 2 | -------------------------------------------------------------------------------- /coverage/.last_run.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "line": 84.51 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /spec/plugin_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | -------------------------------------------------------------------------------- /.template-lintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = require("@discourse/lint-configs/template-lint"); 2 | -------------------------------------------------------------------------------- /.streerc: -------------------------------------------------------------------------------- 1 | --print-width=100 2 | --plugins=plugin/trailing_comma,plugin/disable_auto_ternary 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/* 2 | !coverage/.last_run.json 3 | gems/ 4 | .bundle/ 5 | auto_generated 6 | .DS_Store 7 | node_modules/ 8 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import DiscourseRecommended from "@discourse/lint-configs/eslint"; 2 | 3 | export default [...DiscourseRecommended]; 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/ratings-route-map.js: -------------------------------------------------------------------------------- 1 | export default { 2 | resource: "admin.adminPlugins", 3 | map() { 4 | this.route("ratings"); 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /app/serializers/ratings/object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::ObjectSerializer < ::ApplicationSerializer 3 | attributes :name, :types 4 | end 5 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/star-rating.hbs: -------------------------------------------------------------------------------- 1 | {{#each this.stars as |star|}} 2 | {{rating-star value=star rating=this.rating enabled=this.enabled}} 3 | {{/each}} -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/topic-title/topic-rating-container.hbs: -------------------------------------------------------------------------------- 1 | {{#if this.model.show_ratings}} 2 | {{rating-list this.model.ratings topic=this.model}} 3 | {{/if}} -------------------------------------------------------------------------------- /app/serializers/ratings/rating_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::RatingTypeSerializer < ::ApplicationSerializer 3 | attributes :type, :name 4 | end 5 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/topic-category/topic-tip-container.hbs: -------------------------------------------------------------------------------- 1 | {{#if this.topic.show_ratings}} 2 | {{topic-rating-tip details="topic.tip.ratings.details"}} 3 | {{/if}} -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/topic-title/topic-rating-container.js: -------------------------------------------------------------------------------- 1 | export default { 2 | shouldRender(_, ctx) { 3 | return ctx.siteSettings.rating_enabled; 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /app/serializers/ratings/rating.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::RatingSerializer < ::ApplicationSerializer 3 | attributes :type, :type_name, :value, :count, :weight 4 | end 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | services: 2 | - docker 3 | 4 | before_install: 5 | - git clone --depth=1 https://github.com/discourse/discourse-plugin-ci 6 | 7 | install: true 8 | 9 | script: 10 | - discourse-plugin-ci/script.sh 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.simplecov: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | plugin = "discourse-ratings" 3 | 4 | SimpleCov.configure do 5 | track_files "plugins/#{plugin}/**/*.rb" 6 | add_filter { |src| !(src.filename =~ /(\/#{plugin}\/app\/|\/#{plugin}\/lib\/)/) } 7 | end 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/topic-category/topic-tip-container.js: -------------------------------------------------------------------------------- 1 | export default { 2 | shouldRender(_, ctx) { 3 | return ( 4 | ctx.siteSettings.rating_enabled && ctx.siteSettings.rating_show_topic_tip 5 | ); 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [discourse-ratings.client-en-yml] 5 | file_filter = config/locales/client..yml 6 | minimum_perc = 0 7 | source_file = config/locales/client.en.yml 8 | source_lang = en 9 | type = YML 10 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/composer-fields/composer-controls-rating.hbs: -------------------------------------------------------------------------------- 1 | {{#if this.model.showRatings}} 2 | {{#each this.model.ratings as |rating|}} 3 | {{select-rating rating=rating updateRating=(action "updateRating")}} 4 | {{/each}} 5 | {{/if}} -------------------------------------------------------------------------------- /lib/ratings/engine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ::DiscourseRatings 3 | class Engine < ::Rails::Engine 4 | engine_name "discourse_ratings" 5 | isolate_namespace DiscourseRatings 6 | end 7 | PLUGIN_NAME ||= "discourse_ratings" 8 | end 9 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-actions.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { classNames } from "@ember-decorators/component"; 3 | 4 | @classNames("ratings-action-controls") 5 | export default class RatingActions extends Component {} 6 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/topic-rating-tip.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{d-icon "circle-info"}} 3 | 4 | {{#if this.showDetails}} 5 |
6 | {{html-safe (i18n this.details)}} 7 |
8 | {{/if}} -------------------------------------------------------------------------------- /assets/javascripts/discourse/helpers/rating-list.js: -------------------------------------------------------------------------------- 1 | import { htmlSafe } from "@ember/template"; 2 | import { ratingListHtml } from "../lib/rating-utilities"; 3 | 4 | export default function ratingList(ratings, opts = {}) { 5 | return htmlSafe(ratingListHtml(ratings, opts)); 6 | } 7 | -------------------------------------------------------------------------------- /jobs/regular/destroy_ratings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jobs 4 | class DestroyRatings < ::Jobs::Base 5 | def execute(args) 6 | DiscourseRatings::Rating.destroy(type: args[:type], category_id: args[:category_id]) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | pull_request_title: 'i18n: Update translations' 2 | files: 3 | - source: /config/locales/client.en.yml 4 | translation: /config/locales/client.%two_letters_code%.yml 5 | - source: /config/locales/server.en.yml 6 | translation: /config/locales/server.%two_letters_code%.yml 7 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/topic-list-after-title/topic-list-rating.gjs: -------------------------------------------------------------------------------- 1 | import ratingList from "../../helpers/rating-list"; 2 | 3 | 8 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/star-rating.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { classNames, tagName } from "@ember-decorators/component"; 3 | 4 | @tagName("span") 5 | @classNames("star-rating") 6 | export default class StarRating extends Component { 7 | stars = [1, 2, 3, 4, 5]; 8 | enabled = false; 9 | } 10 | -------------------------------------------------------------------------------- /jobs/regular/migrate_ratings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jobs 4 | class MigrateRatings < ::Jobs::Base 5 | def execute(args) 6 | DiscourseRatings::Rating.migrate( 7 | category_id: args[:category_id], 8 | type: args[:type], 9 | new_type: args[:new_type], 10 | ) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/models/rating.js: -------------------------------------------------------------------------------- 1 | import EmberObject from "@ember/object"; 2 | import { request } from "../lib/rating-utilities"; 3 | 4 | export default class Rating extends EmberObject { 5 | static destroy(type, data) { 6 | return request("DELETE", `rating/${type}`, data); 7 | } 8 | 9 | static migrate(data) { 10 | return request("POST", "rating/migrate", data); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/select-rating.hbs: -------------------------------------------------------------------------------- 1 | {{input type="checkbox" checked=this.rating.include class="include-rating"}} 2 | 3 | 4 | {{#if this.rating.typeName}} 5 | {{this.rating.typeName}} 6 | {{else}} 7 | {{i18n "composer.your_rating"}} 8 | {{/if}} 9 | 10 | 11 | {{star-rating 12 | enabled=this.rating.include 13 | rating=this.rating.value 14 | click=this.triggerUpdateRating 15 | }} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discourse-ratings", 3 | "private": true, 4 | "devDependencies": { 5 | "@discourse/lint-configs": "2.4.0", 6 | "ember-template-lint": "6.1.0", 7 | "eslint": "9.19.0", 8 | "prettier": "2.8.8" 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 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/connectors/composer-fields/composer-controls-rating.js: -------------------------------------------------------------------------------- 1 | import { set } from "@ember/object"; 2 | 3 | export default { 4 | actions: { 5 | updateRating(rating) { 6 | const ratings = this.get("model.ratings") || []; 7 | const index = ratings.findIndex((r) => r.type === rating.type); 8 | set(ratings[index], "value", rating.value); 9 | this.set("model.ratings", ratings); 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /assets/stylesheets/desktop/ratings.scss: -------------------------------------------------------------------------------- 1 | .topic-list-item.has-ratings .link-top-line { 2 | display: flex; 3 | flex-flow: wrap; 4 | 5 | .raw-topic-link { 6 | order: 1; 7 | padding: 0; 8 | display: inline-block; 9 | } 10 | 11 | .topic-post-badges { 12 | order: 2; 13 | } 14 | 15 | .rating-list { 16 | order: 3; 17 | width: 100%; 18 | margin-bottom: 2px; 19 | } 20 | } 21 | 22 | #reply-control .composer-controls-rating { 23 | width: 50%; 24 | } 25 | -------------------------------------------------------------------------------- /jobs/regular/destroy_rating_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jobs 4 | class DestroyRatingType < ::Jobs::Base 5 | def execute(args) 6 | type = args[:type] 7 | 8 | ActiveRecord::Base.transaction do 9 | DiscourseRatings::Rating.destroy(type: type) 10 | DiscourseRatings::Object.remove_type("category", type) 11 | DiscourseRatings::Object.remove_type("tag", type) 12 | DiscourseRatings::RatingType.destroy(type) 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/widgets/rating-star.js: -------------------------------------------------------------------------------- 1 | import { createWidget } from "discourse/widgets/widget"; 2 | 3 | export default createWidget("rating-star", { 4 | tagName: "input", 5 | 6 | buildAttributes(attrs) { 7 | let result = { 8 | type: "radio", 9 | value: attrs.value, 10 | }; 11 | if (attrs.checked) { 12 | result["checked"] = true; 13 | } 14 | if (attrs.disabled) { 15 | result["disabled"] = true; 16 | } 17 | return result; 18 | }, 19 | 20 | html() { 21 | return; 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /config/settings.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | rating_enabled: 3 | default: true 4 | client: true 5 | rating_show_topic_tip: 6 | default: true 7 | client: true 8 | rating_show_numeric_average: 9 | default: true 10 | client: true 11 | rating_show_count: 12 | default: false 13 | client: true 14 | rating_topic_average_enabled: 15 | client: true 16 | default: true 17 | rating_topic_list_average_enabled: 18 | client: true 19 | default: true 20 | rating_hide_except_own_entry: 21 | default: false 22 | client: true 23 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | DiscourseRatings::Engine.routes.draw do 3 | scope constraints: AdminConstraint.new do 4 | resources :rating_type, param: :type, path: "/rating-type" 5 | resources :object, param: :type 6 | post "/rating/migrate" => "rating#migrate" 7 | delete "/rating/:type" => "rating#destroy" 8 | end 9 | end 10 | 11 | Discourse::Application.routes.append do 12 | get "/admin/plugins/ratings" => "admin/plugins#index", :constraints => AdminConstraint.new 13 | mount ::DiscourseRatings::Engine, at: "ratings" 14 | end 15 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/models/rating-type.js: -------------------------------------------------------------------------------- 1 | import EmberObject from "@ember/object"; 2 | import { request } from "../lib/rating-utilities"; 3 | 4 | export default class RatingType extends EmberObject { 5 | static all() { 6 | return request("GET", "rating-type"); 7 | } 8 | 9 | static add(data) { 10 | return request("POST", "rating-type", data); 11 | } 12 | 13 | static update(type, data) { 14 | return request("PUT", `rating-type/${type}`, data); 15 | } 16 | 17 | static destroy(type) { 18 | return request("DELETE", `rating-type/${type}`); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/models/rating-object.js: -------------------------------------------------------------------------------- 1 | import EmberObject from "@ember/object"; 2 | import { request } from "../lib/rating-utilities"; 3 | 4 | export default class RatingObject extends EmberObject { 5 | static all(type) { 6 | return request("GET", `object/${type}`); 7 | } 8 | 9 | static add(data) { 10 | return request("POST", "object", data); 11 | } 12 | 13 | static update(type, data) { 14 | return request("PUT", `object/${type}`, data); 15 | } 16 | 17 | static destroy(type, data) { 18 | return request("DELETE", `object/${type}`, data); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /assets/stylesheets/mobile/ratings.scss: -------------------------------------------------------------------------------- 1 | .topic-rating-tip .tip-details { 2 | left: -100px; 3 | max-width: 80vw; 4 | } 5 | 6 | .topic-list-item.has-ratings .main-link { 7 | display: inline-flex; 8 | flex-direction: column; 9 | 10 | .raw-topic-link { 11 | order: 1; 12 | padding: 0; 13 | } 14 | 15 | .rating-list { 16 | order: 2; 17 | margin: 3px 0 0 0; 18 | } 19 | } 20 | 21 | .topic-meta-data .names.has-ratings .rating-list { 22 | order: 2; 23 | 24 | .rating { 25 | margin: 0 0 2px 0; 26 | } 27 | } 28 | 29 | .reply-control-ratings.open { 30 | height: 100% !important; 31 | } 32 | -------------------------------------------------------------------------------- /extensions/topic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module TopicRatingsExtension 3 | def preload_custom_fields(objects, fields) 4 | ## Remove all rating types 5 | fields = fields.select { |f| !f.starts_with?("#{DiscourseRatings::Rating::KEY}_") } 6 | 7 | ## Build list of current types (type list is cached) 8 | type_list = 9 | DiscourseRatings::RatingType.cached_list.map(&:type) + [DiscourseRatings::RatingType::NONE] 10 | rating_types = type_list.map { |t| DiscourseRatings::Rating.field_name(t) } 11 | 12 | ## Add types to preloaded fields 13 | fields.push(*rating_types) 14 | super 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/widgets/star-rating.js: -------------------------------------------------------------------------------- 1 | import { h } from "virtual-dom"; 2 | import { createWidget } from "discourse/widgets/widget"; 3 | 4 | export default createWidget("star-rating", { 5 | tagName: "span.star-rating", 6 | 7 | html(attrs) { 8 | const stars = [1, 2, 3, 4, 5]; 9 | let contents = []; 10 | 11 | stars.forEach((s) => { 12 | let checked = s <= attrs.rating; 13 | contents.push( 14 | this.attach("rating-star", { 15 | value: s, 16 | checked, 17 | disabled: attrs.disabled, 18 | }), 19 | h("i") 20 | ); 21 | }); 22 | 23 | return contents; 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-actions.hbs: -------------------------------------------------------------------------------- 1 |
2 |

{{i18n "admin.ratings.migrate.title"}}

3 | 4 |
5 | {{i18n "admin.ratings.migrate.description"}} 6 |
7 | 8 |
9 | {{rating-migrate ratingTypes=this.ratingTypes}} 10 |
11 |
12 | 13 |
14 |

{{i18n "admin.ratings.destroy.title"}}

15 | 16 |
17 | {{i18n "admin.ratings.destroy.description"}} 18 |
19 | 20 |
21 | {{rating-destroy ratingTypes=this.ratingTypes}} 22 |
23 |
-------------------------------------------------------------------------------- /assets/javascripts/discourse/components/select-rating.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { action } from "@ember/object"; 3 | import { classNames, tagName } from "@ember-decorators/component"; 4 | import { observes } from "@ember-decorators/object"; 5 | 6 | @tagName("div") 7 | @classNames("rating-container") 8 | export default class SelectRating extends Component { 9 | @observes("rating.include") 10 | removeOnUncheck() { 11 | if (!this.rating.include) { 12 | this.set("rating.value", 0); 13 | this.updateRating(this.rating); 14 | } 15 | } 16 | 17 | @action 18 | triggerUpdateRating() { 19 | this.updateRating(this.rating); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-type-chooser.js: -------------------------------------------------------------------------------- 1 | import { classNames } from "@ember-decorators/component"; 2 | import MultiSelectComponent from "select-kit/components/multi-select"; 3 | import { selectKitOptions } from "select-kit/components/select-kit"; 4 | 5 | @selectKitOptions({ 6 | filterable: true, 7 | }) 8 | @classNames("rating-type-chooser") 9 | export default class RatingTypeChooser extends MultiSelectComponent { 10 | didReceiveAttrs() { 11 | super.didReceiveAttrs(...arguments); 12 | if (this.types) { 13 | this.set("value", this.types.split("|")); 14 | } 15 | } 16 | 17 | onChange(value) { 18 | this.set("types", value.join("|")); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /extensions/posts_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module PostsControllerRatingsExtension 3 | def update 4 | params.require(:post) 5 | if SiteSetting.rating_enabled && params[:id] && params[:post][:ratings] 6 | begin 7 | begin 8 | raw_ratings = JSON.parse(params[:post][:ratings]) 9 | rescue JSON::ParserError 10 | raw_ratings = [] 11 | end 12 | 13 | if raw_ratings.present? 14 | ratings = DiscourseRatings::Rating.build_list(raw_ratings) 15 | DiscourseRatings::Cache.new("update_#{params[:id]}").write(ratings) 16 | end 17 | rescue JSON::ParserError 18 | end 19 | end 20 | super 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-destroy.hbs: -------------------------------------------------------------------------------- 1 | {{category-chooser 2 | value=this.categoryId 3 | onChange=(action (mut this.categoryId)) 4 | }} 5 | 6 | {{combo-box 7 | value=this.type 8 | content=this.ratingTypes 9 | valueProperty="type" 10 | onChange=(action (mut this.type)) 11 | options=(hash none="admin.ratings.type.select") 12 | }} 13 | 14 | {{d-button 15 | action=(action this.destroyRatings) 16 | label="admin.ratings.destroy.btn" 17 | disabled=this.destroyDisabled 18 | }} 19 | 20 | {{#if this.startingDestroy}} 21 | {{loading-spinner size="small"}} 22 | {{/if}} 23 | 24 | {{#if this.destroyMessage}} 25 |
26 | {{i18n this.destroyMessage}} 27 |
28 | {{/if}} -------------------------------------------------------------------------------- /COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | All code in this repository is Copyright 2018 by Angus McLeod. 2 | 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; either version 2 of the License, or (at 6 | your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 10 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 | for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program as the file LICENSE.txt; if not, please see 15 | http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 16 | -------------------------------------------------------------------------------- /lib/ratings/cache.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::Cache 3 | def initialize(key) 4 | @key = "#{DiscourseRatings::PLUGIN_NAME}_#{key}" 5 | end 6 | 7 | def read 8 | cache.read(@key) 9 | end 10 | 11 | def write(data) 12 | synchronize { cache.write(@key, data) } 13 | end 14 | 15 | def delete 16 | synchronize { cache.delete(@key) } 17 | end 18 | 19 | def synchronize 20 | DistributedMutex.synchronize(@key) { yield } 21 | end 22 | 23 | def cache 24 | @cache ||= Discourse.cache 25 | end 26 | 27 | def self.wrap(key, &block) 28 | c = new(key) 29 | 30 | if cached = c.read 31 | cached 32 | else 33 | result = block.call() 34 | c.write(result) 35 | result 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /extensions/post_revisor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module PostRevisorRatingsExtension 3 | def ratings_cache 4 | DiscourseRatings::Cache.new("update_#{@post.id}") 5 | end 6 | 7 | def ratings 8 | @ratings ||= ratings_cache.read 9 | end 10 | 11 | def clear_ratings_cache! 12 | ratings_cache.delete 13 | @ratings = nil 14 | end 15 | 16 | def should_revise? 17 | super || ratings_changed? 18 | end 19 | 20 | def ratings_changed? 21 | return false unless ratings.present? 22 | return true unless @post.ratings.present? 23 | return true if @post.ratings.length != ratings.length 24 | 25 | ratings.any? do |r| 26 | @post.ratings.any? do |pr| 27 | pr.type === r.type && (pr.value != r.value || pr.weight != r.weight) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/views/connectors/topic_header/aggregate_rating.html.erb: -------------------------------------------------------------------------------- 1 | <% if @topic_view.topic.ratings.present? %> 2 |
3 | <%= @topic_view.topic.title %> 4 | <% if @topic_view.topic.image_url.present? %> 5 | <%= @topic_view.topic.image_url %> 6 | <% end %> 7 |
8 | <% @topic_view.topic.ratings.each do |rating| %> 9 | <%= rating.type %> 10 | <%= rating.value %> 11 | <%= rating.count %> 12 | 13 | 14 | <% end %> 15 |
16 |
17 | <% end %> 18 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-star.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { not } from "@ember/object/computed"; 3 | import { attributeBindings, tagName } from "@ember-decorators/component"; 4 | import discourseComputed from "discourse/lib/decorators"; 5 | 6 | @tagName("input") 7 | @attributeBindings("value", "checked:checked", "disabled:disabled") 8 | export default class RatingStar extends Component { 9 | @not("enabled") disabled; 10 | 11 | willInsertElement() { 12 | super.willInsertElement(...arguments); 13 | this.element.type = "radio"; 14 | } 15 | 16 | didRender() { 17 | super.didRender(...arguments); 18 | // For IE support 19 | this.element.value = this.value; 20 | } 21 | 22 | click() { 23 | this.set("rating", this.element.value); 24 | } 25 | 26 | @discourseComputed("rating") 27 | checked(rating) { 28 | return this.get("value") <= rating; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-migrate.hbs: -------------------------------------------------------------------------------- 1 | {{category-chooser 2 | value=this.categoryId 3 | onChange=(action (mut this.categoryId)) 4 | }} 5 | 6 | {{combo-box 7 | value=this.fromType 8 | content=this.ratingTypes 9 | valueProperty="type" 10 | onChange=(action (mut this.fromType)) 11 | options=(hash none="admin.ratings.type.select") 12 | }} 13 | 14 | {{combo-box 15 | value=this.toType 16 | content=this.ratingTypes 17 | valueProperty="type" 18 | onChange=(action (mut this.toType)) 19 | options=(hash none="admin.ratings.type.select") 20 | }} 21 | 22 | {{d-button 23 | action=(action this.migrate) 24 | label="admin.ratings.migrate.btn" 25 | disabled=this.migrateDisabled 26 | }} 27 | 28 | {{#if this.startingMigration}} 29 | {{loading-spinner size="small"}} 30 | {{/if}} 31 | 32 | {{#if this.migrationMessage}} 33 |
34 | {{i18n this.migrationMessage}} 35 |
36 | {{/if}} -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/topic-rating-tip.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { action } from "@ember/object"; 3 | import { bind } from "@ember/runloop"; 4 | import { classNames } from "@ember-decorators/component"; 5 | import $ from "jquery"; 6 | 7 | @classNames("topic-rating-tip") 8 | export default class TopicRatingTip extends Component { 9 | didInsertElement() { 10 | super.didInsertElement(...arguments); 11 | $(document).on("click", bind(this, this.documentClick)); 12 | } 13 | 14 | willDestroyElement() { 15 | super.willDestroyElement(...arguments); 16 | $(document).off("click", bind(this, this.documentClick)); 17 | } 18 | 19 | documentClick(e) { 20 | let $element = $(this.element); 21 | let $target = $(e.target); 22 | 23 | if ($target.closest($element).length < 1 && this._state !== "destroying") { 24 | this.set("showDetails", false); 25 | } 26 | } 27 | 28 | @action 29 | toggleDetails() { 30 | this.toggleProperty("showDetails"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-object-list.hbs: -------------------------------------------------------------------------------- 1 |

{{this.title}}

2 | 3 | {{#if this.loading}} 4 | {{loading-spinner}} 5 | {{else}} 6 | {{#if this.hasObjects}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {{#each this.objects as |object|}} 16 | {{rating-object 17 | object=object 18 | objects=this.objects 19 | objectType=this.objectType 20 | ratingTypes=this.ratingTypes 21 | addObject=(action "addObject") 22 | updateObject=(action "updateObject") 23 | destroyObject=(action "destroyObject") 24 | }} 25 | {{/each}} 26 | 27 |
{{this.nameLabel}}{{i18n "admin.ratings.type.title"}}
28 | {{else}} 29 | {{this.noneLabel}} 30 | {{/if}} 31 | {{/if}} 32 | 33 |
34 | {{d-button 35 | action=(action "newObject") 36 | label="admin.ratings.type.new" 37 | icon="plus" 38 | }} 39 |
-------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-type.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { equal, lt, not, or } from "@ember/object/computed"; 3 | import { classNameBindings, tagName } from "@ember-decorators/component"; 4 | import discourseComputed from "discourse/lib/decorators"; 5 | 6 | const minTypeLength = 2; 7 | const minNameLength = 2; 8 | const noneType = "none"; 9 | 10 | @tagName("tr") 11 | @classNameBindings(":rating-type", ":admin-ratings-list-object", "hasError") 12 | export default class RatingType extends Component { 13 | @lt("type.type.length", minTypeLength) invalidType; 14 | @lt("type.name.length", minNameLength) invalidName; 15 | @or("invalidType", "invalidName") addDisabled; 16 | @equal("type.type", noneType) noneType; 17 | @not("noneType") showControls; 18 | 19 | didReceiveAttrs() { 20 | super.didReceiveAttrs(); 21 | this.set("currentName", this.type.name); 22 | } 23 | 24 | @discourseComputed("invalidName", "type.name", "currentName") 25 | updateDisabled(invalidName, name, currentName) { 26 | return invalidName || name === currentName; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /spec/requests/admin/rating_type_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../../plugin_helper.rb" 4 | 5 | describe DiscourseRatings::RatingTypeController do 6 | let!(:create_params) { { type: "comfort", name: "Comfort" } } 7 | let!(:update_params) { { type: "comfort", name: "Comfort Zone" } } 8 | fab!(:admin) { sign_in(Fabricate(:admin)) } 9 | 10 | describe "#create" do 11 | it "creates the rating type correctly" do 12 | post "/ratings/rating-type.json", params: create_params 13 | expect(response.status).to eq(200) 14 | expect(DiscourseRatings::RatingType.all.map { |t| t.type }).to include(create_params[:type]) 15 | end 16 | end 17 | 18 | describe "#update" do 19 | it "updates the rating type correctly" do 20 | DiscourseRatings::RatingType.create(create_params[:type], create_params[:name]) 21 | put "/ratings/rating-type/" + update_params[:type] + ".json", params: update_params 22 | expect(response.status).to eq(200) 23 | expect(DiscourseRatings::RatingType.get_name(create_params[:type])).to eq( 24 | update_params[:name], 25 | ) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /assets/stylesheets/common/admin.scss: -------------------------------------------------------------------------------- 1 | .admin-contents.ratings { 2 | .admin-ratings-list { 3 | margin-bottom: 30px; 4 | 5 | input { 6 | margin-bottom: 0; 7 | } 8 | } 9 | 10 | .rating-type input { 11 | width: 300px; 12 | } 13 | 14 | .type-controls { 15 | text-align: right; 16 | } 17 | 18 | .admin-ratings-list-controls { 19 | margin-top: 10px; 20 | } 21 | 22 | .admin-ratings-list-object { 23 | position: relative; 24 | 25 | td:first-of-type { 26 | width: 350px; 27 | } 28 | 29 | &.has-error { 30 | border: 2px solid $danger; 31 | min-height: 70px; 32 | 33 | .error { 34 | position: absolute; 35 | bottom: 0; 36 | left: 0; 37 | } 38 | } 39 | } 40 | 41 | .admin-ratings-action { 42 | margin-bottom: 30px; 43 | 44 | .controls { 45 | display: flex; 46 | align-items: flex-start; 47 | margin-top: 10px; 48 | 49 | > * { 50 | margin-right: 10px; 51 | } 52 | 53 | .combo-box { 54 | min-width: 130px; 55 | } 56 | } 57 | 58 | .action-message { 59 | margin-top: 10px; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-destroy.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { action } from "@ember/object"; 3 | import { classNames } from "@ember-decorators/component"; 4 | import discourseComputed from "discourse/lib/decorators"; 5 | import Rating from "../models/rating"; 6 | 7 | @classNames("admin-ratings-destroy", "rating-action") 8 | export default class RatingDestroy extends Component { 9 | @discourseComputed("categoryId", "type") 10 | destroyDisabled(categoryId, type) { 11 | return [categoryId, type].any((i) => !i); 12 | } 13 | 14 | @action 15 | destroyRatings() { 16 | let data = { 17 | category_id: this.categoryId, 18 | }; 19 | 20 | this.set("startingDestroy", true); 21 | 22 | Rating.destroy(this.type, data) 23 | .then((result) => { 24 | if (result.success) { 25 | this.set("destroyMessage", "admin.ratings.destroy.started"); 26 | } else { 27 | this.set( 28 | "destroyMessage", 29 | "admin.ratings.error.destroy_failed_to_start" 30 | ); 31 | } 32 | }) 33 | .finally(() => this.set("startingDestroy", false)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-type.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{#if this.type.isNew}} 3 | {{input 4 | value=this.type.type 5 | placeholder=(i18n "admin.ratings.type.type_placeholder") 6 | }} 7 | {{else}} 8 | {{this.type.type}} 9 | {{/if}} 10 | 11 | 12 | 13 | {{#if this.type.isNone}} 14 | {{i18n "admin.ratings.type.none_type_description"}} 15 | {{else}} 16 | {{input 17 | value=this.type.name 18 | placeholder=(i18n "admin.ratings.type.name_placeholder") 19 | }} 20 | {{/if}} 21 | 22 | 23 | 24 | {{#if this.showControls}} 25 | {{#if this.type.isNew}} 26 | {{d-button 27 | class="btn-primary" 28 | action=this.addType 29 | actionParam=this.type 30 | label="admin.ratings.type.add" 31 | icon="plus" 32 | disabled=this.addDisabled 33 | }} 34 | {{else}} 35 | {{d-button 36 | class="btn-primary" 37 | action=this.updateType 38 | actionParam=this.type 39 | label="admin.ratings.type.update" 40 | icon="save" 41 | disabled=this.updateDisabled 42 | }} 43 | {{/if}} 44 | 45 | {{d-button action=this.destroyType actionParam=this.type icon="times"}} 46 | {{/if}} 47 | -------------------------------------------------------------------------------- /app/controllers/ratings/rating.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::RatingController < ::Admin::AdminController 3 | before_action :check_types_exist 4 | 5 | def migrate 6 | handle_render( 7 | Jobs.enqueue( 8 | :migrate_ratings, 9 | category_id: rating_params[:category_id], 10 | type: rating_params[:type], 11 | new_type: rating_params[:new_type], 12 | ), 13 | ) 14 | end 15 | 16 | def destroy 17 | handle_render( 18 | Jobs.enqueue( 19 | :destroy_ratings, 20 | category_id: rating_params[:category_id], 21 | type: rating_params[:type], 22 | ), 23 | ) 24 | end 25 | 26 | private 27 | 28 | def rating_params 29 | params.permit(:category_id, :type, :new_type) 30 | end 31 | 32 | def check_types_exist 33 | if !DiscourseRatings::RatingType.exists?(rating_params[:type]) 34 | raise Discourse::InvalidParameters.new(:type) 35 | end 36 | 37 | if action_name == "migrate" && !DiscourseRatings::RatingType.exists?(rating_params[:new_type]) 38 | raise Discourse::InvalidParameters.new(:new_type) 39 | end 40 | end 41 | 42 | def handle_render(success) 43 | if success 44 | render_json_dump(success_json) 45 | else 46 | render_json_dump(failed_json) 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-migrate.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { action } from "@ember/object"; 3 | import { classNames } from "@ember-decorators/component"; 4 | import discourseComputed from "discourse/lib/decorators"; 5 | import Rating from "../models/rating"; 6 | 7 | const noneType = "none"; 8 | 9 | @classNames("rating-action-controls") 10 | export default class RatingMigrate extends Component { 11 | @discourseComputed("categoryId", "toType", "fromType") 12 | migrateDisabled(categoryId, toType, fromType) { 13 | return ( 14 | [categoryId, toType, fromType].any((i) => !i) || 15 | (toType !== noneType && fromType !== noneType) 16 | ); 17 | } 18 | 19 | @action 20 | migrate() { 21 | let data = { 22 | category_id: this.categoryId, 23 | type: this.fromType, 24 | new_type: this.toType, 25 | }; 26 | 27 | this.set("startingMigration", true); 28 | 29 | Rating.migrate(data) 30 | .then((result) => { 31 | if (result.success) { 32 | this.set("migrationMessage", "admin.ratings.migrate.started"); 33 | } else { 34 | this.set( 35 | "migrationMessage", 36 | "admin.ratings.error.migration_failed_to_start" 37 | ); 38 | } 39 | }) 40 | .finally(() => this.set("startingMigration", false)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/templates/admin/plugins-ratings.hbs: -------------------------------------------------------------------------------- 1 |
2 |

{{i18n "admin.ratings.type.title"}}

3 | 4 | {{#if this.hasTypes}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{#each this.ratingTypes as |type|}} 14 | {{rating-type 15 | addType=(action "addType") 16 | updateType=(action "updateType") 17 | destroyType=(action "destroyType") 18 | type=type 19 | }} 20 | {{/each}} 21 | 22 |
{{i18n "admin.ratings.type.label"}}{{i18n "admin.ratings.type.name"}}
23 | {{else}} 24 | {{i18n "admin.ratings.type.none"}} 25 | {{/if}} 26 | 27 |
28 | {{d-button 29 | action=(action "newType") 30 | label="admin.ratings.type.new" 31 | icon="plus" 32 | }} 33 |
34 |
35 | 36 | {{rating-object-list 37 | objectType="category" 38 | objects=this.categoryTypes 39 | ratingTypes=this.ratingTypes 40 | refresh=(route-action "refresh") 41 | }} 42 | 43 | {{rating-object-list 44 | objectType="tag" 45 | objects=this.tagTypes 46 | ratingTypes=this.ratingTypes 47 | refresh=(route-action "refresh") 48 | }} 49 | 50 | {{rating-actions ratingTypes=this.ratingTypes}} -------------------------------------------------------------------------------- /assets/javascripts/discourse/routes/admin-plugins-ratings.js: -------------------------------------------------------------------------------- 1 | import { A } from "@ember/array"; 2 | import { action } from "@ember/object"; 3 | import { service } from "@ember/service"; 4 | import { all } from "rsvp"; 5 | import DiscourseRoute from "discourse/routes/discourse"; 6 | import { i18n } from "discourse-i18n"; 7 | import RatingObject from "../models/rating-object"; 8 | import RatingType from "../models/rating-type"; 9 | 10 | const noneType = "none"; 11 | 12 | export default class AdminPluginsRatings extends DiscourseRoute { 13 | @service router; 14 | 15 | model() { 16 | return RatingType.all(); 17 | } 18 | 19 | afterModel() { 20 | return all([this._typesFor("category"), this._typesFor("tag")]); 21 | } 22 | 23 | setupController(controller, model) { 24 | let ratingTypes = model || []; 25 | 26 | ratingTypes.unshift({ 27 | type: noneType, 28 | name: i18n("admin.ratings.type.none_type"), 29 | isNone: true, 30 | }); 31 | 32 | controller.setProperties({ 33 | ratingTypes: A(ratingTypes.map((t) => RatingType.create(t))), 34 | categoryTypes: A(this.categoryTypes), 35 | tagTypes: A(this.tagTypes), 36 | }); 37 | } 38 | 39 | _typesFor(object) { 40 | return RatingObject.all(object).then((result) => { 41 | this.set(`${object}Types`, result); 42 | }); 43 | } 44 | 45 | @action 46 | refresh() { 47 | this.router.refresh(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /spec/lib/ratings/cache_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../../plugin_helper.rb" 4 | 5 | describe DiscourseRatings::Cache do 6 | it "writes and reads values to the cache" do 7 | DiscourseRatings::Cache.new("list").write([1, 2, 3]) 8 | expect(DiscourseRatings::Cache.new("list").read).to eq([1, 2, 3]) 9 | end 10 | 11 | it "deletes values from the cache" do 12 | DiscourseRatings::Cache.new("list").delete 13 | expect(DiscourseRatings::Cache.new("list").read).to eq(nil) 14 | end 15 | 16 | describe "#wrap" do 17 | before { Discourse.cache.clear } 18 | 19 | it "caches the value if non existant" do 20 | wrapped = DiscourseRatings::Cache.wrap("sample") { [1, 2, 3] } 21 | cached = DiscourseRatings::Cache.new("sample") 22 | expect(cached.read).to eq([1, 2, 3]) 23 | end 24 | 25 | it "evaluates the block only if cache is empty" do 26 | value = [1, 2, 3] 27 | cache = DiscourseRatings::Cache.new("testkey") 28 | wrapped = DiscourseRatings::Cache.wrap("testkey") { value } 29 | expect(wrapped).to eq(value) 30 | 31 | new_value = [3, 2, 1] 32 | wrapped_new = DiscourseRatings::Cache.wrap("testkey") { new_value } 33 | expect(cache.read).to eq(value) 34 | 35 | cache.delete 36 | wrapped_new = DiscourseRatings::Cache.wrap("testkey") { new_value } 37 | expect(wrapped_new).to eq(new_value) 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ast (2.4.2) 5 | json (2.7.1) 6 | language_server-protocol (3.17.0.3) 7 | parallel (1.24.0) 8 | parser (3.3.0.4) 9 | ast (~> 2.4.1) 10 | racc 11 | prettier_print (1.2.1) 12 | racc (1.7.3) 13 | rainbow (3.1.1) 14 | regexp_parser (2.9.0) 15 | rexml (3.2.6) 16 | rubocop (1.60.0) 17 | json (~> 2.3) 18 | language_server-protocol (>= 3.17.0) 19 | parallel (~> 1.10) 20 | parser (>= 3.3.0.2) 21 | rainbow (>= 2.2.2, < 4.0) 22 | regexp_parser (>= 1.8, < 3.0) 23 | rexml (>= 3.2.5, < 4.0) 24 | rubocop-ast (>= 1.30.0, < 2.0) 25 | ruby-progressbar (~> 1.7) 26 | unicode-display_width (>= 2.4.0, < 3.0) 27 | rubocop-ast (1.30.0) 28 | parser (>= 3.2.1.0) 29 | rubocop-capybara (2.20.0) 30 | rubocop (~> 1.41) 31 | rubocop-discourse (3.6.0) 32 | rubocop (>= 1.59.0) 33 | rubocop-rspec (>= 2.25.0) 34 | rubocop-factory_bot (2.25.1) 35 | rubocop (~> 1.41) 36 | rubocop-rspec (2.26.1) 37 | rubocop (~> 1.40) 38 | rubocop-capybara (~> 2.17) 39 | rubocop-factory_bot (~> 2.22) 40 | ruby-progressbar (1.13.0) 41 | syntax_tree (6.2.0) 42 | prettier_print (>= 1.2.0) 43 | unicode-display_width (2.5.0) 44 | 45 | PLATFORMS 46 | ruby 47 | 48 | DEPENDENCIES 49 | rubocop-discourse 50 | syntax_tree 51 | 52 | BUNDLED WITH 53 | 2.5.4 54 | -------------------------------------------------------------------------------- /spec/extensions/post_revisor_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../plugin_helper.rb" 4 | require "post_revisor" 5 | 6 | describe PostRevisor do 7 | let!(:post_rating_param) { { type: "awesomeness", value: 4, weight: 1 } } 8 | let!(:post_rating_update_param) { { type: "awesomeness", value: 3, weight: 1 } } 9 | let!(:rating_category) { Fabricate(:category) } 10 | let!(:rating_topic) { Fabricate(:topic, category: rating_category) } 11 | let!(:rating_post) { Fabricate(:post, topic: rating_topic) } 12 | before do 13 | Category.any_instance.stubs(:rating_types).returns(["awesomeness"]) 14 | DiscourseRatings::Rating.build_and_set(rating_post, post_rating_param) 15 | rating_post.save_custom_fields(true) 16 | end 17 | 18 | it "detects change in rating" do 19 | pr = PostRevisor.new(rating_post) 20 | ## write rating to cache to simulate what posts_controller patch does 21 | new_ratings = DiscourseRatings::Rating.build_list([post_rating_update_param]) 22 | DiscourseRatings::Cache.new("update_#{rating_post.id}").write(new_ratings) 23 | pr.revise!(rating_post.user, ratings: new_ratings) 24 | rating_post.reload 25 | 26 | expect(rating_post.ratings[0].value).to eq(3.0) 27 | end 28 | 29 | it "does not error out if post's topic has been deleted first" do 30 | rating_post.topic.destroy 31 | rating_post.reload 32 | 33 | expect { rating_post.ratings }.not_to raise_error 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /app/controllers/ratings/object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::ObjectController < ::Admin::AdminController 3 | before_action :validate_type 4 | before_action :validate_object, only: [:create] 5 | 6 | def show 7 | render_serialized( 8 | DiscourseRatings::Object.list(params[:type]), 9 | DiscourseRatings::ObjectSerializer, 10 | ) 11 | end 12 | 13 | def create 14 | handle_render( 15 | DiscourseRatings::Object.create(params[:type], object_params[:name], object_params[:types]), 16 | ) 17 | end 18 | 19 | def update 20 | handle_render( 21 | DiscourseRatings::Object.set(params[:type], object_params[:name], object_params[:types]), 22 | ) 23 | end 24 | 25 | def destroy 26 | handle_render(DiscourseRatings::Object.destroy(params[:type], object_params[:name])) 27 | end 28 | 29 | private 30 | 31 | def object_params 32 | params.permit(:name, types: []) 33 | end 34 | 35 | def validate_type 36 | unless DiscourseRatings::Object::TYPES.include?(params[:type]) 37 | raise Discourse::InvalidParameters.new(:type) 38 | end 39 | end 40 | 41 | def validate_object 42 | if DiscourseRatings::Object.exists?(params[:type], object_params[:name]) 43 | raise Discourse::InvalidParameters.new(:name) 44 | end 45 | end 46 | 47 | def handle_render(success) 48 | if success 49 | render_json_dump(success_json) 50 | else 51 | render_json_dump(failed_json) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/lib/ratings/rating_type_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../../plugin_helper.rb" 4 | 5 | describe DiscourseRatings::RatingType do 6 | let!(:type_param) { "coolness" } 7 | let!(:name_param) { "Coolness" } 8 | before { DiscourseRatings::RatingType.create(type_param, name_param) } 9 | 10 | it "saves the type" do 11 | type_exists = DiscourseRatings::RatingType.exists?(type_param) 12 | expect(type_exists).to eq(true) 13 | end 14 | 15 | it "includes the created type in the list" do 16 | all_types = DiscourseRatings::RatingType.all 17 | expect(all_types.map { |rating_type| rating_type.type }).to include(type_param) 18 | end 19 | 20 | it "modifies the type name correctly" do 21 | DiscourseRatings::RatingType.set(type_param, "Intelligence") 22 | expect(DiscourseRatings::RatingType.get(type_param)).to eq("Intelligence") 23 | end 24 | 25 | it "correctly updates the cache" do 26 | DiscourseRatings::RatingType.create("professionalism", "Professionalism") 27 | cached_list = DiscourseRatings::RatingType.cached_list.map { |rating_type| rating_type.type } 28 | list = DiscourseRatings::RatingType.all.map { |rating_type| rating_type.type } 29 | expect(list).to eq(cached_list) 30 | end 31 | 32 | it "destroys the type correctly" do 33 | DiscourseRatings::RatingType.destroy("coolness") 34 | all_types = DiscourseRatings::RatingType.all 35 | expect(all_types.map { |rating_type| rating_type.type }).not_to include(type_param) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /db/migrate/20200520084648_add_rating_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class AddRatingTypes < ActiveRecord::Migration[6.0] 3 | def up 4 | Post.reset_column_information 5 | Topic.reset_column_information 6 | 7 | posts = Post.where("id in (SELECT post_id from post_custom_fields where name = 'rating')") 8 | topics = Topic.where(id: posts.pluck(:topic_id).uniq) 9 | 10 | posts.each do |post| 11 | rating = { 12 | type: DiscourseRatings::RatingType::NONE, 13 | value: post.custom_fields["rating"], 14 | weight: post.custom_fields["rating_weight"], 15 | } 16 | DiscourseRatings::Rating.build_and_set(post, rating) 17 | post.save_custom_fields(true) 18 | end 19 | 20 | topics.each do |topic| 21 | rating = { 22 | type: DiscourseRatings::RatingType::NONE, 23 | value: topic.custom_fields["average_rating"], 24 | count: topic.custom_fields["rating_count"], 25 | } 26 | DiscourseRatings::Rating.build_and_set(topic, rating) 27 | topic.save_custom_fields(true) 28 | end 29 | 30 | CategoryCustomField 31 | .where(name: "rating_enabled") 32 | .each do |row| 33 | if ActiveModel::Type::Boolean.new.cast(row.value) 34 | if category = Category.find(row.category_id) 35 | DiscourseRatings::Object.create( 36 | "category", 37 | category.rating_key, 38 | [DiscourseRatings::RatingType::NONE], 39 | ) 40 | end 41 | end 42 | end 43 | end 44 | 45 | def down 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-object.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{#if this.object.isNew}} 3 | {{#if this.isCategory}} 4 | {{category-chooser 5 | value=this.category.id 6 | onChange=(action "updateCategory") 7 | }} 8 | {{/if}} 9 | {{#if this.isTag}} 10 | {{tag-chooser 11 | tags=this.tag 12 | everyTag=true 13 | excludeSynonyms=true 14 | maximum=1 15 | onChange=(action "updateTag") 16 | options=(hash none="select_kit.default_header_text") 17 | }} 18 | {{/if}} 19 | {{else}} 20 | {{#if this.isCategory}} 21 | {{category-badge this.category}} 22 | {{/if}} 23 | {{#if this.isTag}} 24 | {{discourse-tag this.tag}} 25 | {{/if}} 26 | {{/if}} 27 | 28 | 29 | 30 | {{multi-select 31 | value=this.object.types 32 | content=this.ratingTypes 33 | valueProperty="type" 34 | onChange=(action (mut this.object.types)) 35 | }} 36 | 37 | 38 | 39 | {{#if this.object.isNew}} 40 | {{d-button 41 | class="btn-primary" 42 | action=this.addObject 43 | actionParam=this.object 44 | label="admin.ratings.type.add" 45 | icon="plus" 46 | disabled=this.saveDisabled 47 | }} 48 | {{else}} 49 | {{d-button 50 | class="btn-primary" 51 | action=this.updateObject 52 | actionParam=this.object 53 | label="admin.ratings.type.update" 54 | icon="save" 55 | disabled=this.saveDisabled 56 | }} 57 | {{/if}} 58 | 59 | {{d-button action=this.destroyObject actionParam=this.object icon="times"}} 60 | 61 | 62 | {{#if this.error}} 63 | {{this.error}} 64 | {{/if}} -------------------------------------------------------------------------------- /spec/jobs/destroy_rating_type_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../plugin_helper.rb" 4 | 5 | describe Jobs::DestroyRatingType do 6 | let!(:rating_category) { Fabricate(:category) } 7 | let!(:rating_topic) { Fabricate(:topic, category: rating_category) } 8 | let!(:rating_post) { Fabricate(:post, topic: rating_topic) } 9 | let!(:rating_type) { "interest" } 10 | let!(:rating_type_name) { "Interest" } 11 | let(:rating_hash) { JSON.parse('[{"type":"interest","value":"4", "weight":1}]') } 12 | 13 | def data_exists_after_creation? 14 | expect(rating_category.reload.rating_types).to eq([rating_type]) 15 | expect(rating_topic.reload.ratings).to be_present 16 | expect(rating_post.reload.ratings).to be_present 17 | 18 | job = described_class.new 19 | job.execute(type: rating_type) 20 | end 21 | 22 | before do 23 | DiscourseRatings::RatingType.create(rating_type, rating_type_name) 24 | DiscourseRatings::Object.create("category", rating_category.rating_key, [rating_type]) 25 | DiscourseRatings::Rating.build_and_set(rating_post, rating_hash) 26 | rating_post.save_custom_fields(true) 27 | rating_post.update_topic_ratings 28 | data_exists_after_creation? 29 | end 30 | 31 | it "clears the post custom fields " do 32 | expect(rating_post.reload.ratings).not_to be_present 33 | end 34 | 35 | it "clears the topic custom fields " do 36 | expect(rating_topic.reload.ratings).not_to be_present 37 | end 38 | 39 | it "clears the category association" do 40 | expect(rating_category.rating_types).to eq([]) 41 | end 42 | 43 | it "deletes the rating type itself" do 44 | expect(DiscourseRatings::RatingType.all).not_to include(rating_type) 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /app/controllers/ratings/rating_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::RatingTypeController < ::Admin::AdminController 3 | before_action :validate_existence, only: %i[create update destroy] 4 | before_action :validate_name, only: %i[update create] 5 | before_action :validate_type, only: %i[update create] 6 | 7 | MIN_TYPE_LENGTH = 2 8 | MIN_NAME_LENGTH = 2 9 | 10 | def index 11 | render_serialized(DiscourseRatings::RatingType.all, DiscourseRatings::RatingTypeSerializer) 12 | end 13 | 14 | def create 15 | handle_render(DiscourseRatings::RatingType.create(type_params[:type], type_params[:name])) 16 | end 17 | 18 | def update 19 | handle_render(DiscourseRatings::RatingType.set(type_params[:type], type_params[:name])) 20 | end 21 | 22 | def destroy 23 | handle_render(Jobs.enqueue(:destroy_rating_type, type: type_params[:type])) 24 | end 25 | 26 | private 27 | 28 | def type_params 29 | params.permit(:type, :name) 30 | end 31 | 32 | def validate_existence 33 | exists = DiscourseRatings::RatingType.exists?(type_params[:type]) 34 | 35 | if (exists && action_name == "create") || (!exists && %w[update destroy].include?(action_name)) 36 | raise Discourse::InvalidParameters.new(:type) 37 | end 38 | end 39 | 40 | def validate_type 41 | if type_params[:type].length < MIN_TYPE_LENGTH || 42 | type_params[:type] == DiscourseRatings::RatingType::NONE 43 | raise Discourse::InvalidParameters.new(:type) 44 | end 45 | end 46 | 47 | def validate_name 48 | raise Discourse::InvalidParameters.new(:name) if type_params[:name].length < MIN_NAME_LENGTH 49 | end 50 | 51 | def handle_render(success) 52 | if success 53 | render_json_dump(success_json) 54 | else 55 | render_json_dump(failed_json) 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/serializers/post_serializer_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../plugin_helper.rb" 4 | 5 | describe PostSerializer do 6 | let!(:post_rating) { { type: "spec", value: 3, weight: 1 } } 7 | let!(:user1) { Fabricate(:user) } 8 | let!(:rating_post) { Fabricate(:post, user: user1) } 9 | let!(:user2) { Fabricate(:user) } 10 | let!(:admin) { Fabricate(:admin) } 11 | 12 | describe "#ratings" do 13 | before do 14 | rating_post.stubs(:ratings).returns(DiscourseRatings::Rating.build_list([post_rating])) 15 | SiteSetting.rating_hide_except_own_entry = true 16 | end 17 | 18 | it "serializes ratings if the rating is by the author himself" do 19 | serializer = PostSerializer.new(rating_post, scope: Guardian.new(user1), root: false) 20 | rating_data = serializer.as_json[:ratings].as_json 21 | expect(rating_data).not_to eq([]) 22 | expect(rating_data[0][:type]).to eq("spec") 23 | expect(rating_data[0][:value]).to eq(3) 24 | end 25 | 26 | it "respects plugin enabled setting" do 27 | SiteSetting.rating_enabled = false 28 | serializer = PostSerializer.new(rating_post, scope: Guardian.new(user1), root: false) 29 | rating_data = serializer.as_json[:ratings].as_json 30 | expect(rating_data).to eq(nil) 31 | end 32 | 33 | it 'doesn\'t serialize ratings if the rating is by the another user' do 34 | serializer = PostSerializer.new(rating_post, scope: Guardian.new(user2), root: false) 35 | expect(serializer.as_json[:ratings]).to eq(nil) 36 | end 37 | 38 | it "bypasses the restrictions for staff/admin" do 39 | serializer = PostSerializer.new(rating_post, scope: Guardian.new(admin), root: false) 40 | rating_data = serializer.as_json[:ratings].as_json 41 | expect(rating_data).not_to eq([]) 42 | expect(rating_data[0][:type]).to eq("spec") 43 | expect(rating_data[0][:value]).to eq(3) 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/requests/posts_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../plugin_helper.rb" 4 | 5 | describe PostsController do 6 | let(:rating_hash) { JSON.parse('[{"type":"pointers","value":"4", "pavilion": "yes"}]') } 7 | let(:rating_none_type) { "none" } 8 | let(:rating_none_name) { "None" } 9 | fab!(:rating_category) { Fabricate(:category) } 10 | fab!(:user) { sign_in(Fabricate(:user, refresh_auto_groups: true)) } 11 | fab!(:rating_topic) { Fabricate(:topic, category: rating_category) } 12 | fab!(:rating_post) { Fabricate(:post, topic: rating_topic, user: user) } 13 | let(:none_rating_json) { '[{"type":"none","value":"4", "pavilion": "yes"}]' } 14 | let(:multiple_rating_hash) do 15 | JSON.parse( 16 | '[{"type":"pointers","value":"4", "pavilion": "yes"}, {"type":"handwriting","value":"3"}]', 17 | ) 18 | end 19 | let(:create_params) do 20 | { raw: "new body", ratings: none_rating_json, topic_id: rating_topic.id, user_id: user.id } 21 | end 22 | let(:update_params) { { post: { raw: "edited body", ratings: none_rating_json } } } 23 | it "adds the the rating correctly" do 24 | SiteSetting.rating_enabled = true 25 | 26 | Category.any_instance.stubs(:rating_types).returns([rating_none_type]) 27 | post "/posts.json", params: create_params 28 | expect(response.status).to eq(200) 29 | 30 | post_id = JSON.parse(response.body)["id"] 31 | post = Post.find(post_id) 32 | expect(post.custom_fields["rating_none"]).to be_present 33 | end 34 | 35 | it "updates the rating correctly" do 36 | SiteSetting.rating_enabled = true 37 | 38 | post = Fabricate(:post, user: user) 39 | DiscourseRatings::Rating.build_and_set(post, rating_hash) 40 | post.save_custom_fields(true) 41 | Category.any_instance.stubs(:rating_types).returns([rating_none_type]) 42 | put "/posts/#{post.id}.json", params: update_params 43 | expect(response.status).to eq(200) 44 | post.reload 45 | expect(post.custom_fields["rating_none"]).to be_present 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/ratings/rating_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::RatingType 3 | include ActiveModel::SerializerSupport 4 | 5 | KEY ||= "type" 6 | NONE ||= "none" 7 | 8 | attr_accessor :type, :name 9 | 10 | def initialize(attrs) 11 | @type = attrs[:type] 12 | @name = attrs[:name] 13 | end 14 | 15 | def self.all 16 | PluginStoreRow 17 | .where( 18 | " 19 | plugin_name = '#{DiscourseRatings::PLUGIN_NAME}' AND 20 | key LIKE '#{KEY}_%' 21 | ", 22 | ) 23 | .map { |row| new(type: type_from_key(row.key), name: row.value) } 24 | end 25 | 26 | def self.cached_list 27 | DiscourseRatings::Cache.wrap("#{KEY}_list") { all } 28 | end 29 | 30 | def self.clear_cached_list 31 | DiscourseRatings::Cache.new("#{KEY}_list").delete 32 | end 33 | 34 | def self.get_name(type) 35 | if (rating_type = cached_list.select { |rt| rt.type === type }).present? 36 | rating_type.first.name 37 | end 38 | end 39 | 40 | def self.exists?(type) 41 | return true if type == NONE 42 | PluginStoreRow.where( 43 | " 44 | plugin_name = '#{DiscourseRatings::PLUGIN_NAME}' AND 45 | key = ? 46 | ", 47 | build_key(type), 48 | ).exists? 49 | end 50 | 51 | def self.create(type, name) 52 | ## none type can only be set via bulk operation 53 | ## 'count' is a legacy type from 0.2. Remove 'count' exception in early 2021 54 | return false if [NONE, "count"].include?(type) 55 | 56 | self.set(type, name) 57 | end 58 | 59 | def self.get(type) 60 | PluginStore.get(DiscourseRatings::PLUGIN_NAME, build_key(type)) 61 | end 62 | 63 | def self.set(type, name) 64 | PluginStore.set(DiscourseRatings::PLUGIN_NAME, build_key(type), name) 65 | clear_cached_list 66 | end 67 | 68 | def self.destroy(type) 69 | PluginStore.remove(DiscourseRatings::PLUGIN_NAME, build_key(type)) 70 | clear_cached_list 71 | end 72 | 73 | def self.build_key(type) 74 | "#{KEY}_#{type.parameterize.underscore}" 75 | end 76 | 77 | def self.type_from_key(key) 78 | key.split("_", 2).last 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # discourse-ratings 2 | 3 | ![image](https://github.com/paviliondev/discourse-ratings/actions/workflows/plugin-tests.yml/badge.svg) ![image](https://github.com/paviliondev/discourse-ratings/actions/workflows/plugin-linting.yml/badge.svg) 4 | 5 | A Discourse plugin that lets you use topics to rate things. [Read more about this plugin on Discourse Meta](https://meta.discourse.org/t/topic-star-ratings/39578). 6 | 7 | 1. Topics can be designated as 'for rating', by being posted in a category with ratings setting on (see below), or by being given the tag 'rating'. 8 | 9 | 2. Each ratings topic concerns a single thing ("rating subject"); e.g. a service or a product. 10 | 11 | 3. Users rate the rating subject by choosing a star rating when posting (i.e. in the composer). 12 | 13 | 4. The average (mean) of all the ratings in the topic is displayed under the topic title and on the relevant topic list item. 14 | 15 | ## To do 16 | 17 | 1. Prevent a user from posting in a ratings topic more than once. Currently, users cannot rate in a ratings topic more than once. 18 | 19 | 2. Created a sorted topic list (highest to lowest) of all topics within a ratings category or with the 'rating'. Perhaps use Bayseian estimation [as discussed in the code comments](https://github.com/angusmcleod/discourse-ratings/blob/master/plugin.rb#L40). 20 | 21 | 3. Add translations for the ``category.for_ratings`` and ``composer.your_rating`` text. 22 | 23 | 4. Allow the user to select the tag(s) they wish to use to designate ratings topics in the admin config. 24 | 25 | 5. Allow the user to choose the number of total stars in a rating. 26 | 27 | 6. Allow the user to change the rating item image (i.e. use something other than stars). 28 | 29 | ## Installation 30 | 31 | To install using docker, add the following to your app.yml in the plugins section: 32 | 33 | ``` 34 | hooks: 35 | after_code: 36 | - exec: 37 | cd: $home/plugins 38 | cmd: 39 | - mkdir -p plugins 40 | - git clone https://github.com/angusmcleod/discourse-ratings.git 41 | ``` 42 | 43 | and rebuild docker via 44 | 45 | ``` 46 | cd /var/discourse 47 | ./launcher rebuild app 48 | ``` 49 | -------------------------------------------------------------------------------- /spec/lib/ratings/object_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "../../plugin_helper.rb" 4 | 5 | describe DiscourseRatings::Object do 6 | let!(:rating_type) { "interest" } 7 | let!(:rating_type_name) { "Interest" } 8 | let!(:rating_category) { Fabricate(:category) } 9 | let!(:rating_tag) { Fabricate(:tag) } 10 | 11 | before { DiscourseRatings::RatingType.create(rating_type, rating_type_name) } 12 | 13 | describe "#create" do 14 | it "enables rating on a category correctly" do 15 | DiscourseRatings::Object.create("category", rating_category.rating_key, [rating_type]) 16 | expect(DiscourseRatings::Object.exists?("category", rating_category.rating_key)).to eq(true) 17 | expect(rating_category.rating_types).to include(rating_type) 18 | end 19 | 20 | it "enables rating on a tag correctly" do 21 | DiscourseRatings::Object.create("tag", rating_tag.name, [rating_type]) 22 | expect(DiscourseRatings::Object.exists?("tag", rating_tag.name)).to eq(true) 23 | expect(rating_tag.rating_types).to include(rating_type) 24 | end 25 | end 26 | 27 | describe "#destroy" do 28 | it "disables ratings on all types for a given category/tag" do 29 | DiscourseRatings::RatingType.create("another_type", "AnotherType") 30 | DiscourseRatings::Object.destroy("category", rating_category.rating_key) 31 | expect(DiscourseRatings::Object.exists?("category", rating_category.rating_key)).to eq(false) 32 | end 33 | end 34 | 35 | describe "#remove_type" do 36 | it "removes a rating type association from a category/tag" do 37 | DiscourseRatings::Object.create("category", rating_category.rating_key, [rating_type]) 38 | expect(DiscourseRatings::Object.exists?("category", rating_category.rating_key)).to eq(true) 39 | expect(rating_category.rating_types).to include(rating_type) 40 | DiscourseRatings::Object.remove_type("category", rating_type) 41 | rating_category.reload 42 | expect(DiscourseRatings::Object.exists?("category", rating_category.rating_key)).to eq(false) 43 | expect(rating_category.rating_types).not_to include(rating_type) 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/controllers/admin-plugins-ratings.js: -------------------------------------------------------------------------------- 1 | import Controller from "@ember/controller"; 2 | import { action } from "@ember/object"; 3 | import { notEmpty } from "@ember/object/computed"; 4 | import { service } from "@ember/service"; 5 | import { i18n } from "discourse-i18n"; 6 | import RatingType from "../models/rating-type"; 7 | 8 | export default class AdminPluginsRatingsController extends Controller { 9 | @service dialog; 10 | 11 | @notEmpty("ratingTypes") hasTypes; 12 | 13 | @action 14 | newType() { 15 | this.get("ratingTypes").pushObject( 16 | RatingType.create({ 17 | isNew: true, 18 | type: "", 19 | name: "", 20 | }) 21 | ); 22 | } 23 | 24 | @action 25 | addType(typeObj) { 26 | let data = { 27 | type: typeObj.type, 28 | name: typeObj.name, 29 | }; 30 | 31 | this.set("loading", true); 32 | RatingType.add(data).then((result) => { 33 | if (result.success) { 34 | this.send("refresh"); 35 | } else { 36 | typeObj.set("hasError", true); 37 | this.set("loading", false); 38 | } 39 | }); 40 | } 41 | 42 | @action 43 | updateType(typeObj) { 44 | let data = { 45 | name: typeObj.name, 46 | }; 47 | 48 | this.set("loading", true); 49 | RatingType.update(typeObj.type, data).then((result) => { 50 | if (result.success) { 51 | this.send("refresh"); 52 | } else { 53 | typeObj.set("hasError", true); 54 | this.set("loading", false); 55 | } 56 | }); 57 | } 58 | 59 | @action 60 | destroyType(typeObj) { 61 | if (typeObj.isNew) { 62 | this.get("ratingTypes").removeObject(typeObj); 63 | } else { 64 | this.dialog.yesNoConfirm({ 65 | message: i18n("admin.ratings.type.confirm_destroy"), 66 | didConfirm: () => { 67 | this.set("loading", true); 68 | RatingType.destroy(typeObj.type).then((response) => { 69 | if (response.success) { 70 | this.send("refresh"); 71 | } else { 72 | typeObj.set("hasError", true); 73 | this.set("loading", false); 74 | } 75 | }); 76 | }, 77 | }); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /config/locales/client.zh_CN.yml: -------------------------------------------------------------------------------- 1 | zh_CN: 2 | js: 3 | category: 4 | ratings: 5 | heading: "评分" 6 | enabled: "在这个类别中启用评分" 7 | types: "这个类别中启用的评分类型" 8 | 9 | composer: 10 | your_rating: "添加评分" 11 | select_rating: "所有选中的评分类型都需要评分" 12 | 13 | topic: 14 | hidden_ratings: "话题有隐藏评分类型" 15 | no_ratings: "没有评分" 16 | x_rating_count: 17 | one: "评分" 18 | other: "评分" 19 | tip: 20 | ratings: 21 | title: "评分" 22 | details: > 23 | 你可以在这个话题中评分。 24 | 每个评分都附属于一个回帖,所以你可以不评分直接回帖。 25 | 26 | filters: 27 | ratings: 28 | title: "评分" 29 | help: "列出最新评分" 30 | 31 | admin_js: 32 | admin: 33 | ratings: 34 | settings_page: "评分" 35 | type: 36 | title: "类型" 37 | label: "类型" 38 | none: "没有类型" 39 | type_placeholder: "隐藏、短横线连接、不可修改" 40 | name: "名称" 41 | name_placeholder: "可见、句子形式、可以修改" 42 | none_type: "无" 43 | none_type_description: "对于没有类型的评分" 44 | select: "选择评分" 45 | new: "新建" 46 | add: "添加" 47 | update: "保存" 48 | destroy: "删除" 49 | confirm_destroy: > 50 | 确定删除这个类型吗? 51 | 所有这个类型的评分都会被彻底删除。 52 | 如果这个类型有你想保留的评分,请在此操作前将它们迁移到新的类型。 53 | enabled: "已启用" 54 | category: 55 | title: "类别" 56 | name: "类别" 57 | none: "没有评分类别" 58 | tag: 59 | title: "标签" 60 | name: "标签" 61 | none: "没有评分标签" 62 | migrate: 63 | title: "迁移" 64 | description: > 65 | 你可以从类型“空”迁移,或者迁移到类型“空”。可以对每个类别单独设置。 66 | 已经有目标类型的话题会被排除迁移。 67 | btn: "迁移" 68 | started: "迁移开始。可能需要等待几分钟。" 69 | destroy: 70 | title: "清除" 71 | description: > 72 | 你可以不可恢复地清除评分。可以对每个类别单独设置。 73 | 评分关联的话题和回复不会受影响。 74 | btn: "清除" 75 | started: "清除开始。可能需要等待几分钟。" 76 | 77 | error: 78 | object_already_exists: "项 {{objectType}} 已经存在" 79 | migration_failed_to_start: "迁移启动失败" 80 | 81 | site_settings: 82 | rating_enabled: "启用评分插件" 83 | rating_show_numeric_average: "在话题评分旁边显示平均分" 84 | rating_show_count: "在话题评分旁边显示评分数量" 85 | rating_show_topic_tip: "在评分话题标题下方显示评分机制的提示语" 86 | rating_topic_average_enabled: "在话题标题下方显示每项评分的平均分" 87 | rating_topic_list_average_enabled: "在话题列表的话题项中显示话题的每项评分的平均分" 88 | rating_hide_except_own_entry: "只显示用户自己的评分项和话题平均分" 89 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-object-list.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { action } from "@ember/object"; 3 | import { notEmpty } from "@ember/object/computed"; 4 | import { classNameBindings } from "@ember-decorators/component"; 5 | import discourseComputed from "discourse/lib/decorators"; 6 | import { i18n } from "discourse-i18n"; 7 | import RatingObject from "../models/rating-object"; 8 | 9 | @classNameBindings(":object-types", ":admin-ratings-list", "objectType") 10 | export default class RatingObjectList extends Component { 11 | @notEmpty("objects") hasObjects; 12 | 13 | @discourseComputed("objectType") 14 | title(objectType) { 15 | return i18n(`admin.ratings.${objectType}.title`); 16 | } 17 | 18 | @discourseComputed("objectType") 19 | nameLabel(objectType) { 20 | return i18n(`admin.ratings.${objectType}.name`); 21 | } 22 | 23 | @discourseComputed("objectType") 24 | noneLabel(objectType) { 25 | return i18n(`admin.ratings.${objectType}.none`); 26 | } 27 | 28 | @action 29 | newObject() { 30 | this.get("objects").pushObject({ 31 | name: "", 32 | types: [], 33 | isNew: true, 34 | }); 35 | } 36 | 37 | @action 38 | addObject(obj) { 39 | let data = { 40 | name: obj.name, 41 | types: obj.types, 42 | type: this.objectType, 43 | }; 44 | 45 | this.set("loading", true); 46 | RatingObject.add(data).then((result) => { 47 | if (result.success) { 48 | this.refresh(); 49 | } else { 50 | obj.set("hasError", true); 51 | } 52 | this.set("loading", false); 53 | }); 54 | } 55 | 56 | @action 57 | updateObject(obj) { 58 | let data = { 59 | name: obj.name, 60 | types: obj.types, 61 | }; 62 | this.set("loading", true); 63 | RatingObject.update(this.objectType, data).then((result) => { 64 | if (result.success) { 65 | this.refresh(); 66 | } else { 67 | obj.set("hasError", true); 68 | } 69 | this.set("loading", false); 70 | }); 71 | } 72 | 73 | @action 74 | destroyObject(obj) { 75 | if (obj.isNew) { 76 | this.get("objects").removeObject(obj); 77 | } else { 78 | let data = { 79 | name: obj.name, 80 | }; 81 | 82 | this.set("loading", true); 83 | RatingObject.destroy(this.objectType, data).then((result) => { 84 | if (result.success) { 85 | this.refresh(); 86 | } else { 87 | obj.set("hasError", true); 88 | } 89 | this.set("loading", false); 90 | }); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/ratings/object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class DiscourseRatings::Object 3 | include ActiveModel::SerializerSupport 4 | 5 | TYPES ||= %w[category tag] 6 | 7 | attr_accessor :name, :types 8 | 9 | def initialize(name, types) 10 | @name = name 11 | @types = types 12 | end 13 | 14 | def self.list(object_type) 15 | PluginStoreRow 16 | .where( 17 | " 18 | plugin_name = '#{DiscourseRatings::PLUGIN_NAME}' AND 19 | key LIKE '#{object_type}_%' 20 | ", 21 | ) 22 | .map { |r| new(name_from_key(r.key), types_from_value(r.value)) } 23 | end 24 | 25 | def self.exists?(object_type, name) 26 | PluginStoreRow.where( 27 | " 28 | plugin_name = '#{DiscourseRatings::PLUGIN_NAME}' AND 29 | key = ? 30 | ", 31 | build_key(object_type, name), 32 | ).exists? 33 | end 34 | 35 | def self.create(object_type, name, types) 36 | if exists?(object_type, name) || object_type.blank? || name.blank? || types.blank? 37 | false 38 | else 39 | set(object_type, name, types) 40 | end 41 | end 42 | 43 | def self.get(object_type, name) 44 | if ( 45 | value = PluginStore.get(DiscourseRatings::PLUGIN_NAME, build_key(object_type, name)) 46 | ).present? 47 | types_from_value(value) 48 | else 49 | [] 50 | end 51 | end 52 | 53 | def self.set(object_type, name, types) 54 | if TYPES.include?(object_type) 55 | PluginStore.set( 56 | DiscourseRatings::PLUGIN_NAME, 57 | build_key(object_type, name), 58 | build_value(types), 59 | ) 60 | end 61 | end 62 | 63 | def self.destroy(object_type, name) 64 | PluginStore.remove(DiscourseRatings::PLUGIN_NAME, build_key(object_type, name)) 65 | end 66 | 67 | def self.remove_type(object_type, rating_type) 68 | PluginStoreRow 69 | .where( 70 | " 71 | plugin_name = '#{DiscourseRatings::PLUGIN_NAME}' AND 72 | key LIKE '#{object_type}_%' 73 | ", 74 | ) 75 | .each do |r| 76 | types = types_from_value(r.value).select { |t| t != rating_type } 77 | 78 | if types.any? 79 | r.value = build_value(types) 80 | r.save 81 | else 82 | r.destroy 83 | end 84 | end 85 | end 86 | 87 | def self.build_key(object_type, name) 88 | "#{object_type}_#{name}" 89 | end 90 | 91 | def self.name_from_key(key) 92 | key.split("_", 2).last 93 | end 94 | 95 | def self.types_from_value(value) 96 | value.split("|") 97 | end 98 | 99 | def self.build_value(types) 100 | types.join("|") 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/components/rating-object.js: -------------------------------------------------------------------------------- 1 | import Component from "@ember/component"; 2 | import { action } from "@ember/object"; 3 | import { equal } from "@ember/object/computed"; 4 | import { classNameBindings, tagName } from "@ember-decorators/component"; 5 | import discourseComputed from "discourse/lib/decorators"; 6 | import Category from "discourse/models/category"; 7 | import { i18n } from "discourse-i18n"; 8 | 9 | @classNameBindings( 10 | ":rating-object", 11 | ":admin-ratings-list-object", 12 | "error:hasError" 13 | ) 14 | @tagName("tr") 15 | export default class RatingObject extends Component { 16 | @equal("objectType", "category") isCategory; 17 | @equal("objectType", "tag") isTag; 18 | 19 | error = null; 20 | 21 | didReceiveAttrs() { 22 | super.didReceiveAttrs(); 23 | const object = this.object; 24 | 25 | this.setProperties({ 26 | currentName: object.name, 27 | currentTypes: object.types, 28 | }); 29 | 30 | if (object.name) { 31 | if (this.isCategory) { 32 | const slugPath = object.name.split("/"); 33 | this.set("category", Category.findBySlugPath(slugPath)); 34 | } 35 | 36 | if (this.isTag) { 37 | this.set("tag", object.name); 38 | } 39 | } 40 | } 41 | 42 | @discourseComputed("error", "object.name", "object.types.[]") 43 | saveDisabled(error, objectName, objectTypes) { 44 | return ( 45 | error || 46 | !objectName || 47 | !objectTypes.length || 48 | (objectName === this.currentName && 49 | JSON.stringify(objectTypes) === JSON.stringify(this.currentTypes)) 50 | ); 51 | } 52 | 53 | @action 54 | updateCategory(categoryId) { 55 | const category = Category.findById(categoryId); 56 | const slug = Category.slugFor(category); 57 | const objects = this.objects || []; 58 | 59 | if (objects.every((o) => o.name !== slug)) { 60 | this.setProperties({ 61 | "object.name": slug, 62 | category, 63 | error: null, 64 | }); 65 | } else { 66 | this.set( 67 | "error", 68 | i18n("admin.ratings.error.object_already_exists", { 69 | objectType: this.objectType, 70 | }) 71 | ); 72 | } 73 | } 74 | 75 | @action 76 | updateTag(tags) { 77 | const objects = this.objects || []; 78 | const tag = tags[0]; 79 | 80 | if (objects.every((o) => o.name !== tag)) { 81 | this.setProperties({ 82 | "object.name": tag, 83 | tag, 84 | error: null, 85 | }); 86 | } else { 87 | this.set( 88 | "error", 89 | i18n("admin.ratings.error.object_already_exists", { 90 | objectType: this.objectType, 91 | }) 92 | ); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /assets/javascripts/discourse/lib/rating-utilities.js: -------------------------------------------------------------------------------- 1 | import { ajax } from "discourse/lib/ajax"; 2 | import { popupAjaxError } from "discourse/lib/ajax-error"; 3 | import { getOwnerWithFallback } from "discourse/lib/get-owner"; 4 | import { i18n } from "discourse-i18n"; 5 | 6 | let starRatingRaw = function (rating, opts = {}) { 7 | let content = ""; 8 | for (let i = 0; i < 5; i++) { 9 | let value = i + 1; 10 | let checked = value <= rating ? "checked" : ""; 11 | let disabled = opts.enabled ? "" : " disabled"; 12 | let star = ""; 13 | 14 | if (opts.clickable) { 15 | star += ''; 16 | } else { 17 | star += 18 | '"; 26 | } 27 | 28 | star += ""; 29 | content = content.concat(star); 30 | } 31 | 32 | return '' + content + ""; 33 | }; 34 | 35 | function ratingHtml(rating, opts = {}) { 36 | let html = ""; 37 | let title = ""; 38 | let link = null; 39 | 40 | const name = rating.type_name; 41 | if (name) { 42 | html += `${name}`; 43 | title += `${name} `; 44 | } 45 | 46 | let value = Math.round(rating.value * 10) / 10; 47 | html += starRatingRaw(value); 48 | title += value; 49 | 50 | if (opts.topic) { 51 | link = opts.topic.url; 52 | const siteSettings = getOwnerWithFallback(this).lookup( 53 | "service:site-settings" 54 | ); 55 | 56 | if (siteSettings.rating_show_numeric_average) { 57 | html += `(${value})`; 58 | } 59 | 60 | if (siteSettings.rating_show_count) { 61 | let count = rating.count; 62 | let countLabel = i18n("topic.x_rating_count", { count }); 63 | html += `${count} ${countLabel}`; 64 | title += ` ${count} ${countLabel}`; 65 | } 66 | } 67 | 68 | if (opts.linkTo && link) { 69 | return `${html}`; 70 | } else { 71 | return `
${html}
`; 72 | } 73 | } 74 | 75 | function ratingListHtml(ratings, opts = {}) { 76 | if (typeof ratings === "string") { 77 | try { 78 | ratings = JSON.parse(ratings); 79 | } catch { 80 | ratings = null; 81 | } 82 | } 83 | 84 | if (!ratings) { 85 | return ""; 86 | } 87 | 88 | let html = ""; 89 | 90 | ratings.forEach((rating) => { 91 | let showRating = opts.topic ? rating.count > 0 : rating.weight > 0; 92 | 93 | if (showRating) { 94 | html += ratingHtml(rating, opts); 95 | } 96 | }); 97 | 98 | return `
${html}
`; 99 | } 100 | 101 | function request(type, path = "", data = {}) { 102 | return ajax(`/ratings/${path}`, { 103 | type, 104 | data, 105 | }).catch(popupAjaxError); 106 | } 107 | 108 | export { ratingListHtml, request }; 109 | -------------------------------------------------------------------------------- /config/locales/client.bo.yml: -------------------------------------------------------------------------------- 1 | bo: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.id.yml: -------------------------------------------------------------------------------- 1 | id: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.ja.yml: -------------------------------------------------------------------------------- 1 | ja: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.km.yml: -------------------------------------------------------------------------------- 1 | km: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.ko.yml: -------------------------------------------------------------------------------- 1 | ko: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.lo.yml: -------------------------------------------------------------------------------- 1 | lo: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.ms.yml: -------------------------------------------------------------------------------- 1 | ms: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.th.yml: -------------------------------------------------------------------------------- 1 | th: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.tt.yml: -------------------------------------------------------------------------------- 1 | tt: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.vi.yml: -------------------------------------------------------------------------------- 1 | vi: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.zh.yml: -------------------------------------------------------------------------------- 1 | zh-TW: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | other: "ratings" 16 | tip: 17 | ratings: 18 | title: "Rating" 19 | details: > 20 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 21 | filters: 22 | ratings: 23 | title: "Ratings" 24 | help: "List latest ratings." 25 | admin_js: 26 | admin: 27 | ratings: 28 | settings_page: "Ratings" 29 | type: 30 | title: "Types" 31 | label: "Type" 32 | none: "No types." 33 | type_placeholder: "Hidden, dasherized and uneditable." 34 | name: "Name" 35 | name_placeholder: "Visible, sentence case and editable." 36 | none_type: "None" 37 | none_type_description: "For ratings without a type" 38 | select: "Select type" 39 | new: "New" 40 | add: "Add" 41 | update: "Save" 42 | destroy: "Delete" 43 | confirm_destroy: > 44 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 45 | enabled: "Enabled" 46 | category: 47 | title: "Categories" 48 | name: "Category" 49 | none: "No rating categories" 50 | tag: 51 | title: "Tags" 52 | name: "Tag" 53 | none: "No rating tags" 54 | migrate: 55 | title: "Migrate" 56 | description: > 57 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 58 | btn: "Migrate" 59 | started: "The migration has started. It may take a few minutes to complete." 60 | destroy: 61 | title: "Destroy" 62 | description: > 63 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 64 | btn: "Destroy" 65 | started: "The destruction has started. It may take a few minutes to complete." 66 | error: 67 | object_already_exists: "Entry for {{objectType}} already exists" 68 | migration_failed_to_start: "Migration failed to start" 69 | site_settings: 70 | rating_enabled: "Enable ratings." 71 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 72 | rating_show_count: "Show rating counts in topic next to average rating." 73 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 74 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 75 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 76 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 77 | -------------------------------------------------------------------------------- /config/locales/client.af.yml: -------------------------------------------------------------------------------- 1 | af: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.az.yml: -------------------------------------------------------------------------------- 1 | az: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.bg.yml: -------------------------------------------------------------------------------- 1 | bg: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.bn.yml: -------------------------------------------------------------------------------- 1 | bn: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.ca.yml: -------------------------------------------------------------------------------- 1 | ca: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.da.yml: -------------------------------------------------------------------------------- 1 | da: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.de.yml: -------------------------------------------------------------------------------- 1 | de: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.el.yml: -------------------------------------------------------------------------------- 1 | el: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.eo.yml: -------------------------------------------------------------------------------- 1 | eo: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.et.yml: -------------------------------------------------------------------------------- 1 | et: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.eu.yml: -------------------------------------------------------------------------------- 1 | eu: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.fa.yml: -------------------------------------------------------------------------------- 1 | fa: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.fi.yml: -------------------------------------------------------------------------------- 1 | fi: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.gl.yml: -------------------------------------------------------------------------------- 1 | gl: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.hi.yml: -------------------------------------------------------------------------------- 1 | hi: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.hu.yml: -------------------------------------------------------------------------------- 1 | hu: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.hy.yml: -------------------------------------------------------------------------------- 1 | hy: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.is.yml: -------------------------------------------------------------------------------- 1 | is: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.ka.yml: -------------------------------------------------------------------------------- 1 | ka: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.kk.yml: -------------------------------------------------------------------------------- 1 | kk: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.kn.yml: -------------------------------------------------------------------------------- 1 | kn: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.ku.yml: -------------------------------------------------------------------------------- 1 | ku: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.mk.yml: -------------------------------------------------------------------------------- 1 | mk: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.ml.yml: -------------------------------------------------------------------------------- 1 | ml: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.mn.yml: -------------------------------------------------------------------------------- 1 | mn: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.ne.yml: -------------------------------------------------------------------------------- 1 | ne: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.nl.yml: -------------------------------------------------------------------------------- 1 | nl: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.om.yml: -------------------------------------------------------------------------------- 1 | om: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | -------------------------------------------------------------------------------- /config/locales/client.pa.yml: -------------------------------------------------------------------------------- 1 | pa: 2 | js: 3 | category: 4 | ratings: 5 | heading: "Ratings" 6 | enabled: "Enable ratings in this category." 7 | types: "Rating types enabled in this category." 8 | composer: 9 | your_rating: "Add a rating" 10 | select_rating: "All checked ratings must have a rating." 11 | topic: 12 | hidden_ratings: "Topic has hidden ratings" 13 | no_ratings: "No ratings yet" 14 | x_rating_count: 15 | one: "rating" 16 | other: "ratings" 17 | tip: 18 | ratings: 19 | title: "Rating" 20 | details: > 21 | You can rate in this topic. Each rating is attached to a post and you can post without rating. 22 | filters: 23 | ratings: 24 | title: "Ratings" 25 | help: "List latest ratings." 26 | admin_js: 27 | admin: 28 | ratings: 29 | settings_page: "Ratings" 30 | type: 31 | title: "Types" 32 | label: "Type" 33 | none: "No types." 34 | type_placeholder: "Hidden, dasherized and uneditable." 35 | name: "Name" 36 | name_placeholder: "Visible, sentence case and editable." 37 | none_type: "None" 38 | none_type_description: "For ratings without a type" 39 | select: "Select type" 40 | new: "New" 41 | add: "Add" 42 | update: "Save" 43 | destroy: "Delete" 44 | confirm_destroy: > 45 | Are you sure you want to delete this type? All ratings with this type will be irreversibly destroyed. If there are ratings with this type you wish to keep, migrate them to a new type before taking this action. 46 | enabled: "Enabled" 47 | category: 48 | title: "Categories" 49 | name: "Category" 50 | none: "No rating categories" 51 | tag: 52 | title: "Tags" 53 | name: "Tag" 54 | none: "No rating tags" 55 | migrate: 56 | title: "Migrate" 57 | description: > 58 | You can migrate ratings to or from type "None" on a per-category basis. Topics that already have the target type are excluded from the migration. 59 | btn: "Migrate" 60 | started: "The migration has started. It may take a few minutes to complete." 61 | destroy: 62 | title: "Destroy" 63 | description: > 64 | You can irreversibly destroy ratings by type on a per-category basis. Topics and posts associated with ratings will be unaffected. 65 | btn: "Destroy" 66 | started: "The destruction has started. It may take a few minutes to complete." 67 | error: 68 | object_already_exists: "Entry for {{objectType}} already exists" 69 | migration_failed_to_start: "Migration failed to start" 70 | site_settings: 71 | rating_enabled: "Enable ratings." 72 | rating_show_numeric_average: "Show the numerical average next to topic rating inputs." 73 | rating_show_count: "Show rating counts in topic next to average rating." 74 | rating_show_topic_tip: "Show a tip about the mechanics of rating topics under the titles of rating topics" 75 | rating_topic_average_enabled: "Show the average of all ratings in a topic under the topic title." 76 | rating_topic_list_average_enabled: "Show the average of all ratings in a topic in the topic list item." 77 | rating_hide_except_own_entry: "Show only user's own rating entries and topic average" 78 | --------------------------------------------------------------------------------