From 8fc0cc9aaa5795aa078ec6968413d529402f2f88 Mon Sep 17 00:00:00 2001 From: Faizaan Gagan Date: Thu, 10 Oct 2019 22:32:35 +0530 Subject: [PATCH 001/328] Serialize draft (#8175) * DEV: allow serializing data for drafts * Various fixes * added an alias method for 'serializeToDraft' to plugin-api * fixed linting issues * changed single quotes to double quotes to fix linting issue * fixed linting issues * fixed composer model file via prettier * fixed composer controller file via prettier * fixed plugin-api file via prettier --- .../discourse/controllers/composer.js.es6 | 41 +++++++-------- .../discourse/lib/plugin-api.js.es6 | 52 ++++++++++++------- .../discourse/models/composer.js.es6 | 50 +++++++++++------- 3 files changed, 84 insertions(+), 59 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index b96051e906..cf295cb870 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -39,26 +39,21 @@ function loadDraft(store, opts) { ((draft.title && draft.title !== "") || (draft.reply && draft.reply !== "")) ) { const composer = store.createRecord("composer"); + const serializedFields = Composer.serializedFieldsForDraft(); - composer.open({ + let attrs = { draftKey, draftSequence, - action: draft.action, - title: draft.title, - categoryId: draft.categoryId || opts.categoryId, - postId: draft.postId, - archetypeId: draft.archetypeId, - reply: draft.reply, - metaData: draft.metaData, - usernames: draft.usernames, draft: true, - composerState: Composer.DRAFT, - composerTime: draft.composerTime, - typingTime: draft.typingTime, - whisper: draft.whisper, - tags: draft.tags, - noBump: draft.noBump + composerState: Composer.DRAFT + }; + + serializedFields.forEach(f => { + attrs[f] = draft[f] || opts[f]; }); + + composer.open(attrs); + return composer; } } @@ -753,15 +748,15 @@ export default Ember.Controller.extend({ }, /** - Open the composer view + Open the composer view - @method open - @param {Object} opts Options for creating a post - @param {String} opts.action The action we're performing: edit, reply or createTopic - @param {Discourse.Post} [opts.post] The post we're replying to - @param {Discourse.Topic} [opts.topic] The topic we're replying to - @param {String} [opts.quote] If we're opening a reply from a quote, the quote we're making - **/ + @method open + @param {Object} opts Options for creating a post + @param {String} opts.action The action we're performing: edit, reply or createTopic + @param {Discourse.Post} [opts.post] The post we're replying to + @param {Discourse.Topic} [opts.topic] The topic we're replying to + @param {String} [opts.quote] If we're opening a reply from a quote, the quote we're making + **/ open(opts) { opts = opts || {}; diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index 4cf670b3de..76959bdaa6 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -43,6 +43,7 @@ import Sharing from "discourse/lib/sharing"; import { addComposerUploadHandler } from "discourse/components/composer-editor"; import { addCategorySortCriteria } from "discourse/components/edit-category-settings"; import { queryRegistry } from "discourse/widgets/widget"; +import Composer from "discourse/models/composer"; // If you add any methods to the API ensure you bump up this number const PLUGIN_API_VERSION = "0.8.32"; @@ -424,44 +425,44 @@ class PluginApi { } /** - Called whenever the "page" changes. This allows us to set up analytics - and other tracking. + Called whenever the "page" changes. This allows us to set up analytics + and other tracking. - To get notified when the page changes, you can install a hook like so: + To get notified when the page changes, you can install a hook like so: - ```javascript - api.onPageChange((url, title) => { + ```javascript + api.onPageChange((url, title) => { console.log('the page changed to: ' + url + ' and title ' + title); }); - ``` - **/ + ``` + **/ onPageChange(fn) { this.onAppEvent("page:changed", data => fn(data.url, data.title)); } /** - Listen for a triggered `AppEvent` from Discourse. + Listen for a triggered `AppEvent` from Discourse. - ```javascript - api.onAppEvent('inserted-custom-html', () => { + ```javascript + api.onAppEvent('inserted-custom-html', () => { console.log('a custom footer was rendered'); }); - ``` - **/ + ``` + **/ onAppEvent(name, fn) { const appEvents = this._lookupContainer("service:app-events"); appEvents && appEvents.on(name, fn); } /** - Registers a function to generate custom avatar CSS classes - for a particular user. + Registers a function to generate custom avatar CSS classes + for a particular user. - Takes a function that will accept a user as a parameter - and return an array of CSS classes to apply. + Takes a function that will accept a user as a parameter + and return an array of CSS classes to apply. - ```javascript - api.customUserAvatarClasses(user => { + ```javascript + api.customUserAvatarClasses(user => { if (Ember.get(user, 'primary_group_name') === 'managers') { return ['managers']; } @@ -844,6 +845,21 @@ class PluginApi { addComposerUploadHandler(extensions, method); } + /** + * Adds a field to draft serializer + * + * Example: + * + * api.serializeToDraft('key_set_in_model', 'field_name_in_payload'); + * + * to keep both of them same + * api.serializeToDraft('field_name'); + * + */ + serializeToDraft(fieldName, property) { + Composer.serialzeToDraft(fieldName, property); + } + /** * Registers a criteria that can be used as default topic order on category * pages. diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index de9d9042bc..9ba0afe0aa 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -57,6 +57,20 @@ const CLOSED = "closed", tags: "topic.tags", featuredLink: "topic.featured_link" }, + _draft_serializer = { + reply: "reply", + action: "action", + title: "title", + categoryId: "categoryId", + archetypeId: "archetypeId", + whisper: "whisper", + metaData: "metaData", + composerTime: "composerTime", + typingTime: "typingTime", + postId: "post.id", + usernames: "targetUsernames" + }, + _add_draft_fields = {}, FAST_REPLY_LENGTH_THRESHOLD = 10000; export const SAVE_LABELS = { @@ -722,6 +736,11 @@ const Composer = RestModel.extend({ composer.appEvents.trigger("composer:reply-reloaded", composer); } + // Ensure additional draft fields are set + Object.keys(_add_draft_fields).forEach(f => { + this.set(_add_draft_fields[f], opts[f]); + }); + return false; }, @@ -1019,24 +1038,7 @@ const Composer = RestModel.extend({ this._clearingStatus = null; } - let data = this.getProperties( - "reply", - "action", - "title", - "categoryId", - "archetypeId", - "whisper", - "metaData", - "composerTime", - "typingTime", - "tags", - "noBump" - ); - - data = Object.assign(data, { - usernames: this.targetUsernames, - postId: this.get("post.id") - }); + let data = this.serialize(_draft_serializer); if (data.postId && !Ember.isEmpty(this.originalText)) { data.originalText = this.originalText; @@ -1113,6 +1115,18 @@ Composer.reopenClass({ return Object.keys(_create_serializer); }, + serializeToDraft(fieldName, property) { + if (!property) { + property = fieldName; + } + _draft_serializer[fieldName] = property; + _add_draft_fields[fieldName] = property; + }, + + serializedFieldsForDraft() { + return Object.keys(_draft_serializer); + }, + // The status the compose view can have CLOSED, SAVING, From 21f3c044e509945ba36d338b82542506cba912a2 Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Thu, 10 Oct 2019 21:19:49 -0400 Subject: [PATCH 002/328] FIX: Mobile adjustments for reviewable list --- app/assets/stylesheets/mobile/reviewables.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/mobile/reviewables.scss b/app/assets/stylesheets/mobile/reviewables.scss index 2e08bf39a9..16c00d79f1 100644 --- a/app/assets/stylesheets/mobile/reviewables.scss +++ b/app/assets/stylesheets/mobile/reviewables.scss @@ -5,6 +5,7 @@ .reviewable-list { order: 2; width: 100%; + padding-bottom: 4em; } .reviewable-filters { @@ -44,8 +45,9 @@ } .reviewable-contents { + .reviewable-post-header, .post-body { - max-width: 295px; + max-width: 100%; p { overflow-x: scroll; From 5c5845f3f278fbcf88eacb7fd15d4c92e481016b Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Thu, 10 Oct 2019 21:35:36 -0400 Subject: [PATCH 003/328] FIX: Minor Github onebox layout issues - prevents long branch names from overflowing - fixes alignment of inline avatars in preview --- app/assets/stylesheets/common/base/onebox.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/common/base/onebox.scss b/app/assets/stylesheets/common/base/onebox.scss index e707724b4d..b735363b85 100644 --- a/app/assets/stylesheets/common/base/onebox.scss +++ b/app/assets/stylesheets/common/base/onebox.scss @@ -412,6 +412,9 @@ pre.onebox code { .branches { font-size: $font-down-1; + code { + word-break: break-all; + } } .github-info { @@ -445,6 +448,7 @@ pre.onebox code { border-radius: 2px; float: none; margin: 0; + padding: 0; vertical-align: middle; max-width: none; } From 694a5bf229df2d8deb06b0f7cca9b2653ad8983a Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Fri, 11 Oct 2019 17:44:29 +1100 Subject: [PATCH 004/328] FIX: Prevent from creation of duplicated TopicAllowedUsers (#8169) Ensure that we don't try to create duplicated TopicAllowedUsers Related to https://meta.discourse.org/t/error-message-topic-allowed-users-is-invalid/130382/5 Spec amended to cover a case creating an overlap. --- app/models/topic_converter.rb | 1 + spec/models/topic_converter_spec.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/topic_converter.rb b/app/models/topic_converter.rb index f59e96c4d0..aa23da10ad 100644 --- a/app/models/topic_converter.rb +++ b/app/models/topic_converter.rb @@ -81,6 +81,7 @@ class TopicConverter user.user_stat.save! end @topic.topic_allowed_users.build(user_id: @user.id) unless @topic.topic_allowed_users.where(user_id: @user.id).exists? + @topic.topic_allowed_users = @topic.topic_allowed_users.uniq(&:user_id) # update topics count @topic.user.user_stat.topic_count -= 1 @topic.user.user_stat.save! diff --git a/spec/models/topic_converter_spec.rb b/spec/models/topic_converter_spec.rb index fb4b351d21..82b2664b02 100644 --- a/spec/models/topic_converter_spec.rb +++ b/spec/models/topic_converter_spec.rb @@ -114,7 +114,7 @@ describe TopicConverter do context 'success' do it "converts regular topic to private message" do - private_message = topic.convert_to_private_message(admin) + private_message = topic.convert_to_private_message(post.user) expect(private_message).to be_valid expect(topic.archetype).to eq("private_message") expect(topic.category_id).to eq(nil) From 7d2f5240d94fd96760fdf884ec08aee14184cb8e Mon Sep 17 00:00:00 2001 From: Nacho Caballero Date: Fri, 11 Oct 2019 09:50:37 +0200 Subject: [PATCH 005/328] FIX: Show a correct diff when editing consecutive paragraphs (#8177) --- lib/discourse_diff.rb | 2 +- lib/onpdiff.rb | 71 ++++++++++++++++++++++++++ spec/components/discourse_diff_spec.rb | 7 +++ spec/components/onpdiff_spec.rb | 34 ++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/lib/discourse_diff.rb b/lib/discourse_diff.rb index 6445ac88cd..c2b3171623 100644 --- a/lib/discourse_diff.rb +++ b/lib/discourse_diff.rb @@ -12,7 +12,7 @@ class DiscourseDiff before_markdown = tokenize_line(CGI::escapeHTML(@before)) after_markdown = tokenize_line(CGI::escapeHTML(@after)) - @block_by_block_diff = ONPDiff.new(before_html, after_html).diff + @block_by_block_diff = ONPDiff.new(before_html, after_html).paragraph_diff @line_by_line_diff = ONPDiff.new(before_markdown, after_markdown).short_diff end diff --git a/lib/onpdiff.rb b/lib/onpdiff.rb index ef4799f2a4..6c86a79327 100644 --- a/lib/onpdiff.rb +++ b/lib/onpdiff.rb @@ -25,6 +25,10 @@ class ONPDiff @short_diff ||= build_short_edit_script(compose) end + def paragraph_diff + @paragraph_diff ||= build_paragraph_edit_script(diff) + end + private def compose @@ -156,4 +160,71 @@ class ONPDiff ses end + def build_paragraph_edit_script(ses) + paragraph_ses = [] + i = 0 + while i < ses.size + if ses[i][1] == :common + paragraph_ses << ses[i] + else + if ses[i][1] == :add + op_code = :add + opposite_op_code = :delete + else + op_code = :delete + opposite_op_code = :add + end + j = i + 1 + + while j < ses.size && ses[j][1] == op_code + j += 1 + end + + if j >= ses.size + paragraph_ses = paragraph_ses.concat(ses[i..j]) + i = j + else + k = j + j -= 1 + + while k < ses.size && ses[k][1] == opposite_op_code + k += 1 + end + k -= 1 + + num_before = j - i + 1 + num_after = k - j + if num_after > 1 + if num_before > num_after + i2 = i + num_before - num_after + paragraph_ses = paragraph_ses.concat(ses[i..i2 - 1]) + i = i2 + elsif num_after > num_before + k -= num_after - num_before + end + paragraph_ses = paragraph_ses.concat(pair_paragraphs(ses, i, j)) + else + paragraph_ses = paragraph_ses.concat(ses[i..k]) + end + i = k + end + end + i += 1 + end + + paragraph_ses + end + + def pair_paragraphs(ses, i, j) + pairs = [] + num_pairs = j - i + 1 + num_pairs.times do + pairs << ses[i] + pairs << ses[i + num_pairs] + i += 1 + end + + pairs + end + end diff --git a/spec/components/discourse_diff_spec.rb b/spec/components/discourse_diff_spec.rb index a7aefc53fa..d1158aef20 100644 --- a/spec/components/discourse_diff_spec.rb +++ b/spec/components/discourse_diff_spec.rb @@ -76,6 +76,13 @@ describe DiscourseDiff do expect(DiscourseDiff.new(before, after).side_by_side_html).to eq("

this is a paragraph

this is a great paragraph

") end + it "adds and tags on consecutive paragraphs", :focus do + before = "

this is one paragraph

here is yet another

" + after = "

this is one great paragraph

here is another

" + got = DiscourseDiff.new(before, after).side_by_side_html + expect(got).to eq("

this is one paragraph

here is yet another

this is one great paragraph

here is another

") + end + it "adds tags around removed text on the left div" do before = "

this is a great paragraph

" after = "

this is a paragraph

" diff --git a/spec/components/onpdiff_spec.rb b/spec/components/onpdiff_spec.rb index 67c5b0beab..60b4039720 100644 --- a/spec/components/onpdiff_spec.rb +++ b/spec/components/onpdiff_spec.rb @@ -39,4 +39,38 @@ describe ONPDiff do end + describe "paragraph_diff" do + + it "returns an empty array when there is no content to diff" do + expect(ONPDiff.new("", "").paragraph_diff).to eq([]) + end + + it "returns an array with the operation code for each element" do + expect(ONPDiff.new("abc", "acd").paragraph_diff).to eq([["a", :common], ["b", :delete], ["c", :common], ["d", :add]]) + end + + it "pairs as many elements as possible", :focus do + expect(ONPDiff.new("abcd", "abef").paragraph_diff).to eq([ + ["a", :common], ["b", :common], + ["e", :add], ["c", :delete], + ["f", :add], ["d", :delete] + ]) + + expect(ONPDiff.new("abcde", "abfg").paragraph_diff).to eq([ + ["a", :common], ["b", :common], + ["c", :delete], + ["d", :delete], ["f", :add], + ["e", :delete], ["g", :add] + ]) + + expect(ONPDiff.new("abcd", "abefg").paragraph_diff).to eq([ + ["a", :common], ["b", :common], + ["e", :add], + ["f", :add], ["c", :delete], + ["g", :add], ["d", :delete] + ]) + end + + end + end From 3bcfa158a7f3b73e7cb22065691ee529e242a658 Mon Sep 17 00:00:00 2001 From: Faizaan Gagan Date: Fri, 11 Oct 2019 13:21:18 +0530 Subject: [PATCH 006/328] fixed wrong method name while calling (#8182) --- app/assets/javascripts/discourse/lib/plugin-api.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index 76959bdaa6..f54c0f4306 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -857,7 +857,7 @@ class PluginApi { * */ serializeToDraft(fieldName, property) { - Composer.serialzeToDraft(fieldName, property); + Composer.serializeToDraft(fieldName, property); } /** From 67787799bbcba6584189f2e5aec1f086478314fa Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 11 Oct 2019 09:57:55 +0100 Subject: [PATCH 007/328] DEV: Allow plugins to mark user custom fields as editable only by staff This adds a staff_only parameter to the register_editable_user_custom_field API. The default is false, to maintain backwards compatibility. --- app/controllers/users_controller.rb | 3 ++- app/models/user.rb | 20 +++++++++++++++++--- lib/plugin/instance.rb | 4 ++-- spec/requests/users_controller_spec.rb | 22 +++++++++++++++++++--- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 629faaa33c..5ffc97b712 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1425,7 +1425,8 @@ class UsersController < ApplicationController :card_background_upload_url ] - permitted << { custom_fields: User.editable_user_custom_fields } unless User.editable_user_custom_fields.blank? + editable_custom_fields = User.editable_user_custom_fields(by_staff: current_user.try(:staff?)) + permitted << { custom_fields: editable_custom_fields } unless editable_custom_fields.blank? permitted.concat UserUpdater::OPTION_ATTR permitted.concat UserUpdater::CATEGORY_IDS.keys.map { |k| { k => [] } } permitted.concat UserUpdater::TAG_NAMES.keys diff --git a/app/models/user.rb b/app/models/user.rb index 04c6af225a..af28a89a0e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -260,17 +260,31 @@ class User < ActiveRecord::Base @plugin_editable_user_custom_fields ||= {} end - def self.register_plugin_editable_user_custom_field(custom_field_name, plugin) - plugin_editable_user_custom_fields[custom_field_name] = plugin + def self.plugin_staff_editable_user_custom_fields + @plugin_staff_editable_user_custom_fields ||= {} end - def self.editable_user_custom_fields + def self.register_plugin_editable_user_custom_field(custom_field_name, plugin, staff_only: false) + if staff_only + plugin_staff_editable_user_custom_fields[custom_field_name] = plugin + else + plugin_editable_user_custom_fields[custom_field_name] = plugin + end + end + + def self.editable_user_custom_fields(by_staff: false) fields = [] plugin_editable_user_custom_fields.each do |k, v| fields << k if v.enabled? end + if by_staff + plugin_staff_editable_user_custom_fields.each do |k, v| + fields << k if v.enabled? + end + end + fields.uniq end diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index 28a7c34c36..945def58ba 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -141,9 +141,9 @@ class Plugin::Instance end end - def register_editable_user_custom_field(field) + def register_editable_user_custom_field(field, staff_only: false) reloadable_patch do |plugin| - ::User.register_plugin_editable_user_custom_field(field, plugin) # plugin.enabled? is checked at runtime + ::User.register_plugin_editable_user_custom_field(field, plugin, staff_only: staff_only) # plugin.enabled? is checked at runtime end end diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 9d4ab992cc..26a952fca5 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -1764,40 +1764,56 @@ describe UsersController do before do plugin = Plugin::Instance.new plugin.register_editable_user_custom_field :test2 + plugin.register_editable_user_custom_field :test3, staff_only: true end after do User.plugin_editable_user_custom_fields.clear + User.plugin_staff_editable_user_custom_fields.clear end it "only updates allowed user fields" do - put "/u/#{user.username}.json", params: { custom_fields: { test1: :hello1, test2: :hello2 } } + put "/u/#{user.username}.json", params: { custom_fields: { test1: :hello1, test2: :hello2, test3: :hello3 } } expect(response.status).to eq(200) expect(user.custom_fields["test1"]).to be_blank expect(user.custom_fields["test2"]).to eq("hello2") + expect(user.custom_fields["test3"]).to be_blank end it "works alongside a user field" do user_field = Fabricate(:user_field, editable: true) - put "/u/#{user.username}.json", params: { custom_fields: { test1: :hello1, test2: :hello2 }, user_fields: { user_field.id.to_s => 'happy' } } + put "/u/#{user.username}.json", params: { custom_fields: { test1: :hello1, test2: :hello2, test3: :hello3 }, user_fields: { user_field.id.to_s => 'happy' } } expect(response.status).to eq(200) expect(user.custom_fields["test1"]).to be_blank expect(user.custom_fields["test2"]).to eq("hello2") + expect(user.custom_fields["test3"]).to eq(nil) expect(user.user_fields[user_field.id.to_s]).to eq('happy') end it "is secure when there are no registered editable fields" do User.plugin_editable_user_custom_fields.clear - put "/u/#{user.username}.json", params: { custom_fields: { test1: :hello1, test2: :hello2 } } + User.plugin_staff_editable_user_custom_fields.clear + put "/u/#{user.username}.json", params: { custom_fields: { test1: :hello1, test2: :hello2, test3: :hello3 } } expect(response.status).to eq(200) expect(user.custom_fields["test1"]).to be_blank expect(user.custom_fields["test2"]).to be_blank + expect(user.custom_fields["test3"]).to be_blank put "/u/#{user.username}.json", params: { custom_fields: ["arrayitem1", "arrayitem2"] } expect(response.status).to eq(200) end + it "allows staff to edit staff-editable fields" do + sign_in(Fabricate(:admin)) + put "/u/#{user.username}.json", params: { custom_fields: { test1: :hello1, test2: :hello2, test3: :hello3 } } + + expect(response.status).to eq(200) + expect(user.custom_fields["test1"]).to be_blank + expect(user.custom_fields["test2"]).to eq("hello2") + expect(user.custom_fields["test3"]).to eq("hello3") + end + end end From 9a81cb9e556b5b5070ef9256365f1642aeec81ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Fri, 11 Oct 2019 11:13:10 +0200 Subject: [PATCH 008/328] FIX: ensure we remove tempfiles from disk when creating an upload Follow-up to 46d12c5ad3e8116bdc8e1662e55a4e63ed32dfb9 --- lib/upload_creator.rb | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/upload_creator.rb b/lib/upload_creator.rb index 632d7a7da0..0a0c8d43c4 100644 --- a/lib/upload_creator.rb +++ b/lib/upload_creator.rb @@ -143,7 +143,9 @@ class UploadCreator @upload end ensure - @file&.close + if @file + @file.respond_to?(:close!) ? @file.close! : @file.close + end end def extract_image_info! @@ -197,11 +199,11 @@ class UploadCreator keep_jpeg &&= (filesize - new_size) > MIN_CONVERT_TO_JPEG_BYTES_SAVED if keep_jpeg - @file.close + @file.respond_to?(:close!) ? @file.close! : @file.close @file = jpeg_tempfile extract_image_info! else - jpeg_tempfile&.close + jpeg_tempfile.close! end end @@ -230,16 +232,21 @@ class UploadCreator original_size = filesize down_tempfile = Tempfile.new(["down", ".#{@image_info.type}"]) + from = @file.path + to = down_tempfile.path + + OptimizedImage.ensure_safe_paths!(from, to) + OptimizedImage.downsize( - @file.path, - down_tempfile.path, + from, + to, "50%", filename: @filename, allow_animation: allow_animation, raise_on_error: true ) - @file.close + @file.respond_to?(:close!) ? @file.close! : @file.close @file = down_tempfile extract_image_info! From 3a469a79cfb641ec7782a995ca1fd88be1f8dcf3 Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Fri, 11 Oct 2019 11:37:44 -0400 Subject: [PATCH 009/328] FEATURE: search topics when adding a link in composer (#8178) --- .../controllers/insert-hyperlink.js.es6 | 151 ++++++++++++++++-- .../templates/modal/insert-hyperlink.hbs | 23 ++- app/assets/stylesheets/common/base/modal.scss | 33 ++++ config/locales/client.en.yml | 2 +- .../acceptance/composer-hyperlink-test.js.es6 | 53 ++++-- 5 files changed, 237 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 b/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 index d4f15d95cf..313ab332c3 100644 --- a/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 +++ b/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 @@ -1,15 +1,140 @@ import ModalFunctionality from "discourse/mixins/modal-functionality"; +import { searchForTerm } from "discourse/lib/search"; export default Ember.Controller.extend(ModalFunctionality, { - linkUrl: "", - linkText: "", + _debounced: null, + _activeSearch: null, onShow() { - Ember.run.next(() => - $(this) - .find("input.link-url") - .focus() - ); + this.setProperties({ + linkUrl: "", + linkText: "", + searchResults: [], + searchLoading: false, + selectedRow: -1 + }); + + Ember.run.scheduleOnce("afterRender", () => { + const element = document.querySelector(".insert-link"); + + element.addEventListener("keydown", e => this.keyDown(e)); + + element + .closest(".modal-inner-container") + .addEventListener("mousedown", e => this.mouseDown(e)); + + document.querySelector("input.link-url").focus(); + }); + }, + + keyDown(e) { + switch (e.which) { + case 40: + this.highlightRow(e, "down"); + break; + case 38: + this.highlightRow(e, "up"); + break; + case 13: + // override Enter behaviour when a row is selected + if (this.selectedRow > -1) { + const selected = document.querySelectorAll( + ".internal-link-results .search-link" + )[this.selectedRow]; + this.selectLink(selected); + e.preventDefault(); + e.stopPropagation(); + } + break; + case 27: + // Esc should cancel dropdown first + if (this.searchResults.length) { + this.set("searchResults", []); + e.preventDefault(); + e.stopPropagation(); + } + break; + } + }, + + mouseDown(e) { + if (!e.target.closest(".inputs")) { + this.set("searchResults", []); + } + }, + + highlightRow(e, direction) { + const index = + direction === "down" ? this.selectedRow + 1 : this.selectedRow - 1; + + if (index > -1 && index < this.searchResults.length) { + document + .querySelectorAll(".internal-link-results .search-link") + [index].focus(); + this.set("selectedRow", index); + } else { + this.set("selectedRow", -1); + document.querySelector("input.link-url").focus(); + } + + e.preventDefault(); + }, + + selectLink(el) { + this.setProperties({ + linkUrl: el.href, + searchResults: [], + selectedRow: -1 + }); + + if (!this.linkText && el.dataset.title) { + this.set("linkText", el.dataset.title); + } + + document.querySelector("input.link-text").focus(); + }, + + triggerSearch() { + if (this.linkUrl.length > 3 && this.linkUrl.indexOf("http") === -1) { + this.set("searchLoading", true); + this._activeSearch = searchForTerm(this.linkUrl, { + typeFilter: "topic" + }); + this._activeSearch + .then(results => { + if (results && results.topics && results.topics.length > 0) { + this.set("searchResults", results.topics); + } else { + this.set("searchResults", []); + } + }) + .finally(() => { + this.set("searchLoading", false); + this._activeSearch = null; + }); + } else { + this.abortSearch(); + } + }, + + abortSearch() { + if (this._activeSearch) { + this._activeSearch.abort(); + } + this.setProperties({ + searchResults: [], + searchLoading: false + }); + }, + + onClose() { + const element = document.querySelector(".insert-link"); + element.removeEventListener("keydown", this.keyDown); + element + .closest(".modal-inner-container") + .removeEventListener("mousedown", this.mouseDown); + + Ember.run.cancel(this._debounced); }, actions: { @@ -35,12 +160,20 @@ export default Ember.Controller.extend(ModalFunctionality, { this.toolbarEvent.selectText(sel.start + 1, origLink.length); } } - this.set("linkUrl", ""); - this.set("linkText", ""); this.send("closeModal"); }, cancel() { this.send("closeModal"); + }, + linkClick(e) { + if (!e.metaKey && !e.ctrlKey) { + e.preventDefault(); + e.stopPropagation(); + this.selectLink(e.target); + } + }, + search() { + this._debounced = Ember.run.debounce(this, this.triggerSearch, 400); } } }); diff --git a/app/assets/javascripts/discourse/templates/modal/insert-hyperlink.hbs b/app/assets/javascripts/discourse/templates/modal/insert-hyperlink.hbs index 8aa0607266..ec15a2b501 100644 --- a/app/assets/javascripts/discourse/templates/modal/insert-hyperlink.hbs +++ b/app/assets/javascripts/discourse/templates/modal/insert-hyperlink.hbs @@ -1,6 +1,27 @@ {{#d-modal-body title="composer.link_dialog_title" class="insert-link"}}
- {{text-field value=linkUrl placeholderKey="composer.link_url_placeholder" class="link-url"}} + {{text-field + value=linkUrl + placeholderKey="composer.link_url_placeholder" + class="link-url" + key-up=(action "search") + }} + {{#if searchLoading}} + {{loading-spinner}} + {{/if}} + {{#if searchResults}} + + {{/if}}
{{text-field value=linkText placeholderKey="composer.link_optional_text" class="link-text"}} diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index bf181bfc70..44f7c2fbf2 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -201,9 +201,42 @@ } &.insert-link { + overflow-y: visible; input { min-width: 300px; } + + .inputs { + position: relative; + .spinner { + position: absolute; + right: 8px; + top: -15px; + width: 10px; + height: 10px; + } + .internal-link-results { + position: absolute; + top: 70%; + padding: 5px 10px; + box-shadow: shadow("card"); + z-index: 5; + background-color: $secondary; + max-height: 150px; + width: 90%; + overflow-y: auto; + > a { + padding: 6px; + border-bottom: 1px solid $primary-low; + cursor: pointer; + display: block; + &:hover, + &:focus { + background-color: $highlight-medium; + } + } + } + } } textarea { width: 99%; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index f30f1087fb..df10b60207 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1685,7 +1685,7 @@ en: link_description: "enter link description here" link_dialog_title: "Insert Hyperlink" link_optional_text: "optional title" - link_url_placeholder: "https://example.com" + link_url_placeholder: "Paste a URL or type to search topics" quote_title: "Blockquote" quote_text: "Blockquote" code_title: "Preformatted text" diff --git a/test/javascripts/acceptance/composer-hyperlink-test.js.es6 b/test/javascripts/acceptance/composer-hyperlink-test.js.es6 index 52ff6c7d03..dd1914ed8c 100644 --- a/test/javascripts/acceptance/composer-hyperlink-test.js.es6 +++ b/test/javascripts/acceptance/composer-hyperlink-test.js.es6 @@ -9,18 +9,13 @@ QUnit.test("add a hyperlink to a reply", async assert => { await click(".topic-post:first-child button.reply"); await fillIn(".d-editor-input", "This is a link to "); - assert.equal( - find(".insert-link.modal-body").length, - 0, + assert.ok( + !exists(".insert-link.modal-body"), "no hyperlink modal by default" ); await click(".d-editor button.link"); - assert.equal( - find(".insert-link.modal-body").length, - 1, - "hyperlink modal visible" - ); + assert.ok(exists(".insert-link.modal-body"), "hyperlink modal visible"); await fillIn(".modal-body .link-url", "google.com"); await fillIn(".modal-body .link-text", "Google"); @@ -32,9 +27,8 @@ QUnit.test("add a hyperlink to a reply", async assert => { "adds link with url and text, prepends 'http://'" ); - assert.equal( - find(".insert-link.modal-body").length, - 0, + assert.ok( + !exists(".insert-link.modal-body"), "modal dismissed after submitting link" ); @@ -51,9 +45,8 @@ QUnit.test("add a hyperlink to a reply", async assert => { "adds link with url and text, prepends 'http://'" ); - assert.equal( - find(".insert-link.modal-body").length, - 0, + assert.ok( + !exists(".insert-link.modal-body"), "modal dismissed after cancelling" ); @@ -70,4 +63,36 @@ QUnit.test("add a hyperlink to a reply", async assert => { "[Reset](http://somelink.com) textarea contents.", "adds link to a selected text" ); + + await fillIn(".d-editor-input", ""); + + await click(".d-editor button.link"); + await fillIn(".modal-body .link-url", "http://google.com"); + await keyEvent(".modal-body .link-url", "keyup", 32); + assert.ok( + !exists(".internal-link-results"), + "does not show internal links search dropdown when inputting a url" + ); + + await fillIn(".modal-body .link-url", "local"); + await keyEvent(".modal-body .link-url", "keyup", 32); + assert.ok( + exists(".internal-link-results"), + "shows internal links search dropdown when entering keywords" + ); + + await keyEvent(".insert-link", "keydown", 40); + await keyEvent(".insert-link", "keydown", 13); + + assert.ok( + !exists(".internal-link-results"), + "search dropdown dismissed after selecting an internal link" + ); + + assert.ok( + find(".link-url") + .val() + .includes("http"), + "replaces link url field with internal link" + ); }); From 76ab0350f19e72cf33395768a8ce6736fec9565e Mon Sep 17 00:00:00 2001 From: Rafael dos Santos Silva Date: Fri, 11 Oct 2019 12:38:16 -0300 Subject: [PATCH 010/328] FIX: Properly encoded slugs when configured to (#8158) When an admin changes the site setting slug_generation_method to encoded, we weren't really encoding the slug, but just allowing non-ascii characters in the slug (unicode). That brings problems when a user posts a link to topic without the slug, as our topic controller tries to redirect the user to the correct URL that contains the slug with unicode characters. Having unicode in the Location header in a response is a RFC violation and some browsers end up in a redirection loop. Bug report: https://meta.discourse.org/t/-/125371?u=falco This commit also checks if a site uses encoded slugs and clear all saved slugs in the db so they can be regenerated using an onceoff job. --- app/controllers/topics_controller.rb | 6 +++++- app/jobs/onceoff/fix_encoded_topic_slugs.rb | 14 ++++++++++++++ lib/slug.rb | 4 +++- spec/components/slug_spec.rb | 10 +++++----- spec/models/category_spec.rb | 4 ++-- spec/models/topic_spec.rb | 2 +- 6 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 app/jobs/onceoff/fix_encoded_topic_slugs.rb diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index 9de9c79592..d806413fbc 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -900,7 +900,11 @@ class TopicsController < ApplicationController end def slugs_do_not_match - params[:slug] && @topic_view.topic.slug != params[:slug] + if SiteSetting.slug_generation_method != "encoded" + params[:slug] && @topic_view.topic.slug != params[:slug] + else + params[:slug] && CGI.unescape(@topic_view.topic.slug) != params[:slug] + end end def redirect_to_correct_topic(topic, post_number = nil) diff --git a/app/jobs/onceoff/fix_encoded_topic_slugs.rb b/app/jobs/onceoff/fix_encoded_topic_slugs.rb new file mode 100644 index 0000000000..4640493fb9 --- /dev/null +++ b/app/jobs/onceoff/fix_encoded_topic_slugs.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Jobs + + class FixEncodedTopicSlugs < ::Jobs::Onceoff + def execute_onceoff(args) + return unless SiteSetting.slug_generation_method == 'encoded' + + #Make all slugs nil and let the app regenerate with proper encoded ones + Topic.update_all(slug: nil) + end + end + +end diff --git a/lib/slug.rb b/lib/slug.rb index 12fe660c43..8436f74ebc 100644 --- a/lib/slug.rb +++ b/lib/slug.rb @@ -50,7 +50,9 @@ module Slug .gsub(/\s+/, '-') .gsub(CHAR_FILTER_REGEXP, '') - downcase ? string.downcase : string + string = string.downcase if downcase + + CGI.escape(string) end def self.none_generator(string) diff --git a/spec/components/slug_spec.rb b/spec/components/slug_spec.rb index d475e578c2..dba8bcb6f5 100644 --- a/spec/components/slug_spec.rb +++ b/spec/components/slug_spec.rb @@ -60,7 +60,7 @@ describe Slug do after { SiteSetting.slug_generation_method = 'ascii' } it 'generates the slug' do - expect(Slug.for("熱帶風暴畫眉")).to eq('熱帶風暴畫眉') + expect(Slug.for("熱帶風暴畫眉")).to eq('%E7%86%B1%E5%B8%B6%E9%A2%A8%E6%9A%B4%E7%95%AB%E7%9C%89') expect(Slug.for("Jeff hate's !~-_|,=#this")).to eq("jeff-hates-this") end @@ -75,7 +75,7 @@ describe Slug do it "handles the special characters" do expect(Slug.for( " - English and Chinese title with special characters / 中文标题 !@:?\\:'`#^& $%&*()` -- " - )).to eq("english-and-chinese-title-with-special-characters-中文标题") + )).to eq("english-and-chinese-title-with-special-characters-%E4%B8%AD%E6%96%87%E6%A0%87%E9%A2%98") end it "kills the trailing dash" do @@ -151,9 +151,9 @@ describe Slug do after { SiteSetting.slug_generation_method = 'ascii' } it 'generates precentage encoded string' do - expect(Slug.encoded_generator("뉴스피드")).to eq("뉴스피드") - expect(Slug.encoded_generator("آموزش اضافه کردن لینک اختیاری به هدر")).to eq("آموزش-اضافه-کردن-لینک-اختیاری-به-هدر") - expect(Slug.encoded_generator("熱帶風暴畫眉")).to eq("熱帶風暴畫眉") + expect(Slug.encoded_generator("뉴스피드")).to eq("%EB%89%B4%EC%8A%A4%ED%94%BC%EB%93%9C") + expect(Slug.encoded_generator("آموزش اضافه کردن لینک اختیاری به هدر")).to eq("%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%A7%D8%B6%D8%A7%D9%81%D9%87-%DA%A9%D8%B1%D8%AF%D9%86-%D9%84%DB%8C%D9%86%DA%A9-%D8%A7%D8%AE%D8%AA%DB%8C%D8%A7%D8%B1%DB%8C-%D8%A8%D9%87-%D9%87%D8%AF%D8%B1") + expect(Slug.encoded_generator("熱帶風暴畫眉")).to eq("%E7%86%B1%E5%B8%B6%E9%A2%A8%E6%9A%B4%E7%95%AB%E7%9C%89") end it 'reject RFC 3986 reserved character and blank' do diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index 298bfc2b44..581d20b82e 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -313,8 +313,8 @@ describe Category do end it "creates a slug" do - expect(@category.slug).to eq("测试") - expect(@category.slug_for_url).to eq("测试") + expect(@category.slug).to eq("%E6%B5%8B%E8%AF%95") + expect(@category.slug_for_url).to eq("%E6%B5%8B%E8%AF%95") end end end diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index 23dfdf5b75..7674cc6fe9 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -158,7 +158,7 @@ describe Topic do it "returns encoded Slug for a title" do expect(topic.title).to eq(title) - expect(topic.slug).to eq(title) + expect(topic.slug).to eq('%E7%86%B1%E5%B8%B6%E9%A2%A8%E6%9A%B4%E7%95%AB%E7%9C%89') end end From f63db1c4c8f6a8f10defd1daea9fb2ae8d2519b3 Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Fri, 11 Oct 2019 11:07:19 -0500 Subject: [PATCH 011/328] FIX: Accurate sub_total calculation for reviewable_scores (#8184) --- app/models/reviewable.rb | 2 +- app/models/reviewable_score.rb | 8 ++++++-- spec/models/reviewable_score_spec.rb | 29 +++++++++++++++++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/app/models/reviewable.rb b/app/models/reviewable.rb index 750f99544a..8966621a7e 100644 --- a/app/models/reviewable.rb +++ b/app/models/reviewable.rb @@ -158,8 +158,8 @@ class Reviewable < ActiveRecord::Base type_bonus = PostActionType.where(id: reviewable_score_type).pluck(:score_bonus)[0] || 0 take_action_bonus = take_action ? 5.0 : 0.0 - sub_total = (ReviewableScore.user_flag_score(user) + type_bonus + take_action_bonus) user_accuracy_bonus = ReviewableScore.user_accuracy_bonus(user) + sub_total = ReviewableScore.calculate_score(user, type_bonus, take_action_bonus) # We can force a reviewable to hit the threshold, for example with queued posts if force_review && sub_total < Reviewable.min_score_for_priority diff --git a/app/models/reviewable_score.rb b/app/models/reviewable_score.rb index 1fe2897297..cbe561f355 100644 --- a/app/models/reviewable_score.rb +++ b/app/models/reviewable_score.rb @@ -45,12 +45,16 @@ class ReviewableScore < ActiveRecord::Base take_action_bonus > 0 end + def self.calculate_score(user, type_bonus, take_action_bonus) + score = user_flag_score(user) + type_bonus + take_action_bonus + score > 0 ? score : 0 + end + # A user's flag score is: # 1.0 + trust_level + user_accuracy_bonus # (trust_level is 5 for staff) def self.user_flag_score(user) - score = 1.0 + (user.staff? ? 5.0 : user.trust_level.to_f) + user_accuracy_bonus(user) - score >= 0 ? score : 0 + 1.0 + (user.staff? ? 5.0 : user.trust_level.to_f) + user_accuracy_bonus(user) end # A user's accuracy bonus is: diff --git a/spec/models/reviewable_score_spec.rb b/spec/models/reviewable_score_spec.rb index 47fe188f61..1b74a26d48 100644 --- a/spec/models/reviewable_score_spec.rb +++ b/spec/models/reviewable_score_spec.rb @@ -145,7 +145,6 @@ RSpec.describe ReviewableScore, type: :model do user_stat.flags_disagreed = 12 expect(ReviewableScore.user_accuracy_bonus(user).floor(2)).to eq(12.27) end - end describe ".user_flag_score" do @@ -172,13 +171,29 @@ RSpec.describe ReviewableScore, type: :model do user_stat.flags_ignored = 2 expect(ReviewableScore.user_flag_score(user).floor(2)).to eq(7.99) end + end + end - it 'return 0 if the accuracy_bonus would make the score negative' do - user.trust_level = 3 - user_stat.flags_agreed = 0 - user_stat.flags_disagreed = 1000 - expect(ReviewableScore.user_flag_score(user)).to eq(0) - end + describe ".calculate_score" do + fab!(:user) { Fabricate(:user) } + let(:user_stat) { user.user_stat } + + it 'never returns less than 0' do + user.trust_level = 2 + user_stat.flags_agreed = 1 + user_stat.flags_disagreed = 1000 + flag_score = -21.88 + expect(ReviewableScore.user_flag_score(user).floor(2)).to eq(flag_score) + expect(ReviewableScore.calculate_score(user, 5, 5)).to eq(0) + end + + it 'returns user_flag_score + type_bonus + take_action_bonus' do + user.trust_level = 2 + user_stat.flags_agreed = 12 + user_stat.flags_disagreed = 2 + flag_score = 7.99 + expect(ReviewableScore.user_flag_score(user).floor(2)).to eq(flag_score) + expect(ReviewableScore.calculate_score(user, 2, 3)).to eq(flag_score + 2 + 3) end end From 01bc465db819d5ba0e433a8226c80a9bd38b593d Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Fri, 11 Oct 2019 14:38:10 -0300 Subject: [PATCH 012/328] DEV: Split max decompressed setting for themes and backups (#8179) --- config/site_settings.yml | 5 ++++- ...1_migrate_decompressed_file_max_size_mb.rb | 19 +++++++++++++++++++ lib/backup_restore/restorer.rb | 11 +++++++++-- lib/compression/pipeline.rb | 4 ++-- lib/compression/strategy.rb | 8 ++++---- lib/theme_store/zip_importer.rb | 3 ++- .../theme_store/zip_exporter_spec.rb | 3 ++- spec/lib/compression/engine_spec.rb | 8 +++++--- 8 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 db/migrate/20191011131041_migrate_decompressed_file_max_size_mb.rb diff --git a/config/site_settings.yml b/config/site_settings.yml index 2d5daec397..2f3962e4c0 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -1201,9 +1201,12 @@ files: default: 5 min: 0 max: 20 - decompressed_file_max_size_mb: + decompressed_theme_max_file_size_mb: default: 1000 hidden: true + decompressed_backup_max_file_size_mb: + default: 100000 + hidden: true trust: default_trust_level: diff --git a/db/migrate/20191011131041_migrate_decompressed_file_max_size_mb.rb b/db/migrate/20191011131041_migrate_decompressed_file_max_size_mb.rb new file mode 100644 index 0000000000..f3db85da39 --- /dev/null +++ b/db/migrate/20191011131041_migrate_decompressed_file_max_size_mb.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class MigrateDecompressedFileMaxSizeMb < ActiveRecord::Migration[6.0] + def up + current_value = DB.query_single("SELECT value FROM site_settings WHERE name ='decompressed_file_max_size_mb' ").first + + if current_value && current_value != '1000' + DB.exec <<~SQL + INSERT INTO site_settings (name, data_type, value, created_at, updated_at) + VALUES + ('decompressed_theme_max_file_size_mb', 3, #{current_value}, current_timestamp, current_timestamp), + ('decompressed_backup_max_file_size_mb', 3, #{current_value}, current_timestamp, current_timestamp) + SQL + end + end + + def down + end +end diff --git a/lib/backup_restore/restorer.rb b/lib/backup_restore/restorer.rb index 2480941ceb..42fd2db39f 100644 --- a/lib/backup_restore/restorer.rb +++ b/lib/backup_restore/restorer.rb @@ -92,6 +92,9 @@ module BackupRestore extract_uploads after_restore_hook + rescue Compression::Strategy::ExtractFailed + log "The uncompressed file is too big. Consider increasing the decompressed_theme_max_file_size_mb hidden setting." + rollback rescue SystemExit log "Restore process was cancelled!" rollback @@ -138,7 +141,7 @@ module BackupRestore pipeline = Compression::Pipeline.new([Compression::Tar.new, Compression::Gzip.new]) - unzipped_path = pipeline.decompress(@tmp_directory, @archive_filename) + unzipped_path = pipeline.decompress(@tmp_directory, @archive_filename, available_size) pipeline.strip_directory(unzipped_path, @tmp_directory) end @@ -170,11 +173,15 @@ module BackupRestore log "Extracting dump file..." - Compression::Gzip.new.decompress(@tmp_directory, @dump_filename) + Compression::Gzip.new.decompress(@tmp_directory, @dump_filename, available_size) end protected + def available_size + SiteSetting.decompressed_backup_max_file_size_mb + end + def ensure_restore_is_enabled raise BackupRestore::RestoreDisabledError unless Rails.env.development? || SiteSetting.allow_restore? end diff --git a/lib/compression/pipeline.rb b/lib/compression/pipeline.rb index f955268cd5..98a93cce41 100644 --- a/lib/compression/pipeline.rb +++ b/lib/compression/pipeline.rb @@ -20,10 +20,10 @@ module Compression end end - def decompress(dest_path, compressed_file_path, allow_non_root_folder: false) + def decompress(dest_path, compressed_file_path, max_size, allow_non_root_folder: false) @strategies.reverse.reduce(compressed_file_path) do |to_decompress, strategy| last_extension = strategy.extension - strategy.decompress(dest_path, to_decompress, allow_non_root_folder: allow_non_root_folder) + strategy.decompress(dest_path, to_decompress, max_size, allow_non_root_folder: allow_non_root_folder) to_decompress.gsub(last_extension, '') end end diff --git a/lib/compression/strategy.rb b/lib/compression/strategy.rb index 921ebd8013..47151a3bf0 100644 --- a/lib/compression/strategy.rb +++ b/lib/compression/strategy.rb @@ -9,11 +9,11 @@ module Compression file_name.include?(extension) end - def decompress(dest_path, compressed_file_path, allow_non_root_folder: false) + def decompress(dest_path, compressed_file_path, max_size, allow_non_root_folder: false) sanitized_compressed_file_path = sanitize_path(compressed_file_path) get_compressed_file_stream(sanitized_compressed_file_path) do |compressed_file| - available_size = calculate_available_size + available_size = calculate_available_size(max_size) entries_of(compressed_file).each do |entry| entry_path = build_entry_path( @@ -59,8 +59,8 @@ module Compression end end - def calculate_available_size - 1024**2 * (SiteSetting.decompressed_file_max_size_mb / 1.049) # Mb to Mib + def calculate_available_size(max_size) + 1024**2 * (max_size / 1.049) # Mb to Mib end def entries_of(compressed_file) diff --git a/lib/theme_store/zip_importer.rb b/lib/theme_store/zip_importer.rb index c1a4aea098..d252037ace 100644 --- a/lib/theme_store/zip_importer.rb +++ b/lib/theme_store/zip_importer.rb @@ -18,8 +18,9 @@ class ThemeStore::ZipImporter FileUtils.mkdir(@temp_folder) Dir.chdir(@temp_folder) do + available_size = SiteSetting.decompressed_theme_max_file_size_mb Compression::Engine.engine_for(@original_filename).tap do |engine| - engine.decompress(@temp_folder, @filename) + engine.decompress(@temp_folder, @filename, available_size) engine.strip_directory(@temp_folder, @temp_folder, relative: true) end end diff --git a/spec/components/theme_store/zip_exporter_spec.rb b/spec/components/theme_store/zip_exporter_spec.rb index e7df513aa8..922ae3081d 100644 --- a/spec/components/theme_store/zip_exporter_spec.rb +++ b/spec/components/theme_store/zip_exporter_spec.rb @@ -63,7 +63,8 @@ describe ThemeStore::ZipExporter do file = 'discourse-header-icons.zip' dest = 'discourse-header-icons' Dir.chdir(dir) do - Compression::Zip.new.decompress(dir, file, allow_non_root_folder: true) + available_size = SiteSetting.decompressed_theme_max_file_size_mb + Compression::Zip.new.decompress(dir, file, available_size, allow_non_root_folder: true) `rm #{file}` folders = Dir.glob("**/*").reject { |f| File.file?(f) } diff --git a/spec/lib/compression/engine_spec.rb b/spec/lib/compression/engine_spec.rb index 04b6f7d42e..27a161934a 100644 --- a/spec/lib/compression/engine_spec.rb +++ b/spec/lib/compression/engine_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' describe Compression::Engine do + let(:available_size) { SiteSetting.decompressed_theme_max_file_size_mb } + before do @temp_folder = "#{Pathname.new(Dir.tmpdir).realpath}/#{SecureRandom.hex}" @folder_name = 'test' @@ -36,7 +38,7 @@ describe Compression::Engine do it 'decompress the folder and inspect files correctly' do engine = described_class.engine_for(@compressed_path) - engine.decompress(@temp_folder, "#{@temp_folder}/#{@folder_name}.zip") + engine.decompress(@temp_folder, "#{@temp_folder}/#{@folder_name}.zip", available_size) expect(read_file("test/hello.txt")).to eq("hello world") expect(read_file("test/a/inner")).to eq("hello world inner") @@ -49,7 +51,7 @@ describe Compression::Engine do it 'decompress the folder and inspect files correctly' do engine = described_class.engine_for(@compressed_path) - engine.decompress(@temp_folder, "#{@temp_folder}/#{@folder_name}.tar.gz") + engine.decompress(@temp_folder, "#{@temp_folder}/#{@folder_name}.tar.gz", available_size) expect(read_file("test/hello.txt")).to eq("hello world") expect(read_file("test/a/inner")).to eq("hello world inner") @@ -62,7 +64,7 @@ describe Compression::Engine do it 'decompress the folder and inspect files correctly' do engine = described_class.engine_for(@compressed_path) - engine.decompress(@temp_folder, "#{@temp_folder}/#{@folder_name}.tar") + engine.decompress(@temp_folder, "#{@temp_folder}/#{@folder_name}.tar", available_size) expect(read_file("test/hello.txt")).to eq("hello world") expect(read_file("test/a/inner")).to eq("hello world inner") From 4d67f2a8ed6b3c24ffa0cd1bdc2dcfeea8d7c847 Mon Sep 17 00:00:00 2001 From: Faizaan Gagan Date: Fri, 11 Oct 2019 23:26:04 +0530 Subject: [PATCH 013/328] bumped plugin api version to 0.8.33 (#8185) --- app/assets/javascripts/discourse/lib/plugin-api.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index f54c0f4306..da8ba1cedf 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -46,7 +46,7 @@ import { queryRegistry } from "discourse/widgets/widget"; import Composer from "discourse/models/composer"; // If you add any methods to the API ensure you bump up this number -const PLUGIN_API_VERSION = "0.8.32"; +const PLUGIN_API_VERSION = "0.8.33"; class PluginApi { constructor(version, container) { From ee4369f9723a10d1f78838e904cde83448eb825a Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 11 Oct 2019 14:41:05 -0400 Subject: [PATCH 014/328] Hook that allows custom logic before saving the composer --- .../discourse/models/composer.js.es6 | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index 9ba0afe0aa..5f13fb0940 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -744,15 +744,22 @@ const Composer = RestModel.extend({ return false; }, - save(opts) { - if (!this.cantSubmitPost) { - // change category may result in some effect for topic featured link - if (!this.canEditTopicFeaturedLink) { - this.set("featuredLink", null); - } + // Overwrite to implement custom logic + beforeSave() { + return Ember.RSVP.Promise.resolve(); + }, - return this.editingPost ? this.editPost(opts) : this.createPost(opts); - } + save(opts) { + return this.beforeSave().then(() => { + if (!this.cantSubmitPost) { + // change category may result in some effect for topic featured link + if (!this.canEditTopicFeaturedLink) { + this.set("featuredLink", null); + } + + return this.editingPost ? this.editPost(opts) : this.createPost(opts); + } + }); }, clearState() { From c5d03c30ca179ab893508d0aba819a3550111efb Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 11 Oct 2019 14:54:30 -0400 Subject: [PATCH 015/328] DEV: Add a plugin API for registering a "beforeSave" on the composer This allows plugins to perform operations before saves occur, and perhaps reject the post. --- .../discourse/controllers/composer.js.es6 | 4 ++- .../discourse/lib/plugin-api.js.es6 | 26 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index cf295cb870..c5c68d095c 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -721,7 +721,9 @@ export default Ember.Controller.extend({ }) .catch(error => { composer.set("disableDrafts", false); - this.appEvents.one("composer:will-open", () => bootbox.alert(error)); + if (error) { + this.appEvents.one("composer:will-open", () => bootbox.alert(error)); + } }); if ( diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index da8ba1cedf..246470af8c 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -46,7 +46,7 @@ import { queryRegistry } from "discourse/widgets/widget"; import Composer from "discourse/models/composer"; // If you add any methods to the API ensure you bump up this number -const PLUGIN_API_VERSION = "0.8.33"; +const PLUGIN_API_VERSION = "0.8.34"; class PluginApi { constructor(version, container) { @@ -791,7 +791,7 @@ class PluginApi { * * Example: * - * modifySelectKit("topic-footer-mobile-dropdown").appendContent(() => [{ + * api.modifySelectKit("topic-footer-mobile-dropdown").appendContent(() => [{ * name: "discourse", * id: 1 * }]) @@ -807,7 +807,7 @@ class PluginApi { * * Example: * - * addGTMPageChangedCallback( gtmData => gtmData.locale = I18n.currentLocale() ) + * api.addGTMPageChangedCallback( gtmData => gtmData.locale = I18n.currentLocale() ) * */ addGTMPageChangedCallback(fn) { @@ -821,7 +821,7 @@ class PluginApi { * Example: * * // read /discourse/lib/sharing.js.es6 for options - * addSharingSource(options) + * api.addSharingSource(options) * */ addSharingSource(options) { @@ -837,14 +837,28 @@ class PluginApi { * * Example: * - * addComposerUploadHandler(["mp4", "mov"], (file, editor) => { - * console.log("Handling upload for", file.name); + * api.addComposerUploadHandler(["mp4", "mov"], (file, editor) => { + * console.log("Handling upload for", file.name); * }) */ addComposerUploadHandler(extensions, method) { addComposerUploadHandler(extensions, method); } + /** + * Registers a "beforeSave" function on the composer. This allows you to + * implement custom logic that will happen before the user makes a post. + * + * Example: + * + * api.composerBeforeSave(() => { + * console.log("Before saving, do something!"); + * }) + */ + composerBeforeSave(method) { + Composer.reopen({ beforeSave: method }); + } + /** * Adds a field to draft serializer * From 342bbe66dd497a33a78ec2abd0f9c4d32c4b8851 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 11 Oct 2019 15:33:34 -0400 Subject: [PATCH 016/328] FIX: Flaky tests We had acceptance tests that were testing the contents of the post stream preview, not the contents of the eventual topic itself. This became apparent when I introduced a new promise which caused the tests to finish waiting for work properly. Before that, it was up to the speed of the execution, very spooky! --- test/javascripts/acceptance/category-hashtag-test.js.es6 | 9 +-------- test/javascripts/acceptance/composer-test.js.es6 | 4 ++-- test/javascripts/acceptance/emoji-test.js.es6 | 8 -------- test/javascripts/acceptance/tag-hashtag-test.js.es6 | 8 -------- test/javascripts/helpers/create-pretender.js.es6 | 4 +++- 5 files changed, 6 insertions(+), 27 deletions(-) diff --git a/test/javascripts/acceptance/category-hashtag-test.js.es6 b/test/javascripts/acceptance/category-hashtag-test.js.es6 index c2ffdcdcae..e5bbdf3c48 100644 --- a/test/javascripts/acceptance/category-hashtag-test.js.es6 +++ b/test/javascripts/acceptance/category-hashtag-test.js.es6 @@ -7,6 +7,7 @@ QUnit.test("category hashtag is cooked properly", async assert => { await click("#topic-footer-buttons .btn.create"); await fillIn(".d-editor-input", "this is a category hashtag #bug"); + // TODO: Test that the autocomplete shows assert.equal( find(".d-editor-preview:visible") @@ -14,12 +15,4 @@ QUnit.test("category hashtag is cooked properly", async assert => { .trim(), '

this is a category hashtag #bug

' ); - - await click("#reply-control .btn.create"); - assert.equal( - find(".topic-post:last .cooked p") - .html() - .trim(), - 'this is a category hashtag #bug' - ); }); diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6 index 26ccba2be2..5123276c48 100644 --- a/test/javascripts/acceptance/composer-test.js.es6 +++ b/test/javascripts/acceptance/composer-test.js.es6 @@ -249,7 +249,7 @@ QUnit.test("Create a Reply", async assert => { await click("#reply-control button.create"); assert.equal( find(".cooked:last p").text(), - "this is the content of my reply" + "If you use gettext format you could leverage Launchpad 13 translations and the community behind it." ); }); @@ -266,7 +266,7 @@ QUnit.test("Posting on a different topic", async assert => { await click(".btn-reply-here"); assert.equal( find(".cooked:last p").text(), - "this is the content for a different topic" + "If you use gettext format you could leverage Launchpad 13 translations and the community behind it." ); }); diff --git a/test/javascripts/acceptance/emoji-test.js.es6 b/test/javascripts/acceptance/emoji-test.js.es6 index 39dc37696e..087a923906 100644 --- a/test/javascripts/acceptance/emoji-test.js.es6 +++ b/test/javascripts/acceptance/emoji-test.js.es6 @@ -14,14 +14,6 @@ QUnit.test("emoji is cooked properly", async assert => { .trim(), `

this is an emoji :blonde_woman:

` ); - - await click("#reply-control .btn.create"); - assert.equal( - find(".topic-post:last .cooked p") - .html() - .trim(), - `this is an emoji :blonde_woman:` - ); }); QUnit.test("skin toned emoji is cooked properly", async assert => { diff --git a/test/javascripts/acceptance/tag-hashtag-test.js.es6 b/test/javascripts/acceptance/tag-hashtag-test.js.es6 index 1e3e468277..b640d2cb97 100644 --- a/test/javascripts/acceptance/tag-hashtag-test.js.es6 +++ b/test/javascripts/acceptance/tag-hashtag-test.js.es6 @@ -24,12 +24,4 @@ QUnit.test("tag is cooked properly", async assert => { .trim(), '

this is a tag hashtag #monkey

' ); - - await click("#reply-control .btn.create"); - assert.equal( - find(".topic-post:last .cooked") - .html() - .trim(), - '

this is a tag hashtag #monkey

' - ); }); diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index cb4597482e..d05a79a491 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -199,7 +199,9 @@ export default function() { this.get("/t/280.json", () => response(fixturesByUrl["/t/280/1.json"])); this.get("/t/34.json", () => response(fixturesByUrl["/t/34/1.json"])); - this.get("/t/280/20.json", () => response(fixturesByUrl["/t/280/1.json"])); + this.get("/t/280/:post_number.json", () => + response(fixturesByUrl["/t/280/1.json"]) + ); this.get("/t/28830.json", () => response(fixturesByUrl["/t/28830/1.json"])); this.get("/t/9.json", () => response(fixturesByUrl["/t/9/1.json"])); this.get("/t/12.json", () => response(fixturesByUrl["/t/12/1.json"])); From 204cd43861336bae400213857da18f049571e864 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 11 Oct 2019 15:41:19 -0400 Subject: [PATCH 017/328] FIX: This emoji test was broken too --- test/javascripts/acceptance/emoji-test.js.es6 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/javascripts/acceptance/emoji-test.js.es6 b/test/javascripts/acceptance/emoji-test.js.es6 index 087a923906..3efd5f5a8f 100644 --- a/test/javascripts/acceptance/emoji-test.js.es6 +++ b/test/javascripts/acceptance/emoji-test.js.es6 @@ -27,12 +27,4 @@ QUnit.test("skin toned emoji is cooked properly", async assert => { .trim(), `

this is an emoji :blonde_woman:t5:

` ); - - await click("#reply-control .btn.create"); - assert.equal( - find(".topic-post:last .cooked p") - .html() - .trim(), - `this is an emoji :blonde_woman:t5:` - ); }); From de3db0e485528b067ebe8c3da15e6472cf46469c Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 11 Oct 2019 15:52:14 -0400 Subject: [PATCH 018/328] FIX: Remove another broken test --- .../acceptance/composer-test.js.es6 | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6 index 5123276c48..004a4e2938 100644 --- a/test/javascripts/acceptance/composer-test.js.es6 +++ b/test/javascripts/acceptance/composer-test.js.es6 @@ -432,44 +432,6 @@ QUnit.test("Composer can toggle whispers", async assert => { ); }); -QUnit.test("Switching composer whisper state", async assert => { - const menu = selectKit(".toolbar-popup-menu-options"); - - await visit("/t/this-is-a-test-topic/9"); - await click(".topic-post:eq(0) button.reply"); - - await menu.expand(); - await menu.selectRowByValue("toggleWhisper"); - - await fillIn(".d-editor-input", "this is the content of my reply"); - await click("#reply-control button.create"); - - assert.ok(find(".topic-post:last").hasClass("whisper")); - - await click("#topic-footer-buttons .btn.create"); - - assert.ok( - find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0, - "doesn’t set topic reply as whisper" - ); - - await click(".topic-post:last button.reply"); - - assert.ok(find(".topic-post:last").hasClass("whisper")); - assert.ok( - find(".composer-fields .whisper .d-icon-far-eye-slash").length === 1, - "sets post reply as a whisper" - ); - - await click(".topic-post:nth-last-child(2) button.reply"); - - assert.notOk(find(".topic-post:nth-last-child(2)").hasClass("whisper")); - assert.ok( - find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0, - "doesn’t set post reply as a whisper" - ); -}); - QUnit.test( "Composer can toggle layouts (open, fullscreen and draft)", async assert => { From 312ecf2a05b2f29cd180463e35b7e9228fd89076 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Fri, 11 Oct 2019 22:25:28 +0200 Subject: [PATCH 019/328] FIX: allows scrolling of search menu panel when showing more results (#8186) --- app/assets/stylesheets/common/base/menu-panel.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/common/base/menu-panel.scss b/app/assets/stylesheets/common/base/menu-panel.scss index 3b32d81874..a02fccf8b8 100644 --- a/app/assets/stylesheets/common/base/menu-panel.scss +++ b/app/assets/stylesheets/common/base/menu-panel.scss @@ -51,6 +51,7 @@ touch-action: pan-y pinch-zoom; overflow-y: auto; overflow-x: hidden; + max-height: 100vh; } .badge-notification { From 16d8e3f872528839b8c765fefa7b57c393b2683e Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sat, 12 Oct 2019 20:05:34 -0700 Subject: [PATCH 020/328] minor copyedit --- config/locales/server.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 59f48d8d3a..bcefb89f45 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1384,7 +1384,7 @@ en: editing_grace_period_max_diff_high_trust: "Maximum number of character changes allowed in editing grace period, if more changed store another post revision (trust level 2 and up)" staff_edit_locks_post: "Posts will be locked from editing if they are edited by staff members" post_edit_time_limit: "A tl0 or tl1 author can edit their post for (n) minutes after posting. Set to 0 for forever." - tl2_post_edit_time_limit: "A tl2 author can edit their post for (n) minutes after posting. Set to 0 for forever." + tl2_post_edit_time_limit: "A tl2+ author can edit their post for (n) minutes after posting. Set to 0 for forever." edit_history_visible_to_public: "Allow everyone to see previous versions of an edited post. When disabled, only staff members can view." delete_removed_posts_after: "Posts removed by the author will be automatically deleted after (n) hours. If set to 0, posts will be deleted immediately." max_image_width: "Maximum thumbnail width of images in a post" From 2b74dc5885df9b2a6fce07a643ad4e817125bb6c Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Sun, 13 Oct 2019 00:53:57 -0700 Subject: [PATCH 021/328] FIX: allow change password with TOTP --- .../discourse/controllers/password-reset.js.es6 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/password-reset.js.es6 b/app/assets/javascripts/discourse/controllers/password-reset.js.es6 index ae3c5949a5..4194d67f16 100644 --- a/app/assets/javascripts/discourse/controllers/password-reset.js.es6 +++ b/app/assets/javascripts/discourse/controllers/password-reset.js.es6 @@ -16,9 +16,12 @@ export default Ember.Controller.extend(PasswordValidation, { "model.second_factor_required", "model.security_key_required" ), - secondFactorMethod: Ember.computed.alias("model.security_key_required") - ? SECOND_FACTOR_METHODS.SECURITY_KEY - : SECOND_FACTOR_METHODS.TOTP, + @computed("model.security_key_required") + secondFactorMethod(security_key_required) { + return security_key_required + ? SECOND_FACTOR_METHODS.SECURITY_KEY + : SECOND_FACTOR_METHODS.TOTP; + }, passwordRequired: true, errorMessage: null, successMessage: null, From e4fe864c0b7d4d5d1f0cd604829eca81b71bb4ec Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Mon, 14 Oct 2019 08:47:15 +0530 Subject: [PATCH 022/328] FIX: use upload's cdn url in composer preview if available. --- lib/pretty_text/helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pretty_text/helpers.rb b/lib/pretty_text/helpers.rb index 9c898882a7..417600469b 100644 --- a/lib/pretty_text/helpers.rb +++ b/lib/pretty_text/helpers.rb @@ -70,7 +70,7 @@ module PrettyText if short_urls = reverse_map[sha1] short_urls.each do |short_url| result[short_url] = { - url: url, + url: Discourse.store.cdn_url(url), short_path: Upload.short_path(sha1: sha1, extension: extension), base62_sha1: Upload.base62_sha1(sha1) } From 99086edf855df3fb8de5887785ddc687a6911810 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Mon, 14 Oct 2019 15:40:33 +1100 Subject: [PATCH 023/328] FIX: Allow themes to upload and serve js files (#8188) If you set `config.public_file_server.enabled = false` when you try to get uploaded js file you will get an error: `Security warning: an embedded ".html_safe + def preload_script_url(url) + <<~HTML.html_safe + + + HTML end def discourse_csrf_tags diff --git a/app/models/translation_override.rb b/app/models/translation_override.rb index 95e4183589..bef0c3eb1d 100644 --- a/app/models/translation_override.rb +++ b/app/models/translation_override.rb @@ -39,6 +39,7 @@ class TranslationOverride < ActiveRecord::Base def self.i18n_changed(keys) I18n.reload! + ExtraLocalesController.clear_cache! MessageBus.publish('/i18n-flush', refresh: true) keys.flatten.each do |key| diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index fdebcba6f2..3340017d75 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -20,6 +20,9 @@ <%= build_plugin_html 'server:before-script-load' %> <%= preload_script "locales/#{I18n.locale}" %> + <%- if ExtraLocalesController.client_overrides_exist? %> + <%= preload_script_url ExtraLocalesController.url('overrides') %> + <%- end %> <%= preload_script "ember_jquery" %> <%= preload_script "preload-store" %> <%= preload_script "vendor" %> @@ -29,7 +32,7 @@ <%= preload_script file %> <%- end %> <%- if staff? %> - + <%= preload_script_url ExtraLocalesController.url('admin') %> <%= preload_script "admin" %> <%- end %> diff --git a/app/views/wizard/index.html.erb b/app/views/wizard/index.html.erb index 9ccc5e3b15..382f68b433 100644 --- a/app/views/wizard/index.html.erb +++ b/app/views/wizard/index.html.erb @@ -3,9 +3,12 @@ <%= discourse_stylesheet_link_tag :wizard, theme_ids: nil %> <%= preload_script 'ember_jquery' %> <%= preload_script "locales/#{I18n.locale}" %> + <%- if ExtraLocalesController.client_overrides_exist? %> + <%= preload_script_url ExtraLocalesController.url('overrides') %> + <%- end %> <%= preload_script 'wizard-vendor' %> <%= preload_script 'wizard-application' %> - + <%= preload_script_url ExtraLocalesController.url('wizard') %> <%= csrf_meta_tags %> <%= render partial: "layouts/head" %> diff --git a/config/initializers/100-i18n.rb b/config/initializers/100-i18n.rb index d714de498d..10749264a4 100644 --- a/config/initializers/100-i18n.rb +++ b/config/initializers/100-i18n.rb @@ -12,5 +12,8 @@ I18n.reload! I18n.init_accelerator! unless Rails.env.test? - MessageBus.subscribe("/i18n-flush") { I18n.reload! } + MessageBus.subscribe("/i18n-flush") do + I18n.reload! + ExtraLocalesController.clear_cache! + end end diff --git a/lib/freedom_patches/translate_accelerator.rb b/lib/freedom_patches/translate_accelerator.rb index b2a0f51f86..26dff3594c 100644 --- a/lib/freedom_patches/translate_accelerator.rb +++ b/lib/freedom_patches/translate_accelerator.rb @@ -137,9 +137,10 @@ module I18n def overrides_by_locale(locale) return unless @overrides_enabled - return {} if GlobalSetting.skip_db? + execute_reload if @requires_reload + site = RailsMultisite::ConnectionManagement.current_db by_site = @overrides_by_site[site] @@ -170,11 +171,6 @@ module I18n end end - def client_overrides_json(locale) - client_json = (overrides_by_locale(locale) || {}).select { |k, _| k[/^(admin_js|js)\./] } - MultiJson.dump(client_json) - end - def translate(*args) execute_reload if @requires_reload diff --git a/lib/js_locale_helper.rb b/lib/js_locale_helper.rb index 798a67fe87..99d344ef8c 100644 --- a/lib/js_locale_helper.rb +++ b/lib/js_locale_helper.rb @@ -159,6 +159,39 @@ module JsLocaleHelper result end + def self.output_client_overrides(locale) + translations = (I18n.overrides_by_locale(locale) || {}).select { |k, _| k[/^(admin_js|js)\./] } + return "" if translations.blank? + + message_formats = {} + + translations.delete_if do |key, value| + if key.to_s.end_with?("_MF") + message_formats[key] = value + end + end + + message_formats = message_formats.map { |k, v| "#{k.inspect}: #{v}" }.join(", ") + + <<~JS + I18n._mfOverrides = {#{message_formats}}; + I18n._overrides = #{translations.to_json}; + JS + end + + def self.output_extra_locales(bundle, locale) + translations = translations_for(locale) + + translations.keys.each do |l| + translations[l].keys.each do |k| + bundle_translations = translations[l].delete(k) + translations[l].deep_merge!(bundle_translations) if k == bundle + end + end + + translations.present? ? "I18n.extras = #{translations.to_json};" : "" + end + MOMENT_LOCALE_MAPPING ||= { "hy" => "hy-am", "en" => "en-gb" diff --git a/spec/components/freedom_patches/translate_accelerator_spec.rb b/spec/components/freedom_patches/translate_accelerator_spec.rb index fc12655881..9387564864 100644 --- a/spec/components/freedom_patches/translate_accelerator_spec.rb +++ b/spec/components/freedom_patches/translate_accelerator_spec.rb @@ -204,26 +204,5 @@ describe "translate accelerator" do override_translation('en', 'fish', 'fake fish') expect(Fish.model_name.human).to eq('Fish') end - - describe "client json" do - it "is empty by default" do - expect(I18n.client_overrides_json('en')).to eq('{}') - end - - it "doesn't return server overrides" do - override_translation('en', 'foo', 'bar') - expect(I18n.client_overrides_json('en')).to eq('{}') - end - - it "returns client overrides" do - override_translation('en', 'js.foo', 'bar') - override_translation('en', 'admin_js.beep', 'boop') - json = ::JSON.parse(I18n.client_overrides_json('en')) - - expect(json).to be_present - expect(json['js.foo']).to eq('bar') - expect(json['admin_js.beep']).to eq('boop') - end - end end end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 20af731aaa..c03af37509 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -6,13 +6,20 @@ require 'rails_helper' describe ApplicationHelper do describe "preload_script" do + def preload_link(url) + <<~HTML + + + HTML + end + it "provides brotli links to brotli cdn" do set_cdn_url "https://awesome.com" helper.request.env["HTTP_ACCEPT_ENCODING"] = 'br' link = helper.preload_script('application') - expect(link).to eq("\n") + expect(link).to eq(preload_link("https://awesome.com/brotli_asset/application.js")) end context "with s3 CDN" do @@ -45,26 +52,26 @@ describe ApplicationHelper do helper.request.env["HTTP_ACCEPT_ENCODING"] = 'br' link = helper.preload_script('application') - expect(link).to eq("\n") + expect(link).to eq(preload_link("https://s3cdn.com/assets/application.br.js")) end it "gives s3 cdn if asset host is not set" do link = helper.preload_script('application') - expect(link).to eq("\n") + expect(link).to eq(preload_link("https://s3cdn.com/assets/application.js")) end it "can fall back to gzip compression" do helper.request.env["HTTP_ACCEPT_ENCODING"] = 'gzip' link = helper.preload_script('application') - expect(link).to eq("\n") + expect(link).to eq(preload_link("https://s3cdn.com/assets/application.gz.js")) end it "gives s3 cdn even if asset host is set" do set_cdn_url "https://awesome.com" link = helper.preload_script('application') - expect(link).to eq("\n") + expect(link).to eq(preload_link("https://s3cdn.com/assets/application.js")) end end end diff --git a/spec/requests/extra_locales_controller_spec.rb b/spec/requests/extra_locales_controller_spec.rb index 551dceda3d..7c12b1fcfd 100644 --- a/spec/requests/extra_locales_controller_spec.rb +++ b/spec/requests/extra_locales_controller_spec.rb @@ -28,16 +28,16 @@ describe ExtraLocalesController do let(:moderator) { Fabricate(:moderator) } before { sign_in(moderator) } - it "caches for 24 hours if version is provided and it matches current hash" do + it "caches for 1 year if version is provided and it matches current hash" do get "/extra-locales/admin", params: { v: ExtraLocalesController.bundle_js_hash('admin') } expect(response.status).to eq(200) - expect(response.headers["Cache-Control"]).to eq("max-age=86400, public, immutable") + expect(response.headers["Cache-Control"]).to eq("max-age=31556952, public, immutable") end it "does not cache at all if version is invalid" do get "/extra-locales/admin", params: { v: 'a' * 32 } expect(response.status).to eq(200) - expect(response.headers["Cache-Control"]).not_to eq("max-age=86400, public, immutable") + expect(response.headers["Cache-Control"]).not_to include("max-age", "public", "immutable") end context "with plugin" do @@ -67,6 +67,47 @@ describe ExtraLocalesController do end end end + + context "overridden translations" do + after { I18n.reload! } + + it "works for anonymous users" do + TranslationOverride.upsert!(I18n.locale, 'js.some_key', 'client-side translation') + + get "/extra-locales/overrides", params: { v: ExtraLocalesController.bundle_js_hash('overrides') } + expect(response.status).to eq(200) + expect(response.headers["Cache-Control"]).to eq("max-age=31556952, public, immutable") + end + + it "returns nothing when there are not overridden translations" do + get "/extra-locales/overrides" + expect(response.status).to eq(200) + expect(response.body).to be_empty + end + + context "with translations" do + it "returns the correct translations" do + TranslationOverride.upsert!(I18n.locale, 'js.some_key', 'client-side translation') + TranslationOverride.upsert!(I18n.locale, 'js.client_MF', '{NUM_RESULTS, plural, one {1 result} other {many} }') + TranslationOverride.upsert!(I18n.locale, 'admin_js.another_key', 'admin client js') + TranslationOverride.upsert!(I18n.locale, 'server.some_key', 'server-side translation') + TranslationOverride.upsert!(I18n.locale, 'server.some_MF', '{NUM_RESULTS, plural, one {1 result} other {many} }') + + get "/extra-locales/overrides" + expect(response.status).to eq(200) + expect(response.body).to_not include("server.some_key", "server.some_MF") + + ctx = MiniRacer::Context.new + ctx.eval("I18n = {};") + ctx.eval(response.body) + + expect(ctx.eval('typeof I18n._mfOverrides["js.client_MF"]')).to eq("function") + expect(ctx.eval('I18n._overrides["js.some_key"]')).to eq("client-side translation") + expect(ctx.eval('I18n._overrides["js.client_MF"] === undefined')).to eq(true) + expect(ctx.eval('I18n._overrides["admin_js.another_key"]')).to eq("admin client js") + end + end + end end describe ".bundle_js_hash" do @@ -95,4 +136,25 @@ describe ExtraLocalesController do expect(ExtraLocalesController.bundle_js_hash("wizard")).to eq(expected_hash_de) end end + + describe ".client_overrides_exist?" do + after do + I18n.reload! + ExtraLocalesController.clear_cache! + end + + it "returns false if there are no client-side translation overrides" do + expect(ExtraLocalesController.client_overrides_exist?).to eq(false) + + TranslationOverride.upsert!(I18n.locale, 'server.some_key', 'server-side translation') + expect(ExtraLocalesController.client_overrides_exist?).to eq(false) + end + + it "returns true if there are client-side translation overrides" do + expect(ExtraLocalesController.client_overrides_exist?).to eq(false) + + TranslationOverride.upsert!(I18n.locale, 'js.some_key', 'client-side translation') + expect(ExtraLocalesController.client_overrides_exist?).to eq(true) + end + end end diff --git a/test/javascripts/initializers/localization-test.js.es6 b/test/javascripts/initializers/localization-test.js.es6 index 222953482f..7182e6d8f4 100644 --- a/test/javascripts/initializers/localization-test.js.es6 +++ b/test/javascripts/initializers/localization-test.js.es6 @@ -1,9 +1,9 @@ -import PreloadStore from "preload-store"; import LocalizationInitializer from "discourse/initializers/localization"; QUnit.module("initializer:localization", { _locale: I18n.locale, _translations: I18n.translations, + _overrides: I18n._overrides, beforeEach() { I18n.locale = "fr"; @@ -31,14 +31,15 @@ QUnit.module("initializer:localization", { afterEach() { I18n.locale = this._locale; I18n.translations = this._translations; + I18n._overrides = this._overrides; } }); QUnit.test("translation overrides", function(assert) { - PreloadStore.store("translationOverrides", { + I18n._overrides = { "js.composer.reply": "WAT", "js.topic.reply.help": "foobar" - }); + }; LocalizationInitializer.initialize(this.registry); assert.equal( @@ -56,10 +57,10 @@ QUnit.test("translation overrides", function(assert) { QUnit.test( "skip translation override if parent node is not an object", function(assert) { - PreloadStore.store("translationOverrides", { + I18n._overrides = { "js.composer.reply": "WAT", "js.composer.reply.help": "foobar" - }); + }; LocalizationInitializer.initialize(this.registry); assert.equal(I18n.t("composer.reply.help"), "[fr.composer.reply.help]"); From edc135d9c51197997826490d38f0925d9b9eb46c Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Tue, 5 Nov 2019 12:43:49 -0600 Subject: [PATCH 319/328] DEV: Import set, setProperties, helper, and string functions (#8297) --- .../admin/components/secret-value-list.js.es6 | 3 ++- .../admin/controllers/admin-user-index.js.es6 | 3 ++- .../admin/controllers/admin.js.es6 | 3 ++- .../modals/admin-install-theme.js.es6 | 3 ++- .../admin/helpers/disposition-icon.js.es6 | 3 ++- .../admin/helpers/post-action-title.js.es6 | 4 +++- .../discourse-common/lib/helpers.js.es6 | 7 ++++--- .../discourse-common/resolver.js.es6 | 10 ++++----- app/assets/javascripts/discourse-loader.js | 21 +++++++++++++++++-- .../discourse/adapters/post.js.es6 | 3 ++- .../discourse/adapters/rest.js.es6 | 7 ++++--- .../discourse/components/cdn-img.js.es6 | 3 ++- .../components/group-flair-inputs.js.es6 | 3 ++- .../discourse/components/mount-widget.js.es6 | 3 ++- .../components/reviewable-item.js.es6 | 6 ++++-- .../components/user-card-contents.js.es6 | 3 ++- .../controllers/discovery/categories.js.es6 | 3 ++- .../controllers/edit-topic-timer.js.es6 | 3 ++- .../discourse/controllers/user.js.es6 | 3 ++- .../discourse/helpers/dasherize.js.es6 | 4 +++- .../discourse/helpers/editable-value.js.es6 | 4 +++- .../subscribe-user-notifications.js.es6 | 3 ++- .../discourse/lib/show-modal.js.es6 | 4 +++- .../discourse/models/composer.js.es6 | 3 ++- .../javascripts/discourse/models/store.js.es6 | 12 ++++++----- .../widgets/component-connector.js.es6 | 6 ++++-- .../discourse/widgets/connector.js.es6 | 5 +++-- .../components/composer-actions.js.es6 | 6 ++++-- .../components/wizard-field-image.js.es6 | 3 ++- .../wizard/components/wizard-field.js.es6 | 7 ++++--- .../wizard/components/wizard-step.js.es6 | 3 ++- 31 files changed, 103 insertions(+), 51 deletions(-) diff --git a/app/assets/javascripts/admin/components/secret-value-list.js.es6 b/app/assets/javascripts/admin/components/secret-value-list.js.es6 index 1822ba196a..4327f62f80 100644 --- a/app/assets/javascripts/admin/components/secret-value-list.js.es6 +++ b/app/assets/javascripts/admin/components/secret-value-list.js.es6 @@ -1,6 +1,7 @@ import { isEmpty } from "@ember/utils"; import Component from "@ember/component"; import { on } from "ember-addons/ember-computed-decorators"; +import { set } from "@ember/object"; export default Component.extend({ classNameBindings: [":value-list", ":secret-value-list"], @@ -67,7 +68,7 @@ export default Component.extend({ _replaceValue(index, newValue, keyName) { let item = this.collection[index]; - Ember.set(item, keyName, newValue); + set(item, keyName, newValue); this._saveValues(); }, diff --git a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 index 47a54b8ebf..de2e37668f 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 @@ -8,6 +8,7 @@ import { userPath } from "discourse/lib/url"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { fmt } from "discourse/lib/computed"; +import { htmlSafe } from "@ember/template"; export default Controller.extend(CanCheckEmails, { adminTools: service(), @@ -47,7 +48,7 @@ export default Controller.extend(CanCheckEmails, { automaticGroups(automaticGroups) { return automaticGroups .map(group => { - const name = Ember.String.htmlSafe(group.name); + const name = htmlSafe(group.name); return `${name}`; }) .join(", "); diff --git a/app/assets/javascripts/admin/controllers/admin.js.es6 b/app/assets/javascripts/admin/controllers/admin.js.es6 index c615169380..f01a898b0c 100644 --- a/app/assets/javascripts/admin/controllers/admin.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin.js.es6 @@ -1,6 +1,7 @@ import { inject as service } from "@ember/service"; import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; +import { dasherize } from "@ember/string"; export default Controller.extend({ router: service(), @@ -27,7 +28,7 @@ export default Controller.extend({ segment !== "admin" ); }) - .map(Ember.String.dasherize) + .map(dasherize) .join(" "); // this is done to avoid breaking css customizations diff --git a/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 index 949353de7d..81055d733d 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 @@ -10,6 +10,7 @@ import { } from "ember-addons/ember-computed-decorators"; import { THEMES, COMPONENTS } from "admin/models/theme"; import { POPULAR_THEMES } from "discourse-common/helpers/popular-themes"; +import { set } from "@ember/object"; const MIN_NAME_LENGTH = 4; @@ -46,7 +47,7 @@ export default Controller.extend(ModalFunctionality, { themes(installedThemes) { return POPULAR_THEMES.map(t => { if (installedThemes.includes(t.name)) { - Ember.set(t, "installed", true); + set(t, "installed", true); } return t; }); diff --git a/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 b/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 index 2a2440a294..0e1ea29a27 100644 --- a/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 +++ b/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 @@ -1,6 +1,7 @@ import { iconHTML } from "discourse-common/lib/icon-library"; +import Helper from "@ember/component/helper"; -export default Ember.Helper.extend({ +export default Helper.extend({ compute([disposition]) { if (!disposition) { return null; diff --git a/app/assets/javascripts/admin/helpers/post-action-title.js.es6 b/app/assets/javascripts/admin/helpers/post-action-title.js.es6 index 5ce437bf4a..657aee2e9b 100644 --- a/app/assets/javascripts/admin/helpers/post-action-title.js.es6 +++ b/app/assets/javascripts/admin/helpers/post-action-title.js.es6 @@ -1,3 +1,5 @@ +import Helper from "@ember/component/helper"; + function postActionTitle([id, nameKey]) { let title = I18n.t(`admin.flags.short_names.${nameKey}`, { defaultValue: null @@ -11,4 +13,4 @@ function postActionTitle([id, nameKey]) { return title; } -export default Ember.Helper.helper(postActionTitle); +export default Helper.helper(postActionTitle); diff --git a/app/assets/javascripts/discourse-common/lib/helpers.js.es6 b/app/assets/javascripts/discourse-common/lib/helpers.js.es6 index 17bdee941d..5b7d4fdc81 100644 --- a/app/assets/javascripts/discourse-common/lib/helpers.js.es6 +++ b/app/assets/javascripts/discourse-common/lib/helpers.js.es6 @@ -1,4 +1,5 @@ import { get } from "@ember/object"; +import Helper from "@ember/component/helper"; export function makeArray(obj) { if (obj === null || obj === undefined) { @@ -8,7 +9,7 @@ export function makeArray(obj) { } export function htmlHelper(fn) { - return Ember.Helper.helper(function(...args) { + return Helper.helper(function(...args) { args = args.length > 1 ? args[0].concat({ hash: args[args.length - 1] }) : args; return new Handlebars.SafeString(fn.apply(this, args) || ""); @@ -29,7 +30,7 @@ function rawGet(ctx, property, options) { } export function registerHelper(name, fn) { - _helpers[name] = Ember.Helper.helper(fn); + _helpers[name] = Helper.helper(fn); } export function findHelper(name) { @@ -84,7 +85,7 @@ export function registerUnbound(name, fn) { return fn.call(this, ...properties, resolveParams(this, options)); }; - _helpers[name] = Ember.Helper.extend({ + _helpers[name] = Helper.extend({ compute: (params, args) => fn(...params, args) }); Handlebars.registerHelper(name, func); diff --git a/app/assets/javascripts/discourse-common/resolver.js.es6 b/app/assets/javascripts/discourse-common/resolver.js.es6 index e03a9d7ed7..e1507406bb 100644 --- a/app/assets/javascripts/discourse-common/resolver.js.es6 +++ b/app/assets/javascripts/discourse-common/resolver.js.es6 @@ -1,9 +1,7 @@ import { findHelper } from "discourse-common/lib/helpers"; import { get } from "@ember/object"; import deprecated from "discourse-common/lib/deprecated"; - -/* global requirejs, require */ -var classify = Ember.String.classify; +import { classify, dasherize } from "@ember/string"; const _options = {}; @@ -63,7 +61,7 @@ export function buildResolver(baseName) { split[1] = split[1].replace(".templates", "").replace("/templates", ""); // Try slashes - let dashed = Ember.String.dasherize(split[1].replace(/\./g, "/")); + let dashed = dasherize(split[1].replace(/\./g, "/")); if ( requirejs.entries[appBase + dashed] || requirejs.entries[adminBase + dashed] @@ -72,7 +70,7 @@ export function buildResolver(baseName) { } // Try with dashes instead of slashes - dashed = Ember.String.dasherize(split[1].replace(/\./g, "-")); + dashed = dasherize(split[1].replace(/\./g, "-")); if ( requirejs.entries[appBase + dashed] || requirejs.entries[adminBase + dashed] @@ -86,7 +84,7 @@ export function buildResolver(baseName) { customResolve(parsedName) { // If we end with the name we want, use it. This allows us to define components within plugins. const suffix = parsedName.type + "s/" + parsedName.fullNameWithoutType, - dashed = Ember.String.dasherize(suffix), + dashed = dasherize(suffix), moduleName = Object.keys(requirejs.entries).find(function(e) { return ( e.indexOf(suffix, e.length - suffix.length) !== -1 || diff --git a/app/assets/javascripts/discourse-loader.js b/app/assets/javascripts/discourse-loader.js index 21034aa75a..5052771e91 100644 --- a/app/assets/javascripts/discourse-loader.js +++ b/app/assets/javascripts/discourse-loader.js @@ -14,7 +14,9 @@ var define, requirejs; "@ember/object": { default: Ember.Object, get: Ember.get, - getProperties: Ember.getProperties + getProperties: Ember.getProperties, + set: Ember.set, + setProperties: Ember.setProperties }, "@ember/object/computed": { default: Ember.computed, @@ -78,8 +80,23 @@ var define, requirejs; Promise: Ember.RSVP.Promise, hash: Ember.RSVP.hash, all: Ember.RSVP.all + }, + "@ember/string": { + dasherize: Ember.String.dasherize, + classify: Ember.String.classify, + underscore: Ember.String.underscore, + camelize: Ember.String.camelize + }, + "@ember/template": { + htmlSafe: Ember.String.htmlSafe + }, + "@ember/application": { + setOwner: Ember.setOwner, + getOwner: Ember.getOwner + }, + "@ember/component/helper": { + default: Ember.Helper } - }; } diff --git a/app/assets/javascripts/discourse/adapters/post.js.es6 b/app/assets/javascripts/discourse/adapters/post.js.es6 index 5c3268daaa..950198067e 100644 --- a/app/assets/javascripts/discourse/adapters/post.js.es6 +++ b/app/assets/javascripts/discourse/adapters/post.js.es6 @@ -1,6 +1,7 @@ import { ajax } from "discourse/lib/ajax"; import RestAdapter from "discourse/adapters/rest"; import { Result } from "discourse/adapters/rest"; +import { underscore } from "@ember/string"; export default RestAdapter.extend({ find(store, type, findArgs) { @@ -10,7 +11,7 @@ export default RestAdapter.extend({ }, createRecord(store, type, args) { - const typeField = Ember.String.underscore(type); + const typeField = underscore(type); args.nested_post = true; return ajax(this.pathFor(store, type), { method: "POST", data: args }).then( function(json) { diff --git a/app/assets/javascripts/discourse/adapters/rest.js.es6 b/app/assets/javascripts/discourse/adapters/rest.js.es6 index 5ace5dc40b..bc2839985f 100644 --- a/app/assets/javascripts/discourse/adapters/rest.js.es6 +++ b/app/assets/javascripts/discourse/adapters/rest.js.es6 @@ -1,6 +1,7 @@ import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import { hashString } from "discourse/lib/hash"; +import { underscore } from "@ember/string"; const ADMIN_MODELS = [ "plugin", @@ -66,7 +67,7 @@ export default EmberObject.extend({ pathFor(store, type, findArgs) { let path = this.basePath(store, type, findArgs) + - Ember.String.underscore(store.pluralize(this.apiNameFor(type))); + underscore(store.pluralize(this.apiNameFor(type))); return this.appendQueryParams(path, findArgs); }, @@ -108,7 +109,7 @@ export default EmberObject.extend({ update(store, type, id, attrs) { const data = {}; - const typeField = Ember.String.underscore(this.apiNameFor(type)); + const typeField = underscore(this.apiNameFor(type)); data[typeField] = attrs; return ajax( @@ -121,7 +122,7 @@ export default EmberObject.extend({ createRecord(store, type, attrs) { const data = {}; - const typeField = Ember.String.underscore(this.apiNameFor(type)); + const typeField = underscore(this.apiNameFor(type)); data[typeField] = attrs; return ajax(this.pathFor(store, type), this.getPayload("POST", data)).then( function(json) { diff --git a/app/assets/javascripts/discourse/components/cdn-img.js.es6 b/app/assets/javascripts/discourse/components/cdn-img.js.es6 index 5b261e5640..338c71a1ee 100644 --- a/app/assets/javascripts/discourse/components/cdn-img.js.es6 +++ b/app/assets/javascripts/discourse/components/cdn-img.js.es6 @@ -1,5 +1,6 @@ import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; +import { htmlSafe } from "@ember/template"; export default Component.extend({ tagName: "", @@ -12,7 +13,7 @@ export default Component.extend({ @computed("width", "height") style(width, height) { if (width && height) { - return Ember.String.htmlSafe(`--aspect-ratio: ${width / height};`); + return htmlSafe(`--aspect-ratio: ${width / height};`); } } }); diff --git a/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 b/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 index a190ffda1d..7b2b7110a0 100644 --- a/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 +++ b/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 @@ -5,6 +5,7 @@ import { observes } from "ember-addons/ember-computed-decorators"; import { escapeExpression } from "discourse/lib/utilities"; import { convertIconClass } from "discourse-common/lib/icon-library"; import { ajax } from "discourse/lib/ajax"; +import { htmlSafe } from "@ember/template"; export default Component.extend({ classNames: ["group-flair-inputs"], @@ -77,7 +78,7 @@ export default Component.extend({ if (flairHexColor) style += `color: #${flairHexColor};`; - return Ember.String.htmlSafe(style); + return htmlSafe(style); }, @computed("model.flairBackgroundHexColor") diff --git a/app/assets/javascripts/discourse/components/mount-widget.js.es6 b/app/assets/javascripts/discourse/components/mount-widget.js.es6 index 1363750b81..e62b7acab3 100644 --- a/app/assets/javascripts/discourse/components/mount-widget.js.es6 +++ b/app/assets/javascripts/discourse/components/mount-widget.js.es6 @@ -6,6 +6,7 @@ import { WidgetClickHook } from "discourse/widgets/hooks"; import { queryRegistry } from "discourse/widgets/widget"; import { getRegister } from "discourse-common/lib/get-owner"; import DirtyKeys from "discourse/lib/dirty-keys"; +import { camelize } from "@ember/string"; let _cleanCallbacks = {}; export function addWidgetCleanCallback(widgetName, fn) { @@ -80,7 +81,7 @@ export default Component.extend({ afterPatch() {}, eventDispatched(eventName, key, refreshArg) { - const onRefresh = Ember.String.camelize(eventName.replace(/:/, "-")); + const onRefresh = camelize(eventName.replace(/:/, "-")); this.dirtyKeys.keyDirty(key, { onRefresh, refreshArg }); this.queueRerender(); }, diff --git a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 index 23f3b53479..c5aaba8b7b 100644 --- a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 @@ -5,6 +5,8 @@ import computed from "ember-addons/ember-computed-decorators"; import Category from "discourse/models/category"; import optionalService from "discourse/lib/optional-service"; import showModal from "discourse/lib/show-modal"; +import { dasherize } from "@ember/string"; +import { set } from "@ember/object"; let _components = {}; @@ -65,7 +67,7 @@ export default Component.extend({ return _components[type]; } - let dasherized = Ember.String.dasherize(type); + let dasherized = dasherize(type); let templatePath = `components/${dasherized}`; let template = Ember.TEMPLATES[`${templatePath}`] || @@ -185,7 +187,7 @@ export default Component.extend({ }, valueChanged(fieldId, event) { - Ember.set(this._updates, fieldId, event.target.value); + set(this._updates, fieldId, event.target.value); }, perform(action) { diff --git a/app/assets/javascripts/discourse/components/user-card-contents.js.es6 b/app/assets/javascripts/discourse/components/user-card-contents.js.es6 index 1416d39bc4..d7c6eac785 100644 --- a/app/assets/javascripts/discourse/components/user-card-contents.js.es6 +++ b/app/assets/javascripts/discourse/components/user-card-contents.js.es6 @@ -13,6 +13,7 @@ import CanCheckEmails from "discourse/mixins/can-check-emails"; import CardContentsBase from "discourse/mixins/card-contents-base"; import CleansUp from "discourse/mixins/cleans-up"; import { prioritizeNameInUx } from "discourse/lib/settings"; +import { set } from "@ember/object"; export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, { elementId: "user-card", @@ -76,7 +77,7 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, { .filterBy("show_on_user_card", true) .sortBy("position") .map(field => { - Ember.set(field, "dasherized_name", field.get("name").dasherize()); + set(field, "dasherized_name", field.get("name").dasherize()); const value = userFields ? userFields[field.get("id")] : null; return isEmpty(value) ? null : EmberObject.create({ value, field }); }) diff --git a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 index 66532a9952..81542214ef 100644 --- a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 @@ -2,6 +2,7 @@ import { reads } from "@ember/object/computed"; import { inject } from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import DiscoveryController from "discourse/controllers/discovery"; +import { dasherize } from "@ember/string"; const subcategoryStyleComponentNames = { rows: "categories_only", @@ -44,7 +45,7 @@ export default DiscoveryController.extend({ parentCategory && style === "categories_and_latest_topics" ? "categories_only" : style; - return Ember.String.dasherize(componentName); + return dasherize(componentName); }, actions: { refresh() { diff --git a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 index 88a9109d02..7dc26c632c 100644 --- a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 @@ -4,6 +4,7 @@ import { default as computed } from "ember-addons/ember-computed-decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import TopicTimer from "discourse/models/topic-timer"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { setProperties } from "@ember/object"; export const CLOSE_STATUS_TYPE = "close"; export const OPEN_STATUS_TYPE = "open"; @@ -78,7 +79,7 @@ export default Controller.extend(ModalFunctionality, { if (time) { this.send("closeModal"); - Ember.setProperties(this.topicTimer, { + setProperties(this.topicTimer, { execute_at: result.execute_at, duration: result.duration, category_id: result.category_id diff --git a/app/assets/javascripts/discourse/controllers/user.js.es6 b/app/assets/javascripts/discourse/controllers/user.js.es6 index ac48062e8c..e24bf67a68 100644 --- a/app/assets/javascripts/discourse/controllers/user.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user.js.es6 @@ -9,6 +9,7 @@ import computed from "ember-addons/ember-computed-decorators"; import User from "discourse/models/user"; import optionalService from "discourse/lib/optional-service"; import { prioritizeNameInUx } from "discourse/lib/settings"; +import { set } from "@ember/object"; export default Controller.extend(CanCheckEmails, { indexStream: false, @@ -115,7 +116,7 @@ export default Controller.extend(CanCheckEmails, { .filterBy("show_on_profile", true) .sortBy("position") .map(field => { - Ember.set(field, "dasherized_name", field.get("name").dasherize()); + set(field, "dasherized_name", field.get("name").dasherize()); const value = userFields ? userFields[field.get("id").toString()] : null; diff --git a/app/assets/javascripts/discourse/helpers/dasherize.js.es6 b/app/assets/javascripts/discourse/helpers/dasherize.js.es6 index b824006169..ce9aaed3af 100644 --- a/app/assets/javascripts/discourse/helpers/dasherize.js.es6 +++ b/app/assets/javascripts/discourse/helpers/dasherize.js.es6 @@ -1,5 +1,7 @@ +import Helper from "@ember/component/helper"; + function dasherize([value]) { return (value || "").replace(".", "-").dasherize(); } -export default Ember.Helper.helper(dasherize); +export default Helper.helper(dasherize); diff --git a/app/assets/javascripts/discourse/helpers/editable-value.js.es6 b/app/assets/javascripts/discourse/helpers/editable-value.js.es6 index 131973c0b3..ae67cedf5e 100644 --- a/app/assets/javascripts/discourse/helpers/editable-value.js.es6 +++ b/app/assets/javascripts/discourse/helpers/editable-value.js.es6 @@ -1,4 +1,6 @@ import { get } from "@ember/object"; +import Helper from "@ember/component/helper"; + export function formatCurrency([reviewable, fieldId]) { // The field `category_id` corresponds to `category` if (fieldId === "category_id") { @@ -15,4 +17,4 @@ export function formatCurrency([reviewable, fieldId]) { return value; } -export default Ember.Helper.helper(formatCurrency); +export default Helper.helper(formatCurrency); diff --git a/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 b/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 index 2de97db037..c79a94ceaf 100644 --- a/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 +++ b/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 @@ -11,6 +11,7 @@ import { unsubscribe as unsubscribePushNotifications, isPushNotificationsEnabled } from "discourse/lib/push-notifications"; +import { set } from "@ember/object"; export default { name: "subscribe-user-notifications", @@ -120,7 +121,7 @@ export default { }); bus.subscribe("/client_settings", data => - Ember.set(siteSettings, data.name, data.value) + set(siteSettings, data.name, data.value) ); bus.subscribe("/refresh_client", data => Discourse.set("assetVersion", data) diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index 8cf5a2b0be..968f1e399d 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -1,3 +1,5 @@ +import { dasherize } from "@ember/string"; + export default function(name, opts) { opts = opts || {}; const container = Discourse.__container__; @@ -13,7 +15,7 @@ export default function(name, opts) { modalController.set("name", controllerName); let controller = container.lookup("controller:" + controllerName); - const templateName = opts.templateName || Ember.String.dasherize(name); + const templateName = opts.templateName || dasherize(name); const renderArgs = { into: "modal", outlet: "modalBody" }; if (controller) { diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index 3648107d6f..8e3a1af259 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -18,6 +18,7 @@ import { escapeExpression, tinyAvatar } from "discourse/lib/utilities"; import { propertyNotEqual } from "discourse/lib/computed"; import throttle from "discourse/lib/throttle"; import { Promise } from "rsvp"; +import { set } from "@ember/object"; // The actions the composer can take export const CREATE_TOPIC = "createTopic", @@ -859,7 +860,7 @@ const Composer = RestModel.extend({ Object.keys(serializer).forEach(f => { const val = this.get(serializer[f]); if (typeof val !== "undefined") { - Ember.set(dest, f, val); + set(dest, f, val); } }); return dest; diff --git a/app/assets/javascripts/discourse/models/store.js.es6 b/app/assets/javascripts/discourse/models/store.js.es6 index 3160fff6f5..3f5116e611 100644 --- a/app/assets/javascripts/discourse/models/store.js.es6 +++ b/app/assets/javascripts/discourse/models/store.js.es6 @@ -3,6 +3,8 @@ import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import ResultSet from "discourse/models/result-set"; import { getRegister } from "discourse-common/lib/get-owner"; +import { underscore } from "@ember/string"; +import { set } from "@ember/object"; let _identityMap; @@ -96,7 +98,7 @@ export default EmberObject.extend({ const apiName = this.adapterFor(type).apiNameFor(type); return this._hydrate( type, - result[Ember.String.underscore(apiName)], + result[underscore(apiName)], result ); } @@ -154,7 +156,7 @@ export default EmberObject.extend({ refreshResults(resultSet, type, url) { const adapter = this.adapterFor(type); return ajax(url).then(result => { - const typeName = Ember.String.underscore( + const typeName = underscore( this.pluralize(adapter.apiNameFor(type)) ); const content = result[typeName].map(obj => @@ -167,7 +169,7 @@ export default EmberObject.extend({ appendResults(resultSet, type, url) { const adapter = this.adapterFor(type); return ajax(url).then(result => { - const typeName = Ember.String.underscore( + const typeName = underscore( this.pluralize(adapter.apiNameFor(type)) ); @@ -223,7 +225,7 @@ export default EmberObject.extend({ _resultSet(type, result, findArgs) { const adapter = this.adapterFor(type); - const typeName = Ember.String.underscore( + const typeName = underscore( this.pluralize(adapter.apiNameFor(type)) ); const content = result[typeName].map(obj => @@ -327,7 +329,7 @@ export default EmberObject.extend({ obj[subType] = hydrated; delete obj[k]; } else { - Ember.set(obj, subType, null); + set(obj, subType, null); } } } diff --git a/app/assets/javascripts/discourse/widgets/component-connector.js.es6 b/app/assets/javascripts/discourse/widgets/component-connector.js.es6 index 44eabe7c03..d5d9213cf2 100644 --- a/app/assets/javascripts/discourse/widgets/component-connector.js.es6 +++ b/app/assets/javascripts/discourse/widgets/component-connector.js.es6 @@ -1,4 +1,6 @@ import { next } from "@ember/runloop"; +import { setOwner, getOwner } from '@ember/application'; + export default class ComponentConnector { constructor(widget, componentName, opts, trackedProperties) { this.widget = widget; @@ -27,8 +29,8 @@ export default class ComponentConnector { view._compute(); } - if (Ember.setOwner) { - Ember.setOwner(view, Ember.getOwner(mounted)); + if (setOwner) { + setOwner(view, getOwner(mounted)); } mounted._connected.push(view); diff --git a/app/assets/javascripts/discourse/widgets/connector.js.es6 b/app/assets/javascripts/discourse/widgets/connector.js.es6 index d5d1c98f3d..e3c0d9b628 100644 --- a/app/assets/javascripts/discourse/widgets/connector.js.es6 +++ b/app/assets/javascripts/discourse/widgets/connector.js.es6 @@ -1,5 +1,6 @@ import { next } from "@ember/runloop"; import deprecated from "discourse-common/lib/deprecated"; +import { setOwner, getOwner } from "@ember/application"; export default class Connector { constructor(widget, opts) { @@ -52,8 +53,8 @@ export default class Connector { } if (view) { - if (Ember.setOwner) { - Ember.setOwner(view, Ember.getOwner(mounted)); + if (setOwner) { + setOwner(view, getOwner(mounted)); } mounted._connected.push(view); view.renderer.appendTo(view, $elem[0]); diff --git a/app/assets/javascripts/select-kit/components/composer-actions.js.es6 b/app/assets/javascripts/select-kit/components/composer-actions.js.es6 index 328fad5da9..98b1d06410 100644 --- a/app/assets/javascripts/select-kit/components/composer-actions.js.es6 +++ b/app/assets/javascripts/select-kit/components/composer-actions.js.es6 @@ -7,6 +7,8 @@ import { REPLY, EDIT } from "discourse/models/composer"; +import { camelize } from "@ember/string"; +import { empty } from "@ember/object/computed"; // Component can get destroyed and lose state let _topicSnapshot = null; @@ -26,7 +28,7 @@ export default DropdownSelectBoxComponent.extend({ allowInitialValueMutation: false, allowAutoSelectFirst: false, showFullTitle: false, - isHidden: Ember.computed.empty("content"), + isHidden: empty("content"), didReceiveAttrs() { this._super(...arguments); @@ -292,7 +294,7 @@ export default DropdownSelectBoxComponent.extend({ actions: { onSelect(value) { - let action = `${Ember.String.camelize(value)}Selected`; + let action = `${camelize(value)}Selected`; if (this[action]) { let model = this.composerModel; this[action]( diff --git a/app/assets/javascripts/wizard/components/wizard-field-image.js.es6 b/app/assets/javascripts/wizard/components/wizard-field-image.js.es6 index f2022c3ec7..a407bd5046 100644 --- a/app/assets/javascripts/wizard/components/wizard-field-image.js.es6 +++ b/app/assets/javascripts/wizard/components/wizard-field-image.js.es6 @@ -3,6 +3,7 @@ import getUrl from "discourse-common/lib/get-url"; import computed from "ember-addons/ember-computed-decorators"; import { getToken } from "wizard/lib/ajax"; import { getOwner } from "discourse-common/lib/get-owner"; +import { dasherize } from "@ember/string"; export default Component.extend({ classNames: ["wizard-image-row"], @@ -10,7 +11,7 @@ export default Component.extend({ @computed("field.id") previewComponent(id) { - const componentName = `image-preview-${Ember.String.dasherize(id)}`; + const componentName = `image-preview-${dasherize(id)}`; const exists = getOwner(this).lookup(`component:${componentName}`); return exists ? componentName : "wizard-image-preview"; }, diff --git a/app/assets/javascripts/wizard/components/wizard-field.js.es6 b/app/assets/javascripts/wizard/components/wizard-field.js.es6 index f3f7e80523..b0b9d889c9 100644 --- a/app/assets/javascripts/wizard/components/wizard-field.js.es6 +++ b/app/assets/javascripts/wizard/components/wizard-field.js.es6 @@ -1,19 +1,20 @@ import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; +import { dasherize } from "@ember/string"; export default Component.extend({ classNameBindings: [":wizard-field", "typeClass", "field.invalid"], @computed("field.type") - typeClass: type => `${Ember.String.dasherize(type)}-field`, + typeClass: type => `${dasherize(type)}-field`, @computed("field.id") - fieldClass: id => `field-${Ember.String.dasherize(id)} wizard-focusable`, + fieldClass: id => `field-${dasherize(id)} wizard-focusable`, @computed("field.type", "field.id") inputComponentName(type, id) { return type === "component" - ? Ember.String.dasherize(id) + ? dasherize(id) : `wizard-field-${type}`; } }); diff --git a/app/assets/javascripts/wizard/components/wizard-step.js.es6 b/app/assets/javascripts/wizard/components/wizard-step.js.es6 index 1d034d1c47..a1a3372473 100644 --- a/app/assets/javascripts/wizard/components/wizard-step.js.es6 +++ b/app/assets/javascripts/wizard/components/wizard-step.js.es6 @@ -5,6 +5,7 @@ import { default as computed, observes } from "ember-addons/ember-computed-decorators"; +import { htmlSafe } from "@ember/template"; jQuery.fn.wiggle = function(times, duration) { if (times > 0) { @@ -89,7 +90,7 @@ export default Component.extend({ ratio = 1; } - return Ember.String.htmlSafe(`width: ${ratio * 200}px`); + return htmlSafe(`width: ${ratio * 200}px`); }, autoFocus() { From ca14e3d83c7901c49539fbbe7aa85df1b50926e0 Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Tue, 5 Nov 2019 13:32:43 -0600 Subject: [PATCH 320/328] FIX: Build with prettier for imports (#8298) --- .../javascripts/discourse/models/store.js.es6 | 18 ++++-------------- .../widgets/component-connector.js.es6 | 2 +- .../wizard/components/wizard-field.js.es6 | 4 +--- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/app/assets/javascripts/discourse/models/store.js.es6 b/app/assets/javascripts/discourse/models/store.js.es6 index 3f5116e611..39a5ce1434 100644 --- a/app/assets/javascripts/discourse/models/store.js.es6 +++ b/app/assets/javascripts/discourse/models/store.js.es6 @@ -96,11 +96,7 @@ export default EmberObject.extend({ return this._resultSet(type, result, findArgs); } else { const apiName = this.adapterFor(type).apiNameFor(type); - return this._hydrate( - type, - result[underscore(apiName)], - result - ); + return this._hydrate(type, result[underscore(apiName)], result); } }, @@ -156,9 +152,7 @@ export default EmberObject.extend({ refreshResults(resultSet, type, url) { const adapter = this.adapterFor(type); return ajax(url).then(result => { - const typeName = underscore( - this.pluralize(adapter.apiNameFor(type)) - ); + const typeName = underscore(this.pluralize(adapter.apiNameFor(type))); const content = result[typeName].map(obj => this._hydrate(type, obj, result) ); @@ -169,9 +163,7 @@ export default EmberObject.extend({ appendResults(resultSet, type, url) { const adapter = this.adapterFor(type); return ajax(url).then(result => { - const typeName = underscore( - this.pluralize(adapter.apiNameFor(type)) - ); + const typeName = underscore(this.pluralize(adapter.apiNameFor(type))); let pageTarget = result.meta || result; let totalRows = @@ -225,9 +217,7 @@ export default EmberObject.extend({ _resultSet(type, result, findArgs) { const adapter = this.adapterFor(type); - const typeName = underscore( - this.pluralize(adapter.apiNameFor(type)) - ); + const typeName = underscore(this.pluralize(adapter.apiNameFor(type))); const content = result[typeName].map(obj => this._hydrate(type, obj, result) ); diff --git a/app/assets/javascripts/discourse/widgets/component-connector.js.es6 b/app/assets/javascripts/discourse/widgets/component-connector.js.es6 index d5d9213cf2..db53cc314f 100644 --- a/app/assets/javascripts/discourse/widgets/component-connector.js.es6 +++ b/app/assets/javascripts/discourse/widgets/component-connector.js.es6 @@ -1,5 +1,5 @@ import { next } from "@ember/runloop"; -import { setOwner, getOwner } from '@ember/application'; +import { setOwner, getOwner } from "@ember/application"; export default class ComponentConnector { constructor(widget, componentName, opts, trackedProperties) { diff --git a/app/assets/javascripts/wizard/components/wizard-field.js.es6 b/app/assets/javascripts/wizard/components/wizard-field.js.es6 index b0b9d889c9..7636eee0d0 100644 --- a/app/assets/javascripts/wizard/components/wizard-field.js.es6 +++ b/app/assets/javascripts/wizard/components/wizard-field.js.es6 @@ -13,8 +13,6 @@ export default Component.extend({ @computed("field.type", "field.id") inputComponentName(type, id) { - return type === "component" - ? dasherize(id) - : `wizard-field-${type}`; + return type === "component" ? dasherize(id) : `wizard-field-${type}`; } }); From 59241df25179023089d506b84e7f647452a4521e Mon Sep 17 00:00:00 2001 From: Daniel Waterworth Date: Tue, 5 Nov 2019 20:06:47 +0000 Subject: [PATCH 321/328] FIX: Display tags topic list correctly when none is selected for subcategories --- .../discourse/pre-initializers/dynamic-route-builders.js.es6 | 4 ++++ app/assets/javascripts/discourse/routes/app-route-map.js.es6 | 4 ++++ app/assets/javascripts/discourse/routes/tags-show.js.es6 | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 index a8de4fc07d..ecb018fe65 100644 --- a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 +++ b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 @@ -95,6 +95,7 @@ export default { }); app["TagsShowCategoryRoute"] = TagsShowRoute.extend(); + app["TagsShowCategoryNoneRoute"] = TagsShowRoute.extend({ noSubcategories: true }); app["TagsShowParentCategoryRoute"] = TagsShowRoute.extend(); site.get("filters").forEach(function(filter) { @@ -104,6 +105,9 @@ export default { app[ "TagsShowCategory" + filter.capitalize() + "Route" ] = TagsShowRoute.extend({ navMode: filter }); + app[ + "TagsShowNoneCategory" + filter.capitalize() + "Route" + ] = TagsShowRoute.extend({ navMode: filter, noSubcategories: true }); app[ "TagsShowParentCategory" + filter.capitalize() + "Route" ] = TagsShowRoute.extend({ navMode: filter }); diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index 2bc476425c..1da84b4047 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -199,6 +199,7 @@ export default function() { this.route("tags", { resetNamespace: true }, function() { this.route("show", { path: "/:tag_id" }); this.route("showCategory", { path: "/c/:category/:tag_id" }); + this.route("showCategoryNone", { path: "/c/:category/none/:tag_id" }); this.route("showParentCategory", { path: "/c/:parent_category/:category/:tag_id" }); @@ -210,6 +211,9 @@ export default function() { this.route("showCategory" + filter.capitalize(), { path: "/c/:category/:tag_id/l/" + filter }); + this.route("showCategoryNone" + filter.capitalize(), { + path: "/c/:category/:tag_id/l/" + filter + }); this.route("showParentCategory" + filter.capitalize(), { path: "/c/:parent_category/:category/:tag_id/l/" + filter }); diff --git a/app/assets/javascripts/discourse/routes/tags-show.js.es6 b/app/assets/javascripts/discourse/routes/tags-show.js.es6 index 7bf26e26a9..c718cc75ff 100644 --- a/app/assets/javascripts/discourse/routes/tags-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/tags-show.js.es6 @@ -85,6 +85,8 @@ export default DiscourseRoute.extend({ ); if (parentCategorySlug) { filter = `tags/c/${parentCategorySlug}/${categorySlug}/${tagId}/l/${topicFilter}`; + } else if (this.noSubcategories) { + filter = `tags/c/${categorySlug}/none/${tagId}/l/${topicFilter}`; } else { filter = `tags/c/${categorySlug}/${tagId}/l/${topicFilter}`; } @@ -162,7 +164,8 @@ export default DiscourseRoute.extend({ category: this.category, filterMode: this.filterMode, navMode: this.navMode, - tagNotification: this.tagNotification + tagNotification: this.tagNotification, + noSubcategories: this.noSubcategories }); }, From e3b7f0791648043a9d4278fbcd26cc14f2dc41b3 Mon Sep 17 00:00:00 2001 From: Daniel Waterworth Date: Tue, 5 Nov 2019 22:30:23 +0000 Subject: [PATCH 322/328] DEV: Run prettier --- .../discourse/pre-initializers/dynamic-route-builders.js.es6 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 index ecb018fe65..55f4fee1d9 100644 --- a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 +++ b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 @@ -95,7 +95,9 @@ export default { }); app["TagsShowCategoryRoute"] = TagsShowRoute.extend(); - app["TagsShowCategoryNoneRoute"] = TagsShowRoute.extend({ noSubcategories: true }); + app["TagsShowCategoryNoneRoute"] = TagsShowRoute.extend({ + noSubcategories: true + }); app["TagsShowParentCategoryRoute"] = TagsShowRoute.extend(); site.get("filters").forEach(function(filter) { From 5ad0dd0c2349a7ff0537d5b74a692b8c3c67ab21 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Wed, 6 Nov 2019 17:05:33 +1100 Subject: [PATCH 323/328] FIX: tweak restorer spec to make it stableish (#8300) --- spec/lib/backup_restore/restorer_spec.rb | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/spec/lib/backup_restore/restorer_spec.rb b/spec/lib/backup_restore/restorer_spec.rb index fb13bcafd6..2990be9052 100644 --- a/spec/lib/backup_restore/restorer_spec.rb +++ b/spec/lib/backup_restore/restorer_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' # Causes flakiness -xdescribe BackupRestore::Restorer do +describe BackupRestore::Restorer do it 'detects which pg_dump output is restorable to different schemas' do { "9.6.7" => true, @@ -106,22 +106,21 @@ xdescribe BackupRestore::Restorer do let!(:admin) { Fabricate(:admin) } before do SiteSetting.allow_restore = true - @restore_path = File.join(Rails.root, 'public', 'backups', RailsMultisite::ConnectionManagement.current_db) described_class.any_instance.stubs(ensure_we_have_a_filename: true) described_class.any_instance.stubs(initialize_state: true) end + after do - ActiveRecord::Base.clear_all_connections! - Rails.configuration.multisite = false - RailsMultisite::ConnectionManagement.clear_settings! - ActiveRecord::Base.establish_connection + SiteSetting.allow_restore = false + described_class.any_instance.unstub(:ensure_we_have_a_filename) + described_class.any_instance.unstub(:initialize_state) end + let(:conn) { RailsMultisite::ConnectionManagement } let(:restorer) { described_class.new(admin.id) } - it 'correctly reconnects to database' do + it 'correctly reconnects to database', type: :multisite do restorer.instance_variable_set(:@current_db, 'second') - conn.config_filename = "spec/fixtures/multisite/two_dbs.yml" conn.establish_connection(db: 'second') expect(RailsMultisite::ConnectionManagement.current_db).to eq('second') ActiveRecord::Base.connection_pool.spec.config[:db_key] = "incorrect_db" @@ -129,7 +128,7 @@ xdescribe BackupRestore::Restorer do expect(RailsMultisite::ConnectionManagement.current_db).to eq('second') end - it 'it is not erroring for non multisite' do + it 'it is not erroring for non multisite', type: :multisite do RailsMultisite::ConnectionManagement::clear_settings! expect { restorer.send(:reconnect_database) }.not_to raise_error end From b869ef8a7648a677adc19ecb720869ce0fafa041 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Wed, 6 Nov 2019 15:26:46 +0530 Subject: [PATCH 324/328] FIX: add alt attribute for Summary emails --- app/views/user_notifications/digest.html.erb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/views/user_notifications/digest.html.erb b/app/views/user_notifications/digest.html.erb index fc187f6d48..ed0a0e3edd 100644 --- a/app/views/user_notifications/digest.html.erb +++ b/app/views/user_notifications/digest.html.erb @@ -125,7 +125,7 @@ - + <%= t.user.username -%> <% if t.user %> @@ -137,7 +137,7 @@ <%- if show_image_with_url(t.image_url) && t.featured_link.nil? && !(@excerpts[t.first_post&.id]||"").include?(t.image_url) -%> - + topic image <%- end -%> @@ -160,17 +160,17 @@ - + likes

<%= t.like_count -%>

- + replies

<%= t.posts_count - 1 -%>

<% t.posters_summary.each do |ps| %> <% if ps.user %> - + <%= ps.user.username -%> <% end %> <% end %> @@ -243,7 +243,7 @@ - + @@ -253,7 +253,7 @@ - + <%= post.user.username -%> <% if post.user %> @@ -323,16 +323,16 @@ <% t.posters_summary[0,2].each do |ps| %> <% if ps.user %> - + <%= ps.user.username -%> <% end %> <% end %> - + likes

<%= t.like_count -%>

- + replies

<%= t.posts_count - 1 -%>

From 0dfc5947843eb126eeb05a7ecec531665e4b4bb1 Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Wed, 6 Nov 2019 10:32:15 -0500 Subject: [PATCH 325/328] FIX: skip invalid URLs when checking for audio/video in search blurbs Fixes 500 errors on search queries introduced in 580a4a8 --- lib/search/grouped_search_results.rb | 14 ++++++++------ spec/lib/search_spec.rb | 9 ++++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/search/grouped_search_results.rb b/lib/search/grouped_search_results.rb index 88538f02ed..f523901887 100644 --- a/lib/search/grouped_search_results.rb +++ b/lib/search/grouped_search_results.rb @@ -78,13 +78,15 @@ class Search urls = Set.new cooked.scan(URI.regexp(%w{http https})) { urls << $& } - urls.each do |url| - case File.extname(URI(url).path || "") - when Oneboxer::VIDEO_REGEX - cooked.gsub!(url, I18n.t("search.video")) - when Oneboxer::AUDIO_REGEX - cooked.gsub!(url, I18n.t("search.audio")) + begin + case File.extname(URI(url).path || "") + when Oneboxer::VIDEO_REGEX + cooked.gsub!(url, I18n.t("search.video")) + when Oneboxer::AUDIO_REGEX + cooked.gsub!(url, I18n.t("search.audio")) + end + rescue URI::InvalidURIError end end diff --git a/spec/lib/search_spec.rb b/spec/lib/search_spec.rb index c3aaa88130..7b81e27306 100644 --- a/spec/lib/search_spec.rb +++ b/spec/lib/search_spec.rb @@ -28,7 +28,7 @@ describe Search do expect(result).to eq("link to an external page: https://google.com/?u=bar link to an audio file: #{I18n.t("search.audio")} link to a video file: #{I18n.t("search.video")}") end - it "strips URLs correctly when blurb is" do + it "strips URLs correctly when blurb is longer than limit" do cooked = <<~RAW Here goes a test cooked with enough characters to hit the blurb limit. @@ -41,6 +41,13 @@ describe Search do expect(result).to eq("Here goes a test cooked with enough characters to hit the blurb limit. Something is very interesting about this audio file. #{I18n.t("search.audio")}") end + it "does not fail on bad URLs" do + cooked = <<~RAW + invalid URL: http:error] should not trip up blurb generation. + RAW + result = Search::GroupedSearchResults.blurb_for(cooked) + expect(result).to eq("invalid URL: http:error] should not trip up blurb generation.") + end end end From b151963f189137c0f4297ed8b724b8a538445278 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Wed, 6 Nov 2019 10:43:13 -0500 Subject: [PATCH 326/328] Update translations --- config/locales/client.ar.yml | 9 +-- config/locales/client.be.yml | 8 +-- config/locales/client.bg.yml | 9 +-- config/locales/client.bs_BA.yml | 9 +-- config/locales/client.ca.yml | 18 +++-- config/locales/client.cs.yml | 9 +-- config/locales/client.da.yml | 9 +-- config/locales/client.de.yml | 10 ++- config/locales/client.el.yml | 9 +-- config/locales/client.es.yml | 12 ++-- config/locales/client.et.yml | 9 +-- config/locales/client.fa_IR.yml | 9 +-- config/locales/client.fi.yml | 9 +-- config/locales/client.fr.yml | 13 ++-- config/locales/client.gl.yml | 9 +-- config/locales/client.he.yml | 29 ++++++-- config/locales/client.hu.yml | 9 +-- config/locales/client.hy.yml | 10 ++- config/locales/client.id.yml | 1 + config/locales/client.it.yml | 72 +++++++++++++++++-- config/locales/client.ja.yml | 8 +-- config/locales/client.ko.yml | 9 +-- config/locales/client.lt.yml | 9 +-- config/locales/client.lv.yml | 9 +-- config/locales/client.nb_NO.yml | 9 +-- config/locales/client.nl.yml | 29 ++++++-- config/locales/client.pl_PL.yml | 9 +-- config/locales/client.pt.yml | 9 +-- config/locales/client.pt_BR.yml | 10 ++- config/locales/client.ro.yml | 9 +-- config/locales/client.ru.yml | 18 +++-- config/locales/client.sk.yml | 9 +-- config/locales/client.sl.yml | 6 +- config/locales/client.sq.yml | 9 +-- config/locales/client.sr.yml | 9 +-- config/locales/client.sv.yml | 10 ++- config/locales/client.sw.yml | 7 +- config/locales/client.te.yml | 9 +-- config/locales/client.th.yml | 4 +- config/locales/client.tr_TR.yml | 9 +-- config/locales/client.uk.yml | 29 ++++++-- config/locales/client.ur.yml | 9 +-- config/locales/client.vi.yml | 9 +-- config/locales/client.zh_CN.yml | 9 +-- config/locales/client.zh_TW.yml | 9 +-- config/locales/server.ca.yml | 9 +++ config/locales/server.es.yml | 9 --- config/locales/server.he.yml | 19 +++-- config/locales/server.it.yml | 1 + config/locales/server.nl.yml | 3 + config/locales/server.uk.yml | 16 ++++- config/locales/server.zh_CN.yml | 3 - .../config/locales/server.ar.yml | 2 +- .../config/locales/server.bs_BA.yml | 2 +- .../config/locales/server.ca.yml | 2 +- .../config/locales/server.da.yml | 2 +- .../config/locales/server.de.yml | 2 +- .../config/locales/server.es.yml | 2 +- .../config/locales/server.fa_IR.yml | 2 +- .../config/locales/server.fi.yml | 2 +- .../config/locales/server.fr.yml | 2 +- .../config/locales/server.gl.yml | 2 +- .../config/locales/server.he.yml | 2 +- .../config/locales/server.hu.yml | 2 +- .../config/locales/server.hy.yml | 2 +- .../config/locales/server.id.yml | 2 +- .../config/locales/server.it.yml | 2 +- .../config/locales/server.ja.yml | 2 +- .../config/locales/server.ko.yml | 2 +- .../config/locales/server.lt.yml | 2 +- .../config/locales/server.nb_NO.yml | 2 +- .../config/locales/server.nl.yml | 2 +- .../config/locales/server.pl_PL.yml | 2 +- .../config/locales/server.pt_BR.yml | 2 +- .../config/locales/server.ru.yml | 2 +- .../config/locales/server.sk.yml | 2 +- .../config/locales/server.sl.yml | 2 +- .../config/locales/server.sw.yml | 2 +- .../config/locales/server.uk.yml | 2 +- .../config/locales/server.ur.yml | 2 +- .../config/locales/server.zh_CN.yml | 2 +- .../config/locales/server.ar.yml | 4 +- .../config/locales/server.bs_BA.yml | 4 +- .../config/locales/server.ca.yml | 4 +- .../config/locales/server.cs.yml | 4 +- .../config/locales/server.da.yml | 4 +- .../config/locales/server.de.yml | 4 +- .../config/locales/server.el.yml | 2 +- .../config/locales/server.es.yml | 4 +- .../config/locales/server.fa_IR.yml | 2 +- .../config/locales/server.fi.yml | 4 +- .../config/locales/server.fr.yml | 4 +- .../config/locales/server.he.yml | 4 +- .../config/locales/server.hu.yml | 4 +- .../config/locales/server.hy.yml | 4 +- .../config/locales/server.it.yml | 4 +- .../config/locales/server.ko.yml | 4 +- .../config/locales/server.nb_NO.yml | 4 +- .../config/locales/server.nl.yml | 4 +- .../config/locales/server.pl_PL.yml | 4 +- .../config/locales/server.pt.yml | 4 +- .../config/locales/server.pt_BR.yml | 4 +- .../config/locales/server.ro.yml | 4 +- .../config/locales/server.ru.yml | 4 +- .../config/locales/server.sk.yml | 4 +- .../config/locales/server.sl.yml | 4 +- .../config/locales/server.sr.yml | 2 +- .../config/locales/server.sw.yml | 4 +- .../config/locales/server.uk.yml | 4 +- .../config/locales/server.ur.yml | 4 +- .../config/locales/server.vi.yml | 2 +- .../config/locales/server.zh_CN.yml | 4 +- 112 files changed, 407 insertions(+), 364 deletions(-) diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml index d67bb0eee5..1444b1e9b1 100644 --- a/config/locales/client.ar.yml +++ b/config/locales/client.ar.yml @@ -2643,16 +2643,13 @@ ar: none: "لا مفاتيح API نشطة حاليًّا." user: "الاعضاء" title: "API" - key: "مفتاح API" created: أُنشئ في generate: "إنشاء" - regenerate: "إعادة إنشاء" revoke: "الغاء" - confirm_regen: "أمتأكّد من استبدال مفتاح API هذا بواحد جديد؟" - confirm_revoke: "هل أنت متأكد من رغبتك في تعطيل هذا المفتاح؟" - info_html: "مفتاح API الخاص بك سيسمح لك بانشاء أو تعديل مواضيع باستخدام أليات رسائل JSON." all_users: "جميع الاعضاء" - note_html: "حافظ على سرية هذا المفتاح، اي شخص يحصل عليه يستطيع انشاء مواضيع باسم اي مستخدم اخر" + show_details: تفاصيل + description: الوصف + save: احفظ web_hooks: title: "Webhooks" none: "لا يوجد Webhooks حاليا." diff --git a/config/locales/client.be.yml b/config/locales/client.be.yml index 505e4c549a..4899a14964 100644 --- a/config/locales/client.be.yml +++ b/config/locales/client.be.yml @@ -1262,15 +1262,13 @@ be: none: "Пакуль няма ніводнага актыўнага ключа API." user: "Карыстальнік" title: "API" - key: "ключ API" created: створаны generate: "згенераваць" - regenerate: "перегенерировать" revoke: "ануляваць" - confirm_regen: "Are you sure you want to replace that API Key with a new one?" - confirm_revoke: "Are you sure you want to revoke that key?" - info_html: "Your API key will allow you to create and update topics using JSON calls." all_users: "All Users" + show_details: дэталі + description: апісанне + save: Захаваць web_hooks: create: "стварыць" save: "стварыць..." diff --git a/config/locales/client.bg.yml b/config/locales/client.bg.yml index dbb35f2d83..f121a3d606 100644 --- a/config/locales/client.bg.yml +++ b/config/locales/client.bg.yml @@ -2100,16 +2100,13 @@ bg: none: "Няма активни API ключове в момента." user: "Потребител" title: "API" - key: "API ключ" created: Създадени generate: "Генраирай" - regenerate: "Регенерирай" revoke: "Анулирай" - confirm_regen: "Сигурни ли сте, че искате да замените текущия API ключ с нов ? " - confirm_revoke: "Сигурни ли сте, че искате да анулирате този ключ? " - info_html: "Вашият API ключ ще ви разреши да създавате и обновявате темите чрез JSON извиквания. " all_users: "Всички потребители" - note_html: "Запазете този ключ secret, всички потребители които го имат ще може да правят публикации от всеки потребител. " + show_details: "Детайли " + description: Описание + save: Запази web_hooks: save: "Запази" destroy: "Изтрий" diff --git a/config/locales/client.bs_BA.yml b/config/locales/client.bs_BA.yml index 27bee3090d..4cbce93054 100644 --- a/config/locales/client.bs_BA.yml +++ b/config/locales/client.bs_BA.yml @@ -3054,16 +3054,13 @@ bs_BA: none: "There are no active API keys right now." user: "User" title: "API" - key: "API Key" created: Kreiran generate: "Generate" - regenerate: "Regenerate" revoke: "Revoke" - confirm_regen: "Are you sure you want to replace that API Key with a new one?" - confirm_revoke: "Are you sure you want to revoke that key?" - info_html: "Your API key will allow you to create and update topics using JSON calls." all_users: "All Users" - note_html: "Keep this key secret, all users that have it may create arbitrary posts as any user." + show_details: Detalji + description: Opis + save: Sačuvaj web_hooks: title: "Webhooks" none: "Trenutno nema web-hookova." diff --git a/config/locales/client.ca.yml b/config/locales/client.ca.yml index 411bc22d88..ab9f00ae02 100644 --- a/config/locales/client.ca.yml +++ b/config/locales/client.ca.yml @@ -2381,6 +2381,7 @@ ca: tag_groups_placeholder: "Llista (opcional) d'etiquetes de grup permeses" manage_tag_groups_link: "Gestioneu els grups d'etiquetes aquí." allow_global_tags_label: "Permet també altres etiquetes" + tag_group_selector_placeholder: "(Opcional) Grup d’etiquetes" topic_featured_link_allowed: "Permet enllaços destacats dins aquesta categoria" delete: "Suprimeix categoria" create: "Nova categoria" @@ -3046,18 +3047,23 @@ ca: none: "No hi ha claus API actives ara mateix" user: "Usuari" title: "API" - key: "Clau API" created: Creat + updated: Actualitzat last_used: Darrer utilitzat never_used: (mai) generate: "Genera" - regenerate: "Regenera" + undo_revoke: "Desfés revocar" revoke: "Revoca" - confirm_regen: "Esteu segur que voleu reemplaçar aquesta clau API amb una de nova?" - confirm_revoke: "Esteu segur que voleu revocar aquesta clau?" - info_html: "La clau API us permetrà crear i actualitzar temes fent servir crides JSON." all_users: "Tots els usuaris" - note_html: "Conserveu aquesta clau secreta. Tots els usuaris que la tinguin podrien crear publicacions arbitràries en nom de qualsevol usuari." + show_details: Detalls + description: Descripció + no_description: (sense descripció) + all_api_keys: Totes les claus de l'API + user_mode: Nivell d’usuari + description_placeholder: "Per a què es farà servir aquesta clau?" + save: Desa + new_key: Nova clau d’API + revoked: Revocat web_hooks: title: "Webhooks" none: "Ara no hi ha webhooks." diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index 94466288b1..c987e863d9 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -2783,16 +2783,13 @@ cs: none: "Nejsou tu žádné aktivní API klíče." user: "Uživatel" title: "API" - key: "API klíč" created: Vytvořený generate: "Vygenerovat API klíč" - regenerate: "Znovu-vygenerovat API klíč" revoke: "zrušit" - confirm_regen: "Určitě chcete nahradit tenhle API klíč novým?" - confirm_revoke: "Jste si jisti, že chcete tento klíč zrušit?" - info_html: "Váš API klíč umožní vytvářet a aktualizovat témata pomocí JSONových volání." all_users: "Všichni uživatelé" - note_html: "Uchovejte tento klíč v bezpečí, každý, kdo má tento klíč, může libovolně vytvářet příspěvky na fóru i za ostatní uživatele." + show_details: Podrobnosti + description: Popis + save: Uložit web_hooks: title: "Webhooks" none: "Právě tu nejsou žádné webhooks." diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index e80b35d6ce..b03690fb4e 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -3011,16 +3011,13 @@ da: none: "Der er ingen aktive API-nøgler i øjeblikket." user: "Bruger" title: "API" - key: "API-nøgle" created: Oprettet generate: "Generér" - regenerate: "Regenerér" revoke: "Tilbagekald" - confirm_regen: "Er du sikker på, at du ønsker at erstatte API-nøglen med en ny?" - confirm_revoke: "Er du sikker på, at du ønsker at tilbagekalde nøglen?" - info_html: "Din API-nøgle giver dig mulighed for at oprette og opdatere emner vha. JSON-kald." all_users: "Alle brugere" - note_html: "Hold denne nøgle hemmelig, alle brugere som har den kan oprette vilkårlige indlæg, som enhver bruger." + show_details: Detaljer + description: Beskrivelse + save: Gem web_hooks: title: "Webhooks" none: "Der er ingen webhooks i øjeblikket" diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index ee9597f2a6..fa1060f539 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -3038,16 +3038,14 @@ de: none: "Es gibt momentan keine aktiven API-Keys" user: "Benutzer" title: "API" - key: "API-Key" created: Erstellt + updated: Aktualisiert generate: "Erzeugen" - regenerate: "Erneuern" revoke: "Widerrufen" - confirm_regen: "Möchtest du wirklich den API Key mit einem neuen ersetzen?" - confirm_revoke: "Möchtest du wirklich den API Key widerrufen?" - info_html: "Dein API-Key erlaubt dir das Erstellen und Bearbeiten von Themen via JSON-Aufrufen." all_users: "Alle Benutzer" - note_html: "Halte diesen Schlüssel geheim. Alle Benutzer, die diesen Schlüssel besitzen, können beliebige Beiträge als jeder Benutzer erstellen." + show_details: Details + description: Beschreibung + save: Speichern web_hooks: title: "Webhooks" none: "Aktuell gibt es keine Webhooks." diff --git a/config/locales/client.el.yml b/config/locales/client.el.yml index 6fa51098a3..fc302bd0e3 100644 --- a/config/locales/client.el.yml +++ b/config/locales/client.el.yml @@ -2318,16 +2318,13 @@ el: none: "Δεν υπάρχουν ενεργά κλειδιά API αυτή την στιγμή." user: "Χρήστης" title: "API" - key: "API Key" created: Δημιουργήθηκε generate: "Δημιουργία" - regenerate: "Αναδημιουγία" revoke: "Ανάκληση" - confirm_regen: "Θέλεις να αντικαταστήσεις το API Key με ένα καινούργιο;" - confirm_revoke: "Θέλεις σίγουρα να ανακαλέσεις το API Key;" - info_html: "Το API Key σου δίνει τη δυνατότητα να δημιουργήσεις και να επεξεργαστείς νήματα μέσω κλήσεων JSON." all_users: "Όλοι οι χρήστες" - note_html: "Κράτα αυτό το κλειδί κρυφό. Όλοι οι χρήστες που το κατέχουν μπορούν να δημιουργήσουν αναρτήσεις υποδυόμενοι οποιονδήποτε χρήστη χωρίς κανέναν περιορισμό." + show_details: Λεπτομέρειες + description: Περιγραφή + save: Αποθήκευση web_hooks: title: "Webhooks" none: "Δεν υπάρχουν Webhooks αυτή τη στιγμή." diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index 6342a134bf..d3508bdb2f 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -2387,7 +2387,7 @@ es: allow_global_tags_label: "Permitir también otras etiquetas" tag_group_selector_placeholder: "(Opcional) Grupo de etiquetas" required_tag_group_description: "Requiere temas nuevos para tener etiquetas de un grupo de etiquetas:" - min_tags_from_required_group_label: 'Número de etiquetas:' + min_tags_from_required_group_label: "Número de etiquetas:" required_tag_group_label: "Grupo de etiquetas:" topic_featured_link_allowed: "Permitir enlaces destacados en esta categoría" delete: "Eliminar categoría" @@ -3055,18 +3055,16 @@ es: none: "No hay ninguna clave de API activa en este momento." user: "Usuario" title: "API" - key: "Clave de API" created: Creado + updated: Actualizado last_used: Usada por última vez never_used: (nunca) generate: "Generar clave de API" - regenerate: "Regenerar" revoke: "Revocar" - confirm_regen: "¿Estás seguro de que quieres reemplazar esta clave de API por una nueva?" - confirm_revoke: "¿Estás seguro de que quieres revocar esta clave?" - info_html: "Tu clave de API te permitirá crear y actualizar temas usando llamadas a JSON." all_users: "Todos los usuarios" - note_html: "Mantén esta clave secreta a buen recaudo, cualquier usuario que disponga de ella podría realizar publicaciones bajo el nombre de cualquier usuario." + show_details: Detalles + description: Descripción + save: Guardar web_hooks: title: "Webhooks" none: "Ahora mismo no hay webhooks." diff --git a/config/locales/client.et.yml b/config/locales/client.et.yml index 148f9b3da5..56db2d5300 100644 --- a/config/locales/client.et.yml +++ b/config/locales/client.et.yml @@ -2393,16 +2393,13 @@ et: none: "Hetkel aktiivsed API võtmed puuduvad." user: "Kasutaja" title: "API" - key: "API võti" created: Loodud generate: "Genereeri" - regenerate: "Genereeri uus" revoke: "Tühista " - confirm_regen: "Oled kindel, et soovid selle API võtme asendada uuega?" - confirm_revoke: "Oled kindel, et soovid selle võtme tühistada?" - info_html: "See API võti lubab Sul teemasid luua ja uuendada JSON kutsete kaudu." all_users: "Kõik kasutajad" - note_html: "Hoia seda võtit salajas, iga kasutaja, kes seda omab, võib luua suvalisi postitusi suvalise kasutaja nime alt." + show_details: Üksikasjad + description: Kirjeldus + save: Salvesta web_hooks: title: "Veebihaagid" none: "Hetkel veebihaagid puuduvad." diff --git a/config/locales/client.fa_IR.yml b/config/locales/client.fa_IR.yml index 75a9cce7fe..c1be6cf0e9 100644 --- a/config/locales/client.fa_IR.yml +++ b/config/locales/client.fa_IR.yml @@ -2936,16 +2936,13 @@ fa_IR: none: "هم اکنون هیچ کلید API فعالی وجود ندارد" user: "کاربر" title: "API" - key: "کلید API" created: ساخته شده generate: "تولید کردن" - regenerate: "ایجاد مجدد" revoke: "ابطال" - confirm_regen: "آیا می خواهید API موجود را با یک API جدید جایگزین کنید؟" - confirm_revoke: "آیا مطمئن هستید که می خواهید کلید را برگردانید؟" - info_html: "موضوعات تازه پس از آخرین بازدید شما" all_users: "همه کاربران" - note_html: "این کلید را امن نگه دارید، تمام کاربرانی که آن را دارند می توانند به عنوان هر کاربری نوشته‌های دلخواه ایجاد کنند." + show_details: جزئیات + description: توضیح + save: ذخیره web_hooks: title: "webhook ها" none: "در حال حاضر webhook‌ی وجود ندارد" diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index 1ef57f2a5c..631a7a9e7f 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -3045,18 +3045,15 @@ fi: none: "Aktiivisia API avaimia ei ole määritelty." user: "Käyttäjä" title: "Rajapinta" - key: "Rajapinnan avain" created: Luotu last_used: Viimeksi käytetty never_used: (ei koskaan) generate: "Luo" - regenerate: "Tee uusi" revoke: "Peruuta" - confirm_regen: "Oletko varma, että haluat korvata tämän API avaimen uudella?" - confirm_revoke: "Oletko varma, että haluat peruuttaa tämän avaimen?" - info_html: "Rajapinta-avaimen avulla voi aloittaa ja päivittää ketjuja JSON-pyynnöillä." all_users: "Kaikki käyttäjät" - note_html: "Pidä tämä avain salaisena, sen haltija voi luoda viestejä esiintyen minä hyvänsä käyttäjänä." + show_details: Yksityiskohdat + description: Kuvaus + save: Tallenna web_hooks: title: "Webhookit" none: "Webhookeja ei ole nyt." diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index 41b88a8ba5..fd0fcfb40d 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -2368,7 +2368,7 @@ fr: manage_tag_groups_link: "Gérer les groupes d'étiquettes ici." allow_global_tags_label: "Permettre aussi d'autres étiquettes" tag_group_selector_placeholder: "(Facultatif) Groupe d'étiquettes" - min_tags_from_required_group_label: 'Nombre d''étiquettes :' + min_tags_from_required_group_label: "Nombre d'étiquettes :" required_tag_group_label: "Groupe d'étiquettes :" topic_featured_link_allowed: "Autoriser les liens à la une dans cette catégorie" delete: "Supprimer la catégorie" @@ -3048,18 +3048,17 @@ fr: none: "Il n'y a pas de clés API actives en ce moment." user: "Utilisateur" title: "API" - key: "Clé API" + key: "Clé" created: Créé + updated: Mis à jour last_used: Dernière utilisation never_used: (jamais) generate: "Générer" - regenerate: "Regénérer" revoke: "Révoquer" - confirm_regen: "Êtes-vous sûr de vouloir remplacer cette clé API par une nouvelle ?" - confirm_revoke: "Êtes-vous sûr de vouloir révoquer cette clé ?" - info_html: "Cette clé vous permettra de créer et mettre à jour des sujets à l'aide d'appels JSON." all_users: "Tous les utilisateurs" - note_html: "Gardez cette clé secrète. Tous les utilisateurs qui la possèdent peuvent créer des messages au nom de n'importe quel utilisateur." + show_details: Détails + description: Description + save: Sauvegarder web_hooks: title: "Webhooks" none: "Il n'y a aucun Webhook actuellement." diff --git a/config/locales/client.gl.yml b/config/locales/client.gl.yml index a6027b46fd..bbdb734339 100644 --- a/config/locales/client.gl.yml +++ b/config/locales/client.gl.yml @@ -1777,16 +1777,13 @@ gl: none: "Non hai chaves activas da API agora mesmo." user: "Usuario" title: "API" - key: "Chave da API" created: Creado generate: "Xerar" - regenerate: "Rexenerar" revoke: "Revogar" - confirm_regen: "Confirmas a substitución da chave da API por unha nova?" - confirm_revoke: "Confirmas a revogación desta chave?" - info_html: "A chave da API permitirache crear e actualizar temas usando chamadas JSON." all_users: "Todos os usuarios" - note_html: "Manter esta chave en secreto, todos os usuarios que a teñan poderían crear e publicar co nome da calquera usuario." + show_details: Detalles + description: Descrición + save: Gardar web_hooks: save: "Gardar" destroy: "Eliminar" diff --git a/config/locales/client.he.yml b/config/locales/client.he.yml index 2bfcec5a12..141406dc21 100644 --- a/config/locales/client.he.yml +++ b/config/locales/client.he.yml @@ -2569,7 +2569,7 @@ he: allow_global_tags_label: "לאפשר גם תגיות אחרות" tag_group_selector_placeholder: "(רשות) קבוצת תגיות" required_tag_group_description: "לדרוש שלנושאים חדשים יהיו תגיות מקבוצת תגיות:" - min_tags_from_required_group_label: 'מס׳ תגיות:' + min_tags_from_required_group_label: "מס׳ תגיות:" required_tag_group_label: "קבוצת תגיות:" topic_featured_link_allowed: "אפשרו קישורים מומלצים בקטגוריה זו" delete: "מחק קטגוריה" @@ -3283,18 +3283,30 @@ he: none: "אין מפתחות API פעילים כרגע." user: "משתמש" title: "API" - key: "מפתח API" + key: "מפתח" created: נוצר + updated: עודכן last_used: שימוש אחרון never_used: (אף פעם) generate: "ייצר" - regenerate: "ייצר מחדש" + undo_revoke: "ביטול שלילה" revoke: "שלול" - confirm_regen: "האם ברצונך להחליף את מפתח ה-API באחד חדש?" - confirm_revoke: "אתם בטוחים שברצונכם לשלול את המפתח הזה?" - info_html: "מפתח הAPI שלך יאפשר לך ליצור ולעדכן נושאים בעזרת קריאות JSON." all_users: "כל המשתמשים" - note_html: "שמרו על מפתח זה סודי, כל משתמש שיחזיק בו יוכל לייצר פרסומים שרירותית, כאילו היה כל משתמש/ת אחרים." + active_keys: "מפתחות API פעילים" + manage_keys: ניהול מפתחות + show_details: פרטים + description: תיאור + no_description: (אין תיאור) + all_api_keys: כל מפתחות ה־API + user_mode: דרגת משתמש + impersonate_all_users: התחזות לכל משתמש שהוא + single_user: "משתמש בודד" + user_placeholder: נא להקליד שם משתמש + description_placeholder: "למה ישמש המפתח הזה?" + save: שמירה + new_key: מפתח API חדש + revoked: נשל + delete: למחוק לצמיתות web_hooks: title: "Webhooks" none: "אין כרגע webhooks." @@ -3883,6 +3895,9 @@ he: change_theme_setting: "שנוי הגדרות ערכת עיצוב" disable_theme_component: "נטרול רכיב בערכת עיצוב" enable_theme_component: "הפעלת רכיב בערכת עיצוב" + api_key_create: "נוצר מפתח api" + api_key_update: "עודכן מפתח api" + api_key_destroy: "הושמד מפתח api" screened_emails: title: "הודעות דואר מסוננות" description: "כשמישהו מנסה ליצור חשבון חדש, כתובות הדואר האלקטרוני הבאות ייבדקו וההרשמה תחסם או שיבוצו פעולות אחרות." diff --git a/config/locales/client.hu.yml b/config/locales/client.hu.yml index 3d013b62da..64fb35ad9a 100644 --- a/config/locales/client.hu.yml +++ b/config/locales/client.hu.yml @@ -2465,16 +2465,13 @@ hu: none: "Jelenleg nincsenek elérhető API kulcsok." user: "Felhasználó" title: "API" - key: "API kulcs" created: Létrehozott generate: "Generálás" - regenerate: "Regenerálás" revoke: "Visszavonás" - confirm_regen: "Biztosan ki szeretnéd cserélni ezt az API kulcsot egy újra?" - confirm_revoke: "Biztosan vissza szeretnéd vonni ezt a kulcsot?" - info_html: "Az API kulcsod lehetővé fogja tenni számodra, hogy JSON hívásokkal létrehozz és frissíts témaköröket." all_users: "Minden felhasználó" - note_html: "Tartsd meg ezt a kulcsot titkos, minden felhasználó akinek megvan lehet hogy létrehoz egy korlátlan bejegyzést mint akármelyik felhasználó" + show_details: Részletek + description: Leírás + save: Mentés web_hooks: title: "Webhooks" create: "Létrehoz" diff --git a/config/locales/client.hy.yml b/config/locales/client.hy.yml index 59d8c2b194..adb01e91b1 100644 --- a/config/locales/client.hy.yml +++ b/config/locales/client.hy.yml @@ -2768,16 +2768,14 @@ hy: none: "Ակտիվ API Key այս պահին չկա:" user: "Օգտատեր" title: "API" - key: "API Key" created: Ստեղծված + updated: Թարմացված generate: "Գեներացնել" - regenerate: "Վերագեներացնել" revoke: "Հետ կանչել" - confirm_regen: "Դուք համոզվա՞ծ եք, որ ցանկանում եք փոխարինել այդ API Key-ն նորով:" - confirm_revoke: "Դուք համոզվա՞ծ եք, որ ցանկանում եք հետ կանչել այդ API Key-ն:" - info_html: "Ձեր API Key-ն թույլ կտա ստեղծել և թարմացնել թեմաներ՝ օգտագործելով JSON կանչեր:" all_users: "Բոլոր Օգտատերերը" - note_html: "Պահեք այս բանալին գաղտնի, բոլոր օգտատերերը, ովքեր ունեն այն, կարող են ստեղծել կամայական գրառումներ՝ որպես ցանկացած օգտատեր:" + show_details: Մանրամասներ + description: Նկարագրություն + save: Պահպանել web_hooks: title: "Webhook-ներ" none: "Այս պահին webhook-ներ չկան:" diff --git a/config/locales/client.id.yml b/config/locales/client.id.yml index 4f8822c2df..924724e0b8 100644 --- a/config/locales/client.id.yml +++ b/config/locales/client.id.yml @@ -1153,6 +1153,7 @@ id: api: user: "Pengguna" created: Dibuat + show_details: Detil web_hooks: destroy: "Hapus" active: "Aktif" diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index 447c309a95..b76d34c060 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -95,6 +95,12 @@ it: x_days: one: "%{count} giorno fa" other: "%{count}giorni fa" + x_months: + one: "%{count} mese fa" + other: "%{count} mesi fa" + x_years: + one: "%{count} anno fa" + other: "%{count} anni fa" later: x_days: one: "%{count} giorno dopo" @@ -225,6 +231,7 @@ it: other: "{{count}} caratteri" related_messages: title: "Messaggi correlati" + see_all: 'Vedi tutti i messaggi di @ %{username} ...' suggested_topics: title: "Argomenti Suggeriti" pm_title: "Messaggi Suggeriti" @@ -298,6 +305,8 @@ it: banner: close: "Nascondi questo annuncio." edit: "Modifica questo annuncio >>" + pwa: + install_banner: "Vuoi installare %{title} su questo dispositivo?" choose_topic: none_found: "Nessun argomento trovato." title: @@ -312,7 +321,25 @@ it: order_by: "Ordina per" in_reply_to: "in risposta a" explain: + why: "spiega perché questo oggetto è stato aggiunto alla coda" + title: "Punteggio revisionabile" + formula: "Formula" + subtotal: "Totale parziale" total: "Totale" + min_score_visibility: "Punteggio minimo per visibilità" + score_to_hide: "Punteggio per nascondere messaggio" + take_action_bonus: + name: "ha preso provvedimenti" + title: "Quando un membro dello staff sceglie intervenire, la segnalazione riceve un bonus." + user_accuracy_bonus: + name: "precisione dell'utente" + title: "Agli utenti le cui segnalazioni sono state storicamente accettate viene concesso un bonus." + trust_level_bonus: + name: "livello di esperienza" + title: "Gli articoli revisionabili creati da utenti con un livello di esperienza più elevato hanno un punteggio più alto." + type_bonus: + name: "tipo di bonus" + title: "Ad alcune tipologie revisionabili può essere assegnato un bonus dallo staff, per aumentare la loro priorità." claim_help: optional: "Puoi rivendicare questo elemento per evitare che altri lo revisionino." required: "Per poter revisionare gli elementi devi prima rivendicarli." @@ -584,6 +611,7 @@ it: remove_owner: "Rimuovi come Proprietario" remove_owner_description: "Rimuovi %{username}come proprietario di questo gruppo " owner: "Proprietario" + forbidden: "Non puoi ancora visualizzare i membri." topics: "Argomenti" posts: "Messaggi" mentions: "Menzioni" @@ -596,6 +624,7 @@ it: only_admins: "Solo gli amministratori" mods_and_admins: "Solo i moderatori e gli amministratori" members_mods_and_admins: "Solo i membri del gruppo, i moderatori e gli amministratori" + owners_mods_and_admins: "Solo proprietari di gruppi, moderatori e amministratori" everyone: "Chiunque" notifications: watching: @@ -847,14 +876,19 @@ it: disable: "Disabilita" enable: "Abilita" enable_long: "Abilita codici di backup" + manage: "Gestisci i codici di backup. Hai {{count}} codici di backup rimanenti." copied_to_clipboard: "Copiato nella Clipboard" copy_to_clipboard_error: "Errore durante la copia nella Clipboard" remaining_codes: "Ti sono rimasti {{count}} codici di backup." + use: "Usa un codice di backup" + enable_prerequisites: "È necessario abilitare un secondo fattore primario prima di generare codici di backup." codes: title: "Codici di backup generati" description: "Ciascuno di questi codici di backup può essere usato una sola volta. Conservali in un posto sicuro ma accessibile." second_factor: title: "Autenticazione a Due Fattori" + enable: "Gestione autenticazione a due fattori" + forgot_password: "Ha dimenticato la password?" confirm_password_description: "Per favore conferma la tua password per continuare" name: "Nome" label: "Codice" @@ -868,10 +902,28 @@ it: extended_description: | L'autenticazione a due fattori aggiunge ulteriore sicurezza al tuo account attraverso la richiesta di un token usa e getta oltre alla tua password. I token possono essere generati su dispositivi Android e iOS . oauth_enabled_warning: "Tieni presente che gli accessi ai social network saranno disabilitati dopo aver attivato l'autenticazione a due fattori nel tuo account." + use: "Usa l'app Authenticator" enforced_notice: "E' obbligatorio abilitare l'autenticazione a due fattori per accedere a questo sito." + disable: "disabilita" + disable_title: "Disabilita Secondo Fattore" + disable_confirm: "Sei sicuro di voler disabilitare tutti i secondi fattori?" edit: "Modifica" + edit_title: "Modifica secondo fattore" + edit_description: "Nome del secondo fattore" + enable_security_key_description: "Quando la chiave di sicurezza fisica è pronta, premi il pulsante Registra qui sotto." + totp: + title: "Authenticator basati su Token" + add: "Nuovo Authenticator" + default_name: "Il mio Authenticator" security_key: register: "Registrare" + title: "Security Keys" + add: "Registra Security Key" + default_name: "Security Key principale" + not_allowed_error: "Il processo di registrazione della Security Key è scaduto o è stato annullato." + already_added_error: "Hai già registrato questa Security Key. Non è necessario registrarla di nuovo." + edit: "Modifica Security Key" + edit_description: "Nome Security Key" delete: "Elimina" change_about: title: "Modifica i dati personali" @@ -898,6 +950,9 @@ it: uploaded_avatar_empty: "Aggiungi un'immagine personalizzata" upload_title: "Carica la tua foto" image_is_not_a_square: "Attenzione: abbiamo ritagliato l'immagine; la larghezza e l'altezza non erano uguali." + change_profile_background: + title: "Testata Profilo " + instructions: "Le testate dei profili saranno centrate e avranno una larghezza predefinita di 1110 px." change_card_background: title: "Sfondo Scheda Utente" instructions: "Le immagini di sfondo saranno centrate e per difetto avranno un'ampiezza di 590px." @@ -921,6 +976,10 @@ it: revoke: "Revoca" cancel: "Annulla" not_connected: "(non connesso)" + confirm_modal_title: "Collega un account %{provider} " + confirm_description: + account_specific: "Il tuo account %{provider} '%{account_description}' verrà utilizzato per l'autenticazione." + generic: "Il tuo account %{provider} verrà utilizzato per l'autenticazione." name: title: "Nome" instructions: "il tuo nome completo (opzionale)" @@ -1260,6 +1319,7 @@ it: complete_username_not_found: "Nessun account con nome utente %{username}" complete_email_not_found: "Nessun account con email %{email}" confirm_title: "Procedi su %{site_name}." + logging_in_as: "Accesso come %{email}" confirm_button: Completa l'accesso login: title: "Connetti" @@ -1267,8 +1327,11 @@ it: password: "Password" second_factor_title: "Autenticazione a due fattori" second_factor_description: "Per favore, inserisci il codice di autenticazione della tua app:" + second_factor_backup: "Accedi utilizzando un codice di backup" second_factor_backup_title: "Backup Due Fattori" second_factor_backup_description: "Per favore, inserisci uno dei tuoi codici di backup:" + second_factor: "Accedi utilizzando l'app Authenticator" + security_key_description: "Quando hai preparato la chiave di sicurezza fisica, premi il pulsante Autentica con Security Key qui sotto." email_placeholder: "email o nome utente" caps_lock_warning: "Il Blocco Maiuscole è attivo" error: "Errore sconosciuto" @@ -2935,16 +2998,13 @@ it: none: "Non ci sono chiavi API attive al momento." user: "Utente" title: "API" - key: "Chiave API" created: Creazione generate: "Genera" - regenerate: "Rigenera" revoke: "Revoca" - confirm_regen: "Sei sicuro di voler sostituire la API Key con una nuova?" - confirm_revoke: "Sei sicuro di revocare la chiave?" - info_html: "La tua chiave API ti permetterà di creare e aggiornare gli argomenti usando chiamate JSON." all_users: "Tutti gli Utenti" - note_html: "Mantieni segreta questa chiave, tutti gli utenti che la possiedono possono creare messaggi per conto di altri." + show_details: Dettagli + description: Descrizione + save: Salva web_hooks: title: "Webhook" none: "Non ci sono webhook disponibili adesso." diff --git a/config/locales/client.ja.yml b/config/locales/client.ja.yml index 150f3a8163..f37f11cf40 100644 --- a/config/locales/client.ja.yml +++ b/config/locales/client.ja.yml @@ -2448,13 +2448,11 @@ ja: key: "Key" created: 作成者 generate: "API キーを生成" - regenerate: "API キーを再生成" revoke: "無効化" - confirm_regen: "このAPIキーを新しいものに置き換えてもよろしいですか?" - confirm_revoke: "このキーを無効化してもよろしいですか?" - info_html: "API キーを使うと、JSON 呼び出しでトピックの作成・更新を行うことが出来ます。" all_users: "全てのユーザ" - note_html: "このキーは、秘密にしてください。このキーを持っている全てのユーザは任意のユーザとして、好きな投稿を作成できます" + show_details: 詳細 + description: 説明 + save: 保存 web_hooks: title: "Webhooks" none: "現在、Webhooksはありません。" diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index 69a1b1202d..36667d1dfa 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -2436,16 +2436,13 @@ ko: none: "지금 활성화된 API 키가 없습니다." user: "사용자" title: "API" - key: "API 키" created: 생성일자 generate: "API 키 생성" - regenerate: "API 키 재생성" revoke: "폐지" - confirm_regen: "API 키를 새로 발급 받으시겠습니까?" - confirm_revoke: "API 키를 폐지하겠습니까?" - info_html: "당신의 API 키는 JSON호출을 이용하여 토픽을 생성하거나 수정할 수 있습니다." all_users: "전체 유저" - note_html: "이 키의 보안에 특별히 주의하세요. 이 키를 아는 모든 사용자는 다른 사용자의 이름으로 글을 작성할 수 있습니다." + show_details: 세부 내용 + description: 내용 + save: 저장 web_hooks: title: "Webhook" none: "현재 webhook이 없습니다." diff --git a/config/locales/client.lt.yml b/config/locales/client.lt.yml index 6e3419fedd..9601193659 100644 --- a/config/locales/client.lt.yml +++ b/config/locales/client.lt.yml @@ -2423,16 +2423,13 @@ lt: none: "Šiuo metu nėra jokių aktyvių API raktų." user: "Vartotojas" title: "API" - key: "API raktas" created: Sukurta generate: "Generuoti" - regenerate: "Pergeneruoti" revoke: "Pašalinti" - confirm_regen: "Ar tikrai norite pakeisti šį API raktą nauju?" - confirm_revoke: "Ar tikrai norite pašalinti šį raktą?" - info_html: "Jūsų API raktas leis jums kurti ir atnaujinti temas naudojant JSON užklausas." all_users: "Visi vartotojai" - note_html: "Tai slapta funkcija, su ja gali kurti įrašus bet kokiu vardu." + show_details: Detalės + description: Aprašymas + save: Saugoti web_hooks: create: "Sukurti" save: "Saugoti" diff --git a/config/locales/client.lv.yml b/config/locales/client.lv.yml index 578aca394b..2148a4200b 100644 --- a/config/locales/client.lv.yml +++ b/config/locales/client.lv.yml @@ -2283,16 +2283,13 @@ lv: none: "Šobrīd nav aktīvu API atslēgu." user: "Lietotājs" title: "API" - key: "API atslēga" created: Radīts generate: "Radīt" - regenerate: "Atkārtoti radīt" revoke: "Atsaukt" - confirm_regen: "Vai jūs esat drošs, ka vēlaties aizstāt šo API atslēgu ar jaunu?" - confirm_revoke: "Vai jūs esat drošs, ka vēlaties atsaukt šo atslēgu?" - info_html: "Jūsu API atslēga ļaus jums izveidot un atjaunināt tēmas, izmantojot JSON izsaukumus." all_users: "Visi lietotāji" - note_html: "Saglabājiet šo atslēgu slepenu, jo ikviens lietotājs, kam tā ir zināma, var izveidot jebkādus ierakstus ar jebkuru lietotāju kā autoru." + show_details: Detaļas + description: Apraksts + save: Saglabāt web_hooks: detailed_instruction: "Ja būs signāls par izvēlēto notikumu, uz norādīto URL tiks nosūtīts POST pieprasījums." create: "Izveidot" diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index 8537a20d27..9e16295b5a 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -2634,16 +2634,13 @@ nb_NO: none: "Det finnes ingen aktive API-nøkler akkurat nå." user: "Bruker" title: "API" - key: "Nøkkel" created: Opprettet generate: "Generer API-nøkkel" - regenerate: "Regenerer API-nøkkel" revoke: "Trekk tilbake" - confirm_regen: "Er du sikker på at du vil erstatte den API-nøkkelen med en ny?" - confirm_revoke: "Er du sikker på at du vil trekke tilbake den nøkkelen?" - info_html: "API-nøkkelen din vil tillate deg å lage og oppdatere emner ved å bruke JSON-kall." all_users: "Alle brukere" - note_html: "Hold denne nøkkelen hemmelig, alle brukere som har den, vil kunne opprette vilkårlige innlegg som hvilken som helst bruker. " + show_details: Detaljer + description: Beskrivelse + save: Lagre web_hooks: title: "Webhooker" none: "Det finnes ingen webhooker for tiden." diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index b3151379da..4f54aff1e5 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -2387,7 +2387,7 @@ nl: allow_global_tags_label: "Ook andere tags toestaan" tag_group_selector_placeholder: "(Optioneel) Tag-groep" required_tag_group_description: "Nieuwe topics moeten tags hebben uit een tag-groep:" - min_tags_from_required_group_label: 'Aantal tags:' + min_tags_from_required_group_label: "Aantal tags:" required_tag_group_label: "Tag-groep:" topic_featured_link_allowed: "Aanbevolen koppelingen in deze categorie toestaan" delete: "Categorie verwijderen" @@ -3055,18 +3055,30 @@ nl: none: "Er zijn op dit moment geen actieve API-sleutels." user: "Gebruiker" title: "API" - key: "API-sleutel" + key: "Sleutel" created: Gemaakt + updated: Bijgewerkt last_used: Laatst gebruikt never_used: (nooit) generate: "Genereren" - regenerate: "Opnieuw genereren" + undo_revoke: "Intrekken ongedaan maken" revoke: "Intrekken" - confirm_regen: "Weet u zeker dat u die API-sleutel door een nieuwe wilt vervangen?" - confirm_revoke: "Weet u zeker dat u die API-sleutel wilt intrekken?" - info_html: "Met deze API-sleutel kunt u topics maken en bijwerken met behulp van JSON-aanroepen." all_users: "Alle gebruikers" - note_html: "Houd deze sleutel geheim; alle gebruikers die hierover beschikken, kunnen willekeurige berichten plaatsen als een andere gebruiker." + active_keys: "Actieve API-sleutels" + manage_keys: Sleutels beheren + show_details: Details + description: Omschrijving + no_description: (geen omschrijving) + all_api_keys: Alle API-sleutels + user_mode: Gebruikersniveau + impersonate_all_users: Een gebruiker imiteren + single_user: "Enkele gebruiker" + user_placeholder: Voer gebruikersnaam in + description_placeholder: "Waar wordt deze sleutel voor gebruikt?" + save: Opslaan + new_key: Nieuwe API-sleutel + revoked: Ingetrokken + delete: Definitief verwijderen web_hooks: title: "Webhooks" none: "Er zijn op dit moment geen webhooks." @@ -3649,6 +3661,9 @@ nl: change_theme_setting: "thema-instelling wijzigen" disable_theme_component: "themaonderdeel uitschakelen" enable_theme_component: "themaonderdeel inschakelen" + api_key_create: "api-sleutel maken" + api_key_update: "api-sleutel bijwerken" + api_key_destroy: "api-sleutel verwijderen" screened_emails: title: "Gecontroleerde e-mails" description: "Als iemand een nieuwe account probeert aan te maken, worden de volgende e-mailadressen gecontroleerd en de registratie geblokkeerd, of een andere actie uitgevoerd." diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 799c1deca8..3e61775efd 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -3054,16 +3054,13 @@ pl_PL: none: "Nie ma teraz aktywnych kluczy API." user: "Użytkownik" title: "API" - key: "Klucz API" created: Utworzono generate: "Generuj" - regenerate: "Odnów" revoke: "Unieważnij" - confirm_regen: "Czy na pewno chcesz zastąpić ten API Key nowym?" - confirm_revoke: "Czy na pewno chcesz unieważnić ten klucz?" - info_html: "Twoje klucze API dają dostęp do tworzenia i aktualizowania tenatów przez wywołania JSON." all_users: "Wszyscy użytkownicy" - note_html: "Zachowaj ten klucz w tajemnicy, wszyscy którzy go posiadają mogą tworzyć wpisy jako dowolny użytkownik." + show_details: Detale + description: Opis + save: Zapisz web_hooks: title: "Webhooks" none: "Brak webhooks" diff --git a/config/locales/client.pt.yml b/config/locales/client.pt.yml index 3d85fde9c3..e1e1c65222 100644 --- a/config/locales/client.pt.yml +++ b/config/locales/client.pt.yml @@ -2584,16 +2584,13 @@ pt: none: "Não existem chaves API ativas neste momento." user: "Utilizador" title: "API" - key: "Chave API" created: Criado generate: "Gerar" - regenerate: "Regenerar" revoke: "Revogar" - confirm_regen: "Tem a certeza que quer substituir essa chave API por uma nova?" - confirm_revoke: "Tem a certeza que quer revogar essa chave?" - info_html: "A sua chave API permitirá a criação e edição de tópicos usando pedidos JSON." all_users: "Todos os Utilizadores" - note_html: "Manter esta chave secreta, todos os utilizadores que a tenham poderão criar publicações arbitrárias como qualquer utilizador." + show_details: Detalhes + description: Descrição + save: Guardar web_hooks: title: "Webhooks" none: "Não existem webhooks neste momento." diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index 75fbd61682..b20b460230 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -2981,16 +2981,14 @@ pt_BR: none: "Não existem chaves API ativas no momento." user: "Usuário" title: "API" - key: "Chave API" + key: "Chave" created: Criado generate: "Gerar" - regenerate: "Regenerar" revoke: "Revogar" - confirm_regen: "Tem a certeza que quer substituir esta chave API por uma nova?" - confirm_revoke: "Tem a certeza que quer revogar esta chave?" - info_html: "Sua chave de API permitirá a criação e edição de tópicos usando requests JSON." all_users: "Todos os Usuários" - note_html: "Guarde esta chave secretamente, todos usuários que tiverem acesso a ela poderão criar posts arbritários no forum como qualquer usuário." + show_details: Detalhes + description: Descrição + save: Salvar web_hooks: title: "Webhooks" none: "Não existem webhooks no momento." diff --git a/config/locales/client.ro.yml b/config/locales/client.ro.yml index 025dc089bd..519f0d0fda 100644 --- a/config/locales/client.ro.yml +++ b/config/locales/client.ro.yml @@ -2477,16 +2477,13 @@ ro: none: "Nu sunt chei API principale active deocamdată." user: "Utilizator" title: "API" - key: "Cheie API" created: Creat generate: "Generare" - regenerate: "Regenerare" revoke: "Revocă" - confirm_regen: "Ești sigur că dorești să înlocuiești această cheie API cu una nouă?" - confirm_revoke: "Ești sigur că dorești să revoci această cheie?" - info_html: "Cheia ta API îți permite să creezi și să actualizezi subiecte folosind sintaxa JSON." all_users: "Toți utilizatorii" - note_html: "Păstrează această cheie secretă, toți utilizatorii ce o dețin pot crea postări arbitrare pe forum dându-se drept oricare alt utilizator." + show_details: Detalii + description: Descriere + save: Salvează web_hooks: title: "Webhooks" none: "Momentan nu există nici un webhook" diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 8869a8230e..c97588fcff 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -1030,6 +1030,9 @@ ru: uploaded_avatar_empty: "Добавить собственный аватар" upload_title: "Загрузка собственного аватара" image_is_not_a_square: "Внимание: мы обрезали ваше изображение; ширина и высота не равны друг другу." + change_profile_background: + title: "Шапка профиля" + instructions: "Шапка профиля будут отцентрирована и по-умолчанию имеют ширину 1110 пикселей." change_card_background: title: "Фон карточки пользователя" instructions: "Картинки фона будут отцентрированы и по-умолчанию имеют ширину 590 пикселей." @@ -2558,9 +2561,14 @@ ru: tags_allowed_tags: "Ограничить эти теги данной категорией:" tags_allowed_tag_groups: "Ограничьте эти группы тегов этой категорией:" tags_placeholder: "(Необязательно) список доступных тегов" + tags_tab_description: "Теги и группы тегов, указанные здесь, будут доступны только в этой категории и других категориях, в которых они также указаны. Они не будут доступны для использования в других категориях." tag_groups_placeholder: "(Необязательно) список доступных групп тегов" manage_tag_groups_link: "Управлять группами тегов здесь." allow_global_tags_label: "Также разрешить другие теги" + tag_group_selector_placeholder: "(Необязательно) Группа тегов" + required_tag_group_description: "Требовать, чтобы новые темы имели теги из группы тегов:" + min_tags_from_required_group_label: "Номер Тега:" + required_tag_group_label: "Группа тегов:" topic_featured_link_allowed: "Разрешить популярные ссылки в этой категории" delete: "Удалить раздел" create: "Создать Раздел" @@ -3070,6 +3078,7 @@ ru: parent_tag_description: "Теги из этой группы будут доступны только после добавления к теме родительского тега." one_per_topic_label: "Разрешить не более одного тега из этой группы в одной теме" new_name: "Назание новой группы" + name_placeholder: "Имя Группы Тегов" save: "Сохранить" delete: "Удалить" confirm_delete: "Вы уверены, что хотите удалить эту группу тегов?" @@ -3272,18 +3281,15 @@ ru: none: "Отсутствует ключ API." user: "Пользователь" title: "API" - key: "Ключ API" created: Создано last_used: Последнее Использование never_used: (никогда) generate: "Сгенерировать" - regenerate: "Перегенерировать" revoke: "Отозвать" - confirm_regen: "Вы уверены, что хотите заменить ключ API?" - confirm_revoke: "Вы уверены, что хотите отозвать этот ключ?" - info_html: "Ваш API ключ позволит вам создавать и обновлять темы, используя JSON calls." all_users: "Все пользователи" - note_html: "Никому не сообщайте этот ключ. Тот, у кого он есть, сможет создавать сообщения, выдавая себя за любого пользователя форума." + show_details: Детали + description: Описание + save: Сохранить web_hooks: title: "Webhooks" none: "Сейчас нет веб-перехватчиков." diff --git a/config/locales/client.sk.yml b/config/locales/client.sk.yml index c69f182e00..4ee7bc6df4 100644 --- a/config/locales/client.sk.yml +++ b/config/locales/client.sk.yml @@ -2382,16 +2382,13 @@ sk: none: "V súčasnosti neexistujú žiadne aktívne API kľúče." user: "Používateľ" title: "API" - key: "API kľúč" created: Vytvorené generate: "Generovať" - regenerate: "Obnov" revoke: "Zrušiť" - confirm_regen: "Ste si istý, že chcete nahradiť tento API kľúč novým?" - confirm_revoke: "Ste si istý, že chcete obnoviť tento kľúč?" - info_html: "Váš API kľúč Vám umožní vytváranie a aktualizovanie tém prostredníctvom volaní JSON." all_users: "Všetci používatelia" - note_html: "Držte tento kľúč v tajnosti, všetci užívatelia ktorí ho vlastnia môžu vytvárať ľubovoľné príspevky pod ľubovoľným používateľským menom. " + show_details: Detaily + description: Popis + save: Uložiť web_hooks: create: "Vytvoriť" save: "Uložiť" diff --git a/config/locales/client.sl.yml b/config/locales/client.sl.yml index 7017c65897..209e36ac1e 100644 --- a/config/locales/client.sl.yml +++ b/config/locales/client.sl.yml @@ -3138,13 +3138,13 @@ sl: generate_master: "Generiraj glavni API ključ" user: "Uporabnik" title: "API" - key: "API ključ" created: Ustvarjeno generate: "Generiraj" - regenerate: "Regeneriraj" revoke: "Prekliči" - confirm_revoke: "Ali ste prepričani da hočete preklicati ta ključ?" all_users: "Vsi uporabniki" + show_details: Podrobnosti + description: Opis + save: Shrani web_hooks: create: "Ustvari" save: "Shrani" diff --git a/config/locales/client.sq.yml b/config/locales/client.sq.yml index 62fec31079..a90b959f54 100644 --- a/config/locales/client.sq.yml +++ b/config/locales/client.sq.yml @@ -2028,16 +2028,13 @@ sq: none: "Për momentin, nuk ka çelësa API aktivë." user: "Përdorues" title: "API" - key: "API Key" created: Krijuar generate: "Gjenero" - regenerate: "Rigjenero" revoke: "Revoko" - confirm_regen: "Are you sure you want to replace that API Key with a new one?" - confirm_revoke: "Are you sure you want to revoke that key?" - info_html: "Çelësi juaj API ju lejon të krijoni dhe updejtoni tema nëpërmjet thirrjeve JSON." all_users: "Gjithë Përdoruesit" - note_html: "Mbaje këtë çelës sekret, të gjithë përdoruesit që e kanë mund të krijojnë postime me të. " + show_details: Detaje + description: Përshkrimi + save: Ruaj web_hooks: title: "Webhooks" save: "Ruaj" diff --git a/config/locales/client.sr.yml b/config/locales/client.sr.yml index a559ebb30c..f274670118 100644 --- a/config/locales/client.sr.yml +++ b/config/locales/client.sr.yml @@ -1654,16 +1654,13 @@ sr: none: "Nema aktivnih API ključeva" user: "Korisnik" title: "API" - key: "API Ključ" created: Napravljeno generate: "Generiši" - regenerate: "Regeneriši" revoke: "Povuci" - confirm_regen: "Jeste li sigurni da želite zameniti taj API ključ sa novim?" - confirm_revoke: "Jeste li sigurni da želite povući taj ključ?" - info_html: "Vaš API ključ će vam dozvoliti da otvarate i nadograđujete teme koristeći JSON pozive." all_users: "Svi korisnici" - note_html: "Čuvajte ovaj ključ tajnim, svi korisnici koji ga imaju mogu stvarati proizvoljne poruke kao bilo koji korisnici." + show_details: Detalji + description: Opis + save: Sačuvaj web_hooks: save: "Sačuvaj" destroy: "Obriši" diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index 1386d18fb6..12e9342356 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -2179,16 +2179,14 @@ sv: none: "Det finns inga aktiva API-nycklar just nu." user: "Användare" title: "API" - key: "API-nyckel" + key: "Key" created: Skapad generate: "Generera" - regenerate: "Regenerera" revoke: "Återkalla" - confirm_regen: "Är du säker på att du vill ersätta den API-nyckeln med en ny?" - confirm_revoke: "Är du säker på att du vill återkalla den nyckeln?" - info_html: "Din API-nyckel kommer tillåta dig att skapa och uppdatera ämnen med hjälp av JSON-anrop." all_users: "Alla användare" - note_html: "Håll denna nyckel hemlig, alla användare som har den kan skapa godtyckliga inlägg som alla användare." + show_details: Detaljer + description: Beskrivning + save: Spara web_hooks: title: "Webhookar" none: "Det finns inga webhookar just nu." diff --git a/config/locales/client.sw.yml b/config/locales/client.sw.yml index 9cadf45e6f..26727679fa 100644 --- a/config/locales/client.sw.yml +++ b/config/locales/client.sw.yml @@ -2437,14 +2437,13 @@ sw: none: "Hakuna funguo za API zilizo amilifu kwa sasa." user: "Mtumiaji" title: "API" - key: "Ufunguo wa API" created: Imetengenezwa generate: "Tengeneza" - regenerate: "Tengeneza Upya" revoke: "Futa" - confirm_regen: "Una uhakika unataka kufuta ufunguo wa API na kuweka mpya?" - confirm_revoke: "Una uhakika unataka kufuta huo ufunguo?" all_users: "Watumiaji Wote" + show_details: Taarifa + description: Maelezo + save: hifadhi web_hooks: create: "Tengeneza" save: "Hifadhi" diff --git a/config/locales/client.te.yml b/config/locales/client.te.yml index 4e5bd837b0..4354bc07a8 100644 --- a/config/locales/client.te.yml +++ b/config/locales/client.te.yml @@ -1399,16 +1399,13 @@ te: none: "ప్రస్తుతం చేతన ఏపీఐ కీలు లేవు." user: "సభ్యుడు" title: "ఏపీఐ" - key: "ఏపీఐ కీ" created: సృష్టించిన generate: "ఉత్పత్తించు" - regenerate: "పునరుత్పత్తించు" revoke: "రివోక్" - confirm_regen: "మీరు నిజంగా పాత ఏపీఐ కీని కొత్త దానితో రీప్లేస్ చెయ్యాలనుకుంటున్నారా?" - confirm_revoke: "మీరు నిజంగా ఆ కీని రివోకే చెయ్యాలనుకుంటున్నారా? " - info_html: "మీ ఏపీఐ కీ జేసన్ వాడి విషయాలు సృష్టించుట, ఉన్నతీకరించుటకు దోహదం చేస్తుంది." all_users: "అందరు సభ్యులు" - note_html: "ఈ కీ ని రహస్యంగా ఉంచండి , అది కలిగివున్న అందరూ వినియోగదారులు ఏ వినియోగదారునిలా నైనా ఏకపక్ష టపాలు సృష్టించవచ్చు." + show_details: వివరాలు + description: వివరణ + save: భద్రపరచు web_hooks: save: "భద్రపరచు" destroy: "తొలగించు" diff --git a/config/locales/client.th.yml b/config/locales/client.th.yml index 7ef92dd008..1e72bd7338 100644 --- a/config/locales/client.th.yml +++ b/config/locales/client.th.yml @@ -1592,9 +1592,11 @@ th: api: user: "ผู้ใช้" title: "API" - key: "API Key" created: สร้างเมื่อ revoke: "เอาออก" + show_details: รายละเอียด + description: รายละเอียด + save: บันทึก web_hooks: save: "บันทึก" destroy: "ลบ" diff --git a/config/locales/client.tr_TR.yml b/config/locales/client.tr_TR.yml index 3c44d5fe8a..97c86b0a13 100644 --- a/config/locales/client.tr_TR.yml +++ b/config/locales/client.tr_TR.yml @@ -2918,16 +2918,13 @@ tr_TR: none: "Şu an etkin API anahtarı bulunmuyor." user: "Kullanıcı" title: "API" - key: "API Anahtarı" created: Oluşturuldu generate: "Oluştur" - regenerate: "Tekrar Oluştur" revoke: "İptal Et" - confirm_regen: "API anahtarını yenisi ile değiştirmek istediğine emin misin?" - confirm_revoke: "Anahtarı iptal etmek istediğine emin misin?" - info_html: "API anahtarın JSON çağrıları kullanarak konu oluşturup güncelleyebilmene olanak sağlayacak." all_users: "Tüm Kullanıcılar" - note_html: "Bu anahtarı gizli tut, anahtara sahip kullanıcılar herhangi bir kullanıcı adı altında istedikleri gönderiyi oluşturabilirler." + show_details: Detaylar + description: Açıklama + save: Kaydet web_hooks: title: "Web Kancaları" none: "Şu anda bir web kancası yok." diff --git a/config/locales/client.uk.yml b/config/locales/client.uk.yml index 177970d1ae..a7db0a732b 100644 --- a/config/locales/client.uk.yml +++ b/config/locales/client.uk.yml @@ -2567,7 +2567,7 @@ uk: allow_global_tags_label: "Також дозволити інші мітки" tag_group_selector_placeholder: "(Необов’язково) Група тегів" required_tag_group_description: "Потрібні нові теми, щоб мати теги з групи тегів:" - min_tags_from_required_group_label: 'Кількість тегів:' + min_tags_from_required_group_label: "Кількість тегів:" required_tag_group_label: "Група тегів:" topic_featured_link_allowed: "Дозволити популярні посилання в цій категорії" delete: "Видалити категорію" @@ -3281,18 +3281,30 @@ uk: none: "Наразі немає жодного активного ключа API." user: "Користувач" title: "API" - key: "Ключ API" + key: "Ключ" created: Створено + updated: Оновлено last_used: Використано never_used: (ніколи) generate: "Згенерувати" - regenerate: "Перегенерувати" + undo_revoke: "Скасувати відкликання" revoke: "Анулювати" - confirm_regen: "Are you sure you want to replace that API Key with a new one?" - confirm_revoke: "Are you sure you want to revoke that key?" - info_html: "Your API key will allow you to create and update topics using JSON calls." all_users: "All Users" - note_html: "Нікому не повідомляйте цей ключ. Той, у кого він є, зможе створювати повідомлення, видаючи себе за будь-якого користувача форуму." + active_keys: "Активні ключі API" + manage_keys: Керування ключами + show_details: Деталі + description: Опис + no_description: (без опису) + all_api_keys: Усі ключі API + user_mode: Користувацький рівень + impersonate_all_users: Видавати себе за іншого користувача + single_user: "Один користувач" + user_placeholder: Введіть ім’я користувача + description_placeholder: "Для чого цей ключ буде використовуватися?" + save: Зберегти + new_key: Новий ключ API + revoked: Відкликано + delete: Видалити назавжди web_hooks: title: "Вебгуки" none: "Зараз вебгуків немає." @@ -3881,6 +3893,9 @@ uk: change_theme_setting: "змінити налаштування теми" disable_theme_component: "відключити компонент теми" enable_theme_component: "включити компонент теми" + api_key_create: "api ключ створено" + api_key_update: "api ключ оновлено" + api_key_destroy: "api ключ знищено" screened_emails: title: "Screened Emails" description: "Коли хтось намагатиметься створити новий обліковий запис, наступні електронні скриньки буде перевірено, і реєстрацію заблоковано, або вжито якихось інших дій." diff --git a/config/locales/client.ur.yml b/config/locales/client.ur.yml index db26618b01..2546801448 100644 --- a/config/locales/client.ur.yml +++ b/config/locales/client.ur.yml @@ -3017,16 +3017,13 @@ ur: none: "کوئی فعال API کیز اِس وقت موجود نہیں ہیں۔" user: "صارف" title: "API" - key: "API کِی" created: بنایا گیا generate: "تخلیق کریں" - regenerate: "دوبارہ تخلیق کریں" revoke: "منسوخ کریں" - confirm_regen: "کیا آپ واقعی اُس API کِی کو ایک نئی کِی سے تبدیل کرنا چاہتے ہیں؟" - confirm_revoke: "کیا آپ واقعی اُس کِی کو منسوخ کرنا چاہتے ہیں؟" - info_html: "API کِی سے آپ JSON کالز کا استعمال کرتے ہوئے ٹاپک بنانے اور اَپ ڈیٹ کرنے قابل ہو جائیں گے۔" all_users: "تمام صارفین" - note_html: "اس کِی کوخفیہ رکھیں، تمام صارفین جن کے پاس یہ ہو گی، کسی بھی صارف کے طور پر من مانی پوسٹس بنا سکتے ہیں۔ " + show_details: تفصیلات + description: تفصیل + save: محفوظ کریں web_hooks: title: "وَیب ھُوک٘س٘" none: "اِس وقت کوئی وَیب ھُوک٘س٘ نہیں ہیں۔" diff --git a/config/locales/client.vi.yml b/config/locales/client.vi.yml index 485576cfc5..8fdb04c863 100644 --- a/config/locales/client.vi.yml +++ b/config/locales/client.vi.yml @@ -2270,16 +2270,13 @@ vi: none: "Không có API keys nào kích hoạt lúc này." user: "Thành viên" title: "API" - key: "API Key" created: Tạo bởi generate: "Khởi tạo" - regenerate: "Khởi tạo lại" revoke: "Thu hồi" - confirm_regen: "Bạn muốn thay API Key hiện tại bằng cái mới?" - confirm_revoke: "Bạn có chắc chắn muốn hủy bỏ khóa đó?" - info_html: "Khóa API cho phép bạn tạo và cập nhật chủ đề sử dụng JSON." all_users: "Tất cả Thành viên" - note_html: "Giữ khóa nào bảo mật, tất cả tài khoản có thể dùng khóa này để tạo bài viết với bất kỳ tài khoản nào." + show_details: Chi tiết + description: Mô tả + save: Lưu web_hooks: save: "Lưu" destroy: "Xóa" diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index 6dff96bc0f..aaad2a4296 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -2912,16 +2912,13 @@ zh_CN: none: "当前没有可用的 API 密钥。" user: "用户" title: "API" - key: "API 密钥" created: 创建时间 generate: "生成" - regenerate: "重新生成" revoke: "撤销" - confirm_regen: "确定要用新的 API 密钥替代该密钥?" - confirm_revoke: "确定要撤销该密钥?" - info_html: "API 密钥可以用来通过 JSON 调用创建和更新主题。" all_users: "所有用户" - note_html: "请安全地保管密钥,任何拥有该密钥的用户可以使用它以论坛任何用户的名义发帖。" + show_details: 详情 + description: 描述 + save: 保存 web_hooks: title: "Webhooks" none: "当前没有 Webhooks。" diff --git a/config/locales/client.zh_TW.yml b/config/locales/client.zh_TW.yml index 1966221da9..b5ac3ac8a7 100644 --- a/config/locales/client.zh_TW.yml +++ b/config/locales/client.zh_TW.yml @@ -2776,16 +2776,13 @@ zh_TW: none: "目前沒有啟用中的 API 金鑰。" user: "使用者" title: "API" - key: "API 金鑰" created: 已建立 generate: "產生" - regenerate: "重新產生" revoke: "撤銷" - confirm_regen: "你確定要以新的 API 金鑰取代取的嗎?" - confirm_revoke: "你確定要撤銷此金鑰嗎?" - info_html: "你可以使用 API 金鑰呼叫 JSON 建立與更新話題。" all_users: "所有使用者" - note_html: "請安全地保管密鑰,任何擁有該密鑰的使用者,都可以使用它以任何的使用者的名義發文。" + show_details: 詳細訊息 + description: 描述 + save: 儲存 web_hooks: title: "Webhooks" none: "當前沒有 Webhooks。" diff --git a/config/locales/server.ca.yml b/config/locales/server.ca.yml index e074b51ae5..ace7461e4b 100644 --- a/config/locales/server.ca.yml +++ b/config/locales/server.ca.yml @@ -2210,6 +2210,9 @@ ca: Hola. Veiem que heu estat molt ocupat llegint, cosa fantàstica, de manera que us hem promogut un [nivell de confiança!](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/). Estem molt contents que passeu temps amb nosaltres, i ens agradaria conèixer-vos més bé. Dediqueu un moment a [omplir el vostre perfil](%{base_url}/my/preferences/profile), o bé podeu [començar un tema nou](%{base_url}/categories). + welcome_staff: + title: "Benvingut membre de l'equip responsable" + subject_template: "Enhorabona, ara sou %{role}!" welcome_invite: title: "Benvingut convidat" subject_template: "Benvingut a %{site_name}!" @@ -3313,6 +3316,12 @@ ca: user_merged: "%{username} s'ha combinat en aquest compte" user_delete_self: "Suprimit per si mateix des de %{url}" webhook_deactivation_reason: "S'ha desactivat automàticament el vostre webhook. Hem rebut diverses respostes d'error d'estat HTTP '%{status}'." + api_key: + automatic_revoked: + one: "Revocat automàticament, fa més d'un %{count} dia de l'última activitat" + other: "Revocat automàticament, fa més de %{count} dies de l'última activitat" + revoked: Revocat + restored: Restaurat reviewables: priorities: low: "Baixa" diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index 98b6a9272e..a7a3ba7aed 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -2382,15 +2382,6 @@ es: Hola. Hemos visto que has estado leyendo, lo cual nos parece fantástico, ¡por lo que te hemos subido tu [nivel de confianza](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/)! Nos alegramos de ver que estés pasando tiempo con nosotros, y nos gustaría saber más sobre ti. Cuando puedas, [rellena tu perfil](%{base_url}/my/preferences/profile) o [crea un nuevo tema](%{base_url}/categories). - welcome_moderator: - title: "Bienvenido Moderador" - subject_template: "¡Felicidades, ahora eres un moderador!" - text_body_template: | - Has sido promovido con el status de moderador por un miembro del staff. - - Como moderador, ahora tienes acceso a la interfaz de administración. - - Con un gran poder viene una gran responsabilidad. Si eres nuevo en tareas de moderación, por favor sigue la [Guía de Moderación](https://meta.discourse.org/t/discourse-moderation-guide/63116). welcome_invite: title: "Bienvenida al invitado" subject_template: "¡Bienvenido a %{site_name}!" diff --git a/config/locales/server.he.yml b/config/locales/server.he.yml index 2ff63575d9..eb16aead39 100644 --- a/config/locales/server.he.yml +++ b/config/locales/server.he.yml @@ -1906,6 +1906,7 @@ he: default_title_count_mode: "מצב בררת מחדל למונה כותרות עמודים" retain_web_hook_events_period_days: "מספר הימים לשמירת רשומות אירועי התלייה." retry_web_hook_events: "לנסות מחדש אירועי התליה שנכשלו במשך 4 פעמים. פרקי הזמן שבין הניסיונות החוזרים הם 1, 5, 25 ו־125 דקות." + revoke_api_keys_days: "מספר הימים בטרם שלילה אוטומטית של מפתח API שלא היה בשימוש (0 - לעולם לא)." allow_user_api_keys: "איפשור יצירת מפתחות API למשתמשים" allow_user_api_key_scopes: "רשימת אזורים מותרים למפתחות API של משתמשים" max_api_keys_per_user: "מספר מקסימלי של מפתחות API של משתמש לכל משתמש" @@ -2509,13 +2510,13 @@ he: text_body_template: | אהלן. שמנו לב שקריאת הפורום מעסיקה אותך רבות, שזה נהדר, לכן קידמנו את [דרגת האמון](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/) בך! אנו מאוד שמחים לראות שנעים לך לקחת חלק בפעילות הקהילתית ונשמח לדעת עוד עליך. ממליצים לך להשקיע רגע קט כדי [למלא את הפרופיל שלך](%{base_url}/my/preferences/profile), או סתם [לפתוח דיון חדש](%{base_url}/categories). - welcome_moderator: - title: "ברוך בואך לצוות הפיקוח" - subject_template: "ברכותינו, הרשאותיך מעתה מאפשרות לך לפקח!" + welcome_staff: + title: "ברוך בואך לסגל" + subject_template: "ברכותינו, הרשאותיך מעכשיו הן %{role}!" text_body_template: | - הוענק לך מצב פיקוח על ידי מישהו מבין חברי הסגל. + קיבלת הרשאות %{role} על ידי מישהו מבין חברי הסגל. - הרשאות פיקוח מעניקות לך גישה אל מנשק הניהול. + הרשאות %{role} מעניקות לך גישה אל מנשק הניהול. כוח רב טומן בחובו אחריות רבה. אם תחום הפיקוח זר לך, ניתן לפנות אל [המדריך למפקחים](https://meta.discourse.org/t/discourse-moderation-guide/63116). welcome_invite: @@ -4067,6 +4068,14 @@ he: user_merged: "%{username} מוזג לתוך החשבון הזה" user_delete_self: "מחיקה עצמית מתוך %{url}" webhook_deactivation_reason: "ההתלייה שלך הושבתה אוטומטית. קיבלו מגוון תגובות כשל בצורת HTTP ‚%{status}’." + api_key: + automatic_revoked: + one: "נשלל אוטומטית, הפעילות האחרונה התבצעה לפני למעלה מיום (%{count})" + two: "נשלל אוטומטית, הפעילות האחרונה התבצעה לפני למעלה מיומיים (%{count})" + many: "נשלל אוטומטית, הפעילות האחרונה התבצעה לפני למעלה מ־%{count} ימים" + other: "נשלל אוטומטית, הפעילות האחרונה התבצעה לפני למעלה מ־%{count} ימים" + revoked: נשל + restored: שוחזר reviewables: priorities: low: "נמוכה" diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index f0b950e0bc..c326d6c534 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -1944,6 +1944,7 @@ it: autoclosed_disabled_lastpost: "Questo argomento è ora aperto. Sono permesse altre risposte." auto_deleted_by_timer: "Eliminato automaticamente dal timer." login: + security_key_description: "Quando hai preparato la chiave di sicurezza fisica, premi il pulsante Autentica con Security Key qui sotto." not_approved: "Il tuo account non è ancora stato approvato. Verrai avvertito via mail quando potrai collegarti." incorrect_username_email_or_password: "Nome utente, email o password errati" incorrect_password: "Password errata" diff --git a/config/locales/server.nl.yml b/config/locales/server.nl.yml index 7e94f923fd..3b1c409637 100644 --- a/config/locales/server.nl.yml +++ b/config/locales/server.nl.yml @@ -1836,6 +1836,7 @@ nl: default_title_count_mode: "Standaardmodus voor de paginatitelteller" retain_web_hook_events_period_days: "Aantal dagen voor het behouden van records van webhookgebeurtenissen." retry_web_hook_events: "Mislukte webhookgebeurtenissen automatisch 4 keer opnieuw proberen. Tijdsgaten tussen de pogingen zijn 1, 5, 25 en 125 minuten." + revoke_api_keys_days: "Aantal dagen voordat een niet-gebruikte API-sleutel van een gebruiker automatisch wordt ingetrokken (0 voor nooit)" allow_user_api_keys: "Genereren van API-sleutels van gebruiker toestaan" allow_user_api_key_scopes: "Lijst van toegestane scopes voor API-sleutels van gebruiker" max_api_keys_per_user: "Maximale aantal API-aanvragen van gebruiker per gebruiker" @@ -2659,6 +2660,8 @@ nl: not_found: "niet gevonden" unknown: "onbekend" user_merged: "%{username} is met deze account samengevoegd" + api_key: + revoked: Ingetrokken reviewables: priorities: low: "Laag" diff --git a/config/locales/server.uk.yml b/config/locales/server.uk.yml index 0497004728..25504ee025 100644 --- a/config/locales/server.uk.yml +++ b/config/locales/server.uk.yml @@ -2081,9 +2081,6 @@ uk: subject_template: "Повідомлення приховано через скарги спільноти, персонал повідомлено" welcome_user: subject_template: "Ласкаво просимо до сайта %{site_name}!" - welcome_moderator: - title: "Ласкаво просимо модератор" - subject_template: "Вітаємо, ви зараз модератор!" welcome_invite: title: "Ласкаво просимо" subject_template: "Ласкаво просимо до сайта %{site_name}!" @@ -2749,6 +2746,11 @@ uk: few: '"%{tag_name}" обмежено такими категоріями: %{category_names}' many: '"%{tag_name}" обмежено такими категоріями: %{category_names}' other: '"%{tag_name}" обмежено такими категоріями: %{category_names}' + required_tags_from_group: + one: "Ви повинні включити принаймні тег %{count} %{tag_group_name}." + few: "Ви повинні включити принаймні теги %{count} %{tag_group_name}." + many: "Ви повинні включити принаймні теги %{count} %{tag_group_name}." + other: "Ви повинні включити принаймні %{count} %{tag_group_name} теги." rss_by_tag: "Теми з тегом %{tag}" finish_installation: congratulations: "Вітаємо, Ви встановили Дискурс!" @@ -2919,6 +2921,14 @@ uk: user_merged: "%{username} був об'єднаний з цим обліковим записом" user_delete_self: "Вилучено самостійно з %{url}" webhook_deactivation_reason: "Ваш webhook автоматично відключений. Ми отримали декілька відповідей з помилками HTTP-статусу '%{status}'." + api_key: + automatic_revoked: + one: "Автоматично відкликано, останню активність більше, ніж %{count} день тому" + few: "Автоматично відкликано, останню активність більше, ніж %{count} днів тому" + many: "Автоматично відкликано, останню активність більше, ніж %{count} днів тому" + other: "Автоматично відкликано, остання активність більше, ніж %{count} днів тому" + revoked: Скасовано + restored: Відновлено reviewables: priorities: low: "Низький" diff --git a/config/locales/server.zh_CN.yml b/config/locales/server.zh_CN.yml index 34515cd3c9..2c4b010fa9 100644 --- a/config/locales/server.zh_CN.yml +++ b/config/locales/server.zh_CN.yml @@ -2278,9 +2278,6 @@ zh_CN: 嘿。我们看到你一直在忙着阅读,这太棒了,所以我们已经提升你了[信任等级!](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/) 我们很高兴你和我们共度时光,我们很想知道更多关于你的事情。花一点时间[填写你的个人资料](%{base_url}/我的/设置/个人信息),或随时[开始一个新主题](%{base_url}/categories)。 - welcome_moderator: - title: "欢迎版主" - subject_template: "恭喜,你现在是版主了!" welcome_invite: title: "欢迎邀请" subject_template: "欢迎来到 %{site_name}!" diff --git a/plugins/discourse-details/config/locales/server.ar.yml b/plugins/discourse-details/config/locales/server.ar.yml index 08763d4e38..dfe3786c0d 100644 --- a/plugins/discourse-details/config/locales/server.ar.yml +++ b/plugins/discourse-details/config/locales/server.ar.yml @@ -7,4 +7,4 @@ ar: site_settings: - details_enabled: "فعل خاصية التفاصيل. إذا غيرت هذا ، فيجب عليك إعادة بث جميع المشاركات باستخدام: \"rake posts:rebake\"." + details_enabled: 'فعل خاصية التفاصيل. إذا غيرت هذا ، فيجب عليك إعادة بث جميع المشاركات باستخدام: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.bs_BA.yml b/plugins/discourse-details/config/locales/server.bs_BA.yml index abc3f5ed9e..aeda8f970c 100644 --- a/plugins/discourse-details/config/locales/server.bs_BA.yml +++ b/plugins/discourse-details/config/locales/server.bs_BA.yml @@ -7,6 +7,6 @@ bs_BA: site_settings: - details_enabled: "Uključi opciju detalji. Ukoliko ovo izmijenite, morate odraditi ponovno pečenje svih postova koristeći: \"rake posts:rebake\"." + details_enabled: 'Uključi opciju detalji. Ukoliko ovo izmijenite, morate odraditi ponovno pečenje svih postova koristeći: "rake posts:rebake".' details: excerpt_details: "(kliknite za više detalja)" diff --git a/plugins/discourse-details/config/locales/server.ca.yml b/plugins/discourse-details/config/locales/server.ca.yml index ce28317b43..bc31db75a1 100644 --- a/plugins/discourse-details/config/locales/server.ca.yml +++ b/plugins/discourse-details/config/locales/server.ca.yml @@ -7,6 +7,6 @@ ca: site_settings: - details_enabled: "Activa la característica de detalls. Si ho canvieu, haureu de refer totes les publicacions amb: \"rake posts:rebake\"." + details_enabled: 'Activa la característica de detalls. Si ho canvieu, haureu de refer totes les publicacions amb: "rake posts:rebake".' details: excerpt_details: "(feu clic per a més informació)" diff --git a/plugins/discourse-details/config/locales/server.da.yml b/plugins/discourse-details/config/locales/server.da.yml index 18d2178d2b..07b34f75e0 100644 --- a/plugins/discourse-details/config/locales/server.da.yml +++ b/plugins/discourse-details/config/locales/server.da.yml @@ -7,6 +7,6 @@ da: site_settings: - details_enabled: "Aktivér 'detaljer' funktion. Hvis du gennemfører denne ændring, skal du omdirigere alle indlæg med: \"rake posts:rebake\"." + details_enabled: 'Aktivér ''detaljer'' funktion. Hvis du gennemfører denne ændring, skal du omdirigere alle indlæg med: "rake posts:rebake".' details: excerpt_details: "(klik for flere detaljer)" diff --git a/plugins/discourse-details/config/locales/server.de.yml b/plugins/discourse-details/config/locales/server.de.yml index 97cbe0077e..7aac04e558 100644 --- a/plugins/discourse-details/config/locales/server.de.yml +++ b/plugins/discourse-details/config/locales/server.de.yml @@ -7,6 +7,6 @@ de: site_settings: - details_enabled: "Aktiviert die Details-Funktion. Wenn du dies änderst, musst du alle Beiträge neu „backen“ mit: \"rake posts:rebake\"." + details_enabled: 'Aktiviert die Details-Funktion. Wenn du dies änderst, musst du alle Beiträge neu „backen“ mit: "rake posts:rebake".' details: excerpt_details: "(für mehr Details klicken)" diff --git a/plugins/discourse-details/config/locales/server.es.yml b/plugins/discourse-details/config/locales/server.es.yml index 01788e6291..2854d9bf41 100644 --- a/plugins/discourse-details/config/locales/server.es.yml +++ b/plugins/discourse-details/config/locales/server.es.yml @@ -7,6 +7,6 @@ es: site_settings: - details_enabled: "Habilitar la característica de detalles. Si cambias esto, debes hacer rebake de todos los mensajes con: «rake posts:rebake»." + details_enabled: 'Habilitar la característica de detalles. Si cambias esto, debes hacer rebake de todos los mensajes con: «rake posts:rebake».' details: excerpt_details: "(haz clic para más detalles)" diff --git a/plugins/discourse-details/config/locales/server.fa_IR.yml b/plugins/discourse-details/config/locales/server.fa_IR.yml index 2753cbd60c..367957ef6a 100644 --- a/plugins/discourse-details/config/locales/server.fa_IR.yml +++ b/plugins/discourse-details/config/locales/server.fa_IR.yml @@ -7,6 +7,6 @@ fa_IR: site_settings: - details_enabled: "به کار گرفتن جزییات. اگر این گزینه را تغییر دادید باید همه پستها را با \"rake posts:rebake\" بازسازی کنید." + details_enabled: 'به کار گرفتن جزییات. اگر این گزینه را تغییر دادید باید همه پستها را با "rake posts:rebake" بازسازی کنید.' details: excerpt_details: "(برای جزئیات بیشتر کلیک کنید)" diff --git a/plugins/discourse-details/config/locales/server.fi.yml b/plugins/discourse-details/config/locales/server.fi.yml index c1460eefc6..68e9d1caf7 100644 --- a/plugins/discourse-details/config/locales/server.fi.yml +++ b/plugins/discourse-details/config/locales/server.fi.yml @@ -7,6 +7,6 @@ fi: site_settings: - details_enabled: "Ota käyttöön yksityiskohtaominaisuus. Jos muutat asetusta, sinun täytyy rakentaa viestit uudelleen komennolla: \"rake posts:rebake\". " + details_enabled: 'Ota käyttöön yksityiskohtaominaisuus. Jos muutat asetusta, sinun täytyy rakentaa viestit uudelleen komennolla: "rake posts:rebake". ' details: excerpt_details: "(klikkaa saadaksesi lisää tietoa)" diff --git a/plugins/discourse-details/config/locales/server.fr.yml b/plugins/discourse-details/config/locales/server.fr.yml index db138519c9..06c2deadb8 100644 --- a/plugins/discourse-details/config/locales/server.fr.yml +++ b/plugins/discourse-details/config/locales/server.fr.yml @@ -7,6 +7,6 @@ fr: site_settings: - details_enabled: "Activer la fonction details. Si vous modifiez ceci, vous devez exécuter la commande \"rake posts:rebake\"." + details_enabled: 'Activer la fonction details. Si vous modifiez ceci, vous devez exécuter la commande "rake posts:rebake".' details: excerpt_details: "(cliquer pour plus de détails)" diff --git a/plugins/discourse-details/config/locales/server.gl.yml b/plugins/discourse-details/config/locales/server.gl.yml index 5c817d1a24..374264cd6b 100644 --- a/plugins/discourse-details/config/locales/server.gl.yml +++ b/plugins/discourse-details/config/locales/server.gl.yml @@ -7,4 +7,4 @@ gl: site_settings: - details_enabled: "Activar a función de detalles. Se cambias isto, debes rebocar todas as publicacións con: \"publicacións de rake: rebote\"." + details_enabled: 'Activar a función de detalles. Se cambias isto, debes rebocar todas as publicacións con: "publicacións de rake: rebote".' diff --git a/plugins/discourse-details/config/locales/server.he.yml b/plugins/discourse-details/config/locales/server.he.yml index b31d72b54f..77fb8feced 100644 --- a/plugins/discourse-details/config/locales/server.he.yml +++ b/plugins/discourse-details/config/locales/server.he.yml @@ -7,6 +7,6 @@ he: site_settings: - details_enabled: "הפעלת תכונת הפירוט. שינוי הגדרה זו תאלץ אותך להכין את כל הפוסטים מחדש בעזרת: „rake posts:rebake”" + details_enabled: 'הפעלת תכונת הפירוט. שינוי הגדרה זו תאלץ אותך להכין את כל הפוסטים מחדש בעזרת: „rake posts:rebake”' details: excerpt_details: "(לחיצה לפרטים נוספים)" diff --git a/plugins/discourse-details/config/locales/server.hu.yml b/plugins/discourse-details/config/locales/server.hu.yml index 762ea50ca1..3536d6cb31 100644 --- a/plugins/discourse-details/config/locales/server.hu.yml +++ b/plugins/discourse-details/config/locales/server.hu.yml @@ -7,4 +7,4 @@ hu: site_settings: - details_enabled: "Részletek funkció engedélyezése. Ha megváltoztatod ezt, újra kell tenned az összes bejegyzést ezzel: \"rake posts:rebake\"." + details_enabled: 'Részletek funkció engedélyezése. Ha megváltoztatod ezt, újra kell tenned az összes bejegyzést ezzel: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.hy.yml b/plugins/discourse-details/config/locales/server.hy.yml index 7c0bdfbb52..8e76db17fd 100644 --- a/plugins/discourse-details/config/locales/server.hy.yml +++ b/plugins/discourse-details/config/locales/server.hy.yml @@ -7,4 +7,4 @@ hy: site_settings: - details_enabled: "Միացնել մանրամասների հատկանիշը: Եթե Դուք փոփոխեք սա, Դուք պետք է թարմացնեք բոլոր գրառումները՝ \"rake posts:rebake\" :" + details_enabled: 'Միացնել մանրամասների հատկանիշը: Եթե Դուք փոփոխեք սա, Դուք պետք է թարմացնեք բոլոր գրառումները՝ "rake posts:rebake" :' diff --git a/plugins/discourse-details/config/locales/server.id.yml b/plugins/discourse-details/config/locales/server.id.yml index 1de356362b..6662b1bf1a 100644 --- a/plugins/discourse-details/config/locales/server.id.yml +++ b/plugins/discourse-details/config/locales/server.id.yml @@ -7,4 +7,4 @@ id: site_settings: - details_enabled: "Aktifkan fitur detail. Jika Anda mengganti ini, Anda perlu memproses ulang semua post dengan: \"rake posts:rebake\"" + details_enabled: 'Aktifkan fitur detail. Jika Anda mengganti ini, Anda perlu memproses ulang semua post dengan: "rake posts:rebake"' diff --git a/plugins/discourse-details/config/locales/server.it.yml b/plugins/discourse-details/config/locales/server.it.yml index 2367bc7c6f..b1d5fb5ea5 100644 --- a/plugins/discourse-details/config/locales/server.it.yml +++ b/plugins/discourse-details/config/locales/server.it.yml @@ -7,6 +7,6 @@ it: site_settings: - details_enabled: "Attiva la funzione dettagli. Se cambi questa impostazione, devi rielaborare tutti i Messaggi con \"rake posts:rebake\"" + details_enabled: 'Attiva la funzione dettagli. Se cambi questa impostazione, devi rielaborare tutti i Messaggi con "rake posts:rebake"' details: excerpt_details: "(clicca per ulteriori dettagli)" diff --git a/plugins/discourse-details/config/locales/server.ja.yml b/plugins/discourse-details/config/locales/server.ja.yml index fdb1ab2460..179d95d623 100644 --- a/plugins/discourse-details/config/locales/server.ja.yml +++ b/plugins/discourse-details/config/locales/server.ja.yml @@ -7,6 +7,6 @@ ja: site_settings: - details_enabled: "詳細機能を有効にします。これを変更した場合は、「rake posts:rebake」ですべての投稿を再作成する必要があります。" + details_enabled: '詳細機能を有効にします。これを変更した場合は、「rake posts:rebake」ですべての投稿を再作成する必要があります。' details: excerpt_details: "(詳細を見るためにクリック)" diff --git a/plugins/discourse-details/config/locales/server.ko.yml b/plugins/discourse-details/config/locales/server.ko.yml index e82190cf43..a454f55755 100644 --- a/plugins/discourse-details/config/locales/server.ko.yml +++ b/plugins/discourse-details/config/locales/server.ko.yml @@ -7,4 +7,4 @@ ko: site_settings: - details_enabled: "상세 기능을 사용. 이를 변경하면 다음 명령어를 사용하여 모든 게시물을 다시 게시해야합니다: \"rake posts:rebake\"." + details_enabled: '상세 기능을 사용. 이를 변경하면 다음 명령어를 사용하여 모든 게시물을 다시 게시해야합니다: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.lt.yml b/plugins/discourse-details/config/locales/server.lt.yml index 0812841c02..994baefe86 100644 --- a/plugins/discourse-details/config/locales/server.lt.yml +++ b/plugins/discourse-details/config/locales/server.lt.yml @@ -7,4 +7,4 @@ lt: site_settings: - details_enabled: "Įgalinti detalią funkciją. Jei tai pakeisite, turėsite paleisti iš naujo visus įrašus su: \"rake posts:rebake\"." + details_enabled: 'Įgalinti detalią funkciją. Jei tai pakeisite, turėsite paleisti iš naujo visus įrašus su: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.nb_NO.yml b/plugins/discourse-details/config/locales/server.nb_NO.yml index 2795879881..6e263d4097 100644 --- a/plugins/discourse-details/config/locales/server.nb_NO.yml +++ b/plugins/discourse-details/config/locales/server.nb_NO.yml @@ -7,4 +7,4 @@ nb_NO: site_settings: - details_enabled: "Aktiver funksjonen for detaljer. Hvis du endrer dette, må du rebake alle innlegg med: \"rake posts:rebake\"." + details_enabled: 'Aktiver funksjonen for detaljer. Hvis du endrer dette, må du rebake alle innlegg med: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.nl.yml b/plugins/discourse-details/config/locales/server.nl.yml index bdccfcc22e..51d3723541 100644 --- a/plugins/discourse-details/config/locales/server.nl.yml +++ b/plugins/discourse-details/config/locales/server.nl.yml @@ -7,6 +7,6 @@ nl: site_settings: - details_enabled: "De details-functie inschakelen. Als u dit wijzigt, moet u alle berichten opnieuw opbouwen met: 'rake posts:rebake'." + details_enabled: 'De details-functie inschakelen. Als u dit wijzigt, moet u alle berichten opnieuw opbouwen met: ''rake posts:rebake''.' details: excerpt_details: "(klik voor meer details)" diff --git a/plugins/discourse-details/config/locales/server.pl_PL.yml b/plugins/discourse-details/config/locales/server.pl_PL.yml index c8be336edd..545b695e26 100644 --- a/plugins/discourse-details/config/locales/server.pl_PL.yml +++ b/plugins/discourse-details/config/locales/server.pl_PL.yml @@ -7,6 +7,6 @@ pl_PL: site_settings: - details_enabled: "Aktywuj funkcjonalność detali. Jeśli zmienisz tę opcję, będziesz musiał ponownie rebake’ować wszystkie posty przy użyciu \"rake posts:rebake\"." + details_enabled: 'Aktywuj funkcjonalność detali. Jeśli zmienisz tę opcję, będziesz musiał ponownie rebake’ować wszystkie posty przy użyciu "rake posts:rebake".' details: excerpt_details: "(kliknij, by wyświetlić więcej szczegółów)" diff --git a/plugins/discourse-details/config/locales/server.pt_BR.yml b/plugins/discourse-details/config/locales/server.pt_BR.yml index b810bdd2e0..b203b3cd3e 100644 --- a/plugins/discourse-details/config/locales/server.pt_BR.yml +++ b/plugins/discourse-details/config/locales/server.pt_BR.yml @@ -7,6 +7,6 @@ pt_BR: site_settings: - details_enabled: "Habilitar o recurso de detalhes. Se você mudar isso, você deve recompilar todas as postagens com: \"rake posts:rebake\"." + details_enabled: 'Habilitar o recurso de detalhes. Se você mudar isso, você deve recompilar todas as postagens com: "rake posts:rebake".' details: excerpt_details: "(clique para mais detalhes)" diff --git a/plugins/discourse-details/config/locales/server.ru.yml b/plugins/discourse-details/config/locales/server.ru.yml index 64d8acbdc4..607b79a333 100644 --- a/plugins/discourse-details/config/locales/server.ru.yml +++ b/plugins/discourse-details/config/locales/server.ru.yml @@ -7,6 +7,6 @@ ru: site_settings: - details_enabled: "Включить дополнительные возможности. Если вы измените данный пункт, то потребуется обновить все посты с помощью команды: \"rake posts:rebake\"" + details_enabled: 'Включить дополнительные возможности. Если вы измените данный пункт, то потребуется обновить все посты с помощью команды: "rake posts:rebake"' details: excerpt_details: "(нажмите для более подробной информации)" diff --git a/plugins/discourse-details/config/locales/server.sk.yml b/plugins/discourse-details/config/locales/server.sk.yml index 1609e4c7b7..ea18d93dce 100644 --- a/plugins/discourse-details/config/locales/server.sk.yml +++ b/plugins/discourse-details/config/locales/server.sk.yml @@ -7,4 +7,4 @@ sk: site_settings: - details_enabled: "Povoliť vlastnosť detailov. Ak toto zmeníte, musíte znovu sparsovať všetky príspevky: \"rake posts:rebake\"." + details_enabled: 'Povoliť vlastnosť detailov. Ak toto zmeníte, musíte znovu sparsovať všetky príspevky: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.sl.yml b/plugins/discourse-details/config/locales/server.sl.yml index f282cd9077..ccf18a1f0e 100644 --- a/plugins/discourse-details/config/locales/server.sl.yml +++ b/plugins/discourse-details/config/locales/server.sl.yml @@ -7,4 +7,4 @@ sl: site_settings: - details_enabled: "Omogočite skrij besedilo funkcinalnost. Če to spremenite, morate ponovno zapeči vse prispevke z: \"rake posts:rebake\"." + details_enabled: 'Omogočite skrij besedilo funkcinalnost. Če to spremenite, morate ponovno zapeči vse prispevke z: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.sw.yml b/plugins/discourse-details/config/locales/server.sw.yml index 54b75273f7..aba419fb1a 100644 --- a/plugins/discourse-details/config/locales/server.sw.yml +++ b/plugins/discourse-details/config/locales/server.sw.yml @@ -7,4 +7,4 @@ sw: site_settings: - details_enabled: "Wezesha Vipengele vya maelezo. Na kama ukibadilisha, lazima useti machapisho yote kwa kutumia: \"rake posts:rebake\"." + details_enabled: 'Wezesha Vipengele vya maelezo. Na kama ukibadilisha, lazima useti machapisho yote kwa kutumia: "rake posts:rebake".' diff --git a/plugins/discourse-details/config/locales/server.uk.yml b/plugins/discourse-details/config/locales/server.uk.yml index ecedaf9a52..8017dfd076 100644 --- a/plugins/discourse-details/config/locales/server.uk.yml +++ b/plugins/discourse-details/config/locales/server.uk.yml @@ -7,6 +7,6 @@ uk: site_settings: - details_enabled: "Увімкніть функцію деталей. Якщо змінити, то потрібно відредагувати всі дописи: "rake posts:rebake"." + details_enabled: 'Увімкніть функцію деталей. Якщо змінити, то потрібно відредагувати всі дописи: "rake posts:rebake".' details: excerpt_details: "(натисніть для отримання детальної інформації)" diff --git a/plugins/discourse-details/config/locales/server.ur.yml b/plugins/discourse-details/config/locales/server.ur.yml index 1f894bdc3b..0f14e2f1a3 100644 --- a/plugins/discourse-details/config/locales/server.ur.yml +++ b/plugins/discourse-details/config/locales/server.ur.yml @@ -7,6 +7,6 @@ ur: site_settings: - details_enabled: "تفصیلات کی خصوصیت فعال کریں۔ اگر آپ اس کو تبدیل کرتے ہیں تو، آپ کو تمام پوسٹس کو دوبارہ رِیبَیک کرنا ہوگا: \"rake posts:rebake\"" + details_enabled: 'تفصیلات کی خصوصیت فعال کریں۔ اگر آپ اس کو تبدیل کرتے ہیں تو، آپ کو تمام پوسٹس کو دوبارہ رِیبَیک کرنا ہوگا: "rake posts:rebake"' details: excerpt_details: "(مزید تفصیلات کیلئے کلک کریں)" diff --git a/plugins/discourse-details/config/locales/server.zh_CN.yml b/plugins/discourse-details/config/locales/server.zh_CN.yml index 2037c581ef..c5417d6739 100644 --- a/plugins/discourse-details/config/locales/server.zh_CN.yml +++ b/plugins/discourse-details/config/locales/server.zh_CN.yml @@ -7,6 +7,6 @@ zh_CN: site_settings: - details_enabled: "启用细节功能。如果你改变了这个选项,必须通过此命令重新调制全部帖子:\"rake posts:rebake\"。" + details_enabled: '启用细节功能。如果你改变了这个选项,必须通过此命令重新调制全部帖子:"rake posts:rebake"。' details: excerpt_details: "(点击显示详情)" diff --git a/plugins/discourse-presence/config/locales/server.ar.yml b/plugins/discourse-presence/config/locales/server.ar.yml index 6ab62be496..15d898e498 100644 --- a/plugins/discourse-presence/config/locales/server.ar.yml +++ b/plugins/discourse-presence/config/locales/server.ar.yml @@ -7,5 +7,5 @@ ar: site_settings: - presence_enabled: 'أعرض الأعضاء الذين يردون حاليا على موضوع حالي، أو يقومون بالتعديل على منشور حالي؟' - presence_max_users_shown: 'تم اضهار اقصى عدد من الأعضاء.' + presence_enabled: "أعرض الأعضاء الذين يردون حاليا على موضوع حالي، أو يقومون بالتعديل على منشور حالي؟" + presence_max_users_shown: "تم اضهار اقصى عدد من الأعضاء." diff --git a/plugins/discourse-presence/config/locales/server.bs_BA.yml b/plugins/discourse-presence/config/locales/server.bs_BA.yml index 8ea8d053d8..133834b211 100644 --- a/plugins/discourse-presence/config/locales/server.bs_BA.yml +++ b/plugins/discourse-presence/config/locales/server.bs_BA.yml @@ -7,5 +7,5 @@ bs_BA: site_settings: - presence_enabled: 'Prikazuje korisnike koji trenutačno odgovaraju na trnenutnu temu, ili ispravljaju trenutnu objavu' - presence_max_users_shown: 'Maksimalan broj prikazanih korisnika' + presence_enabled: "Prikazuje korisnike koji trenutačno odgovaraju na trnenutnu temu, ili ispravljaju trenutnu objavu" + presence_max_users_shown: "Maksimalan broj prikazanih korisnika" diff --git a/plugins/discourse-presence/config/locales/server.ca.yml b/plugins/discourse-presence/config/locales/server.ca.yml index 3450d7b714..04a43e3c9d 100644 --- a/plugins/discourse-presence/config/locales/server.ca.yml +++ b/plugins/discourse-presence/config/locales/server.ca.yml @@ -7,5 +7,5 @@ ca: site_settings: - presence_enabled: '¿S''han de mostrar els usuaris que en aquests moments responen al tema actual o editen l''entrada actual?' - presence_max_users_shown: 'Nombre màxim d''usuaris mostrats.' + presence_enabled: "¿S'han de mostrar els usuaris que en aquests moments responen al tema actual o editen l'entrada actual?" + presence_max_users_shown: "Nombre màxim d'usuaris mostrats." diff --git a/plugins/discourse-presence/config/locales/server.cs.yml b/plugins/discourse-presence/config/locales/server.cs.yml index 6ca7339ff0..b30107f62c 100644 --- a/plugins/discourse-presence/config/locales/server.cs.yml +++ b/plugins/discourse-presence/config/locales/server.cs.yml @@ -7,5 +7,5 @@ cs: site_settings: - presence_enabled: 'Zobrazit uživatele, kteří právě odpovídají na aktuální téma nebo upravují aktuální příspěvek?' - presence_max_users_shown: ' Maximální počet zobrazených uživatelů.' + presence_enabled: "Zobrazit uživatele, kteří právě odpovídají na aktuální téma nebo upravují aktuální příspěvek?" + presence_max_users_shown: " Maximální počet zobrazených uživatelů." diff --git a/plugins/discourse-presence/config/locales/server.da.yml b/plugins/discourse-presence/config/locales/server.da.yml index 8798c120d3..4a96f02f7c 100644 --- a/plugins/discourse-presence/config/locales/server.da.yml +++ b/plugins/discourse-presence/config/locales/server.da.yml @@ -7,5 +7,5 @@ da: site_settings: - presence_enabled: 'Vis brugere, der i øjeblikket svarer på det aktuelle emne, eller redigerer det aktuelle indlæg?' - presence_max_users_shown: 'Maksimalt antal viste brugere.' + presence_enabled: "Vis brugere, der i øjeblikket svarer på det aktuelle emne, eller redigerer det aktuelle indlæg?" + presence_max_users_shown: "Maksimalt antal viste brugere." diff --git a/plugins/discourse-presence/config/locales/server.de.yml b/plugins/discourse-presence/config/locales/server.de.yml index 803955b4b8..b282127f73 100644 --- a/plugins/discourse-presence/config/locales/server.de.yml +++ b/plugins/discourse-presence/config/locales/server.de.yml @@ -7,5 +7,5 @@ de: site_settings: - presence_enabled: 'Benutzer anzeigen, die gerade im aktuellen Thema antworten, oder den aktuellen Beitrag bearbeiten?' - presence_max_users_shown: 'Maximale Anzahl an angezeigten Benutzern.' + presence_enabled: "Benutzer anzeigen, die gerade im aktuellen Thema antworten, oder den aktuellen Beitrag bearbeiten?" + presence_max_users_shown: "Maximale Anzahl an angezeigten Benutzern." diff --git a/plugins/discourse-presence/config/locales/server.el.yml b/plugins/discourse-presence/config/locales/server.el.yml index 30f4469024..596b434bb0 100644 --- a/plugins/discourse-presence/config/locales/server.el.yml +++ b/plugins/discourse-presence/config/locales/server.el.yml @@ -7,4 +7,4 @@ el: site_settings: - presence_enabled: 'Εμφάνιση των χρηστών που απαντάνε αυτή τη στιγμή στο νήμα ή επεξεργάζονται την τρέχουσα ανάρτηση;' + presence_enabled: "Εμφάνιση των χρηστών που απαντάνε αυτή τη στιγμή στο νήμα ή επεξεργάζονται την τρέχουσα ανάρτηση;" diff --git a/plugins/discourse-presence/config/locales/server.es.yml b/plugins/discourse-presence/config/locales/server.es.yml index fe6046582e..7c4056831b 100644 --- a/plugins/discourse-presence/config/locales/server.es.yml +++ b/plugins/discourse-presence/config/locales/server.es.yml @@ -7,5 +7,5 @@ es: site_settings: - presence_enabled: '¿Mostrar los usuarios que están respondiendo al tema actual o editando la publicación actual?' - presence_max_users_shown: 'Número máximo de usuarios mostrados.' + presence_enabled: "¿Mostrar los usuarios que están respondiendo al tema actual o editando la publicación actual?" + presence_max_users_shown: "Número máximo de usuarios mostrados." diff --git a/plugins/discourse-presence/config/locales/server.fa_IR.yml b/plugins/discourse-presence/config/locales/server.fa_IR.yml index 94d71c910a..2ee856adfd 100644 --- a/plugins/discourse-presence/config/locales/server.fa_IR.yml +++ b/plugins/discourse-presence/config/locales/server.fa_IR.yml @@ -7,4 +7,4 @@ fa_IR: site_settings: - presence_enabled: 'کاربرانی که در حال حاضر به موضوع فعلی پاسخ می دهند و یا در حال یرایش پست فعلی هستند، نمایش داده شوند؟' + presence_enabled: "کاربرانی که در حال حاضر به موضوع فعلی پاسخ می دهند و یا در حال یرایش پست فعلی هستند، نمایش داده شوند؟" diff --git a/plugins/discourse-presence/config/locales/server.fi.yml b/plugins/discourse-presence/config/locales/server.fi.yml index 56d5ac5f20..f9a72140e9 100644 --- a/plugins/discourse-presence/config/locales/server.fi.yml +++ b/plugins/discourse-presence/config/locales/server.fi.yml @@ -7,5 +7,5 @@ fi: site_settings: - presence_enabled: 'Näytä ketkä parhaillaan kirjoittavat tai muokkaavat viestiä ketjussa, jossa käyttäjä on?' - presence_max_users_shown: 'Kuinka monta käyttäjää enintään näytetään.' + presence_enabled: "Näytä ketkä parhaillaan kirjoittavat tai muokkaavat viestiä ketjussa, jossa käyttäjä on?" + presence_max_users_shown: "Kuinka monta käyttäjää enintään näytetään." diff --git a/plugins/discourse-presence/config/locales/server.fr.yml b/plugins/discourse-presence/config/locales/server.fr.yml index 319785b4fd..ea12363f08 100644 --- a/plugins/discourse-presence/config/locales/server.fr.yml +++ b/plugins/discourse-presence/config/locales/server.fr.yml @@ -7,5 +7,5 @@ fr: site_settings: - presence_enabled: 'Afficher les utilisateurs qui sont en train de répondre au sujet actuel ou modifier le message actuel ?' - presence_max_users_shown: 'Nombre maximale d''utilisateurs affiché.' + presence_enabled: "Afficher les utilisateurs qui sont en train de répondre au sujet actuel ou modifier le message actuel ?" + presence_max_users_shown: "Nombre maximale d'utilisateurs affiché." diff --git a/plugins/discourse-presence/config/locales/server.he.yml b/plugins/discourse-presence/config/locales/server.he.yml index 9223c8c7d8..d67d6f9194 100644 --- a/plugins/discourse-presence/config/locales/server.he.yml +++ b/plugins/discourse-presence/config/locales/server.he.yml @@ -7,5 +7,5 @@ he: site_settings: - presence_enabled: 'להציג משתמשים שמגיבים כרגע לנושא הנוכחי או עורכים את הפוסט הנוכחי?' - presence_max_users_shown: ' המספר המרבי של משתמשים שיוצגו.' + presence_enabled: "להציג משתמשים שמגיבים כרגע לנושא הנוכחי או עורכים את הפוסט הנוכחי?" + presence_max_users_shown: " המספר המרבי של משתמשים שיוצגו." diff --git a/plugins/discourse-presence/config/locales/server.hu.yml b/plugins/discourse-presence/config/locales/server.hu.yml index 39564af39d..239ea23c17 100644 --- a/plugins/discourse-presence/config/locales/server.hu.yml +++ b/plugins/discourse-presence/config/locales/server.hu.yml @@ -7,5 +7,5 @@ hu: site_settings: - presence_enabled: 'Felhasználók mutatása akik jelenleg válaszolnak a jelenlegi témára, vagy szerkesztik a jelenlegi bejegyzést.' - presence_max_users_shown: 'Maximális számú ember amit mutat.' + presence_enabled: "Felhasználók mutatása akik jelenleg válaszolnak a jelenlegi témára, vagy szerkesztik a jelenlegi bejegyzést." + presence_max_users_shown: "Maximális számú ember amit mutat." diff --git a/plugins/discourse-presence/config/locales/server.hy.yml b/plugins/discourse-presence/config/locales/server.hy.yml index 3da6e6457d..86cb7c5feb 100644 --- a/plugins/discourse-presence/config/locales/server.hy.yml +++ b/plugins/discourse-presence/config/locales/server.hy.yml @@ -7,5 +7,5 @@ hy: site_settings: - presence_enabled: 'Ցուցադրե՞լ այն օգտատերերին, որոնք այս պահին պատասխանում են ներկայիս թեմային կամ խմբագրում են ներկայիս գրառումը:' - presence_max_users_shown: 'Ցուցադրված օգտատերերի առավելագույն քանակը:' + presence_enabled: "Ցուցադրե՞լ այն օգտատերերին, որոնք այս պահին պատասխանում են ներկայիս թեմային կամ խմբագրում են ներկայիս գրառումը:" + presence_max_users_shown: "Ցուցադրված օգտատերերի առավելագույն քանակը:" diff --git a/plugins/discourse-presence/config/locales/server.it.yml b/plugins/discourse-presence/config/locales/server.it.yml index 9183a04a3a..25d9b31f6a 100644 --- a/plugins/discourse-presence/config/locales/server.it.yml +++ b/plugins/discourse-presence/config/locales/server.it.yml @@ -7,5 +7,5 @@ it: site_settings: - presence_enabled: 'Mostrare gli utenti mentre stanno rispondendo ad un argomento oppure modificando il messaggio corrente?' - presence_max_users_shown: 'Massimo numero di utenti visualizzati.' + presence_enabled: "Mostrare gli utenti mentre stanno rispondendo ad un argomento oppure modificando il messaggio corrente?" + presence_max_users_shown: "Massimo numero di utenti visualizzati." diff --git a/plugins/discourse-presence/config/locales/server.ko.yml b/plugins/discourse-presence/config/locales/server.ko.yml index 80a4c1ba0e..a9f2511b4a 100644 --- a/plugins/discourse-presence/config/locales/server.ko.yml +++ b/plugins/discourse-presence/config/locales/server.ko.yml @@ -7,5 +7,5 @@ ko: site_settings: - presence_enabled: '지금 현재의 주제에 답장하는 사용자를 표시하거나 지금의 글을 수정 하시겠습니까?' - presence_max_users_shown: '표시되는 최대 사용자 수입니다.' + presence_enabled: "지금 현재의 주제에 답장하는 사용자를 표시하거나 지금의 글을 수정 하시겠습니까?" + presence_max_users_shown: "표시되는 최대 사용자 수입니다." diff --git a/plugins/discourse-presence/config/locales/server.nb_NO.yml b/plugins/discourse-presence/config/locales/server.nb_NO.yml index bdad24301b..fa8f8d5260 100644 --- a/plugins/discourse-presence/config/locales/server.nb_NO.yml +++ b/plugins/discourse-presence/config/locales/server.nb_NO.yml @@ -7,5 +7,5 @@ nb_NO: site_settings: - presence_enabled: 'Vis brukere som akkurat nå svarer på gjeldende emne, eller redigerer gjeldende innlegg?' - presence_max_users_shown: 'Maksimalt antall brukere som vises.' + presence_enabled: "Vis brukere som akkurat nå svarer på gjeldende emne, eller redigerer gjeldende innlegg?" + presence_max_users_shown: "Maksimalt antall brukere som vises." diff --git a/plugins/discourse-presence/config/locales/server.nl.yml b/plugins/discourse-presence/config/locales/server.nl.yml index 61be2c2d39..9850fb9871 100644 --- a/plugins/discourse-presence/config/locales/server.nl.yml +++ b/plugins/discourse-presence/config/locales/server.nl.yml @@ -7,5 +7,5 @@ nl: site_settings: - presence_enabled: 'Gebruikers tonen die momenteel op het huidige topic antwoorden, of die het huidige bericht bewerken?' - presence_max_users_shown: 'Maximale aantal getoonde gebruikers.' + presence_enabled: "Gebruikers tonen die momenteel op het huidige topic antwoorden, of die het huidige bericht bewerken?" + presence_max_users_shown: "Maximale aantal getoonde gebruikers." diff --git a/plugins/discourse-presence/config/locales/server.pl_PL.yml b/plugins/discourse-presence/config/locales/server.pl_PL.yml index 75a498a1f3..0ad086457a 100644 --- a/plugins/discourse-presence/config/locales/server.pl_PL.yml +++ b/plugins/discourse-presence/config/locales/server.pl_PL.yml @@ -7,5 +7,5 @@ pl_PL: site_settings: - presence_enabled: 'Pokaż użytkowników, którzy aktualnie odpowiadają na bieżący temat lub edytują bieżący wpis?' - presence_max_users_shown: 'Maksymalna liczba pokazywanych użytkowników.' + presence_enabled: "Pokaż użytkowników, którzy aktualnie odpowiadają na bieżący temat lub edytują bieżący wpis?" + presence_max_users_shown: "Maksymalna liczba pokazywanych użytkowników." diff --git a/plugins/discourse-presence/config/locales/server.pt.yml b/plugins/discourse-presence/config/locales/server.pt.yml index 92bc905171..ead949ccda 100644 --- a/plugins/discourse-presence/config/locales/server.pt.yml +++ b/plugins/discourse-presence/config/locales/server.pt.yml @@ -7,5 +7,5 @@ pt: site_settings: - presence_enabled: 'Mostrar os utilizadores que estão a responder no tópico atual, ou a editar a publicação atual?' - presence_max_users_shown: 'Número máximo de utilizadores exibidos.' + presence_enabled: "Mostrar os utilizadores que estão a responder no tópico atual, ou a editar a publicação atual?" + presence_max_users_shown: "Número máximo de utilizadores exibidos." diff --git a/plugins/discourse-presence/config/locales/server.pt_BR.yml b/plugins/discourse-presence/config/locales/server.pt_BR.yml index f9be26cebc..a3dc62adba 100644 --- a/plugins/discourse-presence/config/locales/server.pt_BR.yml +++ b/plugins/discourse-presence/config/locales/server.pt_BR.yml @@ -7,5 +7,5 @@ pt_BR: site_settings: - presence_enabled: 'Mostrar usuários que estão atualmente respondendo ao tópico atual, ou editando a postagem atual?' - presence_max_users_shown: 'Número máximo de usuários exibidos.' + presence_enabled: "Mostrar usuários que estão atualmente respondendo ao tópico atual, ou editando a postagem atual?" + presence_max_users_shown: "Número máximo de usuários exibidos." diff --git a/plugins/discourse-presence/config/locales/server.ro.yml b/plugins/discourse-presence/config/locales/server.ro.yml index bba2871a96..d5da3df1fb 100644 --- a/plugins/discourse-presence/config/locales/server.ro.yml +++ b/plugins/discourse-presence/config/locales/server.ro.yml @@ -7,5 +7,5 @@ ro: site_settings: - presence_enabled: 'Afișează utilizatorii care răspund acum la subiectul curent sau editează subiectul?' - presence_max_users_shown: 'Numărul maxim de utilizatori afișați.' + presence_enabled: "Afișează utilizatorii care răspund acum la subiectul curent sau editează subiectul?" + presence_max_users_shown: "Numărul maxim de utilizatori afișați." diff --git a/plugins/discourse-presence/config/locales/server.ru.yml b/plugins/discourse-presence/config/locales/server.ru.yml index b11ac84378..96b5428fa4 100644 --- a/plugins/discourse-presence/config/locales/server.ru.yml +++ b/plugins/discourse-presence/config/locales/server.ru.yml @@ -7,5 +7,5 @@ ru: site_settings: - presence_enabled: 'Показать пользователей, которые отвечают на текущую тему или редактируют текущий пост прямо сейчас?' - presence_max_users_shown: 'Максимальное отражаемое количество пользователей, которые отвечают прямо сейчас.' + presence_enabled: "Показать пользователей, которые отвечают на текущую тему или редактируют текущий пост прямо сейчас?" + presence_max_users_shown: "Максимальное отражаемое количество пользователей, которые отвечают прямо сейчас." diff --git a/plugins/discourse-presence/config/locales/server.sk.yml b/plugins/discourse-presence/config/locales/server.sk.yml index f1324fa754..e379ba7a25 100644 --- a/plugins/discourse-presence/config/locales/server.sk.yml +++ b/plugins/discourse-presence/config/locales/server.sk.yml @@ -7,5 +7,5 @@ sk: site_settings: - presence_enabled: 'Chcete zobraziť používateľov, ktorí momentálne odpovedajú na aktuálnu tému, alebo upravujú aktuálny príspevok?' - presence_max_users_shown: 'Mazimálny počet zobrazených používateľov.' + presence_enabled: "Chcete zobraziť používateľov, ktorí momentálne odpovedajú na aktuálnu tému, alebo upravujú aktuálny príspevok?" + presence_max_users_shown: "Mazimálny počet zobrazených používateľov." diff --git a/plugins/discourse-presence/config/locales/server.sl.yml b/plugins/discourse-presence/config/locales/server.sl.yml index c78811cd11..9da96d7378 100644 --- a/plugins/discourse-presence/config/locales/server.sl.yml +++ b/plugins/discourse-presence/config/locales/server.sl.yml @@ -7,5 +7,5 @@ sl: site_settings: - presence_enabled: 'Pokaži uporabnike, ki trenutno odgovarjajo na odprto temo ali urejujejo objavo?' - presence_max_users_shown: 'Maksimalno prikazano število uporabnikov.' + presence_enabled: "Pokaži uporabnike, ki trenutno odgovarjajo na odprto temo ali urejujejo objavo?" + presence_max_users_shown: "Maksimalno prikazano število uporabnikov." diff --git a/plugins/discourse-presence/config/locales/server.sr.yml b/plugins/discourse-presence/config/locales/server.sr.yml index 5e01d18a51..809f5a4706 100644 --- a/plugins/discourse-presence/config/locales/server.sr.yml +++ b/plugins/discourse-presence/config/locales/server.sr.yml @@ -7,4 +7,4 @@ sr: site_settings: - presence_enabled: 'Prikaži da korisnici trenutno kucaju odgovor ili menjaju poruku' + presence_enabled: "Prikaži da korisnici trenutno kucaju odgovor ili menjaju poruku" diff --git a/plugins/discourse-presence/config/locales/server.sw.yml b/plugins/discourse-presence/config/locales/server.sw.yml index a27006af01..861a144406 100644 --- a/plugins/discourse-presence/config/locales/server.sw.yml +++ b/plugins/discourse-presence/config/locales/server.sw.yml @@ -7,5 +7,5 @@ sw: site_settings: - presence_enabled: 'Onyesha watumiaji ambao wanaongelea mada ya sasa, au wana hariri mada?' - presence_max_users_shown: 'Kiwango cha juu cha watumiaji kilicho onyeshwa.' + presence_enabled: "Onyesha watumiaji ambao wanaongelea mada ya sasa, au wana hariri mada?" + presence_max_users_shown: "Kiwango cha juu cha watumiaji kilicho onyeshwa." diff --git a/plugins/discourse-presence/config/locales/server.uk.yml b/plugins/discourse-presence/config/locales/server.uk.yml index 565efc5398..9a5f332d5a 100644 --- a/plugins/discourse-presence/config/locales/server.uk.yml +++ b/plugins/discourse-presence/config/locales/server.uk.yml @@ -7,5 +7,5 @@ uk: site_settings: - presence_enabled: 'Показати користувачів, які зараз відповідають на поточну тему чи редагують поточну публікацію?' - presence_max_users_shown: 'Максимальна кількість показаних користувачів.' + presence_enabled: "Показати користувачів, які зараз відповідають на поточну тему чи редагують поточну публікацію?" + presence_max_users_shown: "Максимальна кількість показаних користувачів." diff --git a/plugins/discourse-presence/config/locales/server.ur.yml b/plugins/discourse-presence/config/locales/server.ur.yml index 583c94a21a..73dad64d3c 100644 --- a/plugins/discourse-presence/config/locales/server.ur.yml +++ b/plugins/discourse-presence/config/locales/server.ur.yml @@ -7,5 +7,5 @@ ur: site_settings: - presence_enabled: 'صارفین کو دکھائیں جو فی الحال موجودہ موضوع کا جواب دے رہے ہیں، یا موجودہ پوسٹ میں ترمیم کر رہے ہیں؟' - presence_max_users_shown: 'دکھائے گئے صارفین کی زیادہ سے زیادہ تعداد۔' + presence_enabled: "صارفین کو دکھائیں جو فی الحال موجودہ موضوع کا جواب دے رہے ہیں، یا موجودہ پوسٹ میں ترمیم کر رہے ہیں؟" + presence_max_users_shown: "دکھائے گئے صارفین کی زیادہ سے زیادہ تعداد۔" diff --git a/plugins/discourse-presence/config/locales/server.vi.yml b/plugins/discourse-presence/config/locales/server.vi.yml index a4eeab0d58..123ba83e3b 100644 --- a/plugins/discourse-presence/config/locales/server.vi.yml +++ b/plugins/discourse-presence/config/locales/server.vi.yml @@ -7,4 +7,4 @@ vi: site_settings: - presence_max_users_shown: 'Số lượng người dùng tối đa được hiển thị.' + presence_max_users_shown: "Số lượng người dùng tối đa được hiển thị." diff --git a/plugins/discourse-presence/config/locales/server.zh_CN.yml b/plugins/discourse-presence/config/locales/server.zh_CN.yml index 75928a8176..0671316e0b 100644 --- a/plugins/discourse-presence/config/locales/server.zh_CN.yml +++ b/plugins/discourse-presence/config/locales/server.zh_CN.yml @@ -7,5 +7,5 @@ zh_CN: site_settings: - presence_enabled: '显示正在回复或者编辑当前主题的用户' - presence_max_users_shown: '展示用户数量的最大值。' + presence_enabled: "显示正在回复或者编辑当前主题的用户" + presence_max_users_shown: "展示用户数量的最大值。" From f611aa6ada7b9f63789c283b9b3a7f86e1b9ae25 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Wed, 6 Nov 2019 16:13:12 +0000 Subject: [PATCH 327/328] FIX: Correct translation key for api key revoke button --- app/assets/javascripts/admin/templates/api-keys-index.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/templates/api-keys-index.hbs b/app/assets/javascripts/admin/templates/api-keys-index.hbs index 19999029ea..a0d5bf9f77 100644 --- a/app/assets/javascripts/admin/templates/api-keys-index.hbs +++ b/app/assets/javascripts/admin/templates/api-keys-index.hbs @@ -52,7 +52,7 @@ {{d-button action=(action "undoRevokeKey") actionParam=k icon="undo" - title="admin.api.undo-revoke"}} + title="admin.api.undo_revoke"}} {{else}} {{d-button class="btn-danger" From 1aa96a5da40ccdf068fdc6532a3ff7c9a26a4520 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Wed, 6 Nov 2019 12:31:03 -0500 Subject: [PATCH 328/328] Version bump to v2.4.0.beta7 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 2116856b1b..748dd2f438 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -9,7 +9,7 @@ module Discourse MAJOR = 2 MINOR = 4 TINY = 0 - PRE = 'beta6' + PRE = 'beta7' STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end